aboutsummaryrefslogtreecommitdiff
path: root/packages/numap/numa.go
diff options
context:
space:
mode:
Diffstat (limited to 'packages/numap/numa.go')
-rw-r--r--packages/numap/numa.go116
1 files changed, 116 insertions, 0 deletions
diff --git a/packages/numap/numa.go b/packages/numap/numa.go
new file mode 100644
index 0000000..402ea1d
--- /dev/null
+++ b/packages/numap/numa.go
@@ -0,0 +1,116 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "golang.fcuny.net/numap/internal/hwids"
+ "golang.fcuny.net/numap/internal/sysfs"
+)
+
+const (
+ node_root = "/sys/devices/system/node/node*"
+ CLASS_NVMe = 67586
+ CLASS_ETHERNET = 131072
+ CLASS_GPU = 197120
+)
+
+type node struct {
+ Name string `json:"name"`
+ Path string `json:"path"`
+ CpuList string `json:"cpulist"`
+ PCIDevices []PCIDevice `json:"pci_devices"`
+}
+
+type PCIDevice struct {
+ Vendor string `json:"vendor"`
+ Name string `json:"name"`
+}
+
+func findNodes(hwdb hwids.PciDevices) (map[string]node, error) {
+ nodes := make(map[string]node)
+
+ files, err := filepath.Glob(node_root)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to find NUMA nodes under %s: %+v", node_root, err)
+ }
+ if len(files) == 0 {
+ return nil, fmt.Errorf("Could not find NUMA node in %s", node_root)
+ }
+
+ for _, f := range files {
+ n, err := newNode(f)
+ if err != nil {
+ return make(map[string]node), err
+ }
+ nodes[n.Name] = n
+ }
+
+ r, err := mapPCIDevicesToNumaNode(hwdb)
+ if err != nil {
+ panic(err)
+ }
+ for k, v := range r {
+ nodeName := fmt.Sprintf("node%d", k)
+ n := nodes[nodeName]
+ n.PCIDevices = v
+ nodes[nodeName] = n
+ }
+ return nodes, nil
+}
+
+func mapPCIDevicesToNumaNode(hwdb hwids.PciDevices) (map[int][]PCIDevice, error) {
+ devices := sysfs.ScanPCIDevices()
+ r := map[int][]PCIDevice{}
+
+ for _, d := range devices {
+ if d.Class == CLASS_NVMe || d.Class == CLASS_ETHERNET || d.Class == CLASS_GPU {
+ _, ok := hwdb[uint16(d.Vendor)]
+ if ok {
+ desc := hwdb[uint16(d.Vendor)]
+ var vendor, name string
+ for _, m := range desc {
+ if uint64(m.Device) == d.Device && uint64(m.Vendor) == d.Vendor {
+ vendor = m.VendorName
+ name = m.DeviceName
+ break
+ }
+ }
+ pciDevice := PCIDevice{
+ Vendor: vendor,
+ Name: name,
+ }
+ r[d.NumaNode] = append(r[d.NumaNode], pciDevice)
+ }
+ }
+ }
+ return r, nil
+}
+
+func newNode(p string) (node, error) {
+ _, name := path.Split(p)
+
+ cpulist, err := cpuList(p)
+ if err != nil {
+ return node{}, err
+ }
+
+ return node{
+ Name: name,
+ Path: p,
+ CpuList: cpulist,
+ PCIDevices: []PCIDevice{},
+ }, nil
+}
+
+func cpuList(p string) (string, error) {
+ lpath := filepath.Join(p, "cpulist")
+ c, err := ioutil.ReadFile(lpath)
+ if err != nil {
+ return "", fmt.Errorf("Failed to open %s: %+v", lpath, err)
+ }
+ return strings.TrimRight(string(c), "\n"), nil
+}