mirror of
https://github.com/ClusterCockpit/cc-metric-collector.git
synced 2024-11-10 12:37:25 +01:00
fdb58b0be2
* Use sink-specific configurations to have more flexibility. Adjust sample sink configuration files * Add documentation * Add links to individual sink readmes * Fix link in README * HTTPS for HttpSink * If no CPU die id available, use the socket id instead
398 lines
8.1 KiB
Go
398 lines
8.1 KiB
Go
package ccTopology
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
cclogger "github.com/ClusterCockpit/cc-metric-collector/internal/ccLogger"
|
|
)
|
|
|
|
// intArrayContains scans an array of ints if the value str is present in the array
|
|
// If the specified value is found, the corresponding array index is returned.
|
|
// The bool value is used to signal success or failure
|
|
func intArrayContains(array []int, str int) (int, bool) {
|
|
for i, a := range array {
|
|
if a == str {
|
|
return i, true
|
|
}
|
|
}
|
|
return -1, false
|
|
}
|
|
|
|
func fileToInt(path string) int {
|
|
buffer, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
log.Print(err)
|
|
cclogger.ComponentError("ccTopology", "Reading", path, ":", err.Error())
|
|
return -1
|
|
}
|
|
sbuffer := strings.Replace(string(buffer), "\n", "", -1)
|
|
var id int64
|
|
//_, err = fmt.Scanf("%d", sbuffer, &id)
|
|
id, err = strconv.ParseInt(sbuffer, 10, 32)
|
|
if err != nil {
|
|
cclogger.ComponentError("ccTopology", "Parsing", path, ":", sbuffer, err.Error())
|
|
return -1
|
|
}
|
|
return int(id)
|
|
}
|
|
|
|
func SocketList() []int {
|
|
buffer, err := ioutil.ReadFile("/proc/cpuinfo")
|
|
if err != nil {
|
|
log.Print(err)
|
|
return nil
|
|
}
|
|
ll := strings.Split(string(buffer), "\n")
|
|
var packs []int
|
|
for _, line := range ll {
|
|
if strings.HasPrefix(line, "physical id") {
|
|
lv := strings.Fields(line)
|
|
id, err := strconv.ParseInt(lv[3], 10, 32)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return packs
|
|
}
|
|
_, found := intArrayContains(packs, int(id))
|
|
if !found {
|
|
packs = append(packs, int(id))
|
|
}
|
|
}
|
|
}
|
|
return packs
|
|
}
|
|
|
|
func CpuList() []int {
|
|
buffer, err := ioutil.ReadFile("/proc/cpuinfo")
|
|
if err != nil {
|
|
log.Print(err)
|
|
return nil
|
|
}
|
|
ll := strings.Split(string(buffer), "\n")
|
|
cpulist := make([]int, 0)
|
|
for _, line := range ll {
|
|
if strings.HasPrefix(line, "processor") {
|
|
lv := strings.Fields(line)
|
|
id, err := strconv.ParseInt(lv[2], 10, 32)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return cpulist
|
|
}
|
|
_, found := intArrayContains(cpulist, int(id))
|
|
if !found {
|
|
cpulist = append(cpulist, int(id))
|
|
}
|
|
}
|
|
}
|
|
return cpulist
|
|
}
|
|
|
|
func CoreList() []int {
|
|
buffer, err := ioutil.ReadFile("/proc/cpuinfo")
|
|
if err != nil {
|
|
log.Print(err)
|
|
return nil
|
|
}
|
|
ll := strings.Split(string(buffer), "\n")
|
|
corelist := make([]int, 0)
|
|
for _, line := range ll {
|
|
if strings.HasPrefix(line, "core id") {
|
|
lv := strings.Fields(line)
|
|
id, err := strconv.ParseInt(lv[3], 10, 32)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return corelist
|
|
}
|
|
_, found := intArrayContains(corelist, int(id))
|
|
if !found {
|
|
corelist = append(corelist, int(id))
|
|
}
|
|
}
|
|
}
|
|
return corelist
|
|
}
|
|
|
|
func NumaNodeList() []int {
|
|
numalist := make([]int, 0)
|
|
files, err := filepath.Glob("/sys/devices/system/node/node*")
|
|
if err != nil {
|
|
log.Print(err)
|
|
}
|
|
for _, f := range files {
|
|
finfo, err := os.Lstat(f)
|
|
if err == nil && (finfo.IsDir() || finfo.Mode()&os.ModeSymlink != 0) {
|
|
var id int
|
|
parts := strings.Split(f, "/")
|
|
_, err = fmt.Scanf("node%d", parts[len(parts)-1], &id)
|
|
if err == nil {
|
|
_, found := intArrayContains(numalist, int(id))
|
|
if !found {
|
|
numalist = append(numalist, int(id))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return numalist
|
|
}
|
|
|
|
func DieList() []int {
|
|
cpulist := CpuList()
|
|
dielist := make([]int, 0)
|
|
for _, c := range cpulist {
|
|
dieid := fileToInt(fmt.Sprintf("/sys/devices/system/cpu/cpu%d/topology/die_id", c))
|
|
_, found := intArrayContains(dielist, int(dieid))
|
|
if !found {
|
|
dielist = append(dielist, int(dieid))
|
|
}
|
|
}
|
|
return dielist
|
|
}
|
|
|
|
type CpuEntry struct {
|
|
Cpuid int
|
|
SMT int
|
|
Core int
|
|
Socket int
|
|
Numadomain int
|
|
Die int
|
|
}
|
|
|
|
func CpuData() []CpuEntry {
|
|
|
|
fileToInt := func(path string) int {
|
|
buffer, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
log.Print(err)
|
|
//cclogger.ComponentError("ccTopology", "Reading", path, ":", err.Error())
|
|
return -1
|
|
}
|
|
sbuffer := strings.Replace(string(buffer), "\n", "", -1)
|
|
var id int64
|
|
//_, err = fmt.Scanf("%d", sbuffer, &id)
|
|
id, err = strconv.ParseInt(sbuffer, 10, 32)
|
|
if err != nil {
|
|
cclogger.ComponentError("ccTopology", "Parsing", path, ":", sbuffer, err.Error())
|
|
return -1
|
|
}
|
|
return int(id)
|
|
}
|
|
getCore := func(basepath string) int {
|
|
return fileToInt(fmt.Sprintf("%s/core_id", basepath))
|
|
}
|
|
|
|
getSocket := func(basepath string) int {
|
|
return fileToInt(fmt.Sprintf("%s/physical_package_id", basepath))
|
|
}
|
|
|
|
getDie := func(basepath string) int {
|
|
return fileToInt(fmt.Sprintf("%s/die_id", basepath))
|
|
}
|
|
|
|
getSMT := func(cpuid int, basepath string) int {
|
|
buffer, err := ioutil.ReadFile(fmt.Sprintf("%s/thread_siblings_list", basepath))
|
|
if err != nil {
|
|
log.Print(err)
|
|
}
|
|
threadlist := make([]int, 0)
|
|
sbuffer := strings.Replace(string(buffer), "\n", "", -1)
|
|
for _, x := range strings.Split(sbuffer, ",") {
|
|
id, err := strconv.ParseInt(x, 10, 32)
|
|
if err != nil {
|
|
log.Print(err)
|
|
}
|
|
threadlist = append(threadlist, int(id))
|
|
}
|
|
for i, x := range threadlist {
|
|
if x == cpuid {
|
|
return i
|
|
}
|
|
}
|
|
return 1
|
|
}
|
|
|
|
getNumaDomain := func(basepath string) int {
|
|
files, err := filepath.Glob(fmt.Sprintf("%s/node*", basepath))
|
|
if err != nil {
|
|
log.Print(err)
|
|
}
|
|
for _, f := range files {
|
|
finfo, err := os.Lstat(f)
|
|
if err == nil && (finfo.IsDir() || finfo.Mode()&os.ModeSymlink != 0) {
|
|
var id int
|
|
parts := strings.Split(f, "/")
|
|
_, err = fmt.Scanf("node%d", parts[len(parts)-1], &id)
|
|
if err == nil {
|
|
return id
|
|
}
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
clist := make([]CpuEntry, 0)
|
|
for _, c := range CpuList() {
|
|
clist = append(clist, CpuEntry{Cpuid: c})
|
|
}
|
|
for _, centry := range clist {
|
|
centry.Socket = -1
|
|
centry.Numadomain = -1
|
|
centry.Die = -1
|
|
centry.Core = -1
|
|
// Set base directory for topology lookup
|
|
base := fmt.Sprintf("/sys/devices/system/cpu/cpu%d/topology", centry.Cpuid)
|
|
|
|
// Lookup CPU core id
|
|
centry.Core = getCore(base)
|
|
|
|
// Lookup CPU socket id
|
|
centry.Socket = getSocket(base)
|
|
|
|
// Lookup CPU die id
|
|
centry.Die = getDie(base)
|
|
if centry.Die < 0 {
|
|
centry.Die = centry.Socket
|
|
}
|
|
|
|
// Lookup SMT thread id
|
|
centry.SMT = getSMT(centry.Cpuid, base)
|
|
|
|
// Lookup NUMA domain id
|
|
centry.Numadomain = getNumaDomain(base)
|
|
|
|
}
|
|
return clist
|
|
}
|
|
|
|
type CpuInformation struct {
|
|
NumHWthreads int
|
|
SMTWidth int
|
|
NumSockets int
|
|
NumDies int
|
|
NumCores int
|
|
NumNumaDomains int
|
|
}
|
|
|
|
func CpuInfo() CpuInformation {
|
|
var c CpuInformation
|
|
|
|
smt := 0
|
|
numa := 0
|
|
die := 0
|
|
socket := 0
|
|
core := 0
|
|
cdata := CpuData()
|
|
for _, d := range cdata {
|
|
if d.SMT > smt {
|
|
smt = d.SMT
|
|
}
|
|
if d.Numadomain > numa {
|
|
numa = d.Numadomain
|
|
}
|
|
if d.Die > die {
|
|
die = d.Die
|
|
}
|
|
if d.Socket > socket {
|
|
socket = d.Socket
|
|
}
|
|
if d.Core > core {
|
|
core = d.Core
|
|
}
|
|
}
|
|
c.NumNumaDomains = numa + 1
|
|
c.SMTWidth = smt + 1
|
|
c.NumDies = die + 1
|
|
c.NumCores = core + 1
|
|
c.NumSockets = socket + 1
|
|
c.NumHWthreads = len(cdata)
|
|
return c
|
|
}
|
|
|
|
func GetCpuSocket(cpuid int) int {
|
|
cdata := CpuData()
|
|
for _, d := range cdata {
|
|
if d.Cpuid == cpuid {
|
|
return d.Socket
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func GetCpuNumaDomain(cpuid int) int {
|
|
cdata := CpuData()
|
|
for _, d := range cdata {
|
|
if d.Cpuid == cpuid {
|
|
return d.Numadomain
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func GetCpuDie(cpuid int) int {
|
|
cdata := CpuData()
|
|
for _, d := range cdata {
|
|
if d.Cpuid == cpuid {
|
|
return d.Die
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func GetCpuCore(cpuid int) int {
|
|
cdata := CpuData()
|
|
for _, d := range cdata {
|
|
if d.Cpuid == cpuid {
|
|
return d.Core
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func GetSocketCpus(socket int) []int {
|
|
all := CpuData()
|
|
cpulist := make([]int, 0)
|
|
for _, d := range all {
|
|
if d.Socket == socket {
|
|
cpulist = append(cpulist, d.Cpuid)
|
|
}
|
|
}
|
|
return cpulist
|
|
}
|
|
|
|
func GetNumaDomainCpus(domain int) []int {
|
|
all := CpuData()
|
|
cpulist := make([]int, 0)
|
|
for _, d := range all {
|
|
if d.Numadomain == domain {
|
|
cpulist = append(cpulist, d.Cpuid)
|
|
}
|
|
}
|
|
return cpulist
|
|
}
|
|
|
|
func GetDieCpus(die int) []int {
|
|
all := CpuData()
|
|
cpulist := make([]int, 0)
|
|
for _, d := range all {
|
|
if d.Die == die {
|
|
cpulist = append(cpulist, d.Cpuid)
|
|
}
|
|
}
|
|
return cpulist
|
|
}
|
|
|
|
func GetCoreCpus(core int) []int {
|
|
all := CpuData()
|
|
cpulist := make([]int, 0)
|
|
for _, d := range all {
|
|
if d.Core == core {
|
|
cpulist = append(cpulist, d.Cpuid)
|
|
}
|
|
}
|
|
return cpulist
|
|
}
|