mirror of
				https://github.com/ClusterCockpit/cc-metric-collector.git
				synced 2025-11-04 10:45:06 +01:00 
			
		
		
		
	Fixed topology detection
This commit is contained in:
		@@ -32,10 +32,19 @@ func readOneLine(filename string) (text string, ok bool) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CPUFreqCollectorCPU struct {
 | 
					type CPUFreqCollectorTopology struct {
 | 
				
			||||||
	// coreID, packageID, num_cores, num_package
 | 
						processor          string // logical processor number (continuous, starting at 0)
 | 
				
			||||||
	tagSet             map[string]string
 | 
						coreID             string // socket local core ID
 | 
				
			||||||
 | 
						coreID_int         int
 | 
				
			||||||
 | 
						physicalID         string // socket / package ID
 | 
				
			||||||
 | 
						physicalID_int     int
 | 
				
			||||||
 | 
						numPhysicalID      string // number of  sockets / packages
 | 
				
			||||||
 | 
						numPhysicalID_int  int
 | 
				
			||||||
 | 
						isHT               bool
 | 
				
			||||||
 | 
						numNonHT           string // number of non hyperthreading processors
 | 
				
			||||||
 | 
						numNonHT_int       int
 | 
				
			||||||
	scalingCurFreqFile string
 | 
						scalingCurFreqFile string
 | 
				
			||||||
 | 
						tagSet             map[string]string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
@@ -48,10 +57,10 @@ type CPUFreqCollectorCPU struct {
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
type CPUFreqCollector struct {
 | 
					type CPUFreqCollector struct {
 | 
				
			||||||
	MetricCollector
 | 
						MetricCollector
 | 
				
			||||||
 | 
						topology []CPUFreqCollectorTopology
 | 
				
			||||||
	config   struct {
 | 
						config   struct {
 | 
				
			||||||
		ExcludeMetrics []string `json:"exclude_metrics,omitempty"`
 | 
							ExcludeMetrics []string `json:"exclude_metrics,omitempty"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cpus []CPUFreqCollectorCPU
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *CPUFreqCollector) Init(config []byte) error {
 | 
					func (m *CPUFreqCollector) Init(config []byte) error {
 | 
				
			||||||
@@ -64,9 +73,6 @@ func (m *CPUFreqCollector) Init(config []byte) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Initialize CPU list
 | 
					 | 
				
			||||||
	m.cpus = make([]CPUFreqCollectorCPU, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Loop for all CPU directories
 | 
						// Loop for all CPU directories
 | 
				
			||||||
	baseDir := "/sys/devices/system/cpu"
 | 
						baseDir := "/sys/devices/system/cpu"
 | 
				
			||||||
	globPattern := filepath.Join(baseDir, "cpu[0-9]*")
 | 
						globPattern := filepath.Join(baseDir, "cpu[0-9]*")
 | 
				
			||||||
@@ -78,21 +84,15 @@ func (m *CPUFreqCollector) Init(config []byte) error {
 | 
				
			|||||||
		return fmt.Errorf("CPUFreqCollector.Init() unable to find any files with pattern %s", globPattern)
 | 
							return fmt.Errorf("CPUFreqCollector.Init() unable to find any files with pattern %s", globPattern)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	maxPackageID := 0
 | 
						// Initialize CPU topology
 | 
				
			||||||
	maxCoreID := 0
 | 
						m.topology = make([]CPUFreqCollectorTopology, len(cpuDirs))
 | 
				
			||||||
	for _, cpuDir := range cpuDirs {
 | 
						for _, cpuDir := range cpuDirs {
 | 
				
			||||||
		cpuID := strings.TrimPrefix(cpuDir, "/sys/devices/system/cpu/cpu")
 | 
							processor := strings.TrimPrefix(cpuDir, "/sys/devices/system/cpu/cpu")
 | 
				
			||||||
 | 
							processor_int, err := strconv.Atoi(processor)
 | 
				
			||||||
		// Read thread sibling list
 | 
							if err != nil {
 | 
				
			||||||
		threadSiblingListFile := filepath.Join(cpuDir, "topology", "thread_siblings_list")
 | 
								return fmt.Errorf("CPUFreqCollector.Init() unable to convert cpuID to int: %v", err)
 | 
				
			||||||
		threadSiblingList, ok := readOneLine(threadSiblingListFile)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return fmt.Errorf("CPUFreqCollector.Init() unable to read thread siblings list from %s", threadSiblingListFile)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Read frequency only from first hardware thread
 | 
					 | 
				
			||||||
		// Ignore Simultaneous Multithreading (SMT) / Hyper-Threading
 | 
					 | 
				
			||||||
		if strings.Split(threadSiblingList, ",")[0] == cpuID {
 | 
					 | 
				
			||||||
		// Read package ID
 | 
							// Read package ID
 | 
				
			||||||
		packageIDFile := filepath.Join(cpuDir, "topology", "physical_package_id")
 | 
							packageIDFile := filepath.Join(cpuDir, "topology", "physical_package_id")
 | 
				
			||||||
		packageID, ok := readOneLine(packageIDFile)
 | 
							packageID, ok := readOneLine(packageIDFile)
 | 
				
			||||||
@@ -104,11 +104,6 @@ func (m *CPUFreqCollector) Init(config []byte) error {
 | 
				
			|||||||
			return fmt.Errorf("CPUFreqCollector.Init() unable to convert packageID to int: %v", err)
 | 
								return fmt.Errorf("CPUFreqCollector.Init() unable to convert packageID to int: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Update maxPackageID
 | 
					 | 
				
			||||||
			if packageID_int > maxPackageID {
 | 
					 | 
				
			||||||
				maxPackageID = packageID_int
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Read core ID
 | 
							// Read core ID
 | 
				
			||||||
		coreIDFile := filepath.Join(cpuDir, "topology", "core_id")
 | 
							coreIDFile := filepath.Join(cpuDir, "topology", "core_id")
 | 
				
			||||||
		coreID, ok := readOneLine(coreIDFile)
 | 
							coreID, ok := readOneLine(coreIDFile)
 | 
				
			||||||
@@ -120,11 +115,6 @@ func (m *CPUFreqCollector) Init(config []byte) error {
 | 
				
			|||||||
			return fmt.Errorf("CPUFreqCollector.Init() unable to convert coreID to int: %v", err)
 | 
								return fmt.Errorf("CPUFreqCollector.Init() unable to convert coreID to int: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Update maxCoreID
 | 
					 | 
				
			||||||
			if coreID_int > maxCoreID {
 | 
					 | 
				
			||||||
				maxCoreID = coreID_int
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Check access to current frequency file
 | 
							// Check access to current frequency file
 | 
				
			||||||
		scalingCurFreqFile := filepath.Join(cpuDir, "cpufreq", "scaling_cur_freq")
 | 
							scalingCurFreqFile := filepath.Join(cpuDir, "cpufreq", "scaling_cur_freq")
 | 
				
			||||||
		err = unix.Access(scalingCurFreqFile, unix.R_OK)
 | 
							err = unix.Access(scalingCurFreqFile, unix.R_OK)
 | 
				
			||||||
@@ -132,28 +122,60 @@ func (m *CPUFreqCollector) Init(config []byte) error {
 | 
				
			|||||||
			return fmt.Errorf("CPUFreqCollector.Init() unable to access %s: %v", scalingCurFreqFile, err)
 | 
								return fmt.Errorf("CPUFreqCollector.Init() unable to access %s: %v", scalingCurFreqFile, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			m.cpus = append(
 | 
							t := &m.topology[processor_int]
 | 
				
			||||||
				m.cpus,
 | 
							t.processor = processor
 | 
				
			||||||
				CPUFreqCollectorCPU{
 | 
							t.physicalID = packageID
 | 
				
			||||||
					tagSet: map[string]string{
 | 
							t.physicalID_int = packageID_int
 | 
				
			||||||
 | 
							t.coreID = coreID
 | 
				
			||||||
 | 
							t.coreID_int = coreID_int
 | 
				
			||||||
 | 
							t.scalingCurFreqFile = scalingCurFreqFile
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// is processor a hyperthread?
 | 
				
			||||||
 | 
						coreSeenBefore := make(map[string]bool)
 | 
				
			||||||
 | 
						for i := range m.topology {
 | 
				
			||||||
 | 
							t := &m.topology[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							globalID := t.physicalID + ":" + t.coreID
 | 
				
			||||||
 | 
							t.isHT = coreSeenBefore[globalID]
 | 
				
			||||||
 | 
							coreSeenBefore[globalID] = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// number of non hyper thread cores and packages / sockets
 | 
				
			||||||
 | 
						numNonHT_int := 0
 | 
				
			||||||
 | 
						maxPhysicalID := 0
 | 
				
			||||||
 | 
						for i := range m.topology {
 | 
				
			||||||
 | 
							t := &m.topology[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Update maxPackageID
 | 
				
			||||||
 | 
							if t.physicalID_int > maxPhysicalID {
 | 
				
			||||||
 | 
								maxPhysicalID = t.physicalID_int
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !t.isHT {
 | 
				
			||||||
 | 
								numNonHT_int++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						numPhysicalID_int := maxPhysicalID + 1
 | 
				
			||||||
 | 
						numPhysicalID := fmt.Sprint(numPhysicalID_int)
 | 
				
			||||||
 | 
						numNonHT := fmt.Sprint(numNonHT_int)
 | 
				
			||||||
 | 
						for i := range m.topology {
 | 
				
			||||||
 | 
							t := &m.topology[i]
 | 
				
			||||||
 | 
							t.numPhysicalID = numPhysicalID
 | 
				
			||||||
 | 
							t.numPhysicalID_int = numPhysicalID_int
 | 
				
			||||||
 | 
							t.numNonHT = numNonHT
 | 
				
			||||||
 | 
							t.numNonHT_int = numNonHT_int
 | 
				
			||||||
 | 
							t.tagSet = map[string]string{
 | 
				
			||||||
			"type":        "cpu",
 | 
								"type":        "cpu",
 | 
				
			||||||
						"type-id":   strings.TrimSpace(coreID),
 | 
								"type-id":     t.processor,
 | 
				
			||||||
						"packageID": strings.TrimSpace(packageID),
 | 
								"num_core":    t.numNonHT,
 | 
				
			||||||
					},
 | 
								"package_id":  t.physicalID,
 | 
				
			||||||
					scalingCurFreqFile: scalingCurFreqFile,
 | 
								"num_package": t.numPhysicalID,
 | 
				
			||||||
				})
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add num packages and num cores as tags
 | 
						fmt.Printf("%+v\n", m.topology)
 | 
				
			||||||
	numPackages := strconv.Itoa(maxPackageID + 1)
 | 
					 | 
				
			||||||
	numCores := strconv.Itoa(maxCoreID + 1)
 | 
					 | 
				
			||||||
	for i := range m.cpus {
 | 
					 | 
				
			||||||
		c := &m.cpus[i]
 | 
					 | 
				
			||||||
		c.tagSet["num_core"] = numCores
 | 
					 | 
				
			||||||
		c.tagSet["num_package"] = numPackages
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m.init = true
 | 
						m.init = true
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -164,13 +186,18 @@ func (m *CPUFreqCollector) Read(interval time.Duration, out *[]lp.MutableMetric)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	now := time.Now()
 | 
						now := time.Now()
 | 
				
			||||||
	for i := range m.cpus {
 | 
						for i := range m.topology {
 | 
				
			||||||
		cpu := &m.cpus[i]
 | 
							t := &m.topology[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// skip hyperthreads
 | 
				
			||||||
 | 
							if t.isHT {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Read current frequency
 | 
							// Read current frequency
 | 
				
			||||||
		line, ok := readOneLine(cpu.scalingCurFreqFile)
 | 
							line, ok := readOneLine(t.scalingCurFreqFile)
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			log.Printf("CPUFreqCollector.Read(): Failed to read one line from file '%s'", cpu.scalingCurFreqFile)
 | 
								log.Printf("CPUFreqCollector.Read(): Failed to read one line from file '%s'", t.scalingCurFreqFile)
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cpuFreq, err := strconv.Atoi(line)
 | 
							cpuFreq, err := strconv.Atoi(line)
 | 
				
			||||||
@@ -179,7 +206,7 @@ func (m *CPUFreqCollector) Read(interval time.Duration, out *[]lp.MutableMetric)
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		y, err := lp.New("cpufreq", cpu.tagSet, map[string]interface{}{"value": cpuFreq}, now)
 | 
							y, err := lp.New("cpufreq", t.tagSet, map[string]interface{}{"value": cpuFreq}, now)
 | 
				
			||||||
		if err == nil {
 | 
							if err == nil {
 | 
				
			||||||
			*out = append(*out, y)
 | 
								*out = append(*out, y)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user