Skip to content

Commit 51f7d13

Browse files
authored
feat: Add support for CONFIG_CPU_FREQ_STAT (prometheus#627)
Extracts data from the following files: * `total_trans` * `trans_table` * `time_in_state` Refer: https://www.kernel.org/doc/html/latest/cpu-freq/cpufreq-stats.html#configuring-cpufreq-stats. Fixes: prometheus#428 Signed-off-by: Pranshu Srivastava <[email protected]>
1 parent 5a801c6 commit 51f7d13

File tree

3 files changed

+160
-27
lines changed

3 files changed

+160
-27
lines changed

sysfs/system_cpu.go

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ type SystemCPUCpufreqStats struct {
6565
Governor string
6666
RelatedCpus string
6767
SetSpeed string
68+
// Refer `CONFIG_CPU_FREQ_STAT`: https://www.kernel.org/doc/html/latest/cpu-freq/cpufreq-stats.html#configuring-cpufreq-stats
69+
CpuinfoFrequencyDuration *map[uint64]uint64
70+
CpuinfoFrequencyTransitionsTotal *uint64
71+
CpuinfoTransitionTable *[][]uint64
6872
}
6973

7074
// CPUs returns a slice of all CPUs in `/sys/devices/system/cpu`.
@@ -292,19 +296,93 @@ func parseCpufreqCpuinfo(cpuPath string) (*SystemCPUCpufreqStats, error) {
292296
}
293297
}
294298

299+
// "total_trans" is the total number of times the CPU has changed frequency.
300+
var cpuinfoFrequencyTransitionsTotal *uint64 = nil
301+
cpuinfoFrequencyTransitionsTotalUint, err := util.ReadUintFromFile(filepath.Join(cpuPath, "stats", "total_trans"))
302+
if err != nil {
303+
if !(os.IsNotExist(err) || os.IsPermission(err)) {
304+
return &SystemCPUCpufreqStats{}, err
305+
}
306+
} else {
307+
cpuinfoFrequencyTransitionsTotal = &cpuinfoFrequencyTransitionsTotalUint
308+
}
309+
310+
// "time_in_state" is the total time spent at each frequency.
311+
var cpuinfoFrequencyDuration *map[uint64]uint64 = nil
312+
cpuinfoFrequencyDurationString, err := util.ReadFileNoStat(filepath.Join(cpuPath, "stats", "time_in_state"))
313+
if err != nil {
314+
if !(os.IsNotExist(err) || os.IsPermission(err)) {
315+
return &SystemCPUCpufreqStats{}, err
316+
}
317+
} else {
318+
cpuinfoFrequencyDuration = &map[uint64]uint64{}
319+
for _, line := range strings.Split(string(cpuinfoFrequencyDurationString), "\n") {
320+
if line == "" {
321+
continue
322+
}
323+
fields := strings.Fields(line)
324+
if len(fields) != 2 {
325+
return &SystemCPUCpufreqStats{}, fmt.Errorf("unexpected number of fields in time_in_state: %v", fields)
326+
}
327+
freq, err := strconv.ParseUint(fields[0], 10, 64)
328+
if err != nil {
329+
return &SystemCPUCpufreqStats{}, err
330+
}
331+
duration, err := strconv.ParseUint(fields[1], 10, 64)
332+
if err != nil {
333+
return &SystemCPUCpufreqStats{}, err
334+
}
335+
(*cpuinfoFrequencyDuration)[freq] = duration
336+
}
337+
}
338+
339+
// "trans_table" contains information about all the CPU frequency transitions.
340+
var cpuinfoTransitionTable *[][]uint64 = nil
341+
cpuinfoTransitionTableString, err := util.ReadFileNoStat(filepath.Join(cpuPath, "stats", "trans_table"))
342+
if err != nil {
343+
if !(os.IsNotExist(err) || os.IsPermission(err)) {
344+
return &SystemCPUCpufreqStats{}, err
345+
}
346+
} else {
347+
cpuinfoTransitionTable = &[][]uint64{}
348+
for i, line := range strings.Split(string(cpuinfoTransitionTableString), "\n") {
349+
// Skip the "From: To" header.
350+
if i == 0 || line == "" {
351+
continue
352+
}
353+
fields := strings.Fields(line)
354+
fields[0] = strings.TrimSuffix(fields[0], ":")
355+
cpuinfoTransitionTableRow := make([]uint64, len(fields))
356+
for i := range fields {
357+
if len(fields[i]) == 0 {
358+
continue
359+
}
360+
f, err := strconv.ParseUint(fields[i], 10, 64)
361+
if err != nil {
362+
return &SystemCPUCpufreqStats{}, err
363+
}
364+
cpuinfoTransitionTableRow[i] = f
365+
}
366+
*cpuinfoTransitionTable = append(*cpuinfoTransitionTable, cpuinfoTransitionTableRow)
367+
}
368+
}
369+
295370
return &SystemCPUCpufreqStats{
296-
CpuinfoCurrentFrequency: uintOut[0],
297-
CpuinfoMaximumFrequency: uintOut[1],
298-
CpuinfoMinimumFrequency: uintOut[2],
299-
CpuinfoTransitionLatency: uintOut[3],
300-
ScalingCurrentFrequency: uintOut[4],
301-
ScalingMaximumFrequency: uintOut[5],
302-
ScalingMinimumFrequency: uintOut[6],
303-
AvailableGovernors: stringOut[0],
304-
Driver: stringOut[1],
305-
Governor: stringOut[2],
306-
RelatedCpus: stringOut[3],
307-
SetSpeed: stringOut[4],
371+
CpuinfoCurrentFrequency: uintOut[0],
372+
CpuinfoMaximumFrequency: uintOut[1],
373+
CpuinfoMinimumFrequency: uintOut[2],
374+
CpuinfoTransitionLatency: uintOut[3],
375+
ScalingCurrentFrequency: uintOut[4],
376+
ScalingMaximumFrequency: uintOut[5],
377+
ScalingMinimumFrequency: uintOut[6],
378+
AvailableGovernors: stringOut[0],
379+
Driver: stringOut[1],
380+
Governor: stringOut[2],
381+
RelatedCpus: stringOut[3],
382+
SetSpeed: stringOut[4],
383+
CpuinfoFrequencyDuration: cpuinfoFrequencyDuration,
384+
CpuinfoFrequencyTransitionsTotal: cpuinfoFrequencyTransitionsTotal,
385+
CpuinfoTransitionTable: cpuinfoTransitionTable,
308386
}, nil
309387
}
310388

sysfs/system_cpu_test.go

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -104,23 +104,38 @@ func TestSystemCpufreq(t *testing.T) {
104104
}
105105

106106
systemCpufreq := []SystemCPUCpufreqStats{
107-
// Has missing `cpuinfo_cur_freq` file.
107+
// The following files are missing for the first CPU:
108+
// * `cpuinfo_cur_freq`
109+
// * `time_in_state`
110+
// * `total_trans`
108111
{
109-
Name: "0",
110-
CpuinfoCurrentFrequency: nil,
111-
CpuinfoMinimumFrequency: makeUint64(800000),
112-
CpuinfoMaximumFrequency: makeUint64(2400000),
113-
CpuinfoTransitionLatency: makeUint64(0),
114-
ScalingCurrentFrequency: makeUint64(1219917),
115-
ScalingMinimumFrequency: makeUint64(800000),
116-
ScalingMaximumFrequency: makeUint64(2400000),
117-
AvailableGovernors: "performance powersave",
118-
Driver: "intel_pstate",
119-
Governor: "powersave",
120-
RelatedCpus: "0",
121-
SetSpeed: "<unsupported>",
112+
Name: "0",
113+
CpuinfoCurrentFrequency: nil,
114+
CpuinfoMinimumFrequency: makeUint64(800000),
115+
CpuinfoMaximumFrequency: makeUint64(2400000),
116+
CpuinfoTransitionLatency: makeUint64(0),
117+
ScalingCurrentFrequency: makeUint64(1219917),
118+
ScalingMinimumFrequency: makeUint64(800000),
119+
ScalingMaximumFrequency: makeUint64(2400000),
120+
AvailableGovernors: "performance powersave",
121+
Driver: "intel_pstate",
122+
Governor: "powersave",
123+
RelatedCpus: "0",
124+
SetSpeed: "<unsupported>",
125+
CpuinfoFrequencyDuration: nil,
126+
CpuinfoFrequencyTransitionsTotal: nil,
127+
CpuinfoTransitionTable: &[][]uint64{
128+
{0, 3600000, 3400000, 3200000, 3000000, 2800000},
129+
{3600000, 0, 5, 0, 0, 0},
130+
{3400000, 4, 0, 2, 0, 0},
131+
{3200000, 0, 1, 0, 2, 0},
132+
{3000000, 0, 0, 1, 0, 3},
133+
{2800000, 0, 0, 0, 2, 0},
134+
},
122135
},
123-
// Has missing `scaling_cur_freq` file.
136+
// The following files are missing for the second CPU:
137+
// * `scaling_cur_freq`
138+
// * `trans_table`
124139
{
125140
Name: "1",
126141
CpuinfoCurrentFrequency: makeUint64(1200195),
@@ -135,6 +150,15 @@ func TestSystemCpufreq(t *testing.T) {
135150
Governor: "powersave",
136151
RelatedCpus: "1",
137152
SetSpeed: "<unsupported>",
153+
CpuinfoFrequencyDuration: &map[uint64]uint64{
154+
3600000: 2089,
155+
3400000: 136,
156+
3200000: 34,
157+
3000000: 67,
158+
2800000: 172488,
159+
},
160+
CpuinfoFrequencyTransitionsTotal: makeUint64(20),
161+
CpuinfoTransitionTable: nil,
138162
},
139163
}
140164

testdata/fixtures.ttar

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13548,6 +13548,23 @@ Lines: 1
1354813548
<unsupported>
1354913549
Mode: 664
1355013550
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13551+
Directory: fixtures/sys/devices/system/cpu/cpu1/cpufreq/stats
13552+
Mode: 755
13553+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13554+
Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/stats/time_in_state
13555+
Lines: 5
13556+
3600000 2089
13557+
3400000 136
13558+
3200000 34
13559+
3000000 67
13560+
2800000 172488
13561+
Mode: 644
13562+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13563+
Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/stats/total_trans
13564+
Lines: 1
13565+
20
13566+
Mode: 644
13567+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1355113568
Directory: fixtures/sys/devices/system/cpu/cpu1/thermal_throttle
1355213569
Mode: 755
1355313570
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -13663,6 +13680,20 @@ Lines: 1
1366313680
<unsupported>
1366413681
Mode: 644
1366513682
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13683+
Directory: fixtures/sys/devices/system/cpu/cpufreq/policy0/stats
13684+
Mode: 755
13685+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13686+
Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/stats/trans_table
13687+
Lines: 7
13688+
From : To
13689+
: 3600000 3400000 3200000 3000000 2800000
13690+
3600000: 0 5 0 0 0
13691+
3400000: 4 0 2 0 0
13692+
3200000: 0 1 0 2 0
13693+
3000000: 0 0 1 0 3
13694+
2800000: 0 0 0 2 0
13695+
Mode: 644
13696+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1366613697
Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1
1366713698
Mode: 755
1366813699
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

0 commit comments

Comments
 (0)