mirror of
https://github.com/ClusterCockpit/cc-metric-collector.git
synced 2024-12-27 23:59:05 +01:00
Use init function to initalize cache structure to avoid multi threading problems
This commit is contained in:
parent
b3922b3255
commit
ae106566dd
@ -32,11 +32,164 @@ type HwthreadEntry struct {
|
|||||||
|
|
||||||
var cache struct {
|
var cache struct {
|
||||||
SocketList []int
|
SocketList []int
|
||||||
|
uniqSocketList []int
|
||||||
HwthreadList []int
|
HwthreadList []int
|
||||||
|
uniqHwthreadList []int
|
||||||
CoreList []int
|
CoreList []int
|
||||||
|
uniqCoreList []int
|
||||||
CpuData []HwthreadEntry
|
CpuData []HwthreadEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
file, err := os.Open(PROCFS_CPUINFO)
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lineSplit := strings.Split(scanner.Text(), ":")
|
||||||
|
if len(lineSplit) == 2 {
|
||||||
|
key := strings.TrimSpace(lineSplit[0])
|
||||||
|
value := strings.TrimSpace(lineSplit[1])
|
||||||
|
switch key {
|
||||||
|
case "physical id":
|
||||||
|
id, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cache.SocketList = append(cache.SocketList, id)
|
||||||
|
case "processor":
|
||||||
|
id, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cache.HwthreadList = append(cache.HwthreadList, id)
|
||||||
|
case "core id":
|
||||||
|
id, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cache.CoreList = append(cache.CoreList, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.uniqHwthreadList = slices.Clone(cache.HwthreadList)
|
||||||
|
slices.Sort(cache.uniqHwthreadList)
|
||||||
|
cache.uniqHwthreadList = slices.Compact(cache.uniqHwthreadList)
|
||||||
|
|
||||||
|
cache.uniqCoreList = slices.Clone(cache.CoreList)
|
||||||
|
slices.Sort(cache.uniqCoreList)
|
||||||
|
cache.uniqCoreList = slices.Compact(cache.uniqCoreList)
|
||||||
|
|
||||||
|
cache.uniqSocketList = slices.Clone(cache.SocketList)
|
||||||
|
slices.Sort(cache.uniqSocketList)
|
||||||
|
cache.uniqSocketList = slices.Compact(cache.uniqSocketList)
|
||||||
|
|
||||||
|
getCore :=
|
||||||
|
func(basePath string) int {
|
||||||
|
return fileToInt(filepath.Join(basePath, "core_id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getSocket :=
|
||||||
|
func(basePath string) int {
|
||||||
|
return fileToInt(filepath.Join(basePath, "physical_package_id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getDie :=
|
||||||
|
func(basePath string) int {
|
||||||
|
return fileToInt(filepath.Join(basePath, "die_id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getSMT :=
|
||||||
|
func(cpuID int, basePath string) int {
|
||||||
|
buffer, err := os.ReadFile(filepath.Join(basePath, "thread_siblings_list"))
|
||||||
|
if err != nil {
|
||||||
|
cclogger.ComponentError("CCTopology", "CpuData:getSMT", err.Error())
|
||||||
|
}
|
||||||
|
threadList := make([]int, 0)
|
||||||
|
stringBuffer := strings.TrimSpace(string(buffer))
|
||||||
|
for _, x := range strings.Split(stringBuffer, ",") {
|
||||||
|
id, err := strconv.Atoi(x)
|
||||||
|
if err != nil {
|
||||||
|
cclogger.ComponentError("CCTopology", "CpuData:getSMT", err.Error())
|
||||||
|
}
|
||||||
|
threadList = append(threadList, id)
|
||||||
|
}
|
||||||
|
if i := slices.Index(threadList, cpuID); i != -1 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
getNumaDomain :=
|
||||||
|
func(basePath string) int {
|
||||||
|
globPath := filepath.Join(basePath, "node*")
|
||||||
|
regexPath := filepath.Join(basePath, "node([[:digit:]]+)")
|
||||||
|
regex := regexp.MustCompile(regexPath)
|
||||||
|
files, err := filepath.Glob(globPath)
|
||||||
|
if err != nil {
|
||||||
|
cclogger.ComponentError("CCTopology", "CpuData:getNumaDomain", err.Error())
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
matches := regex.FindStringSubmatch(file)
|
||||||
|
if len(matches) == 2 {
|
||||||
|
id, err := strconv.Atoi(matches[1])
|
||||||
|
if err == nil {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cache.HwthreadList {
|
||||||
|
cache.CpuData =
|
||||||
|
append(
|
||||||
|
cache.CpuData,
|
||||||
|
HwthreadEntry{
|
||||||
|
CpuID: c,
|
||||||
|
Socket: -1,
|
||||||
|
NumaDomain: -1,
|
||||||
|
Die: -1,
|
||||||
|
Core: -1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for i := range cache.CpuData {
|
||||||
|
cEntry := &cache.CpuData[i]
|
||||||
|
|
||||||
|
// Set base directory for topology lookup
|
||||||
|
cpuStr := fmt.Sprintf("cpu%d", cEntry.CpuID)
|
||||||
|
base := filepath.Join("/sys/devices/system/cpu", cpuStr)
|
||||||
|
topoBase := filepath.Join(base, "topology")
|
||||||
|
|
||||||
|
// Lookup CPU core id
|
||||||
|
cEntry.Core = getCore(topoBase)
|
||||||
|
|
||||||
|
// Lookup CPU socket id
|
||||||
|
cEntry.Socket = getSocket(topoBase)
|
||||||
|
|
||||||
|
// Lookup CPU die id
|
||||||
|
cEntry.Die = getDie(topoBase)
|
||||||
|
if cEntry.Die < 0 {
|
||||||
|
cEntry.Die = cEntry.Socket
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup SMT thread id
|
||||||
|
cEntry.SMT = getSMT(cEntry.CpuID, topoBase)
|
||||||
|
|
||||||
|
// Lookup NUMA domain id
|
||||||
|
cEntry.NumaDomain = getNumaDomain(base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fileToInt reads an integer value from a file
|
// fileToInt reads an integer value from a file
|
||||||
// In case of an error -1 is returned
|
// In case of an error -1 is returned
|
||||||
// Used internally for sysfs file reads
|
// Used internally for sysfs file reads
|
||||||
@ -56,67 +209,14 @@ func fileToInt(path string) int {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSocketHwthreadCoreList() {
|
|
||||||
file, err := os.Open(PROCFS_CPUINFO)
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
for scanner.Scan() {
|
|
||||||
lineSplit := strings.Split(scanner.Text(), ":")
|
|
||||||
if len(lineSplit) == 2 {
|
|
||||||
key := strings.TrimSpace(lineSplit[0])
|
|
||||||
value := strings.TrimSpace(lineSplit[1])
|
|
||||||
switch key {
|
|
||||||
case "physical id":
|
|
||||||
id, err := strconv.Atoi(value)
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if found := slices.Contains(cache.SocketList, id); !found {
|
|
||||||
cache.SocketList = append(cache.SocketList, id)
|
|
||||||
}
|
|
||||||
case "processor":
|
|
||||||
id, err := strconv.Atoi(value)
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if found := slices.Contains(cache.HwthreadList, id); !found {
|
|
||||||
cache.HwthreadList = append(cache.HwthreadList, id)
|
|
||||||
}
|
|
||||||
case "core id":
|
|
||||||
id, err := strconv.Atoi(value)
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if found := slices.Contains(cache.CoreList, id); !found {
|
|
||||||
cache.CoreList = append(cache.CoreList, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SocketList gets the list of CPU socket IDs
|
// SocketList gets the list of CPU socket IDs
|
||||||
func SocketList() []int {
|
func SocketList() []int {
|
||||||
if cache.SocketList == nil {
|
return slices.Clone(cache.uniqSocketList)
|
||||||
initSocketHwthreadCoreList()
|
|
||||||
}
|
|
||||||
return slices.Clone(cache.SocketList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HwthreadList gets the list of hardware thread IDs in the order of listing in /proc/cpuinfo
|
// HwthreadList gets the list of hardware thread IDs in the order of listing in /proc/cpuinfo
|
||||||
func HwthreadList() []int {
|
func HwthreadList() []int {
|
||||||
if cache.HwthreadList == nil {
|
return slices.Clone(cache.uniqHwthreadList)
|
||||||
initSocketHwthreadCoreList()
|
|
||||||
}
|
|
||||||
return slices.Clone(cache.HwthreadList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get list of hardware thread IDs in the order of listing in /proc/cpuinfo
|
// Get list of hardware thread IDs in the order of listing in /proc/cpuinfo
|
||||||
@ -127,10 +227,7 @@ func CpuList() []int {
|
|||||||
|
|
||||||
// CoreList gets the list of CPU core IDs in the order of listing in /proc/cpuinfo
|
// CoreList gets the list of CPU core IDs in the order of listing in /proc/cpuinfo
|
||||||
func CoreList() []int {
|
func CoreList() []int {
|
||||||
if cache.CoreList == nil {
|
return slices.Clone(cache.uniqCoreList)
|
||||||
initSocketHwthreadCoreList()
|
|
||||||
}
|
|
||||||
return slices.Clone(cache.CoreList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get list of NUMA node IDs
|
// Get list of NUMA node IDs
|
||||||
@ -208,110 +305,7 @@ func GetTypeList(topology_type string) []int {
|
|||||||
return []int{}
|
return []int{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initCpuData() {
|
|
||||||
|
|
||||||
getCore :=
|
|
||||||
func(basePath string) int {
|
|
||||||
return fileToInt(filepath.Join(basePath, "core_id"))
|
|
||||||
}
|
|
||||||
|
|
||||||
getSocket :=
|
|
||||||
func(basePath string) int {
|
|
||||||
return fileToInt(filepath.Join(basePath, "physical_package_id"))
|
|
||||||
}
|
|
||||||
|
|
||||||
getDie :=
|
|
||||||
func(basePath string) int {
|
|
||||||
return fileToInt(filepath.Join(basePath, "die_id"))
|
|
||||||
}
|
|
||||||
|
|
||||||
getSMT :=
|
|
||||||
func(cpuID int, basePath string) int {
|
|
||||||
buffer, err := os.ReadFile(filepath.Join(basePath, "thread_siblings_list"))
|
|
||||||
if err != nil {
|
|
||||||
cclogger.ComponentError("CCTopology", "CpuData:getSMT", err.Error())
|
|
||||||
}
|
|
||||||
threadList := make([]int, 0)
|
|
||||||
stringBuffer := strings.TrimSpace(string(buffer))
|
|
||||||
for _, x := range strings.Split(stringBuffer, ",") {
|
|
||||||
id, err := strconv.Atoi(x)
|
|
||||||
if err != nil {
|
|
||||||
cclogger.ComponentError("CCTopology", "CpuData:getSMT", err.Error())
|
|
||||||
}
|
|
||||||
threadList = append(threadList, id)
|
|
||||||
}
|
|
||||||
if i := slices.Index(threadList, cpuID); i != -1 {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
getNumaDomain :=
|
|
||||||
func(basePath string) int {
|
|
||||||
globPath := filepath.Join(basePath, "node*")
|
|
||||||
regexPath := filepath.Join(basePath, "node([[:digit:]]+)")
|
|
||||||
regex := regexp.MustCompile(regexPath)
|
|
||||||
files, err := filepath.Glob(globPath)
|
|
||||||
if err != nil {
|
|
||||||
cclogger.ComponentError("CCTopology", "CpuData:getNumaDomain", err.Error())
|
|
||||||
}
|
|
||||||
for _, file := range files {
|
|
||||||
matches := regex.FindStringSubmatch(file)
|
|
||||||
if len(matches) == 2 {
|
|
||||||
id, err := strconv.Atoi(matches[1])
|
|
||||||
if err == nil {
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range HwthreadList() {
|
|
||||||
cache.CpuData =
|
|
||||||
append(
|
|
||||||
cache.CpuData,
|
|
||||||
HwthreadEntry{
|
|
||||||
CpuID: c,
|
|
||||||
Socket: -1,
|
|
||||||
NumaDomain: -1,
|
|
||||||
Die: -1,
|
|
||||||
Core: -1,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for i := range cache.CpuData {
|
|
||||||
cEntry := &cache.CpuData[i]
|
|
||||||
|
|
||||||
// Set base directory for topology lookup
|
|
||||||
cpuStr := fmt.Sprintf("cpu%d", cEntry.CpuID)
|
|
||||||
base := filepath.Join("/sys/devices/system/cpu", cpuStr)
|
|
||||||
topoBase := filepath.Join(base, "topology")
|
|
||||||
|
|
||||||
// Lookup CPU core id
|
|
||||||
cEntry.Core = getCore(topoBase)
|
|
||||||
|
|
||||||
// Lookup CPU socket id
|
|
||||||
cEntry.Socket = getSocket(topoBase)
|
|
||||||
|
|
||||||
// Lookup CPU die id
|
|
||||||
cEntry.Die = getDie(topoBase)
|
|
||||||
if cEntry.Die < 0 {
|
|
||||||
cEntry.Die = cEntry.Socket
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lookup SMT thread id
|
|
||||||
cEntry.SMT = getSMT(cEntry.CpuID, topoBase)
|
|
||||||
|
|
||||||
// Lookup NUMA domain id
|
|
||||||
cEntry.NumaDomain = getNumaDomain(base)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CpuData() []HwthreadEntry {
|
func CpuData() []HwthreadEntry {
|
||||||
if cache.CpuData == nil {
|
|
||||||
initCpuData()
|
|
||||||
}
|
|
||||||
return slices.Clone(cache.CpuData)
|
return slices.Clone(cache.CpuData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user