Skip to content

Commit

Permalink
feat: Add support for CONFIG_CPU_FREQ_STAT
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
rexagod committed Apr 1, 2024
1 parent c5ada8d commit 9e52bd1
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 28 deletions.
102 changes: 90 additions & 12 deletions sysfs/system_cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ type SystemCPUCpufreqStats struct {
Governor string
RelatedCpus string
SetSpeed string
// Refer `CONFIG_CPU_FREQ_STAT`: https://www.kernel.org/doc/html/latest/cpu-freq/cpufreq-stats.html#configuring-cpufreq-stats
CpuinfoFrequencyDuration *map[uint64]uint64
CpuinfoFrequencyTransitionsTotal *uint64
CpuinfoTransitionTable *[][]uint64
}

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

// "total_trans" is the total number of times the CPU has changed frequency.
var cpuinfoFrequencyTransitionsTotal *uint64 = nil

Check failure on line 300 in sysfs/system_cpu.go

View workflow job for this annotation

GitHub Actions / lint

var-declaration: should drop = nil from declaration of var cpuinfoFrequencyTransitionsTotal; it is the zero value (revive)
cpuinfoFrequencyTransitionsTotalUint, err := util.ReadUintFromFile(filepath.Join(cpuPath, "stats", "total_trans"))
if err != nil {
if !(os.IsNotExist(err) || os.IsPermission(err)) {
return &SystemCPUCpufreqStats{}, err
}
} else {
cpuinfoFrequencyTransitionsTotal = &cpuinfoFrequencyTransitionsTotalUint
}

// "time_in_state" is the total time spent at each frequency.
var cpuinfoFrequencyDuration *map[uint64]uint64 = nil

Check failure on line 311 in sysfs/system_cpu.go

View workflow job for this annotation

GitHub Actions / lint

var-declaration: should drop = nil from declaration of var cpuinfoFrequencyDuration; it is the zero value (revive)
cpuinfoFrequencyDurationString, err := util.ReadFileNoStat(filepath.Join(cpuPath, "stats", "time_in_state"))
if err != nil {
if !(os.IsNotExist(err) || os.IsPermission(err)) {
return &SystemCPUCpufreqStats{}, err
}
} else {
cpuinfoFrequencyDuration = &map[uint64]uint64{}
for _, line := range strings.Split(string(cpuinfoFrequencyDurationString), "\n") {
if line == "" {
continue
}
fields := strings.Fields(line)
if len(fields) != 2 {
return &SystemCPUCpufreqStats{}, fmt.Errorf("unexpected number of fields in time_in_state: %v", fields)
}
freq, err := strconv.ParseUint(fields[0], 10, 64)
if err != nil {
return &SystemCPUCpufreqStats{}, err
}
duration, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
return &SystemCPUCpufreqStats{}, err
}
(*cpuinfoFrequencyDuration)[freq] = duration
}
}

// "trans_table" contains information about all the CPU frequency transitions.
var cpuinfoTransitionTable *[][]uint64 = nil

Check failure on line 340 in sysfs/system_cpu.go

View workflow job for this annotation

GitHub Actions / lint

var-declaration: should drop = nil from declaration of var cpuinfoTransitionTable; it is the zero value (revive)
cpuinfoTransitionTableString, err := util.ReadFileNoStat(filepath.Join(cpuPath, "stats", "trans_table"))
if err != nil {
if !(os.IsNotExist(err) || os.IsPermission(err)) {
return &SystemCPUCpufreqStats{}, err
}
} else {
cpuinfoTransitionTable = &[][]uint64{}
for i, line := range strings.Split(string(cpuinfoTransitionTableString), "\n") {
// Skip the "From: To" header.
if i == 0 || line == "" {
continue
}
fields := strings.Fields(line)
fields[0] = strings.TrimSuffix(fields[0], ":")
cpuinfoTransitionTableRow := make([]uint64, len(fields))
for i := range fields {
if len(fields[i]) == 0 {
continue
}
f, err := strconv.ParseUint(fields[i], 10, 64)
if err != nil {
return &SystemCPUCpufreqStats{}, err
}
cpuinfoTransitionTableRow[i] = f
}
*cpuinfoTransitionTable = append(*cpuinfoTransitionTable, cpuinfoTransitionTableRow)
}
}

return &SystemCPUCpufreqStats{
CpuinfoCurrentFrequency: uintOut[0],
CpuinfoMaximumFrequency: uintOut[1],
CpuinfoMinimumFrequency: uintOut[2],
CpuinfoTransitionLatency: uintOut[3],
ScalingCurrentFrequency: uintOut[4],
ScalingMaximumFrequency: uintOut[5],
ScalingMinimumFrequency: uintOut[6],
AvailableGovernors: stringOut[0],
Driver: stringOut[1],
Governor: stringOut[2],
RelatedCpus: stringOut[3],
SetSpeed: stringOut[4],
CpuinfoCurrentFrequency: uintOut[0],
CpuinfoMaximumFrequency: uintOut[1],
CpuinfoMinimumFrequency: uintOut[2],
CpuinfoTransitionLatency: uintOut[3],
ScalingCurrentFrequency: uintOut[4],
ScalingMaximumFrequency: uintOut[5],
ScalingMinimumFrequency: uintOut[6],
AvailableGovernors: stringOut[0],
Driver: stringOut[1],
Governor: stringOut[2],
RelatedCpus: stringOut[3],
SetSpeed: stringOut[4],
CpuinfoFrequencyDuration: cpuinfoFrequencyDuration,
CpuinfoFrequencyTransitionsTotal: cpuinfoFrequencyTransitionsTotal,
CpuinfoTransitionTable: cpuinfoTransitionTable,
}, nil
}

Expand Down
57 changes: 41 additions & 16 deletions sysfs/system_cpu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package sysfs

import (
"errors"
"github.com/google/go-cmp/cmp"
"reflect"
"testing"
)
Expand Down Expand Up @@ -104,23 +105,38 @@ func TestSystemCpufreq(t *testing.T) {
}

systemCpufreq := []SystemCPUCpufreqStats{
// Has missing `cpuinfo_cur_freq` file.
// The following files are missing for the first CPU:
// * `cpuinfo_cur_freq`
// * `time_in_state`
// * `total_trans`
{
Name: "0",
CpuinfoCurrentFrequency: nil,
CpuinfoMinimumFrequency: makeUint64(800000),
CpuinfoMaximumFrequency: makeUint64(2400000),
CpuinfoTransitionLatency: makeUint64(0),
ScalingCurrentFrequency: makeUint64(1219917),
ScalingMinimumFrequency: makeUint64(800000),
ScalingMaximumFrequency: makeUint64(2400000),
AvailableGovernors: "performance powersave",
Driver: "intel_pstate",
Governor: "powersave",
RelatedCpus: "0",
SetSpeed: "<unsupported>",
Name: "0",
CpuinfoCurrentFrequency: nil,
CpuinfoMinimumFrequency: makeUint64(800000),
CpuinfoMaximumFrequency: makeUint64(2400000),
CpuinfoTransitionLatency: makeUint64(0),
ScalingCurrentFrequency: makeUint64(1219917),
ScalingMinimumFrequency: makeUint64(800000),
ScalingMaximumFrequency: makeUint64(2400000),
AvailableGovernors: "performance powersave",
Driver: "intel_pstate",
Governor: "powersave",
RelatedCpus: "0",
SetSpeed: "<unsupported>",
CpuinfoFrequencyDuration: nil,
CpuinfoFrequencyTransitionsTotal: nil,
CpuinfoTransitionTable: &[][]uint64{
{0, 3600000, 3400000, 3200000, 3000000, 2800000},
{3600000, 0, 5, 0, 0, 0},
{3400000, 4, 0, 2, 0, 0},
{3200000, 0, 1, 0, 2, 0},
{3000000, 0, 0, 1, 0, 3},
{2800000, 0, 0, 0, 2, 0},
},
},
// Has missing `scaling_cur_freq` file.
// The following files are missing for the second CPU:
// * `scaling_cur_freq`
// * `trans_table`
{
Name: "1",
CpuinfoCurrentFrequency: makeUint64(1200195),
Expand All @@ -135,11 +151,20 @@ func TestSystemCpufreq(t *testing.T) {
Governor: "powersave",
RelatedCpus: "1",
SetSpeed: "<unsupported>",
CpuinfoFrequencyDuration: &map[uint64]uint64{
3600000: 2089,
3400000: 136,
3200000: 34,
3000000: 67,
2800000: 172488,
},
CpuinfoFrequencyTransitionsTotal: makeUint64(20),
CpuinfoTransitionTable: nil,
},
}

if !reflect.DeepEqual(systemCpufreq, c) {
t.Errorf("Result not correct: want %v, have %v", systemCpufreq, c)
t.Error(cmp.Diff(systemCpufreq, c))
}
}

Expand Down
31 changes: 31 additions & 0 deletions testdata/fixtures.ttar
Original file line number Diff line number Diff line change
Expand Up @@ -13548,6 +13548,23 @@ Lines: 1
<unsupported>
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/devices/system/cpu/cpu1/cpufreq/stats
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/stats/time_in_state
Lines: 5
3600000 2089
3400000 136
3200000 34
3000000 67
2800000 172488
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/stats/total_trans
Lines: 1
20
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/devices/system/cpu/cpu1/thermal_throttle
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down Expand Up @@ -13663,6 +13680,20 @@ Lines: 1
<unsupported>
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/devices/system/cpu/cpufreq/policy0/stats
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/stats/trans_table
Lines: 7
From : To
: 3600000 3400000 3200000 3000000 2800000
3600000: 0 5 0 0 0
3400000: 4 0 2 0 0
3200000: 0 1 0 2 0
3000000: 0 0 1 0 3
2800000: 0 0 0 2 0
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down

0 comments on commit 9e52bd1

Please sign in to comment.