(v0.1.1) Automated packaging of release by Packagr
This commit is contained in:
+142
@@ -0,0 +1,142 @@
|
||||
// Use and distribution licensed under the Apache license version 2.
|
||||
//
|
||||
// See the COPYING file in the root project directory for full text.
|
||||
//
|
||||
|
||||
package ghw
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
_WARN_NO_SYS_CLASS_DRM = `
|
||||
/sys/class/drm does not exist on this system (likely the host system is a
|
||||
virtual machine or container with no graphics). Therefore,
|
||||
GPUInfo.GraphicsCards will be an empty array.
|
||||
`
|
||||
)
|
||||
|
||||
func (ctx *context) gpuFillInfo(info *GPUInfo) error {
|
||||
// In Linux, each graphics card is listed under the /sys/class/drm
|
||||
// directory as a symbolic link named "cardN", where N is a zero-based
|
||||
// index of the card in the system. "DRM" stands for Direct Rendering
|
||||
// Manager and is the Linux subsystem that is responsible for graphics I/O
|
||||
//
|
||||
// Each card may have multiple symbolic
|
||||
// links in this directory representing the interfaces from the graphics
|
||||
// card over a particular wire protocol (HDMI, DisplayPort, etc). These
|
||||
// symbolic links are named cardN-<INTERFACE_TYPE>-<DISPLAY_ID>. For
|
||||
// instance, on one of my local workstations with an NVIDIA GTX 1050ti
|
||||
// graphics card with one HDMI, one DisplayPort, and one DVI interface to
|
||||
// the card, I see the following in /sys/class/drm:
|
||||
//
|
||||
// $ ll /sys/class/drm/
|
||||
// total 0
|
||||
// drwxr-xr-x 2 root root 0 Jul 16 11:50 ./
|
||||
// drwxr-xr-x 75 root root 0 Jul 16 11:50 ../
|
||||
// lrwxrwxrwx 1 root root 0 Jul 16 11:50 card0 -> ../../devices/pci0000:00/0000:00:03.0/0000:03:00.0/drm/card0/
|
||||
// lrwxrwxrwx 1 root root 0 Jul 16 11:50 card0-DP-1 -> ../../devices/pci0000:00/0000:00:03.0/0000:03:00.0/drm/card0/card0-DP-1/
|
||||
// lrwxrwxrwx 1 root root 0 Jul 16 11:50 card0-DVI-D-1 -> ../../devices/pci0000:00/0000:00:03.0/0000:03:00.0/drm/card0/card0-DVI-D-1/
|
||||
// lrwxrwxrwx 1 root root 0 Jul 16 11:50 card0-HDMI-A-1 -> ../../devices/pci0000:00/0000:00:03.0/0000:03:00.0/drm/card0/card0-HDMI-A-1/
|
||||
//
|
||||
// In this routine, we are only interested in the first link (card0), which
|
||||
// we follow to gather information about the actual device from the PCI
|
||||
// subsystem (we query the modalias file of the PCI device's sysfs
|
||||
// directory using the `ghw.PCIInfo.GetDevice()` function.
|
||||
links, err := ioutil.ReadDir(ctx.pathSysClassDrm())
|
||||
if err != nil {
|
||||
warn(_WARN_NO_SYS_CLASS_DRM)
|
||||
return nil
|
||||
}
|
||||
cards := make([]*GraphicsCard, 0)
|
||||
for _, link := range links {
|
||||
lname := link.Name()
|
||||
if !strings.HasPrefix(lname, "card") {
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(lname, '-') {
|
||||
continue
|
||||
}
|
||||
// Grab the card's zero-based integer index
|
||||
lnameBytes := []byte(lname)
|
||||
cardIdx, err := strconv.Atoi(string(lnameBytes[4:]))
|
||||
if err != nil {
|
||||
cardIdx = -1
|
||||
}
|
||||
|
||||
// Calculate the card's PCI address by looking at the symbolic link's
|
||||
// target
|
||||
lpath := filepath.Join(ctx.pathSysClassDrm(), lname)
|
||||
dest, err := os.Readlink(lpath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
pathParts := strings.Split(dest, "/")
|
||||
numParts := len(pathParts)
|
||||
pciAddress := pathParts[numParts-3]
|
||||
card := &GraphicsCard{
|
||||
Address: pciAddress,
|
||||
Index: cardIdx,
|
||||
}
|
||||
cards = append(cards, card)
|
||||
}
|
||||
ctx.gpuFillNUMANodes(cards)
|
||||
ctx.gpuFillPCIDevice(cards)
|
||||
info.GraphicsCards = cards
|
||||
return nil
|
||||
}
|
||||
|
||||
// Loops through each GraphicsCard struct and attempts to fill the DeviceInfo
|
||||
// attribute with PCI device information
|
||||
func (ctx *context) gpuFillPCIDevice(cards []*GraphicsCard) {
|
||||
pci, err := PCI()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, card := range cards {
|
||||
if card.DeviceInfo == nil {
|
||||
card.DeviceInfo = pci.GetDevice(card.Address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loops through each GraphicsCard struct and find which NUMA node the card is
|
||||
// affined to, setting the GraphicsCard.Node field accordingly. If the host
|
||||
// system is not a NUMA system, the Node field will be set to nil.
|
||||
func (ctx *context) gpuFillNUMANodes(cards []*GraphicsCard) {
|
||||
topo := &TopologyInfo{}
|
||||
if err := ctx.topologyFillInfo(topo); err != nil {
|
||||
for _, card := range cards {
|
||||
if topo.Architecture != ARCHITECTURE_NUMA {
|
||||
card.Node = nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, card := range cards {
|
||||
// Each graphics card on a NUMA system will have a pseudo-file
|
||||
// called /sys/class/drm/card$CARD_INDEX/device/numa_node which
|
||||
// contains the NUMA node that the card is affined to
|
||||
cardIndexStr := strconv.Itoa(card.Index)
|
||||
fpath := filepath.Join(
|
||||
ctx.pathSysClassDrm(),
|
||||
"card"+cardIndexStr,
|
||||
"device",
|
||||
"numa_node",
|
||||
)
|
||||
nodeIdx := safeIntFromFile(fpath)
|
||||
if nodeIdx == -1 {
|
||||
continue
|
||||
}
|
||||
for _, node := range topo.Nodes {
|
||||
if nodeIdx == int(node.Id) {
|
||||
card.Node = node
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user