Add per-node memory information to machine endpoint.
This commit is contained in:
parent
22cee3a89c
commit
8fa6389c64
@ -24,6 +24,8 @@ type FsInfo struct {
|
|||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Id int `json:"node_id"`
|
Id int `json:"node_id"`
|
||||||
|
// Per-node memory
|
||||||
|
Memory uint64 `json:"memory"`
|
||||||
Cores []Core `json:"cores"`
|
Cores []Core `json:"cores"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,20 @@ func getClockSpeed(procInfo []byte) (uint64, error) {
|
|||||||
return uint64(speed * 1000), nil
|
return uint64(speed * 1000), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMemoryCapacity(b []byte) (int64, error) {
|
||||||
|
matches := memoryCapacityRegexp.FindSubmatch(b)
|
||||||
|
if len(matches) != 2 {
|
||||||
|
return -1, fmt.Errorf("failed to find memory capacity in output: %q", string(b))
|
||||||
|
}
|
||||||
|
m, err := strconv.ParseInt(string(matches[1]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to bytes.
|
||||||
|
return m * 1024, err
|
||||||
|
}
|
||||||
|
|
||||||
func extractValue(s string, r *regexp.Regexp) (bool, int, error) {
|
func extractValue(s string, r *regexp.Regexp) (bool, int, error) {
|
||||||
matches := r.FindSubmatch([]byte(s))
|
matches := r.FindSubmatch([]byte(s))
|
||||||
if len(matches) == 2 {
|
if len(matches) == 2 {
|
||||||
@ -86,7 +100,7 @@ func findNode(nodes []info.Node, id int) (bool, int) {
|
|||||||
return false, -1
|
return false, -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func addNode(nodes *[]info.Node, id int) int {
|
func addNode(nodes *[]info.Node, id int) (int, error) {
|
||||||
var idx int
|
var idx int
|
||||||
if id == -1 {
|
if id == -1 {
|
||||||
// Some VMs don't fill topology data. Export single package.
|
// Some VMs don't fill topology data. Export single package.
|
||||||
@ -97,10 +111,21 @@ func addNode(nodes *[]info.Node, id int) int {
|
|||||||
if !ok {
|
if !ok {
|
||||||
// New node
|
// New node
|
||||||
node := info.Node{Id: id}
|
node := info.Node{Id: id}
|
||||||
|
// Add per-node memory information.
|
||||||
|
meminfo := fmt.Sprintf("/sys/devices/system/node/node%d/meminfo", id)
|
||||||
|
out, err := ioutil.ReadFile(meminfo)
|
||||||
|
// Ignore if per-node info is not available.
|
||||||
|
if err == nil {
|
||||||
|
m, err := getMemoryCapacity(out)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
node.Memory = uint64(m)
|
||||||
|
}
|
||||||
*nodes = append(*nodes, node)
|
*nodes = append(*nodes, node)
|
||||||
idx = len(*nodes) - 1
|
idx = len(*nodes) - 1
|
||||||
}
|
}
|
||||||
return idx
|
return idx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTopology(cpuinfo string) ([]info.Node, int, error) {
|
func getTopology(cpuinfo string) ([]info.Node, int, error) {
|
||||||
@ -112,14 +137,17 @@ func getTopology(cpuinfo string) ([]info.Node, int, error) {
|
|||||||
for _, line := range strings.Split(cpuinfo, "\n") {
|
for _, line := range strings.Split(cpuinfo, "\n") {
|
||||||
ok, val, err := extractValue(line, cpuRegExp)
|
ok, val, err := extractValue(line, cpuRegExp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, fmt.Errorf("could not parse cpu info from %q: %s", line, err)
|
return nil, -1, fmt.Errorf("could not parse cpu info from %q: %v", line, err)
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
thread := val
|
thread := val
|
||||||
numCores++
|
numCores++
|
||||||
if lastThread != -1 {
|
if lastThread != -1 {
|
||||||
// New cpu section. Save last one.
|
// New cpu section. Save last one.
|
||||||
nodeIdx := addNode(&nodes, lastNode)
|
nodeIdx, err := addNode(&nodes, lastNode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, fmt.Errorf("failed to add node %d: %v", lastNode, err)
|
||||||
|
}
|
||||||
nodes[nodeIdx].AddThread(lastThread, lastCore)
|
nodes[nodeIdx].AddThread(lastThread, lastCore)
|
||||||
lastCore = -1
|
lastCore = -1
|
||||||
lastNode = -1
|
lastNode = -1
|
||||||
@ -128,20 +156,23 @@ func getTopology(cpuinfo string) ([]info.Node, int, error) {
|
|||||||
}
|
}
|
||||||
ok, val, err = extractValue(line, coreRegExp)
|
ok, val, err = extractValue(line, coreRegExp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, fmt.Errorf("could not parse core info from %q: %s", line, err)
|
return nil, -1, fmt.Errorf("could not parse core info from %q: %v", line, err)
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
lastCore = val
|
lastCore = val
|
||||||
}
|
}
|
||||||
ok, val, err = extractValue(line, nodeRegExp)
|
ok, val, err = extractValue(line, nodeRegExp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, fmt.Errorf("could not parse node info from %q: %s", line, err)
|
return nil, -1, fmt.Errorf("could not parse node info from %q: %v", line, err)
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
lastNode = val
|
lastNode = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodeIdx := addNode(&nodes, lastNode)
|
nodeIdx, err := addNode(&nodes, lastNode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, fmt.Errorf("failed to add node %d: %v", lastNode, err)
|
||||||
|
}
|
||||||
nodes[nodeIdx].AddThread(lastThread, lastCore)
|
nodes[nodeIdx].AddThread(lastThread, lastCore)
|
||||||
if numCores < 1 {
|
if numCores < 1 {
|
||||||
return nil, numCores, fmt.Errorf("could not detect any cores")
|
return nil, numCores, fmt.Errorf("could not detect any cores")
|
||||||
@ -161,18 +192,12 @@ func getMachineInfo(sysFs sysfs.SysFs) (*info.MachineInfo, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
matches := memoryCapacityRegexp.FindSubmatch(out)
|
|
||||||
if len(matches) != 2 {
|
memoryCapacity, err := getMemoryCapacity(out)
|
||||||
return nil, fmt.Errorf("failed to find memory capacity in output: %s", string(out))
|
|
||||||
}
|
|
||||||
memoryCapacity, err := strconv.ParseInt(string(matches[1]), 10, 64)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capacity is in KB, convert it to bytes.
|
|
||||||
memoryCapacity = memoryCapacity * 1024
|
|
||||||
|
|
||||||
fsInfo, err := fs.NewFsInfo()
|
fsInfo, err := fs.NewFsInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -42,6 +42,8 @@ func TestTopology(t *testing.T) {
|
|||||||
numThreads := 2
|
numThreads := 2
|
||||||
for i := 0; i < numNodes; i++ {
|
for i := 0; i < numNodes; i++ {
|
||||||
node := info.Node{Id: i}
|
node := info.Node{Id: i}
|
||||||
|
// Copy over Memory from result. TODO(rjnagal): Use memory from fake.
|
||||||
|
node.Memory = topology[i].Memory
|
||||||
for j := 0; j < numCoresPerNode; j++ {
|
for j := 0; j < numCoresPerNode; j++ {
|
||||||
core := info.Core{Id: i*numCoresPerNode + j}
|
core := info.Core{Id: i*numCoresPerNode + j}
|
||||||
for k := 0; k < numThreads; k++ {
|
for k := 0; k < numThreads; k++ {
|
||||||
@ -66,6 +68,8 @@ func TestTopologyWithSimpleCpuinfo(t *testing.T) {
|
|||||||
core := info.Core{Id: 0}
|
core := info.Core{Id: 0}
|
||||||
core.Threads = append(core.Threads, 0)
|
core.Threads = append(core.Threads, 0)
|
||||||
node.Cores = append(node.Cores, core)
|
node.Cores = append(node.Cores, core)
|
||||||
|
// Copy over Memory from result. TODO(rjnagal): Use memory from fake.
|
||||||
|
node.Memory = topology[0].Memory
|
||||||
expected := []info.Node{node}
|
expected := []info.Node{node}
|
||||||
if !reflect.DeepEqual(topology, expected) {
|
if !reflect.DeepEqual(topology, expected) {
|
||||||
t.Errorf("Expected topology %+v, got %+v", expected, topology)
|
t.Errorf("Expected topology %+v, got %+v", expected, topology)
|
||||||
|
Loading…
Reference in New Issue
Block a user