Add Simultaneous Multithreading siblings

This commit is contained in:
Holger Obermaier 2023-09-08 11:07:37 +02:00
parent 7246278745
commit f3ffa29a37

View File

@ -17,12 +17,13 @@ const SYSFS_CPUBASE = `/sys/devices/system/cpu`
// Structure holding all information about a hardware thread // Structure holding all information about a hardware thread
type HwthreadEntry struct { type HwthreadEntry struct {
CpuID int // CPU hardware threads CpuID int // CPU hardware threads
SMT int // symmetric hyper threading ID SMT int // Simultaneous Multithreading ID
Core int // CPU core ID ThreadSiblingsList []int // Simultaneous Multithreading siblings
Socket int // CPU sockets (physical) ID Core int // CPU core ID
Die int // CPU Die ID Socket int // CPU sockets (physical) ID
NumaDomain int // NUMA Domain Die int // CPU Die ID
NumaDomain int // NUMA Domain
} }
var cache struct { var cache struct {
@ -36,30 +37,28 @@ var cache struct {
CpuData []HwthreadEntry CpuData []HwthreadEntry
} }
// fileToInt reads an integer value from a file // fileToInt reads an integer value from a sysfs file
// In case of an error -1 is returned // In case of an error -1 is returned
// Used internally for sysfs file reads
func fileToInt(path string) int { func fileToInt(path string) int {
buffer, err := os.ReadFile(path) buffer, err := os.ReadFile(path)
if err != nil { if err != nil {
log.Print(err) log.Print(err)
cclogger.ComponentError("ccTopology", "Reading", path, ":", err.Error()) cclogger.ComponentError("ccTopology", "fileToInt", "Reading", path, ":", err.Error())
return -1 return -1
} }
stringBuffer := strings.TrimSpace(string(buffer)) stringBuffer := strings.TrimSpace(string(buffer))
id, err := strconv.Atoi(stringBuffer) id, err := strconv.Atoi(stringBuffer)
if err != nil { if err != nil {
cclogger.ComponentError("ccTopology", "Parsing", path, ":", stringBuffer, err.Error()) cclogger.ComponentError("ccTopology", "fileToInt", "Parsing", path, ":", stringBuffer, err.Error())
return -1 return -1
} }
return id return id
} }
// fileToList reads a list from a file // fileToList reads a list from a sysfs file
// A list consists of value ranges separated by colon // A list consists of value ranges separated by colon
// A range can be a single value or a range of values given by a startValue-endValue // A range can be a single value or a range of values given by a startValue-endValue
// In case of an error nil is returned // In case of an error nil is returned
// Used internally for sysfs file reads
func fileToList(path string) []int { func fileToList(path string) []int {
// Read thread sibling list // Read thread sibling list
buffer, err := os.ReadFile(path) buffer, err := os.ReadFile(path)
@ -78,23 +77,25 @@ func fileToList(path string) []int {
case 1: case 1:
singleValue, err := strconv.Atoi(valueRange[0]) singleValue, err := strconv.Atoi(valueRange[0])
if err != nil { if err != nil {
cclogger.ComponentError("CCTopology", "fileToList", err.Error()) cclogger.ComponentError("CCTopology", "fileToList", "Parsing", valueRange[0], ":", err.Error())
return nil
} }
list = append(list, singleValue) list = append(list, singleValue)
case 2: case 2:
startValue, err := strconv.Atoi(valueRange[0]) startValue, err := strconv.Atoi(valueRange[0])
if err != nil { if err != nil {
cclogger.ComponentError("CCTopology", "fileToList", err.Error()) cclogger.ComponentError("CCTopology", "fileToList", "Parsing", valueRange[0], ":", err.Error())
return nil
} }
endValue, err := strconv.Atoi(valueRange[1]) endValue, err := strconv.Atoi(valueRange[1])
if err != nil { if err != nil {
cclogger.ComponentError("CCTopology", "fileToList", err.Error()) cclogger.ComponentError("CCTopology", "fileToList", "Parsing", valueRange[1], ":", err.Error())
return nil
} }
for value := startValue; value <= endValue; value++ { for value := startValue; value <= endValue; value++ {
list = append(list, value) list = append(list, value)
} }
} }
} }
return list return list
@ -149,19 +150,26 @@ func init() {
// File globbing for NUMA node // File globbing for NUMA node
files, err := filepath.Glob(globPath) files, err := filepath.Glob(globPath)
if err != nil { if err != nil {
cclogger.ComponentError("CCTopology", "CpuData:getNumaDomain", err.Error()) cclogger.ComponentError("CCTopology", "init:getNumaDomain", err.Error())
return -1
} }
// Check, that exactly one NUMA domain was found
if len(files) != 1 { if len(files) != 1 {
cclogger.ComponentError("CCTopology", "init:getNumaDomain", "Number of NUMA domains != 1: ", len(files))
return -1 return -1
} }
// Extract NUMA node ID // Extract NUMA node ID
matches := regex.FindStringSubmatch(files[0]) matches := regex.FindStringSubmatch(files[0])
if len(matches) != 2 { if len(matches) != 2 {
cclogger.ComponentError("CCTopology", "init:getNumaDomain", "Failed to extract NUMA node ID from: ", files[0])
return -1 return -1
} }
id, err := strconv.Atoi(matches[1]) id, err := strconv.Atoi(matches[1])
if err != nil { if err != nil {
cclogger.ComponentError("CCTopology", "init:getNumaDomain", "Failed to parse NUMA node ID from: ", matches[1])
return -1 return -1
} }
@ -174,14 +182,11 @@ func init() {
cache.DieList = make([]int, len(cache.HwthreadList)) cache.DieList = make([]int, len(cache.HwthreadList))
cache.SMTList = make([]int, len(cache.HwthreadList)) cache.SMTList = make([]int, len(cache.HwthreadList))
cache.NumaDomainList = make([]int, len(cache.HwthreadList)) cache.NumaDomainList = make([]int, len(cache.HwthreadList))
cache.CpuData = make([]HwthreadEntry, len(cache.HwthreadList))
for i, c := range cache.HwthreadList { for i, c := range cache.HwthreadList {
// Set base directory for topology lookup // Set cpuBase directory for topology lookup
base := cpuBase := filepath.Join(SYSFS_CPUBASE, fmt.Sprintf("cpu%d", c))
filepath.Join( topoBase := filepath.Join(cpuBase, "topology")
SYSFS_CPUBASE,
fmt.Sprintf("cpu%d", c),
)
topoBase := filepath.Join(base, "topology")
// Lookup Core ID // Lookup Core ID
cache.CoreList[i] = fileToInt(filepath.Join(topoBase, "core_id")) cache.CoreList[i] = fileToInt(filepath.Join(topoBase, "core_id"))
@ -196,14 +201,25 @@ func init() {
} }
// Lookup thread siblings list // Lookup thread siblings list
threadList := fileToList(filepath.Join(topoBase, "thread_siblings_list")) threadSiblingList := fileToList(filepath.Join(topoBase, "thread_siblings_list"))
// Find index of CPU ID in thread sibling list // Find index of CPU ID in thread sibling list
// if not found return -1 // if not found return -1
cache.SMTList[i] = slices.Index(threadList, c) cache.SMTList[i] = slices.Index(threadSiblingList, c)
// Lookup NUMA domain id // Lookup NUMA domain id
cache.NumaDomainList[i] = getNumaDomain(base) cache.NumaDomainList[i] = getNumaDomain(cpuBase)
cache.CpuData[i] =
HwthreadEntry{
CpuID: cache.HwthreadList[i],
SMT: cache.SMTList[i],
ThreadSiblingsList: threadSiblingList,
Socket: cache.SocketList[i],
NumaDomain: cache.NumaDomainList[i],
Die: cache.DieList[i],
Core: cache.CoreList[i],
}
} }
cache.uniqHwthreadList = slices.Clone(cache.HwthreadList) cache.uniqHwthreadList = slices.Clone(cache.HwthreadList)
@ -229,19 +245,6 @@ func init() {
cache.uniqNumaDomainList = slices.Clone(cache.NumaDomainList) cache.uniqNumaDomainList = slices.Clone(cache.NumaDomainList)
slices.Sort(cache.uniqNumaDomainList) slices.Sort(cache.uniqNumaDomainList)
cache.uniqNumaDomainList = slices.Compact(cache.uniqNumaDomainList) cache.uniqNumaDomainList = slices.Compact(cache.uniqNumaDomainList)
cache.CpuData = make([]HwthreadEntry, len(cache.HwthreadList))
for i := range cache.HwthreadList {
cache.CpuData[i] =
HwthreadEntry{
CpuID: cache.HwthreadList[i],
SMT: cache.SMTList[i],
Socket: cache.SocketList[i],
NumaDomain: cache.NumaDomainList[i],
Die: cache.DieList[i],
Core: cache.CoreList[i],
}
}
} }
// SocketList gets the list of CPU socket IDs // SocketList gets the list of CPU socket IDs
@ -299,7 +302,12 @@ func GetTypeList(topology_type string) []int {
// CpuData returns CPU data for each hardware thread // CpuData returns CPU data for each hardware thread
func CpuData() []HwthreadEntry { func CpuData() []HwthreadEntry {
return slices.Clone(cache.CpuData) // return a deep copy to protect cache data
c := slices.Clone(cache.CpuData)
for i := range c {
c[i].ThreadSiblingsList = slices.Clone(cache.CpuData[i].ThreadSiblingsList)
}
return c
} }
// Structure holding basic information about a CPU // Structure holding basic information about a CPU