{"id":13393630,"url":"https://github.com/jaypipes/ghw","last_synced_at":"2025-05-14T12:02:28.216Z","repository":{"id":27843380,"uuid":"92529879","full_name":"jaypipes/ghw","owner":"jaypipes","description":"Go HardWare discovery/inspection library","archived":false,"fork":false,"pushed_at":"2025-04-22T15:21:44.000Z","size":1304,"stargazers_count":1743,"open_issues_count":59,"forks_count":192,"subscribers_count":28,"default_branch":"main","last_synced_at":"2025-05-07T11:41:39.378Z","etag":null,"topics":["discovery","go-hardware","go-hardware-discovery","golang-hardware-discovery","golang-library","hardware","inspection-library"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaypipes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"COPYING","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-05-26T16:39:02.000Z","updated_at":"2025-05-07T03:22:41.000Z","dependencies_parsed_at":"2023-01-14T07:36:04.390Z","dependency_job_id":"d20997bf-be20-469c-986b-029f73dc2173","html_url":"https://github.com/jaypipes/ghw","commit_stats":{"total_commits":456,"total_committers":44,"mean_commits":"10.363636363636363","dds":"0.45394736842105265","last_synced_commit":"f88acb306593c0c13bdd6978c24e943f7ae92c51"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fghw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fghw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fghw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fghw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaypipes","download_url":"https://codeload.github.com/jaypipes/ghw/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254140738,"owners_count":22021218,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discovery","go-hardware","go-hardware-discovery","golang-hardware-discovery","golang-library","hardware","inspection-library"],"created_at":"2024-07-30T17:00:57.545Z","updated_at":"2025-05-14T12:02:28.142Z","avatar_url":"https://github.com/jaypipes.png","language":"Go","readme":"# `ghw` - Go HardWare discovery/inspection library\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/jaypipes/ghw.svg)](https://pkg.go.dev/github.com/jaypipes/ghw)\n[![Go Report Card](https://goreportcard.com/badge/github.com/jaypipes/ghw)](https://goreportcard.com/report/github.com/jaypipes/ghw)\n[![Build Status](https://github.com/jaypipes/ghw/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/jaypipes/ghw/actions)\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)\n\n![ghw mascot](images/ghw-gopher.png)\n\n`ghw` is a Go library providing hardware inspection and discovery for Linux and\nWindows. There currently exists partial support for MacOSX.\n\n## Design Principles\n\n* No root privileges needed for discovery\n\n  `ghw` goes the extra mile to be useful without root priveleges. We query for\n  host hardware information as directly as possible without relying on shellouts\n  to programs like `dmidecode` that require root privileges to execute.\n\n  Elevated privileges are indeed required to query for some information, but\n  `ghw` will never error out if blocked from reading that information. Instead,\n  `ghw` will print a warning message about the information that could not be\n  retrieved. You may disable these warning messages with the\n  `GHW_DISABLE_WARNINGS` environment variable.\n\n* Well-documented code and plenty of example code\n\n  The code itself should be well-documented with lots of usage examples.\n\n* Interfaces should be consistent across modules\n\n  Each module in the library should be structured in a consistent fashion, and\n  the structs returned by various library functions should have consistent\n  attribute and method names.\n\n## Inspecting != Monitoring\n\n`ghw` is a tool for gathering information about your hardware's **capacity**\nand **capabilities**.\n\nIt is important to point out that `ghw` does **NOT** report information that is\ntemporary or variable. It is **NOT** a system monitor nor is it an appropriate\ntool for gathering data points for metrics that change over time.  If you are\nlooking for a system that tracks **usage** of CPU, memory, network I/O or disk\nI/O, there are plenty of great open source tools that do this! Check out the\n[Prometheus project](https://prometheus.io/) for a great example.\n\n## Usage\n\n`ghw` has functions that return an `Info` object about a particular hardware\ndomain (e.g. CPU, Memory, Block storage, etc).\n\nUse the following functions in `ghw` to inspect information about the host\nhardware:\n\n* [`ghw.CPU()`](#cpu)\n* [`ghw.Memory()`](#memory)\n* [`ghw.Block()`](#block-storage) (block storage)\n* [`ghw.Topology()`](#topology) (processor architecture, NUMA topology and\n  memory cache hierarchy)\n* [`ghw.Network()`](#network)\n* [`ghw.PCI()`](#pci)\n* [`ghw.GPU()`](#gpu) (graphical processing unit)\n* [`ghw.Accelerator()`](#accelerator) (processing accelerators, AI)\n* [`ghw.Chassis()`](#chassis)\n* [`ghw.BIOS()`](#bios)\n* [`ghw.Baseboard()`](#baseboard)\n* [`ghw.Product()`](#product)\n\n### CPU\n\nThe `ghw.CPU()` function returns a `ghw.CPUInfo` struct that contains\ninformation about the CPUs on the host system.\n\n`ghw.CPUInfo` contains the following fields:\n\n* `ghw.CPUInfo.TotalCores` has the total number of physical cores the host\n  system contains\n* `ghw.CPUInfo.TotalHardwareThreads` has the total number of hardware threads\n  the host system contains\n* `ghw.CPUInfo.Processors` is an array of `ghw.Processor` structs, one for each\n  physical processor package contained in the host\n\nEach `ghw.Processor` struct contains a number of fields:\n\n* `ghw.Processor.ID` is the physical processor `uint32` ID according to the\n  system\n* `ghw.Processor.TotalCores` is the number of physical cores in the processor\n  package\n* `ghw.Processor.TotalHardwareThreads` is the number of hardware threads in the\n  processor package\n* `ghw.Processor.Vendor` is a string containing the vendor name\n* `ghw.Processor.Model` is a string containing the vendor's model name\n* `ghw.Processor.Capabilities` (Linux only) is an array of strings indicating\n  the features the processor has enabled\n* `ghw.Processor.Cores` (Linux only) is an array of `ghw.ProcessorCore` structs\n  that are packed onto this physical processor\n\nA `ghw.ProcessorCore` has the following fields:\n\n* `ghw.ProcessorCore.ID` is the `uint32` identifier that the host gave this\n  core. Note that this does *not* necessarily equate to a zero-based index of\n  the core within a physical package. For example, the core IDs for an Intel Core\n  i7 are 0, 1, 2, 8, 9, and 10\n* `ghw.ProcessorCore.TotalHardwareThreads` is the number of hardware threads\n  associated with the core\n* `ghw.ProcessorCore.LogicalProcessors` is an array of ints representing the\n  logical processor IDs assigned to any processing unit for the core. These are\n  sometimes called the \"thread siblings\". Logical processor IDs are the\n  *zero-based* index of the processor on the host and are *not* related to the\n  core ID.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tcpu, err := ghw.CPU()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting CPU info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", cpu)\n\n\tfor _, proc := range cpu.Processors {\n\t\tfmt.Printf(\" %v\\n\", proc)\n\t\tfor _, core := range proc.Cores {\n\t\t\tfmt.Printf(\"  %v\\n\", core)\n\t\t}\n\t\tif len(proc.Capabilities) \u003e 0 {\n\t\t\t// pretty-print the (large) block of capability strings into rows\n\t\t\t// of 6 capability strings\n\t\t\trows := int(math.Ceil(float64(len(proc.Capabilities)) / float64(6)))\n\t\t\tfor row := 1; row \u003c rows; row = row + 1 {\n\t\t\t\trowStart := (row * 6) - 1\n\t\t\t\trowEnd := int(math.Min(float64(rowStart+6), float64(len(proc.Capabilities))))\n\t\t\t\trowElems := proc.Capabilities[rowStart:rowEnd]\n\t\t\t\tcapStr := strings.Join(rowElems, \" \")\n\t\t\t\tif row == 1 {\n\t\t\t\t\tfmt.Printf(\"  capabilities: [%s\\n\", capStr)\n\t\t\t\t} else if rowEnd \u003c len(proc.Capabilities) {\n\t\t\t\t\tfmt.Printf(\"                 %s\\n\", capStr)\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Printf(\"                 %s]\\n\", capStr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample output from my personal workstation:\n\n```\ncpu (1 physical package, 6 cores, 12 hardware threads)\n physical package #0 (6 cores, 12 hardware threads)\n  processor core #0 (2 threads), logical processors [0 6]\n  processor core #1 (2 threads), logical processors [1 7]\n  processor core #2 (2 threads), logical processors [2 8]\n  processor core #3 (2 threads), logical processors [3 9]\n  processor core #4 (2 threads), logical processors [4 10]\n  processor core #5 (2 threads), logical processors [5 11]\n  capabilities: [msr pae mce cx8 apic sep\n                 mtrr pge mca cmov pat pse36\n                 clflush dts acpi mmx fxsr sse\n                 sse2 ss ht tm pbe syscall\n                 nx pdpe1gb rdtscp lm constant_tsc arch_perfmon\n                 pebs bts rep_good nopl xtopology nonstop_tsc\n                 cpuid aperfmperf pni pclmulqdq dtes64 monitor\n                 ds_cpl vmx est tm2 ssse3 cx16\n                 xtpr pdcm pcid sse4_1 sse4_2 popcnt\n                 aes lahf_lm pti retpoline tpr_shadow vnmi\n                 flexpriority ept vpid dtherm ida arat]\n```\n\n### Memory\n\nThe `ghw.Memory()` function returns a `ghw.MemoryInfo` struct that contains\ninformation about the RAM on the host system.\n\n`ghw.MemoryInfo` contains the following fields:\n\n* `ghw.MemoryInfo.TotalPhysicalBytes` contains the amount of physical memory on\n  the host\n* `ghw.MemoryInfo.TotalUsableBytes` contains the amount of memory the\n  system can actually use. Usable memory accounts for things like the kernel's\n  resident memory size and some reserved system bits. Please note this value is\n  **NOT** the amount of memory currently in use by processes in the system. See\n  [the discussion][#physical-versus-usage-memory] about the difference.\n* `ghw.MemoryInfo.SupportedPageSizes` is an array of integers representing the\n  size, in bytes, of memory pages the system supports\n* `ghw.MemoryInfo.Modules` is an array of pointers to `ghw.MemoryModule`\n  structs, one for each physical [DIMM](https://en.wikipedia.org/wiki/DIMM).\n  Currently, this information is only included on Windows, with Linux support\n  [planned](https://github.com/jaypipes/ghw/pull/171#issuecomment-597082409).\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tmemory, err := ghw.Memory()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting memory info: %v\", err)\n\t}\n\n\tfmt.Println(memory.String())\n}\n```\n\nExample output from my personal workstation:\n\n```\nmemory (24GB physical, 24GB usable)\n```\n\n#### Physical versus Usable Memory\n\nThere has been [some](https://github.com/jaypipes/ghw/pull/171)\n[confusion](https://github.com/jaypipes/ghw/issues/183) regarding the\ndifference between the total physical bytes versus total usable bytes of\nmemory.\n\nSome of this confusion has been due to a misunderstanding of the term \"usable\".\nAs mentioned [above](#inspection!=monitoring), `ghw` does inspection of the\nsystem's capacity.\n\nA host computer has two capacities when it comes to RAM. The first capacity is\nthe amount of RAM that is contained in all memory banks (DIMMs) that are\nattached to the motherboard. `ghw.MemoryInfo.TotalPhysicalBytes` refers to this\nfirst capacity.\n\nThere is a (usually small) amount of RAM that is consumed by the bootloader\nbefore the operating system is started (booted). Once the bootloader has booted\nthe operating system, the amount of RAM that may be used by the operating\nsystem and its applications is fixed. `ghw.MemoryInfo.TotalUsableBytes` refers\nto this second capacity.\n\nYou can determine the amount of RAM that the bootloader used (that is not made\navailable to the operating system) by subtracting\n`ghw.MemoryInfo.TotalUsableBytes` from `ghw.MemoryInfo.TotalPhysicalBytes`:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tmemory, err := ghw.Memory()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting memory info: %v\", err)\n\t}\n\n        phys := memory.TotalPhysicalBytes\n        usable := memory.TotalUsableBytes\n\n\tfmt.Printf(\"The bootloader consumes %d bytes of RAM\\n\", phys - usable)\n}\n```\n\nExample output from my personal workstation booted into a Windows10 operating\nsystem with a Linux GRUB bootloader:\n\n```\nThe bootloader consumes 3832720 bytes of RAM\n```\n\n### Block storage\n\nThe `ghw.Block()` function returns a `ghw.BlockInfo` struct that contains\ninformation about the block storage on the host system.\n\n`ghw.BlockInfo` contains the following fields:\n\n* `ghw.BlockInfo.TotalSizeBytes` contains the amount of physical block storage\n  on the host.\n* `ghw.BlockInfo.Disks` is an array of pointers to `ghw.Disk` structs, one for\n  each disk found by the system\n\nEach `ghw.Disk` struct contains the following fields:\n\n* `ghw.Disk.Name` contains a string with the short name of the disk, e.g. \"sda\"\n* `ghw.Disk.SizeBytes` contains the amount of storage the disk provides\n* `ghw.Disk.PhysicalBlockSizeBytes` contains the size of the physical blocks\n  used on the disk, in bytes. This is typically the minimum amount of data that\n  will be written in a single write operation for the disk.\n* `ghw.Disk.IsRemovable` contains a boolean indicating if the disk drive is\n  removable\n* `ghw.Disk.DriveType` is the type of drive. It is of type `ghw.DriveType`\n  which has a `ghw.DriveType.String()` method that can be called to return a\n  string representation of the bus. This string will be `HDD`, `FDD`, `ODD`,\n  or `SSD`, which correspond to a hard disk drive (rotational), floppy drive,\n  optical (CD/DVD) drive and solid-state drive.\n* `ghw.Disk.StorageController` is the type of storage controller. It is of type\n  `ghw.StorageController` which has a `ghw.StorageController.String()` method\n  that can be called to return a string representation of the bus. This string\n  will be `SCSI`, `IDE`, `virtio`, `MMC`, or `NVMe`\n* `ghw.Disk.BusPath` (Linux, Darwin only) is the filepath to the bus used by\n  the disk.\n* `ghw.Disk.NUMANodeID` (Linux only) is the numeric index of the NUMA node this\n  disk is local to, or -1 if the host system is not a NUMA system or is not\n  Linux.\n* `ghw.Disk.Vendor` contains a string with the name of the hardware vendor for\n  the disk\n* `ghw.Disk.Model` contains a string with the vendor-assigned disk model name\n* `ghw.Disk.SerialNumber` contains a string with the disk's serial number\n* `ghw.Disk.WWN` contains a string with the disk's\n  [World Wide Name](https://en.wikipedia.org/wiki/World_Wide_Name)\n* `ghw.Disk.Partitions` contains an array of pointers to `ghw.Partition`\n  structs, one for each partition on the disk\n\nEach `ghw.Partition` struct contains these fields:\n\n* `ghw.Partition.Name` contains a string with the short name of the partition,\n  e.g. `sda1`\n* `ghw.Partition.Label` contains the label for the partition itself. On Linux\n  systems, this is derived from the `ID_PART_ENTRY_NAME` [udev][udev] entry for\n  the partition.\n* `ghw.Partition.FilesystemLabel` contains the label for the filesystem housed\n  on the partition. On Linux systems, this is derived from the `ID_FS_NAME`\n  [udev][udev] entry for the partition.\n* `ghw.Partition.SizeBytes` contains the amount of storage the partition\n  provides\n* `ghw.Partition.MountPoint` contains a string with the partition's mount\n  point, or `\"\"` if no mount point was discovered\n* `ghw.Partition.Type` contains a string indicated the filesystem type for the\n  partition, or `\"\"` if the system could not determine the type\n* `ghw.Partition.IsReadOnly` is a bool indicating the partition is read-only\n* `ghw.Partition.Disk` is a pointer to the `ghw.Disk` object associated with\n  the partition.\n* `ghw.Partition.UUID` is a string containing the partition UUID on Linux and MacOS,\n  and the `VolumeSerialNumber` on Windows (e.g. \"A8C3D032\"). On Linux systems, this is\n  derived from the `ID_PART_ENTRY_UUID` [udev][udev] entry for the partition.\n\n[udev]: https://en.wikipedia.org/wiki/Udev\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tblock, err := ghw.Block()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting block storage info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", block)\n\n\tfor _, disk := range block.Disks {\n\t\tfmt.Printf(\" %v\\n\", disk)\n\t\tfor _, part := range disk.Partitions {\n\t\t\tfmt.Printf(\"  %v\\n\", part)\n\t\t}\n\t}\n}\n```\n\nExample output from my personal workstation:\n\n```\nblock storage (1 disk, 2TB physical storage)\n 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\n  /dev/sda1 (100MB)\n  /dev/sda2 (187GB)\n  /dev/sda3 (449MB)\n  /dev/sda4 (1KB)\n  /dev/sda5 (15GB)\n  /dev/sda6 (2TB) [ext4] mounted@/\n```\n\n\u003e **NOTE**: `ghw` looks in the udev runtime database for some information. If\n\u003e you are using `ghw` in a container, remember to bind mount `/dev/disk` and\n\u003e `/run` into your container, otherwise `ghw` won't be able to query the udev\n\u003e DB or sysfs paths for information.\n\n### Topology\n\n\u003e **NOTE**: Topology support is currently Linux-only. Windows support is\n\u003e [planned](https://github.com/jaypipes/ghw/issues/166).\n\nThe `ghw.Topology()` function returns a `ghw.TopologyInfo` struct that contains\ninformation about the host computer's architecture (NUMA vs. SMP), the host's\nNUMA node layout and processor-specific memory caches.\n\nThe `ghw.TopologyInfo` struct contains two fields:\n\n* `ghw.TopologyInfo.Architecture` contains an enum with the value `ghw.NUMA` or\n  `ghw.SMP` depending on what the topology of the system is\n* `ghw.TopologyInfo.Nodes` is an array of pointers to `ghw.TopologyNode`\n  structs, one for each topology node (typically physical processor package)\n  found by the system\n\nEach `ghw.TopologyNode` struct contains the following fields:\n\n* `ghw.TopologyNode.ID` is the system's `uint32` identifier for the node\n* `ghw.TopologyNode.Memory` is a `ghw.MemoryArea` struct describing the memory\n  attached to this node.\n* `ghw.TopologyNode.Cores` is an array of pointers to `ghw.ProcessorCore` structs that\n  are contained in this node\n* `ghw.TopologyNode.Caches` is an array of pointers to `ghw.MemoryCache` structs that\n  represent the low-level caches associated with processors and cores on the\n  system\n* `ghw.TopologyNode.Distance` is an array of distances between NUMA nodes as reported\n  by the system.\n\n`ghw.MemoryArea` describes a collection of *physical* RAM on the host.\n\nIn the simplest and most common case, all system memory fits in a single memory\narea. In more complex host systems, like [NUMA systems][numa], many memory\nareas may be present in the host system (e.g. one for each NUMA cell).\n\n[numa]: https://en.wikipedia.org/wiki/Non-uniform_memory_access\n\nThe `ghw.MemoryArea` struct contains the following fields:\n\n* `ghw.MemoryArea.TotalPhysicalBytes` contains the amount of physical memory\n  associated with this memory area.\n* `ghw.MemoryArea.TotalUsableBytes` contains the amount of memory of this\n  memory area the system can actually use. Usable memory accounts for things\n  like the kernel's resident memory size and some reserved system bits. Please\n  note this value is **NOT** the amount of memory currently in use by processes\n  in the system. See [the discussion][#physical-versus-usage-memory] about\n  the difference.\n\nSee above in the [CPU](#cpu) section for information about the\n`ghw.ProcessorCore` struct and how to use and query it.\n\nEach `ghw.MemoryCache` struct contains the following fields:\n\n* `ghw.MemoryCache.Type` is an enum that contains one of `ghw.DATA`,\n  `ghw.INSTRUCTION` or `ghw.UNIFIED` depending on whether the cache stores CPU\n  instructions, program data, or both\n* `ghw.MemoryCache.Level` is a positive integer indicating how close the cache\n  is to the processor. The lower the number, the closer the cache is to the\n  processor and the faster the processor can access its contents\n* `ghw.MemoryCache.SizeBytes` is an integer containing the number of bytes the\n  cache can contain\n* `ghw.MemoryCache.LogicalProcessors` is an array of integers representing the\n  logical processors that use the cache\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\ttopology, err := ghw.Topology()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting topology info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", topology)\n\n\tfor _, node := range topology.Nodes {\n\t\tfmt.Printf(\" %v\\n\", node)\n\t\tfor _, cache := range node.Caches {\n\t\t\tfmt.Printf(\"  %v\\n\", cache)\n\t\t}\n\t}\n}\n```\n\nExample output from my personal workstation:\n\n```\ntopology SMP (1 nodes)\n node #0 (6 cores)\n  L1i cache (32 KB) shared with logical processors: 3,9\n  L1i cache (32 KB) shared with logical processors: 2,8\n  L1i cache (32 KB) shared with logical processors: 11,5\n  L1i cache (32 KB) shared with logical processors: 10,4\n  L1i cache (32 KB) shared with logical processors: 0,6\n  L1i cache (32 KB) shared with logical processors: 1,7\n  L1d cache (32 KB) shared with logical processors: 11,5\n  L1d cache (32 KB) shared with logical processors: 10,4\n  L1d cache (32 KB) shared with logical processors: 3,9\n  L1d cache (32 KB) shared with logical processors: 1,7\n  L1d cache (32 KB) shared with logical processors: 0,6\n  L1d cache (32 KB) shared with logical processors: 2,8\n  L2 cache (256 KB) shared with logical processors: 2,8\n  L2 cache (256 KB) shared with logical processors: 3,9\n  L2 cache (256 KB) shared with logical processors: 0,6\n  L2 cache (256 KB) shared with logical processors: 10,4\n  L2 cache (256 KB) shared with logical processors: 1,7\n  L2 cache (256 KB) shared with logical processors: 11,5\n  L3 cache (12288 KB) shared with logical processors: 0,1,10,11,2,3,4,5,6,7,8,9\n```\n\n### Network\n\nThe `ghw.Network()` function returns a `ghw.NetworkInfo` struct that contains\ninformation about the host computer's networking hardware.\n\nThe `ghw.NetworkInfo` struct contains one field:\n\n* `ghw.NetworkInfo.NICs` is an array of pointers to `ghw.NIC` structs, one\n  for each network interface controller found for the systen\n\nEach `ghw.NIC` struct contains the following fields:\n\n* `ghw.NIC.Name` is the system's identifier for the NIC\n* `ghw.NIC.MACAddress` is the Media Access Control (MAC) address for the NIC,\n  if any\n* `ghw.NIC.IsVirtual` is a boolean indicating if the NIC is a virtualized\n  device\n* `ghw.NIC.Capabilities` (Linux only) is an array of pointers to\n  `ghw.NICCapability` structs that can describe the things the NIC supports.\n  These capabilities match the returned values from the `ethtool -k \u003cDEVICE\u003e`\n  call on Linux as well as the AutoNegotiation and PauseFrameUse capabilities\n  from `ethtool`.\n* `ghw.NIC.PCIAddress` (Linux only) is the PCI device address of the device\n  backing the NIC.  this is not-nil only if the backing device is indeed a PCI\n  device; more backing devices (e.g. USB) will be added in future versions.\n* `ghw.NIC.Speed` (Linux only) is a string showing the current link speed.  On\n  Linux, this field will be present even if `ethtool` is not available.\n* `ghw.NIC.Duplex` (Linux only) is a string showing the current link duplex. On\n  Linux, this field will be present even if `ethtool` is not available.\n* `ghw.NIC.SupportedLinkModes` (Linux only) is a string slice containing a list\n  of supported link modes, e.g. \"10baseT/Half\", \"1000baseT/Full\".\n* `ghw.NIC.SupportedPorts` (Linux only) is a string slice containing the list\n  of supported port types, e.g. \"MII\", \"TP\", \"FIBRE\", \"Twisted Pair\".\n* `ghw.NIC.SupportedFECModes` (Linux only) is a string slice containing a list\n  of supported Forward Error Correction (FEC) Modes.\n* `ghw.NIC.AdvertisedLinkModes` (Linux only) is a string slice containing the\n  link modes being advertised during auto negotiation.\n* `ghw.NIC.AdvertisedFECModes` (Linux only) is a string slice containing the\n  Forward Error Correction (FEC) modes advertised during auto negotiation.\n\nThe `ghw.NICCapability` struct contains the following fields:\n\n* `ghw.NICCapability.Name` is the string name of the capability (e.g.\n  \"tcp-segmentation-offload\")\n* `ghw.NICCapability.IsEnabled` is a boolean indicating whether the capability\n  is currently enabled/active on the NIC\n* `ghw.NICCapability.CanEnable` is a boolean indicating whether the capability\n  may be enabled\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n\n    \"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n    net, err := ghw.Network()\n    if err != nil {\n        fmt.Printf(\"Error getting network info: %v\", err)\n    }\n\n    fmt.Printf(\"%v\\n\", net)\n\n    for _, nic := range net.NICs {\n        fmt.Printf(\" %v\\n\", nic)\n\n        enabledCaps := make([]int, 0)\n        for x, cap := range nic.Capabilities {\n            if cap.IsEnabled {\n                enabledCaps = append(enabledCaps, x)\n            }\n        }\n        if len(enabledCaps) \u003e 0 {\n            fmt.Printf(\"  enabled capabilities:\\n\")\n            for _, x := range enabledCaps {\n                fmt.Printf(\"   - %s\\n\", nic.Capabilities[x].Name)\n            }\n        }\n    }\n}\n```\n\nExample output from my personal laptop:\n\n```\nnet (3 NICs)\n docker0\n  enabled capabilities:\n   - tx-checksumming\n   - tx-checksum-ip-generic\n   - scatter-gather\n   - tx-scatter-gather\n   - tx-scatter-gather-fraglist\n   - tcp-segmentation-offload\n   - tx-tcp-segmentation\n   - tx-tcp-ecn-segmentation\n   - tx-tcp-mangleid-segmentation\n   - tx-tcp6-segmentation\n   - udp-fragmentation-offload\n   - generic-segmentation-offload\n   - generic-receive-offload\n   - tx-vlan-offload\n   - highdma\n   - tx-lockless\n   - netns-local\n   - tx-gso-robust\n   - tx-fcoe-segmentation\n   - tx-gre-segmentation\n   - tx-gre-csum-segmentation\n   - tx-ipxip4-segmentation\n   - tx-ipxip6-segmentation\n   - tx-udp_tnl-segmentation\n   - tx-udp_tnl-csum-segmentation\n   - tx-gso-partial\n   - tx-sctp-segmentation\n   - tx-esp-segmentation\n   - tx-vlan-stag-hw-insert\n enp58s0f1\n  enabled capabilities:\n   - rx-checksumming\n   - generic-receive-offload\n   - rx-vlan-offload\n   - tx-vlan-offload\n   - highdma\n   - auto-negotiation\n wlp59s0\n  enabled capabilities:\n   - scatter-gather\n   - tx-scatter-gather\n   - generic-segmentation-offload\n   - generic-receive-offload\n   - highdma\n   - netns-local\n```\n\n### PCI\n\n`ghw` contains a PCI database inspection and querying facility that allows\ndevelopers to not only gather information about devices on a local PCI bus but\nalso query for information about hardware device classes, vendor and product\ninformation.\n\n\u003e **NOTE**: Parsing of the PCI-IDS file database is provided by the separate\n\u003e [github.com/jaypipes/pcidb library](http://github.com/jaypipes/pcidb). You\n\u003e can read that library's README for more information about the various structs\n\u003e that are exposed on the `ghw.PCIInfo` struct.\n\nThe `ghw.PCI()` function returns a `ghw.PCIInfo` struct that contains\ninformation about the host computer's PCI devices.\n\nThe `ghw.PCIInfo` struct contains one field:\n\n* `ghw.PCIInfo.Devices` is a slice of pointers to `ghw.PCIDevice` structs that\n  describe the PCI devices on the host system\n\n\u003e **NOTE**: PCI products are often referred to by their \"device ID\". We use the\n\u003e term \"product ID\" in `ghw` because it more accurately reflects what the\n\u003e identifier is for: a specific product line produced by the vendor.\n\nThe `ghw.PCIDevice` struct has the following fields:\n\n* `ghw.PCIDevice.Vendor` is a pointer to a `pcidb.Vendor` struct that\n  describes the device's primary vendor. This will always be non-nil.\n* `ghw.PCIDevice.Product` is a pointer to a `pcidb.Product` struct that\n  describes the device's primary product. This will always be non-nil.\n* `ghw.PCIDevice.Subsystem` is a pointer to a `pcidb.Product` struct that\n  describes the device's secondary/sub-product. This will always be non-nil.\n* `ghw.PCIDevice.Class` is a pointer to a `pcidb.Class` struct that\n  describes the device's class. This will always be non-nil.\n* `ghw.PCIDevice.Subclass` is a pointer to a `pcidb.Subclass` struct\n  that describes the device's subclass. This will always be non-nil.\n* `ghw.PCIDevice.ProgrammingInterface` is a pointer to a\n  `pcidb.ProgrammingInterface` struct that describes the device subclass'\n  programming interface. This will always be non-nil.\n* `ghw.PCIDevice.Driver` is a string representing the device driver the\n  system is using to handle this device. Can be empty string if this\n  information is not available. If the information is not available, this does\n  not mean the device is not functioning, but rather that `ghw` was not able to\n  retrieve driver information.\n\nThe `ghw.PCIAddress` (which is an alias for the `ghw.pci.address.Address`\nstruct) contains the PCI address fields. It has a `ghw.PCIAddress.String()`\nmethod that returns the canonical Domain:Bus:Device.Function ([D]BDF)\nrepresentation of this Address.\n\nThe `ghw.PCIAddress` struct has the following fields:\n\n* `ghw.PCIAddress.Domain` is a string representing the PCI domain component of\n  the address.\n* `ghw.PCIAddress.Bus` is a string representing the PCI bus component of\n  the address.\n* `ghw.PCIAddress.Device` is a string representing the PCI device component of\n  the address.\n* `ghw.PCIAddress.Function` is a string representing the PCI function component of\n  the address.\n\n\u003e **NOTE**: Older versions (pre-`v0.9.0`) erroneously referred to the `Device`\n\u003e field as the `Slot` field. As noted by [@pearsonk](https://github.com/pearsonk)\n\u003e in [#220](https://github.com/jaypipes/ghw/issues/220), this was a misnomer.\n\nThe following code snippet shows how to list the PCI devices on the host system\nand output a simple list of PCI address and vendor/product information:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tpci, err := ghw.PCI()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting PCI info: %v\", err)\n\t}\n\tfmt.Printf(\"host PCI devices:\\n\")\n\tfmt.Println(\"====================================================\")\n\n\tfor _, device := range pci.Devices {\n\t\tvendor := device.Vendor\n\t\tvendorName := vendor.Name\n\t\tif len(vendor.Name) \u003e 20 {\n\t\t\tvendorName = string([]byte(vendorName)[0:17]) + \"...\"\n\t\t}\n\t\tproduct := device.Product\n\t\tproductName := product.Name\n\t\tif len(product.Name) \u003e 40 {\n\t\t\tproductName = string([]byte(productName)[0:37]) + \"...\"\n\t\t}\n\t\tfmt.Printf(\"%-12s\\t%-20s\\t%-40s\\n\", device.Address, vendorName, productName)\n\t}\n}\n```\n\non my local workstation the output of the above looks like the following:\n\n```\nhost PCI devices:\n====================================================\n0000:00:00.0\tIntel Corporation   \t5520/5500/X58 I/O Hub to ESI Port\n0000:00:01.0\tIntel Corporation   \t5520/5500/X58 I/O Hub PCI Express Roo...\n0000:00:02.0\tIntel Corporation   \t5520/5500/X58 I/O Hub PCI Express Roo...\n0000:00:03.0\tIntel Corporation   \t5520/5500/X58 I/O Hub PCI Express Roo...\n0000:00:07.0\tIntel Corporation   \t5520/5500/X58 I/O Hub PCI Express Roo...\n0000:00:10.0\tIntel Corporation   \t7500/5520/5500/X58 Physical and Link ...\n0000:00:10.1\tIntel Corporation   \t7500/5520/5500/X58 Routing and Protoc...\n0000:00:14.0\tIntel Corporation   \t7500/5520/5500/X58 I/O Hub System Man...\n0000:00:14.1\tIntel Corporation   \t7500/5520/5500/X58 I/O Hub GPIO and S...\n0000:00:14.2\tIntel Corporation   \t7500/5520/5500/X58 I/O Hub Control St...\n0000:00:14.3\tIntel Corporation   \t7500/5520/5500/X58 I/O Hub Throttle R...\n0000:00:19.0\tIntel Corporation   \t82567LF-2 Gigabit Network Connection\n0000:00:1a.0\tIntel Corporation   \t82801JI (ICH10 Family) USB UHCI Contr...\n0000:00:1a.1\tIntel Corporation   \t82801JI (ICH10 Family) USB UHCI Contr...\n0000:00:1a.2\tIntel Corporation   \t82801JI (ICH10 Family) USB UHCI Contr...\n0000:00:1a.7\tIntel Corporation   \t82801JI (ICH10 Family) USB2 EHCI Cont...\n0000:00:1b.0\tIntel Corporation   \t82801JI (ICH10 Family) HD Audio Contr...\n0000:00:1c.0\tIntel Corporation   \t82801JI (ICH10 Family) PCI Express Ro...\n0000:00:1c.1\tIntel Corporation   \t82801JI (ICH10 Family) PCI Express Po...\n0000:00:1c.4\tIntel Corporation   \t82801JI (ICH10 Family) PCI Express Ro...\n0000:00:1d.0\tIntel Corporation   \t82801JI (ICH10 Family) USB UHCI Contr...\n0000:00:1d.1\tIntel Corporation   \t82801JI (ICH10 Family) USB UHCI Contr...\n0000:00:1d.2\tIntel Corporation   \t82801JI (ICH10 Family) USB UHCI Contr...\n0000:00:1d.7\tIntel Corporation   \t82801JI (ICH10 Family) USB2 EHCI Cont...\n0000:00:1e.0\tIntel Corporation   \t82801 PCI Bridge\n0000:00:1f.0\tIntel Corporation   \t82801JIR (ICH10R) LPC Interface Contr...\n0000:00:1f.2\tIntel Corporation   \t82801JI (ICH10 Family) SATA AHCI Cont...\n0000:00:1f.3\tIntel Corporation   \t82801JI (ICH10 Family) SMBus Controller\n0000:01:00.0\tNEC Corporation     \tuPD720200 USB 3.0 Host Controller\n0000:02:00.0\tMarvell Technolog...\t88SE9123 PCIe SATA 6.0 Gb/s controller\n0000:02:00.1\tMarvell Technolog...\t88SE912x IDE Controller\n0000:03:00.0\tNVIDIA Corporation  \tGP107 [GeForce GTX 1050 Ti]\n0000:03:00.1\tNVIDIA Corporation  \tUNKNOWN\n0000:04:00.0\tLSI Logic / Symbi...\tSAS2004 PCI-Express Fusion-MPT SAS-2 ...\n0000:06:00.0\tQualcomm Atheros    \tAR5418 Wireless Network Adapter [AR50...\n0000:08:03.0\tLSI Corporation     \tFW322/323 [TrueFire] 1394a Controller\n0000:3f:00.0\tIntel Corporation   \tUNKNOWN\n0000:3f:00.1\tIntel Corporation   \tXeon 5600 Series QuickPath Architectu...\n0000:3f:02.0\tIntel Corporation   \tXeon 5600 Series QPI Link 0\n0000:3f:02.1\tIntel Corporation   \tXeon 5600 Series QPI Physical 0\n0000:3f:02.2\tIntel Corporation   \tXeon 5600 Series Mirror Port Link 0\n0000:3f:02.3\tIntel Corporation   \tXeon 5600 Series Mirror Port Link 1\n0000:3f:03.0\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:03.1\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:03.4\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:04.0\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:04.1\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:04.2\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:04.3\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:05.0\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:05.1\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:05.2\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:05.3\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:06.0\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:06.1\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:06.2\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n0000:3f:06.3\tIntel Corporation   \tXeon 5600 Series Integrated Memory Co...\n```\n\n#### Finding a PCI device by PCI address\n\nIn addition to the above information, the `ghw.PCIInfo` struct has the\nfollowing method:\n\n* `ghw.PCIInfo.GetDevice(address string)`\n\nThe following code snippet shows how to call the `ghw.PCIInfo.GetDevice()`\nmethod and use its returned `ghw.PCIDevice` struct pointer:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tpci, err := ghw.PCI()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting PCI info: %v\", err)\n\t}\n\n\taddr := \"0000:00:00.0\"\n\tif len(os.Args) == 2 {\n\t\taddr = os.Args[1]\n\t}\n\tfmt.Printf(\"PCI device information for %s\\n\", addr)\n\tfmt.Println(\"====================================================\")\n\tdeviceInfo := pci.GetDevice(addr)\n\tif deviceInfo == nil {\n\t\tfmt.Printf(\"could not retrieve PCI device information for %s\\n\", addr)\n\t\treturn\n\t}\n\n\tvendor := deviceInfo.Vendor\n\tfmt.Printf(\"Vendor: %s [%s]\\n\", vendor.Name, vendor.ID)\n\tproduct := deviceInfo.Product\n\tfmt.Printf(\"Product: %s [%s]\\n\", product.Name, product.ID)\n\tsubsystem := deviceInfo.Subsystem\n\tsubvendor := pci.Vendors[subsystem.VendorID]\n\tsubvendorName := \"UNKNOWN\"\n\tif subvendor != nil {\n\t\tsubvendorName = subvendor.Name\n\t}\n\tfmt.Printf(\"Subsystem: %s [%s] (Subvendor: %s)\\n\", subsystem.Name, subsystem.ID, subvendorName)\n\tclass := deviceInfo.Class\n\tfmt.Printf(\"Class: %s [%s]\\n\", class.Name, class.ID)\n\tsubclass := deviceInfo.Subclass\n\tfmt.Printf(\"Subclass: %s [%s]\\n\", subclass.Name, subclass.ID)\n\tprogIface := deviceInfo.ProgrammingInterface\n\tfmt.Printf(\"Programming Interface: %s [%s]\\n\", progIface.Name, progIface.ID)\n}\n```\n\nHere's a sample output from my local workstation:\n\n```\nPCI device information for 0000:03:00.0\n====================================================\nVendor: NVIDIA Corporation [10de]\nProduct: GP107 [GeForce GTX 1050 Ti] [1c82]\nSubsystem: UNKNOWN [8613] (Subvendor: ASUSTeK Computer Inc.)\nClass: Display controller [03]\nSubclass: VGA compatible controller [00]\nProgramming Interface: VGA controller [00]\n```\n\n### GPU\n\nThe `ghw.GPU()` function returns a `ghw.GPUInfo` struct that contains\ninformation about the host computer's graphics hardware.\n\nThe `ghw.GPUInfo` struct contains one field:\n\n* `ghw.GPUInfo.GraphicCards` is an array of pointers to `ghw.GraphicsCard`\n  structs, one for each graphics card found for the system\n\nEach `ghw.GraphicsCard` struct contains the following fields:\n\n* `ghw.GraphicsCard.Index` is the system's numeric zero-based index for the\n  card on the bus\n* `ghw.GraphicsCard.Address` is the PCI address for the graphics card\n* `ghw.GraphicsCard.DeviceInfo` is a pointer to a `ghw.PCIDevice` struct\n  describing the graphics card. This may be `nil` if no PCI device information\n  could be determined for the card.\n* `ghw.GraphicsCard.Node` is an pointer to a `ghw.TopologyNode` struct that the\n  GPU/graphics card is affined to. On non-NUMA systems, this will always be\n  `nil`.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tgpu, err := ghw.GPU()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting GPU info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", gpu)\n\n\tfor _, card := range gpu.GraphicsCards {\n\t\tfmt.Printf(\" %v\\n\", card)\n\t}\n}\n```\n\nExample output from my personal workstation:\n\n```\ngpu (1 graphics card)\n card #0 @0000:03:00.0 -\u003e class: 'Display controller' vendor: 'NVIDIA Corporation' product: 'GP107 [GeForce GTX 1050 Ti]'\n```\n\n**NOTE**: You can [read more](#pci) about the fields of the `ghw.PCIDevice`\nstruct if you'd like to dig deeper into PCI subsystem and programming interface\ninformation\n\n**NOTE**: You can [read more](#topology) about the fields of the\n`ghw.TopologyNode` struct if you'd like to dig deeper into the NUMA/topology\nsubsystem\n\n### Accelerator\n\nThe `ghw.Accelerator()` function returns a `ghw.AcceleratorInfo` struct that contains\ninformation about the host computer's processing accelerator hardware. In this category\nwe can find used hardware for AI. The hardware detected in this category will be\nprocessing accelerators (PCI class `1200`), 3D controllers (`0302`) and Display\ncontrollers (`0380`).\n\nThe `ghw.AcceleratorInfo` struct contains one field:\n\n* `ghw.AcceleratorInfo.Devices` is an array of pointers to `ghw.AcceleratorDevice`\n  structs, one for each processing accelerator card found for the system.\n\nEach `ghw.AcceleratorDevice` struct contains the following fields:\n\n* `ghw.AcceleratorDevice.Address` is the PCI address for the processing accelerator card.\n* `ghw.AcceleratorDevice.PCIDevice` is a pointer to a `ghw.PCIDevice` struct.\n  describing the processing accelerator card. This may be `nil` if no PCI device\n  information could be determined for the card.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\taccel, err := ghw.Accelerator()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting processing accelerator info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", accel)\n\n\tfor _, card := range accel.Devices {\n\t\tfmt.Printf(\" %v\\n\", device)\n\t}\n}\n```\n\nExample output from a testing machine:\n\n```\nprocessing accelerators (1 device)\n device @0000:00:04.0 -\u003e driver: 'fake_pci_driver' class: 'Processing accelerators' vendor: 'Red Hat, Inc.' product: 'QEMU PCI Test Device'\n```\n\n**NOTE**: You can [read more](#pci) about the fields of the `ghw.PCIDevice`\nstruct if you'd like to dig deeper into PCI subsystem and programming interface\ninformation\n\n### Chassis\n\nThe `ghw.Chassis()` function returns a `ghw.ChassisInfo` struct that contains\ninformation about the host computer's hardware chassis.\n\nThe `ghw.ChassisInfo` struct contains multiple fields:\n\n* `ghw.ChassisInfo.AssetTag` is a string with the chassis asset tag\n* `ghw.ChassisInfo.SerialNumber` is a string with the chassis serial number\n* `ghw.ChassisInfo.Type` is a string with the chassis type *code*\n* `ghw.ChassisInfo.TypeDescription` is a string with a description of the\n  chassis type\n* `ghw.ChassisInfo.Vendor` is a string with the chassis vendor\n* `ghw.ChassisInfo.Version` is a string with the chassis version\n\n\u003e **NOTE**: These fields are often missing for non-server hardware. Don't be\n\u003e surprised to see empty string or \"None\" values.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tchassis, err := ghw.Chassis()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting chassis info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", chassis)\n}\n```\n\nExample output from my personal workstation:\n\n```\nchassis type=Desktop vendor=System76 version=thelio-r1\n```\n\n\u003e **NOTE**: Some of the values such as serial numbers are shown as unknown\n\u003e because the Linux kernel by default disallows access to those fields if\n\u003e you're not running as root. They will be populated if it runs as root or\n\u003e otherwise you may see warnings like the following:\n\n```\nWARNING: Unable to read chassis_serial: open /sys/class/dmi/id/chassis_serial: permission denied\n```\n\nYou can ignore them or use the [Disabling warning messages](#disabling-warning-messages)\nfeature to quiet things down.\n\n### BIOS\n\nThe `ghw.BIOS()` function returns a `ghw.BIOSInfo` struct that contains\ninformation about the host computer's basis input/output system (BIOS).\n\nThe `ghw.BIOSInfo` struct contains multiple fields:\n\n* `ghw.BIOSInfo.Vendor` is a string with the BIOS vendor\n* `ghw.BIOSInfo.Version` is a string with the BIOS version\n* `ghw.BIOSInfo.Date` is a string with the date the BIOS was flashed/created\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tbios, err := ghw.BIOS()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting BIOS info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", bios)\n}\n```\n\nExample output from my personal workstation:\n\n```\nbios vendor=System76 version=F2 Z5 date=11/14/2018\n```\n\n### Baseboard\n\nThe `ghw.Baseboard()` function returns a `ghw.BaseboardInfo` struct that\ncontains information about the host computer's hardware baseboard.\n\nThe `ghw.BaseboardInfo` struct contains multiple fields:\n\n* `ghw.BaseboardInfo.AssetTag` is a string with the baseboard asset tag\n* `ghw.BaseboardInfo.SerialNumber` is a string with the baseboard serial number\n* `ghw.BaseboardInfo.Vendor` is a string with the baseboard vendor\n* `ghw.BaseboardInfo.Product` is a string with the baseboard name on Linux and\n  Product on Windows\n* `ghw.BaseboardInfo.Version` is a string with the baseboard version\n\n\u003e **NOTE**: These fields are often missing for non-server hardware. Don't be\n\u003e surprised to see empty string or \"None\" values.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tbaseboard, err := ghw.Baseboard()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting baseboard info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", baseboard)\n}\n```\n\nExample output from my personal workstation:\n\n```\nbaseboard vendor=System76 version=thelio-r1\n```\n\n\u003e **NOTE**: Some of the values such as serial numbers are shown as unknown\n\u003e because the Linux kernel by default disallows access to those fields if\n\u003e you're not running as root. They will be populated if it runs as root or\n\u003e otherwise you may see warnings like the following:\n\n```\nWARNING: Unable to read board_serial: open /sys/class/dmi/id/board_serial: permission denied\n```\n\nYou can ignore them or use the [Disabling warning messages](#disabling-warning-messages)\nfeature to quiet things down.\n\n### Product\n\nThe `ghw.Product()` function returns a `ghw.ProductInfo` struct that\ncontains information about the host computer's hardware product line.\n\nThe `ghw.ProductInfo` struct contains multiple fields:\n\n* `ghw.ProductInfo.Family` is a string describing the product family\n* `ghw.ProductInfo.Name` is a string with the product name\n* `ghw.ProductInfo.SerialNumber` is a string with the product serial number\n* `ghw.ProductInfo.UUID` is a string with the product UUID\n* `ghw.ProductInfo.SKU` is a string with the product stock unit identifier\n  (SKU)\n* `ghw.ProductInfo.Vendor` is a string with the product vendor\n* `ghw.ProductInfo.Version` is a string with the product version\n\n\u003e **NOTE**: These fields are often missing for non-server hardware. Don't be\n\u003e surprised to see empty string, \"Default string\" or \"None\" values.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tproduct, err := ghw.Product()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting product info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%v\\n\", product)\n}\n```\n\nExample output from my personal workstation:\n\n```\nproduct family=Default string name=Thelio vendor=System76 sku=Default string version=thelio-r1\n```\n\n\u003e **NOTE**: Some of the values such as serial numbers are shown as unknown\n\u003e because the Linux kernel by default disallows access to those fields if\n\u003e you're not running as root.  They will be populated if it runs as root or\n\u003e otherwise you may see warnings like the following:\n\n```\nWARNING: Unable to read product_serial: open /sys/class/dmi/id/product_serial: permission denied\n```\n\nYou can ignore them or use the [Disabling warning messages](#disabling-warning-messages)\nfeature to quiet things down.\n\n## Advanced Usage\n\n### Disabling warning messages\n\nWhen `ghw` isn't able to retrieve some information, it may print certain\nwarning messages to `stderr`. To disable these warnings, simply set the\n`GHW_DISABLE_WARNINGS` environs variable:\n\n```\n$ ghwc memory\nWARNING:\nCould not determine total physical bytes of memory. This may\nbe due to the host being a virtual machine or container with no\n/var/log/syslog file, or the current user may not have necessary\nprivileges to read the syslog. We are falling back to setting the\ntotal physical amount of memory to the total usable amount of memory\nmemory (24GB physical, 24GB usable)\n```\n\n```\n$ GHW_DISABLE_WARNINGS=1 ghwc memory\nmemory (24GB physical, 24GB usable)\n```\n\nYou can disable warning programmatically using the `WithDisableWarnings` option:\n\n```go\n\nimport (\n\t\"github.com/jaypipes/ghw\"\n)\n\nmem, err := ghw.Memory(ghw.WithDisableWarnings())\n```\n\n`WithDisableWarnings` is a alias for the `WithNullAlerter` option, which in turn\nleverages the more general `Alerter` feature of ghw.\n\nYou may supply a `Alerter` to ghw to redirect all the warnings there, like\nlogger objects (see for example golang's stdlib `log.Logger`).\n`Alerter` is in fact the minimal logging interface `ghw needs.\nTo learn more, please check the `option.Alerter` interface and the `ghw.WithAlerter()`\nfunction.\n\n### Overriding the root mountpoint `ghw` uses\n\nWhen `ghw` looks for information about the host system, it considers `/` as its\nroot mountpoint. So, for example, when looking up CPU information on a Linux\nsystem, `ghw.CPU()` will use the path `/proc/cpuinfo`.\n\nIf you are calling `ghw` from a system that has an alternate root mountpoint,\nyou can either set the `GHW_CHROOT` environment variable to that alternate\npath, or call one of the functions like `ghw.CPU()` or `ghw.Memory()` with the\n`ghw.WithChroot()` modifier.\n\nFor example, if you are executing from within an application container that has\nbind-mounted the root host filesystem to the mount point `/host`, you would set\n`GHW_CHROOT` to `/host` so that `ghw` can find `/proc/cpuinfo` at\n`/host/proc/cpuinfo`.\n\nAlternately, you can use the `ghw.WithChroot()` function like so:\n\n```go\ncpu, err := ghw.CPU(ghw.WithChroot(\"/host\"))\n```\n\n### Serialization to JSON or YAML\n\nAll of the `ghw` `XXXInfo` structs -- e.g. `ghw.CPUInfo` -- have two methods\nfor producing a serialized JSON or YAML string representation of the contained\ninformation:\n\n* `JSONString()` returns a string containing the information serialized into\n  JSON. It accepts a single boolean parameter indicating whether to use\n  indentation when outputting the string\n* `YAMLString()` returns a string containing the information serialized into\n  YAML\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jaypipes/ghw\"\n)\n\nfunc main() {\n\tmem, err := ghw.Memory()\n\tif err != nil {\n\t\tfmt.Printf(\"Error getting memory info: %v\", err)\n\t}\n\n\tfmt.Printf(\"%s\", mem.YAMLString())\n}\n```\n\nthe above example code prints the following out on my local workstation:\n\n```\nmemory:\n  supported_page_sizes:\n  - 1073741824\n  - 2097152\n  total_physical_bytes: 25263415296\n  total_usable_bytes: 25263415296\n```\n\n### Overriding a specific mountpoint (Linux only)\n\nWhen running inside containers, it can be cumbersome to only override the root\nmountpoint. Inside containers, when granting access to the host file systems,\nit is common to bind-mount them to a non-standard location, like `/sys` on\n`/host-sys` or `/proc` to `/host-proc`.  It is rarer to mount them to a common\nsubtree (e.g. `/sys` to `/host/sys` and `/proc` to `/host/proc`...)\n\nTo better cover this use case, `ghw.WithPathOverrides()` can be used to supply\na mapping of directories to mountpoints, like this example shows:\n\n```go\ncpu, err := ghw.CPU(ghw.WithPathOverrides(ghw.PathOverrides{\n\t\"/proc\": \"/host-proc\",\n\t\"/sys\": \"/host-sys\",\n}))\n```\n\n**NOTE**: This feature works in addition and is composable with the\n`ghw.WithChroot()` function and `GHW_CHROOT` environment variable.\n\n### Reading hardware information from a `ghw` snapshot (Linux only)\n\nThe `ghw-snapshot` tool can create a snapshot of a host's hardware information.\n\nPlease read [`SNAPSHOT.md`](SNAPSHOT.md) to learn about creating snapshots with\nthe `ghw-snapshot` tool.\n\nYou can make `ghw` read hardware information from a snapshot created with\n`ghw-snapshot` using environment variables or programmatically.\n\nUse the `GHW_SNAPSHOT_PATH` environment variable to specify the filepath to a\nsnapshot that `ghw` will read to determine hardware information. All the needed\nchroot changes will be automatically performed. By default, the snapshot is\nunpacked into a temporary directory managed by `ghw`. This temporary directory\nis automatically deleted when `ghw` is finished reading the snapshot.\n\nThree other environment variables are relevant if and only if `GHW_SNAPSHOT_PATH`\nis not empty:\n\n* `GHW_SNAPSHOT_ROOT` let users specify the directory on which the snapshot\n  should be unpacked. This moves the ownership of that directory from `ghw` to\n  users. For this reason, `ghw` will *not* automatically clean up the content\n  unpacked into `GHW_SNAPSHOT_ROOT`.\n* `GHW_SNAPSHOT_EXCLUSIVE` tells `ghw` that the directory is meant only to\n  contain the given snapshot, thus `ghw` will *not* attempt to unpack it unless\n  the directory is empty.  You can use both `GHW_SNAPSHOT_ROOT` and\n  `GHW_SNAPSHOT_EXCLUSIVE` to make sure `ghw` unpacks the snapshot only once\n  regardless of how many `ghw` packages (e.g. cpu, memory) access it. Set the\n  value of this environment variable to any non-empty string.\n* `GHW_SNAPSHOT_PRESERVE` tells `ghw` not to clean up the unpacked snapshot.\n  Set the value of this environment variable to any non-empty string.\n\n```go\ncpu, err := ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{\n\tPath: \"/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz\",\n}))\n\n\nmyRoot := \"/my/safe/directory\"\ncpu, err := ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{\n\tPath: \"/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz\",\n\tRoot: \u0026myRoot,\n}))\n\nmyOtherRoot := \"/my/other/safe/directory\"\ncpu, err := ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{\n\tPath:      \"/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz\",\n\tRoot:      \u0026myOtherRoot,\n\tExclusive: true,\n}))\n```\n\n### Creating snapshots\n\nYou can create `ghw` snapshots using the `ghw-snapshot` tool or\nprogrammatically using the `pkg/snapshot` package.\n\nBelow is an example of creating a `ghw` snapshot using the `pkg/snapshot`\npackage.\n\n```go\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jaypipes/ghw/pkg/snapshot\"\n)\n\n// ...\n\nscratchDir, err := os.MkdirTemp(\"\", \"ghw-snapshot-*\")\nif err != nil {\n\tfmt.Printf(\"Error creating clone directory: %v\", err)\n}\ndefer os.RemoveAll(scratchDir)\n\n// this step clones all the files and directories ghw cares about\nif err := snapshot.CloneTreeInto(scratchDir); err != nil {\n\tfmt.Printf(\"error cloning into %q: %v\", scratchDir, err)\n}\n\n// optionally, you may add extra content into your snapshot.\n// ghw will ignore the extra content.\n// Glob patterns like `filepath.Glob` are supported.\nfileSpecs := []string{\n\t\"/proc/cmdline\",\n}\n\n// options allows the client code to optionally deference symlinks, or copy\n// them into the cloned tree as symlinks\nvar opts *snapshot.CopyFileOptions\nif err := snapshot.CopyFilesInto(fileSpecs, scratchDir, opts); err != nil {\n\tfmt.Printf(\"error cloning extra files into %q: %v\", scratchDir, err)\n}\n\n// automates the creation of the gzipped tarball out of the given tree.\nif err := snapshot.PackFrom(\"my-snapshot.tgz\", scratchDir); err != nil {\n\tfmt.Printf(\"error packing %q into %q: %v\", scratchDir, *output, err)\n}\n```\n\n## Calling external programs\n\nBy default `ghw` may call external programs, for example `ethtool`, to learn\nabout hardware capabilities.  In some rare circumstances it may be useful to\nopt out from this behaviour and rely only on the data provided by\npseudo-filesystems, like sysfs.\n\nThe most common use case is when we want to read a snapshot from `ghw`. In\nthese cases the information provided by tools will be inconsistent with the\ndata from the snapshot - since they will be run on a different host than the\nhost the snapshot was created for.\n\nTo prevent `ghw` from calling external tools, set the `GHW_DISABLE_TOOLS`\nenvironment variable to any value, or, programmatically, use the\n`ghw.WithDisableTools()` function.  The default behaviour of ghw is to call\nexternal tools when available.\n\n\u003e **WARNING**: on all platforms, disabling external tools make ghw return less\n\u003e data.  Unless noted otherwise, there is _no fallback flow_ if external tools\n\u003e are disabled. On MacOSX/Darwin, disabling external tools disables block\n\u003e support entirely\n\n## Developers\n\n[Contributions](CONTRIBUTING.md) to `ghw` are welcomed! Fork the repo on GitHub\nand submit a pull request with your proposed changes. Or, feel free to log an\nissue for a feature request or bug report.\n","funding_links":[],"categories":["Misc","开源类库","Go","Open source library","Hardware","硬件交互","硬件","Relational Databases"],"sub_categories":["系统信息","System Message","Search and Analytic Databases","Tutorials","检索及分析资料库","Advanced Console UIs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaypipes%2Fghw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaypipes%2Fghw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaypipes%2Fghw/lists"}