Ghw
Go HardWare discovery/inspection library
Install / Use
/learn @jaypipes/GhwREADME
ghw - Go HardWare discovery/inspection library

ghw is a Go library providing hardware inspection and discovery for Linux and
Windows. There currently exists partial support for MacOSX.
Design Principles
-
No root privileges needed for discovery
ghwgoes the extra mile to be useful without root privileges. We query for host hardware information as directly as possible without relying on shellouts to programs likedmidecodethat require root privileges to execute.Elevated privileges are indeed required to query for some information, but
ghwwill never error out if blocked from reading that information. Instead,ghwwill print a warning message about the information that could not be retrieved. You may disable these warning messages with theGHW_DISABLE_WARNINGSenvironment 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, and the structs returned by various library functions should have consistent attribute and method names.
Inspecting != Monitoring
ghw is a tool for gathering information about your hardware's capacity
and capabilities.
It is important to point out that ghw does NOT report information that is
temporary or variable. It is NOT a system monitor nor is it an appropriate
tool for gathering data points for metrics that change over time. If you are
looking for a system that tracks usage of CPU, memory, network I/O or disk
I/O, there are plenty of great open source tools that do this! Check out the
Prometheus project for a great example.
Usage
ghw has functions that return an Info object about a particular hardware
domain (e.g. CPU, Memory, Block storage, etc).
Use the following functions in ghw to inspect information about the host
hardware:
ghw.CPU()ghw.Memory()ghw.Block()(block storage)ghw.Topology()(processor architecture, NUMA topology and memory cache hierarchy)ghw.Network()ghw.PCI()ghw.GPU()(graphical processing unit)ghw.Accelerator()(processing accelerators, AI)ghw.Chassis()ghw.BIOS()ghw.Baseboard()ghw.Product()
CPU
The ghw.CPU() function returns a ghw.CPUInfo struct that contains
information about the CPUs on the host system.
ghw.CPUInfo contains the following fields:
ghw.CPUInfo.TotalCoreshas the total number of physical cores the host system containsghw.CPUInfo.TotalHardwareThreadshas the total number of hardware threads the host system containsghw.CPUInfo.Processorsis an array ofghw.Processorstructs, one for each physical processor package contained in the host
Each ghw.Processor struct contains a number of fields:
ghw.Processor.IDis the physical processoruint32ID according to the systemghw.Processor.TotalCoresis the number of physical cores in the processor packageghw.Processor.TotalHardwareThreadsis the number of hardware threads in the processor packageghw.Processor.Vendoris a string containing the vendor nameghw.Processor.Modelis a string containing the vendor's model nameghw.Processor.Capabilities(Linux only) is an array of strings indicating the features the processor has enabledghw.Processor.Cores(Linux only) is an array ofghw.ProcessorCorestructs that are packed onto this physical processor
A ghw.ProcessorCore has the following fields:
ghw.ProcessorCore.IDis theuint32identifier that the host gave this core. Note that this does not necessarily equate to a zero-based index of the core within a physical package. For example, the core IDs for an Intel Core i7 are 0, 1, 2, 8, 9, and 10ghw.ProcessorCore.TotalHardwareThreadsis the number of hardware threads associated with the coreghw.ProcessorCore.LogicalProcessorsis an array of ints representing the logical processor IDs assigned to any processing unit for the core. These are sometimes called the "thread siblings". Logical processor IDs are the zero-based index of the processor on the host and are not related to the core ID.
package main
import (
"fmt"
"math"
"strings"
"github.com/jaypipes/ghw"
)
func main() {
cpu, err := ghw.CPU()
if err != nil {
fmt.Printf("Error getting CPU info: %v", err)
}
fmt.Printf("%v\n", cpu)
for _, proc := range cpu.Processors {
fmt.Printf(" %v\n", proc)
for _, core := range proc.Cores {
fmt.Printf(" %v\n", core)
}
if len(proc.Capabilities) > 0 {
// pretty-print the (large) block of capability strings into rows
// of 6 capability strings
rows := int(math.Ceil(float64(len(proc.Capabilities)) / float64(6)))
for row := 1; row < rows; row = row + 1 {
rowStart := (row * 6) - 1
rowEnd := int(math.Min(float64(rowStart+6), float64(len(proc.Capabilities))))
rowElems := proc.Capabilities[rowStart:rowEnd]
capStr := strings.Join(rowElems, " ")
if row == 1 {
fmt.Printf(" capabilities: [%s\n", capStr)
} else if rowEnd < 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]
Memory
The ghw.Memory() function returns a ghw.MemoryInfo struct that contains
information about the RAM on the host system.
ghw.MemoryInfo contains the following fields:
ghw.MemoryInfo.TotalPhysicalBytescontains the amount of physical memory on the hostghw.MemoryInfo.TotalUsableBytescontains the amount of memory the system can actually use. Usable memory accounts for things like the kernel's resident memory size and some reserved system bits. Please note this value is NOT the amount of memory currently in use by processes in the system. See [the discussion][#physical-versus-usage-memory] about the difference.ghw.MemoryInfo.SupportedPageSizesis an array of integers representing the size, in bytes, of memory pages the system supportsghw.MemoryInfo.Modulesis an array of pointers toghw.MemoryModulestructs, one for each physical DIMM. Currently, this information is only included on Windows, with Linux support planned.
package main
import (
"fmt"
"github.com/jaypipes/ghw"
)
func main() {
memory, err := ghw.Memory()
if err != nil {
fmt.Printf("Error getting memory info: %v", err)
}
fmt.Println(memory.String())
}
Example output from my personal workstation:
memory (24GB physical, 24GB usable)
Physical versus Usable Memory
There has been some confusion regarding the difference between the total physical bytes versus total usable bytes of memory.
Some of this confusion has been due to a misunderstanding of the term "usable".
As mentioned above, ghw does inspection of the
system's capacity.
A host computer has two capacities when it comes to RAM. The first capacity is
the amount of RAM that is contained in all memory banks (DIMMs) that are
attached to the motherboard. ghw.MemoryInfo.TotalPhysicalBytes refers to this
first capacity.
There is a (usually small) amount of RAM that is consumed by the bootloader
before the operating system is started (booted). Once the bootloader has booted
the operating system, the amount of RAM that may be used by the operating
system and its applications is fixed. ghw.MemoryInfo.TotalUsableBytes refers
to this second capacity.
You can determine the amount of RAM that the bootloader used (that is not made
available to the operating system) by subtracting
ghw.MemoryInfo.TotalUsableBytes from ghw.MemoryInfo.TotalPhysicalBytes:
package main
import (
"fmt"
"github.com/jaypipes/ghw"
)
func main() {
memory, err := ghw.Memory()
if err != nil {
fmt.Printf("Error getting memory info: %v", err)
}
phys := memory.TotalPhysicalBytes
Related Skills
pestel-analysis
Analyze political, economic, social, technological, environmental, and legal forces
next
A beautifully designed, floating Pomodoro timer that respects your workspace.
product-manager-skills
41PM skill for Claude Code, Codex, Cursor, and Windsurf: diagnose SaaS metrics, critique PRDs, plan roadmaps, run discovery, and coach PM career transitions.
snap-vis-manager
The planning agent for the snap-vis project. Coordinates other specialized agents and manages the overall project roadmap.
