Add per-node memory information to machine endpoint.

This commit is contained in:
Rohit Jnagal 2014-12-21 01:03:53 +00:00
parent 22cee3a89c
commit 8fa6389c64
3 changed files with 48 additions and 17 deletions

View File

@ -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"`
} }

View File

@ -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

View File

@ -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)