- Notifications
You must be signed in to change notification settings - Fork187
Go HardWare discovery/inspection library
License
jaypipes/ghw
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
ghw
is a Go library providing hardware inspection and discovery for Linux andWindows. There currently exists partial support for MacOSX.
No root privileges needed for discovery
ghw
goes the extra mile to be useful without root priveleges. We query forhost hardware information as directly as possible without relying on shelloutsto programs likedmidecode
that require root privileges to execute.Elevated privileges are indeed required to query for some information, but
ghw
will never error out if blocked from reading that information. Instead,ghw
will print a warning message about the information that could not beretrieved. You may disable these warning messages with theGHW_DISABLE_WARNINGS
environment variable.Well-documented code and plenty of example code
The code itself should be well-documented with lots of usage examples.
Interfaces should be consistent across modules
Each module in the library should be structured in a consistent fashion, andthe structs returned by various library functions should have consistentattribute and method names.
ghw
is a tool for gathering information about your hardware'scapacityandcapabilities.
It is important to point out thatghw
doesNOT report information that istemporary or variable. It isNOT a system monitor nor is it an appropriatetool for gathering data points for metrics that change over time. If you arelooking for a system that tracksusage of CPU, memory, network I/O or diskI/O, there are plenty of great open source tools that do this! Check out thePrometheus project for a great example.
ghw
has functions that return anInfo
object about a particular hardwaredomain (e.g. CPU, Memory, Block storage, etc).
Use the following functions inghw
to inspect information about the hosthardware:
ghw.CPU()
ghw.Memory()
ghw.Block()
(block storage)ghw.Topology()
(processor architecture, NUMA topology andmemory cache hierarchy)ghw.Network()
ghw.PCI()
ghw.GPU()
(graphical processing unit)ghw.Accelerator()
(processing accelerators, AI)ghw.Chassis()
ghw.BIOS()
ghw.Baseboard()
ghw.Product()
Theghw.CPU()
function returns aghw.CPUInfo
struct that containsinformation about the CPUs on the host system.
ghw.CPUInfo
contains the following fields:
ghw.CPUInfo.TotalCores
has the total number of physical cores the hostsystem containsghw.CPUInfo.TotalHardwareThreads
has the total number of hardware threadsthe host system containsghw.CPUInfo.Processors
is an array ofghw.Processor
structs, one for eachphysical processor package contained in the host
Eachghw.Processor
struct contains a number of fields:
ghw.Processor.ID
is the physical processoruint32
ID according to thesystemghw.Processor.TotalCores
is the number of physical cores in the processorpackageghw.Processor.TotalHardwareThreads
is the number of hardware threads in theprocessor packageghw.Processor.Vendor
is a string containing the vendor nameghw.Processor.Model
is a string containing the vendor's model nameghw.Processor.Capabilities
(Linux only) is an array of strings indicatingthe features the processor has enabledghw.Processor.Cores
(Linux only) is an array ofghw.ProcessorCore
structsthat are packed onto this physical processor
Aghw.ProcessorCore
has the following fields:
ghw.ProcessorCore.ID
is theuint32
identifier that the host gave thiscore. Note that this doesnot necessarily equate to a zero-based index ofthe core within a physical package. For example, the core IDs for an Intel Corei7 are 0, 1, 2, 8, 9, and 10ghw.ProcessorCore.TotalHardwareThreads
is the number of hardware threadsassociated with the coreghw.ProcessorCore.LogicalProcessors
is an array of ints representing thelogical processor IDs assigned to any processing unit for the core. These aresometimes called the "thread siblings". Logical processor IDs are thezero-based index of the processor on the host and arenot related to thecore ID.
package mainimport ("fmt""math""strings""github.com/jaypipes/ghw")funcmain() {cpu,err:=ghw.CPU()iferr!=nil {fmt.Printf("Error getting CPU info: %v",err)}fmt.Printf("%v\n",cpu)for_,proc:=rangecpu.Processors {fmt.Printf(" %v\n",proc)for_,core:=rangeproc.Cores {fmt.Printf(" %v\n",core)}iflen(proc.Capabilities)>0 {// pretty-print the (large) block of capability strings into rows// of 6 capability stringsrows:=int(math.Ceil(float64(len(proc.Capabilities))/float64(6)))forrow:=1;row<rows;row=row+1 {rowStart:= (row*6)-1rowEnd:=int(math.Min(float64(rowStart+6),float64(len(proc.Capabilities))))rowElems:=proc.Capabilities[rowStart:rowEnd]capStr:=strings.Join(rowElems," ")ifrow==1 {fmt.Printf(" capabilities: [%s\n",capStr)}elseifrowEnd<len(proc.Capabilities) {fmt.Printf(" %s\n",capStr)}else {fmt.Printf(" %s]\n",capStr)}}}}}
Example output from my personal workstation:
cpu (1 physical package, 6 cores, 12 hardware threads) physical package #0 (6 cores, 12 hardware threads) processor core #0 (2 threads), logical processors [0 6] processor core #1 (2 threads), logical processors [1 7] processor core #2 (2 threads), logical processors [2 8] processor core #3 (2 threads), logical processors [3 9] processor core #4 (2 threads), logical processors [4 10] processor core #5 (2 threads), logical processors [5 11] capabilities: [msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 popcnt aes lahf_lm pti retpoline tpr_shadow vnmi flexpriority ept vpid dtherm ida arat]
Theghw.Memory()
function returns aghw.MemoryInfo
struct that containsinformation about the RAM on the host system.
ghw.MemoryInfo
contains the following fields:
ghw.MemoryInfo.TotalPhysicalBytes
contains the amount of physical memory onthe hostghw.MemoryInfo.TotalUsableBytes
contains the amount of memory thesystem can actually use. Usable memory accounts for things like the kernel'sresident memory size and some reserved system bits. Please note this value isNOT the amount of memory currently in use by processes in the system. See[the discussion][#physical-versus-usage-memory] about the difference.ghw.MemoryInfo.SupportedPageSizes
is an array of integers representing thesize, in bytes, of memory pages the system supportsghw.MemoryInfo.Modules
is an array of pointers toghw.MemoryModule
structs, one for each physicalDIMM.Currently, this information is only included on Windows, with Linux supportplanned.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {memory,err:=ghw.Memory()iferr!=nil {fmt.Printf("Error getting memory info: %v",err)}fmt.Println(memory.String())}
Example output from my personal workstation:
memory (24GB physical, 24GB usable)
There has beensomeconfusion regarding thedifference between the total physical bytes versus total usable bytes ofmemory.
Some of this confusion has been due to a misunderstanding of the term "usable".As mentionedabove,ghw
does inspection of thesystem's capacity.
A host computer has two capacities when it comes to RAM. The first capacity isthe amount of RAM that is contained in all memory banks (DIMMs) that areattached to the motherboard.ghw.MemoryInfo.TotalPhysicalBytes
refers to thisfirst capacity.
There is a (usually small) amount of RAM that is consumed by the bootloaderbefore the operating system is started (booted). Once the bootloader has bootedthe operating system, the amount of RAM that may be used by the operatingsystem and its applications is fixed.ghw.MemoryInfo.TotalUsableBytes
refersto this second capacity.
You can determine the amount of RAM that the bootloader used (that is not madeavailable to the operating system) by subtractingghw.MemoryInfo.TotalUsableBytes
fromghw.MemoryInfo.TotalPhysicalBytes
:
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {memory,err:=ghw.Memory()iferr!=nil {fmt.Printf("Error getting memory info: %v",err)}phys:=memory.TotalPhysicalBytesusable:=memory.TotalUsableBytesfmt.Printf("The bootloader consumes %d bytes of RAM\n",phys-usable)}
Example output from my personal workstation booted into a Windows10 operatingsystem with a Linux GRUB bootloader:
The bootloader consumes 3832720 bytes of RAM
Theghw.Block()
function returns aghw.BlockInfo
struct that containsinformation about the block storage on the host system.
ghw.BlockInfo
contains the following fields:
ghw.BlockInfo.TotalSizeBytes
contains the amount of physical block storageon the host.ghw.BlockInfo.Disks
is an array of pointers toghw.Disk
structs, one foreach disk found by the system
Eachghw.Disk
struct contains the following fields:
ghw.Disk.Name
contains a string with the short name of the disk, e.g. "sda"ghw.Disk.SizeBytes
contains the amount of storage the disk providesghw.Disk.PhysicalBlockSizeBytes
contains the size of the physical blocksused on the disk, in bytes. This is typically the minimum amount of data thatwill be written in a single write operation for the disk.ghw.Disk.IsRemovable
contains a boolean indicating if the disk drive isremovableghw.Disk.DriveType
is the type of drive. It is of typeghw.DriveType
which has aghw.DriveType.String()
method that can be called to return astring representation of the bus. This string will beHDD
,FDD
,ODD
,orSSD
, which correspond to a hard disk drive (rotational), floppy drive,optical (CD/DVD) drive and solid-state drive.ghw.Disk.StorageController
is the type of storage controller. It is of typeghw.StorageController
which has aghw.StorageController.String()
methodthat can be called to return a string representation of the bus. This stringwill beSCSI
,IDE
,virtio
,MMC
, orNVMe
ghw.Disk.BusPath
(Linux, Darwin only) is the filepath to the bus used bythe disk.ghw.Disk.NUMANodeID
(Linux only) is the numeric index of the NUMA node thisdisk is local to, or -1 if the host system is not a NUMA system or is notLinux.ghw.Disk.Vendor
contains a string with the name of the hardware vendor forthe diskghw.Disk.Model
contains a string with the vendor-assigned disk model nameghw.Disk.SerialNumber
contains a string with the disk's serial numberghw.Disk.WWN
contains a string with the disk'sWorld Wide Nameghw.Disk.Partitions
contains an array of pointers toghw.Partition
structs, one for each partition on the disk
Eachghw.Partition
struct contains these fields:
ghw.Partition.Name
contains a string with the short name of the partition,e.g.sda1
ghw.Partition.Label
contains the label for the partition itself. On Linuxsystems, this is derived from theID_PART_ENTRY_NAME
udev entry forthe partition.ghw.Partition.FilesystemLabel
contains the label for the filesystem housedon the partition. On Linux systems, this is derived from theID_FS_NAME
udev entry for the partition.ghw.Partition.SizeBytes
contains the amount of storage the partitionprovidesghw.Partition.MountPoint
contains a string with the partition's mountpoint, or""
if no mount point was discoveredghw.Partition.Type
contains a string indicated the filesystem type for thepartition, or""
if the system could not determine the typeghw.Partition.IsReadOnly
is a bool indicating the partition is read-onlyghw.Partition.Disk
is a pointer to theghw.Disk
object associated withthe partition.ghw.Partition.UUID
is a string containing the partition UUID on Linux, thepartition UUID on MacOS and nothing on Windows. On Linux systems, this isderived from theID_PART_ENTRY_UUID
udev entry for the partition.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {block,err:=ghw.Block()iferr!=nil {fmt.Printf("Error getting block storage info: %v",err)}fmt.Printf("%v\n",block)for_,disk:=rangeblock.Disks {fmt.Printf(" %v\n",disk)for_,part:=rangedisk.Partitions {fmt.Printf(" %v\n",part)}}}
Example output from my personal workstation:
block storage (1 disk, 2TB physical storage) sda HDD (2TB) SCSI [@pci-0000:04:00.0-scsi-0:1:0:0 (node #0)] vendor=LSI model=Logical_Volume serial=600508e000000000f8253aac9a1abd0c WWN=0x600508e000000000f8253aac9a1abd0c /dev/sda1 (100MB) /dev/sda2 (187GB) /dev/sda3 (449MB) /dev/sda4 (1KB) /dev/sda5 (15GB) /dev/sda6 (2TB) [ext4] mounted@/
NOTE:
ghw
looks in the udev runtime database for some information. Ifyou are usingghw
in a container, remember to bind mount/dev/disk
and/run
into your container, otherwiseghw
won't be able to query the udevDB or sysfs paths for information.
NOTE: Topology support is currently Linux-only. Windows support isplanned.
Theghw.Topology()
function returns aghw.TopologyInfo
struct that containsinformation about the host computer's architecture (NUMA vs. SMP), the host'sNUMA node layout and processor-specific memory caches.
Theghw.TopologyInfo
struct contains two fields:
ghw.TopologyInfo.Architecture
contains an enum with the valueghw.NUMA
orghw.SMP
depending on what the topology of the system isghw.TopologyInfo.Nodes
is an array of pointers toghw.TopologyNode
structs, one for each topology node (typically physical processor package)found by the system
Eachghw.TopologyNode
struct contains the following fields:
ghw.TopologyNode.ID
is the system'suint32
identifier for the nodeghw.TopologyNode.Memory
is aghw.MemoryArea
struct describing the memoryattached to this node.ghw.TopologyNode.Cores
is an array of pointers toghw.ProcessorCore
structs thatare contained in this nodeghw.TopologyNode.Caches
is an array of pointers toghw.MemoryCache
structs thatrepresent the low-level caches associated with processors and cores on thesystemghw.TopologyNode.Distance
is an array of distances between NUMA nodes as reportedby the system.
ghw.MemoryArea
describes a collection ofphysical RAM on the host.
In the simplest and most common case, all system memory fits in a single memoryarea. In more complex host systems, likeNUMA systems, many memoryareas may be present in the host system (e.g. one for each NUMA cell).
Theghw.MemoryArea
struct contains the following fields:
ghw.MemoryArea.TotalPhysicalBytes
contains the amount of physical memoryassociated with this memory area.ghw.MemoryArea.TotalUsableBytes
contains the amount of memory of thismemory area the system can actually use. Usable memory accounts for thingslike the kernel's resident memory size and some reserved system bits. Pleasenote this value isNOT the amount of memory currently in use by processesin the system. See [the discussion][#physical-versus-usage-memory] aboutthe difference.
See above in theCPU section for information about theghw.ProcessorCore
struct and how to use and query it.
Eachghw.MemoryCache
struct contains the following fields:
ghw.MemoryCache.Type
is an enum that contains one ofghw.DATA
,ghw.INSTRUCTION
orghw.UNIFIED
depending on whether the cache stores CPUinstructions, program data, or bothghw.MemoryCache.Level
is a positive integer indicating how close the cacheis to the processor. The lower the number, the closer the cache is to theprocessor and the faster the processor can access its contentsghw.MemoryCache.SizeBytes
is an integer containing the number of bytes thecache can containghw.MemoryCache.LogicalProcessors
is an array of integers representing thelogical processors that use the cache
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {topology,err:=ghw.Topology()iferr!=nil {fmt.Printf("Error getting topology info: %v",err)}fmt.Printf("%v\n",topology)for_,node:=rangetopology.Nodes {fmt.Printf(" %v\n",node)for_,cache:=rangenode.Caches {fmt.Printf(" %v\n",cache)}}}
Example output from my personal workstation:
topology SMP (1 nodes) node #0 (6 cores) L1i cache (32 KB) shared with logical processors: 3,9 L1i cache (32 KB) shared with logical processors: 2,8 L1i cache (32 KB) shared with logical processors: 11,5 L1i cache (32 KB) shared with logical processors: 10,4 L1i cache (32 KB) shared with logical processors: 0,6 L1i cache (32 KB) shared with logical processors: 1,7 L1d cache (32 KB) shared with logical processors: 11,5 L1d cache (32 KB) shared with logical processors: 10,4 L1d cache (32 KB) shared with logical processors: 3,9 L1d cache (32 KB) shared with logical processors: 1,7 L1d cache (32 KB) shared with logical processors: 0,6 L1d cache (32 KB) shared with logical processors: 2,8 L2 cache (256 KB) shared with logical processors: 2,8 L2 cache (256 KB) shared with logical processors: 3,9 L2 cache (256 KB) shared with logical processors: 0,6 L2 cache (256 KB) shared with logical processors: 10,4 L2 cache (256 KB) shared with logical processors: 1,7 L2 cache (256 KB) shared with logical processors: 11,5 L3 cache (12288 KB) shared with logical processors: 0,1,10,11,2,3,4,5,6,7,8,9
Theghw.Network()
function returns aghw.NetworkInfo
struct that containsinformation about the host computer's networking hardware.
Theghw.NetworkInfo
struct contains one field:
ghw.NetworkInfo.NICs
is an array of pointers toghw.NIC
structs, onefor each network interface controller found for the systen
Eachghw.NIC
struct contains the following fields:
ghw.NIC.Name
is the system's identifier for the NICghw.NIC.MACAddress
is the Media Access Control (MAC) address for the NIC,if anyghw.NIC.IsVirtual
is a boolean indicating if the NIC is a virtualizeddeviceghw.NIC.Capabilities
(Linux only) is an array of pointers toghw.NICCapability
structs that can describe the things the NIC supports.These capabilities match the returned values from theethtool -k <DEVICE>
call on Linux as well as the AutoNegotiation and PauseFrameUse capabilitiesfromethtool
.ghw.NIC.PCIAddress
(Linux only) is the PCI device address of the devicebacking the NIC. this is not-nil only if the backing device is indeed a PCIdevice; more backing devices (e.g. USB) will be added in future versions.ghw.NIC.Speed
(Linux only) is a string showing the current link speed. OnLinux, this field will be present even ifethtool
is not available.ghw.NIC.Duplex
(Linux only) is a string showing the current link duplex. OnLinux, this field will be present even ifethtool
is not available.ghw.NIC.SupportedLinkModes
(Linux only) is a string slice containing a listof supported link modes, e.g. "10baseT/Half", "1000baseT/Full".ghw.NIC.SupportedPorts
(Linux only) is a string slice containing the listof supported port types, e.g. "MII", "TP", "FIBRE", "Twisted Pair".ghw.NIC.SupportedFECModes
(Linux only) is a string slice containing a listof supported Forward Error Correction (FEC) Modes.ghw.NIC.AdvertisedLinkModes
(Linux only) is a string slice containing thelink modes being advertised during auto negotiation.ghw.NIC.AdvertisedFECModes
(Linux only) is a string slice containing theForward Error Correction (FEC) modes advertised during auto negotiation.
Theghw.NICCapability
struct contains the following fields:
ghw.NICCapability.Name
is the string name of the capability (e.g."tcp-segmentation-offload")ghw.NICCapability.IsEnabled
is a boolean indicating whether the capabilityis currently enabled/active on the NICghw.NICCapability.CanEnable
is a boolean indicating whether the capabilitymay be enabled
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {net,err:=ghw.Network()iferr!=nil {fmt.Printf("Error getting network info: %v",err) }fmt.Printf("%v\n",net)for_,nic:=rangenet.NICs {fmt.Printf(" %v\n",nic)enabledCaps:=make([]int,0)forx,cap:=rangenic.Capabilities {ifcap.IsEnabled {enabledCaps=append(enabledCaps,x) } }iflen(enabledCaps)>0 {fmt.Printf(" enabled capabilities:\n")for_,x:=rangeenabledCaps {fmt.Printf(" - %s\n",nic.Capabilities[x].Name) } } }}
Example output from my personal laptop:
net (3 NICs) docker0 enabled capabilities: - tx-checksumming - tx-checksum-ip-generic - scatter-gather - tx-scatter-gather - tx-scatter-gather-fraglist - tcp-segmentation-offload - tx-tcp-segmentation - tx-tcp-ecn-segmentation - tx-tcp-mangleid-segmentation - tx-tcp6-segmentation - udp-fragmentation-offload - generic-segmentation-offload - generic-receive-offload - tx-vlan-offload - highdma - tx-lockless - netns-local - tx-gso-robust - tx-fcoe-segmentation - tx-gre-segmentation - tx-gre-csum-segmentation - tx-ipxip4-segmentation - tx-ipxip6-segmentation - tx-udp_tnl-segmentation - tx-udp_tnl-csum-segmentation - tx-gso-partial - tx-sctp-segmentation - tx-esp-segmentation - tx-vlan-stag-hw-insert enp58s0f1 enabled capabilities: - rx-checksumming - generic-receive-offload - rx-vlan-offload - tx-vlan-offload - highdma - auto-negotiation wlp59s0 enabled capabilities: - scatter-gather - tx-scatter-gather - generic-segmentation-offload - generic-receive-offload - highdma - netns-local
ghw
contains a PCI database inspection and querying facility that allowsdevelopers to not only gather information about devices on a local PCI bus butalso query for information about hardware device classes, vendor and productinformation.
NOTE: Parsing of the PCI-IDS file database is provided by the separategithub.com/jaypipes/pcidb library. Youcan read that library's README for more information about the various structsthat are exposed on the
ghw.PCIInfo
struct.
Theghw.PCI()
function returns aghw.PCIInfo
struct that containsinformation about the host computer's PCI devices.
Theghw.PCIInfo
struct contains one field:
ghw.PCIInfo.Devices
is a slice of pointers toghw.PCIDevice
structs thatdescribe the PCI devices on the host system
NOTE: PCI products are often referred to by their "device ID". We use theterm "product ID" in
ghw
because it more accurately reflects what theidentifier is for: a specific product line produced by the vendor.
Theghw.PCIDevice
struct has the following fields:
ghw.PCIDevice.Vendor
is a pointer to apcidb.Vendor
struct thatdescribes the device's primary vendor. This will always be non-nil.ghw.PCIDevice.Product
is a pointer to apcidb.Product
struct thatdescribes the device's primary product. This will always be non-nil.ghw.PCIDevice.Subsystem
is a pointer to apcidb.Product
struct thatdescribes the device's secondary/sub-product. This will always be non-nil.ghw.PCIDevice.Class
is a pointer to apcidb.Class
struct thatdescribes the device's class. This will always be non-nil.ghw.PCIDevice.Subclass
is a pointer to apcidb.Subclass
structthat describes the device's subclass. This will always be non-nil.ghw.PCIDevice.ProgrammingInterface
is a pointer to apcidb.ProgrammingInterface
struct that describes the device subclass'programming interface. This will always be non-nil.ghw.PCIDevice.Driver
is a string representing the device driver thesystem is using to handle this device. Can be empty string if thisinformation is not available. If the information is not available, this doesnot mean the device is not functioning, but rather thatghw
was not able toretrieve driver information.
Theghw.PCIAddress
(which is an alias for theghw.pci.address.Address
struct) contains the PCI address fields. It has aghw.PCIAddress.String()
method that returns the canonical Domain:Bus:Device.Function ([D]BDF)representation of this Address.
Theghw.PCIAddress
struct has the following fields:
ghw.PCIAddress.Domain
is a string representing the PCI domain component ofthe address.ghw.PCIAddress.Bus
is a string representing the PCI bus component ofthe address.ghw.PCIAddress.Device
is a string representing the PCI device component ofthe address.ghw.PCIAddress.Function
is a string representing the PCI function component ofthe address.
NOTE: Older versions (pre-
v0.9.0
) erroneously referred to theDevice
field as theSlot
field. As noted by@pearsonkin#220, this was a misnomer.
The following code snippet shows how to list the PCI devices on the host systemand output a simple list of PCI address and vendor/product information:
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {pci,err:=ghw.PCI()iferr!=nil {fmt.Printf("Error getting PCI info: %v",err)}fmt.Printf("host PCI devices:\n")fmt.Println("====================================================")for_,device:=rangepci.Devices {vendor:=device.VendorvendorName:=vendor.Nameiflen(vendor.Name)>20 {vendorName=string([]byte(vendorName)[0:17])+"..."}product:=device.ProductproductName:=product.Nameiflen(product.Name)>40 {productName=string([]byte(productName)[0:37])+"..."}fmt.Printf("%-12s\t%-20s\t%-40s\n",device.Address,vendorName,productName)}}
on my local workstation the output of the above looks like the following:
host PCI devices:====================================================0000:00:00.0Intel Corporation 5520/5500/X58 I/O Hub to ESI Port0000:00:01.0Intel Corporation 5520/5500/X58 I/O Hub PCI Express Roo...0000:00:02.0Intel Corporation 5520/5500/X58 I/O Hub PCI Express Roo...0000:00:03.0Intel Corporation 5520/5500/X58 I/O Hub PCI Express Roo...0000:00:07.0Intel Corporation 5520/5500/X58 I/O Hub PCI Express Roo...0000:00:10.0Intel Corporation 7500/5520/5500/X58 Physical and Link ...0000:00:10.1Intel Corporation 7500/5520/5500/X58 Routing and Protoc...0000:00:14.0Intel Corporation 7500/5520/5500/X58 I/O Hub System Man...0000:00:14.1Intel Corporation 7500/5520/5500/X58 I/O Hub GPIO and S...0000:00:14.2Intel Corporation 7500/5520/5500/X58 I/O Hub Control St...0000:00:14.3Intel Corporation 7500/5520/5500/X58 I/O Hub Throttle R...0000:00:19.0Intel Corporation 82567LF-2 Gigabit Network Connection0000:00:1a.0Intel Corporation 82801JI (ICH10 Family) USB UHCI Contr...0000:00:1a.1Intel Corporation 82801JI (ICH10 Family) USB UHCI Contr...0000:00:1a.2Intel Corporation 82801JI (ICH10 Family) USB UHCI Contr...0000:00:1a.7Intel Corporation 82801JI (ICH10 Family) USB2 EHCI Cont...0000:00:1b.0Intel Corporation 82801JI (ICH10 Family) HD Audio Contr...0000:00:1c.0Intel Corporation 82801JI (ICH10 Family) PCI Express Ro...0000:00:1c.1Intel Corporation 82801JI (ICH10 Family) PCI Express Po...0000:00:1c.4Intel Corporation 82801JI (ICH10 Family) PCI Express Ro...0000:00:1d.0Intel Corporation 82801JI (ICH10 Family) USB UHCI Contr...0000:00:1d.1Intel Corporation 82801JI (ICH10 Family) USB UHCI Contr...0000:00:1d.2Intel Corporation 82801JI (ICH10 Family) USB UHCI Contr...0000:00:1d.7Intel Corporation 82801JI (ICH10 Family) USB2 EHCI Cont...0000:00:1e.0Intel Corporation 82801 PCI Bridge0000:00:1f.0Intel Corporation 82801JIR (ICH10R) LPC Interface Contr...0000:00:1f.2Intel Corporation 82801JI (ICH10 Family) SATA AHCI Cont...0000:00:1f.3Intel Corporation 82801JI (ICH10 Family) SMBus Controller0000:01:00.0NEC Corporation uPD720200 USB 3.0 Host Controller0000:02:00.0Marvell Technolog...88SE9123 PCIe SATA 6.0 Gb/s controller0000:02:00.1Marvell Technolog...88SE912x IDE Controller0000:03:00.0NVIDIA Corporation GP107 [GeForce GTX 1050 Ti]0000:03:00.1NVIDIA Corporation UNKNOWN0000:04:00.0LSI Logic / Symbi...SAS2004 PCI-Express Fusion-MPT SAS-2 ...0000:06:00.0Qualcomm Atheros AR5418 Wireless Network Adapter [AR50...0000:08:03.0LSI Corporation FW322/323 [TrueFire] 1394a Controller0000:3f:00.0Intel Corporation UNKNOWN0000:3f:00.1Intel Corporation Xeon 5600 Series QuickPath Architectu...0000:3f:02.0Intel Corporation Xeon 5600 Series QPI Link 00000:3f:02.1Intel Corporation Xeon 5600 Series QPI Physical 00000:3f:02.2Intel Corporation Xeon 5600 Series Mirror Port Link 00000:3f:02.3Intel Corporation Xeon 5600 Series Mirror Port Link 10000:3f:03.0Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:03.1Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:03.4Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:04.0Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:04.1Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:04.2Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:04.3Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:05.0Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:05.1Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:05.2Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:05.3Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:06.0Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:06.1Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:06.2Intel Corporation Xeon 5600 Series Integrated Memory Co...0000:3f:06.3Intel Corporation Xeon 5600 Series Integrated Memory Co...
In addition to the above information, theghw.PCIInfo
struct has thefollowing method:
ghw.PCIInfo.GetDevice(address string)
The following code snippet shows how to call theghw.PCIInfo.GetDevice()
method and use its returnedghw.PCIDevice
struct pointer:
package mainimport ("fmt""os""github.com/jaypipes/ghw")funcmain() {pci,err:=ghw.PCI()iferr!=nil {fmt.Printf("Error getting PCI info: %v",err)}addr:="0000:00:00.0"iflen(os.Args)==2 {addr=os.Args[1]}fmt.Printf("PCI device information for %s\n",addr)fmt.Println("====================================================")deviceInfo:=pci.GetDevice(addr)ifdeviceInfo==nil {fmt.Printf("could not retrieve PCI device information for %s\n",addr)return}vendor:=deviceInfo.Vendorfmt.Printf("Vendor: %s [%s]\n",vendor.Name,vendor.ID)product:=deviceInfo.Productfmt.Printf("Product: %s [%s]\n",product.Name,product.ID)subsystem:=deviceInfo.Subsystemsubvendor:=pci.Vendors[subsystem.VendorID]subvendorName:="UNKNOWN"ifsubvendor!=nil {subvendorName=subvendor.Name}fmt.Printf("Subsystem: %s [%s] (Subvendor: %s)\n",subsystem.Name,subsystem.ID,subvendorName)class:=deviceInfo.Classfmt.Printf("Class: %s [%s]\n",class.Name,class.ID)subclass:=deviceInfo.Subclassfmt.Printf("Subclass: %s [%s]\n",subclass.Name,subclass.ID)progIface:=deviceInfo.ProgrammingInterfacefmt.Printf("Programming Interface: %s [%s]\n",progIface.Name,progIface.ID)}
Here's a sample output from my local workstation:
PCI device information for 0000:03:00.0====================================================Vendor: NVIDIA Corporation [10de]Product: GP107 [GeForce GTX 1050 Ti] [1c82]Subsystem: UNKNOWN [8613] (Subvendor: ASUSTeK Computer Inc.)Class: Display controller [03]Subclass: VGA compatible controller [00]Programming Interface: VGA controller [00]
Theghw.GPU()
function returns aghw.GPUInfo
struct that containsinformation about the host computer's graphics hardware.
Theghw.GPUInfo
struct contains one field:
ghw.GPUInfo.GraphicCards
is an array of pointers toghw.GraphicsCard
structs, one for each graphics card found for the system
Eachghw.GraphicsCard
struct contains the following fields:
ghw.GraphicsCard.Index
is the system's numeric zero-based index for thecard on the busghw.GraphicsCard.Address
is the PCI address for the graphics cardghw.GraphicsCard.DeviceInfo
is a pointer to aghw.PCIDevice
structdescribing the graphics card. This may benil
if no PCI device informationcould be determined for the card.ghw.GraphicsCard.Node
is an pointer to aghw.TopologyNode
struct that theGPU/graphics card is affined to. On non-NUMA systems, this will always benil
.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {gpu,err:=ghw.GPU()iferr!=nil {fmt.Printf("Error getting GPU info: %v",err)}fmt.Printf("%v\n",gpu)for_,card:=rangegpu.GraphicsCards {fmt.Printf(" %v\n",card)}}
Example output from my personal workstation:
gpu (1 graphics card) card #0 @0000:03:00.0 -> class: 'Display controller' vendor: 'NVIDIA Corporation' product: 'GP107 [GeForce GTX 1050 Ti]'
NOTE: You canread more about the fields of theghw.PCIDevice
struct if you'd like to dig deeper into PCI subsystem and programming interfaceinformation
NOTE: You canread more about the fields of theghw.TopologyNode
struct if you'd like to dig deeper into the NUMA/topologysubsystem
Theghw.Accelerator()
function returns aghw.AcceleratorInfo
struct that containsinformation about the host computer's processing accelerator hardware. In this categorywe can find used hardware for AI. The hardware detected in this category will beprocessing accelerators (PCI class1200
), 3D controllers (0302
) and Displaycontrollers (0380
).
Theghw.AcceleratorInfo
struct contains one field:
ghw.AcceleratorInfo.Devices
is an array of pointers toghw.AcceleratorDevice
structs, one for each processing accelerator card found for the system.
Eachghw.AcceleratorDevice
struct contains the following fields:
ghw.AcceleratorDevice.Address
is the PCI address for the processing accelerator card.ghw.AcceleratorDevice.PCIDevice
is a pointer to aghw.PCIDevice
struct.describing the processing accelerator card. This may benil
if no PCI deviceinformation could be determined for the card.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {accel,err:=ghw.Accelerator()iferr!=nil {fmt.Printf("Error getting processing accelerator info: %v",err)}fmt.Printf("%v\n",accel)for_,card:=rangeaccel.Devices {fmt.Printf(" %v\n",device)}}
Example output from a testing machine:
processing accelerators (1 device) device @0000:00:04.0 -> driver: 'fake_pci_driver' class: 'Processing accelerators' vendor: 'Red Hat, Inc.' product: 'QEMU PCI Test Device'
NOTE: You canread more about the fields of theghw.PCIDevice
struct if you'd like to dig deeper into PCI subsystem and programming interfaceinformation
Theghw.Chassis()
function returns aghw.ChassisInfo
struct that containsinformation about the host computer's hardware chassis.
Theghw.ChassisInfo
struct contains multiple fields:
ghw.ChassisInfo.AssetTag
is a string with the chassis asset tagghw.ChassisInfo.SerialNumber
is a string with the chassis serial numberghw.ChassisInfo.Type
is a string with the chassis typecodeghw.ChassisInfo.TypeDescription
is a string with a description of thechassis typeghw.ChassisInfo.Vendor
is a string with the chassis vendorghw.ChassisInfo.Version
is a string with the chassis version
NOTE: These fields are often missing for non-server hardware. Don't besurprised to see empty string or "None" values.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {chassis,err:=ghw.Chassis()iferr!=nil {fmt.Printf("Error getting chassis info: %v",err)}fmt.Printf("%v\n",chassis)}
Example output from my personal workstation:
chassis type=Desktop vendor=System76 version=thelio-r1
NOTE: Some of the values such as serial numbers are shown as unknownbecause the Linux kernel by default disallows access to those fields ifyou're not running as root. They will be populated if it runs as root orotherwise you may see warnings like the following:
WARNING: Unable to read chassis_serial: open /sys/class/dmi/id/chassis_serial: permission denied
You can ignore them or use theDisabling warning messagesfeature to quiet things down.
Theghw.BIOS()
function returns aghw.BIOSInfo
struct that containsinformation about the host computer's basis input/output system (BIOS).
Theghw.BIOSInfo
struct contains multiple fields:
ghw.BIOSInfo.Vendor
is a string with the BIOS vendorghw.BIOSInfo.Version
is a string with the BIOS versionghw.BIOSInfo.Date
is a string with the date the BIOS was flashed/created
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {bios,err:=ghw.BIOS()iferr!=nil {fmt.Printf("Error getting BIOS info: %v",err)}fmt.Printf("%v\n",bios)}
Example output from my personal workstation:
bios vendor=System76 version=F2 Z5 date=11/14/2018
Theghw.Baseboard()
function returns aghw.BaseboardInfo
struct thatcontains information about the host computer's hardware baseboard.
Theghw.BaseboardInfo
struct contains multiple fields:
ghw.BaseboardInfo.AssetTag
is a string with the baseboard asset tagghw.BaseboardInfo.SerialNumber
is a string with the baseboard serial numberghw.BaseboardInfo.Vendor
is a string with the baseboard vendorghw.BaseboardInfo.Product
is a string with the baseboard name on Linux andProduct on Windowsghw.BaseboardInfo.Version
is a string with the baseboard version
NOTE: These fields are often missing for non-server hardware. Don't besurprised to see empty string or "None" values.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {baseboard,err:=ghw.Baseboard()iferr!=nil {fmt.Printf("Error getting baseboard info: %v",err)}fmt.Printf("%v\n",baseboard)}
Example output from my personal workstation:
baseboard vendor=System76 version=thelio-r1
NOTE: Some of the values such as serial numbers are shown as unknownbecause the Linux kernel by default disallows access to those fields ifyou're not running as root. They will be populated if it runs as root orotherwise you may see warnings like the following:
WARNING: Unable to read board_serial: open /sys/class/dmi/id/board_serial: permission denied
You can ignore them or use theDisabling warning messagesfeature to quiet things down.
Theghw.Product()
function returns aghw.ProductInfo
struct thatcontains information about the host computer's hardware product line.
Theghw.ProductInfo
struct contains multiple fields:
ghw.ProductInfo.Family
is a string describing the product familyghw.ProductInfo.Name
is a string with the product nameghw.ProductInfo.SerialNumber
is a string with the product serial numberghw.ProductInfo.UUID
is a string with the product UUIDghw.ProductInfo.SKU
is a string with the product stock unit identifier(SKU)ghw.ProductInfo.Vendor
is a string with the product vendorghw.ProductInfo.Version
is a string with the product version
NOTE: These fields are often missing for non-server hardware. Don't besurprised to see empty string, "Default string" or "None" values.
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {product,err:=ghw.Product()iferr!=nil {fmt.Printf("Error getting product info: %v",err)}fmt.Printf("%v\n",product)}
Example output from my personal workstation:
product family=Default string name=Thelio vendor=System76 sku=Default string version=thelio-r1
NOTE: Some of the values such as serial numbers are shown as unknownbecause the Linux kernel by default disallows access to those fields ifyou're not running as root. They will be populated if it runs as root orotherwise you may see warnings like the following:
WARNING: Unable to read product_serial: open /sys/class/dmi/id/product_serial: permission denied
You can ignore them or use theDisabling warning messagesfeature to quiet things down.
Whenghw
isn't able to retrieve some information, it may print certainwarning messages tostderr
. To disable these warnings, simply set theGHW_DISABLE_WARNINGS
environs variable:
$ ghwc memoryWARNING:Could not determine total physical bytes of memory. This maybe due to the host being a virtual machine or container with no/var/log/syslog file, or the current user may not have necessaryprivileges to read the syslog. We are falling back to setting thetotal physical amount of memory to the total usable amount of memorymemory (24GB physical, 24GB usable)
$ GHW_DISABLE_WARNINGS=1 ghwc memorymemory (24GB physical, 24GB usable)
You can disable warning programmatically using theWithDisableWarnings
option:
import ("github.com/jaypipes/ghw")mem,err:=ghw.Memory(ghw.WithDisableWarnings())
WithDisableWarnings
is a alias for theWithNullAlerter
option, which in turnleverages the more generalAlerter
feature of ghw.
You may supply aAlerter
to ghw to redirect all the warnings there, likelogger objects (see for example golang's stdliblog.Logger
).Alerter
is in fact the minimal logging interfaceghw needs. To learn more, please check the
option.Alerterinterface and the
ghw.WithAlerter()`function.
Whenghw
looks for information about the host system, it considers/
as itsroot mountpoint. So, for example, when looking up CPU information on a Linuxsystem,ghw.CPU()
will use the path/proc/cpuinfo
.
If you are callingghw
from a system that has an alternate root mountpoint,you can either set theGHW_CHROOT
environment variable to that alternatepath, or call one of the functions likeghw.CPU()
orghw.Memory()
with theghw.WithChroot()
modifier.
For example, if you are executing from within an application container that hasbind-mounted the root host filesystem to the mount point/host
, you would setGHW_CHROOT
to/host
so thatghw
can find/proc/cpuinfo
at/host/proc/cpuinfo
.
Alternately, you can use theghw.WithChroot()
function like so:
cpu,err:=ghw.CPU(ghw.WithChroot("/host"))
All of theghw
XXXInfo
structs -- e.g.ghw.CPUInfo
-- have two methodsfor producing a serialized JSON or YAML string representation of the containedinformation:
JSONString()
returns a string containing the information serialized intoJSON. It accepts a single boolean parameter indicating whether to useindentation when outputting the stringYAMLString()
returns a string containing the information serialized intoYAML
package mainimport ("fmt""github.com/jaypipes/ghw")funcmain() {mem,err:=ghw.Memory()iferr!=nil {fmt.Printf("Error getting memory info: %v",err)}fmt.Printf("%s",mem.YAMLString())}
the above example code prints the following out on my local workstation:
memory: supported_page_sizes: - 1073741824 - 2097152 total_physical_bytes: 25263415296 total_usable_bytes: 25263415296
When running inside containers, it can be cumbersome to only override the rootmountpoint. Inside containers, when granting access to the host file systems,it is common to bind-mount them to a non-standard location, like/sys
on/host-sys
or/proc
to/host-proc
. It is rarer to mount them to a commonsubtree (e.g./sys
to/host/sys
and/proc
to/host/proc
...)
To better cover this use case,ghw.WithPathOverrides()
can be used to supplya mapping of directories to mountpoints, like this example shows:
cpu,err:=ghw.CPU(ghw.WithPathOverrides(ghw.PathOverrides{"/proc":"/host-proc","/sys":"/host-sys",}))
NOTE: This feature works in addition and is composable with theghw.WithChroot()
function andGHW_CHROOT
environment variable.
Theghw-snapshot
tool can create a snapshot of a host's hardware information.
Please readSNAPSHOT.md
to learn about creating snapshots withtheghw-snapshot
tool.
You can makeghw
read hardware information from a snapshot created withghw-snapshot
using environment variables or programmatically.
Use theGHW_SNAPSHOT_PATH
environment variable to specify the filepath to asnapshot thatghw
will read to determine hardware information. All the neededchroot changes will be automatically performed. By default, the snapshot isunpacked into a temporary directory managed byghw
. This temporary directoryis automatically deleted whenghw
is finished reading the snapshot.
Three other environment variables are relevant if and only ifGHW_SNAPSHOT_PATH
is not empty:
GHW_SNAPSHOT_ROOT
let users specify the directory on which the snapshotshould be unpacked. This moves the ownership of that directory fromghw
tousers. For this reason,ghw
willnot automatically clean up the contentunpacked intoGHW_SNAPSHOT_ROOT
.GHW_SNAPSHOT_EXCLUSIVE
tellsghw
that the directory is meant only tocontain the given snapshot, thusghw
willnot attempt to unpack it unlessthe directory is empty. You can use bothGHW_SNAPSHOT_ROOT
andGHW_SNAPSHOT_EXCLUSIVE
to make sureghw
unpacks the snapshot only onceregardless of how manyghw
packages (e.g. cpu, memory) access it. Set thevalue of this environment variable to any non-empty string.GHW_SNAPSHOT_PRESERVE
tellsghw
not to clean up the unpacked snapshot.Set the value of this environment variable to any non-empty string.
cpu,err:=ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{Path:"/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz",}))myRoot:="/my/safe/directory"cpu,err:=ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{Path:"/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz",Root:&myRoot,}))myOtherRoot:="/my/other/safe/directory"cpu,err:=ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{Path:"/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz",Root:&myOtherRoot,Exclusive:true,}))
You can createghw
snapshots using theghw-snapshot
tool orprogrammatically using thepkg/snapshot
package.
Below is an example of creating aghw
snapshot using thepkg/snapshot
package.
import ("fmt""os""github.com/jaypipes/ghw/pkg/snapshot")// ...scratchDir,err:=os.MkdirTemp("","ghw-snapshot-*")iferr!=nil {fmt.Printf("Error creating clone directory: %v",err)}deferos.RemoveAll(scratchDir)// this step clones all the files and directories ghw cares aboutiferr:=snapshot.CloneTreeInto(scratchDir);err!=nil {fmt.Printf("error cloning into %q: %v",scratchDir,err)}// optionally, you may add extra content into your snapshot.// ghw will ignore the extra content.// Glob patterns like `filepath.Glob` are supported.fileSpecs:= []string{"/proc/cmdline",}// options allows the client code to optionally deference symlinks, or copy// them into the cloned tree as symlinksvaropts*snapshot.CopyFileOptionsiferr:=snapshot.CopyFilesInto(fileSpecs,scratchDir,opts);err!=nil {fmt.Printf("error cloning extra files into %q: %v",scratchDir,err)}// automates the creation of the gzipped tarball out of the given tree.iferr:=snapshot.PackFrom("my-snapshot.tgz",scratchDir);err!=nil {fmt.Printf("error packing %q into %q: %v",scratchDir,*output,err)}
By defaultghw
may call external programs, for exampleethtool
, to learnabout hardware capabilities. In some rare circumstances it may be useful toopt out from this behaviour and rely only on the data provided bypseudo-filesystems, like sysfs.
The most common use case is when we want to read a snapshot fromghw
. Inthese cases the information provided by tools will be inconsistent with thedata from the snapshot - since they will be run on a different host than thehost the snapshot was created for.
To preventghw
from calling external tools, set theGHW_DISABLE_TOOLS
environment variable to any value, or, programmatically, use theghw.WithDisableTools()
function. The default behaviour of ghw is to callexternal tools when available.
WARNING: on all platforms, disabling external tools make ghw return lessdata. Unless noted otherwise, there isno fallback flow if external toolsare disabled. On MacOSX/Darwin, disabling external tools disables blocksupport entirely
Contributions toghw
are welcomed! Fork the repo on GitHuband submit a pull request with your proposed changes. Or, feel free to log anissue for a feature request or bug report.
About
Go HardWare discovery/inspection library