Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for CONFIG_CPU_FREQ_STAT #627

Merged
merged 1 commit into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
cpuinfoFrequencyTransitionsTotalUint, err := util.ReadUintFromFile(filepath.Join(cpuPath, "stats", "total_trans"))
if err != nil {
if !(os.IsNotExist(err) || os.IsPermission(err)) {
return &SystemCPUCpufreqStats{}, err
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you not returning the error here but continue silently?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

procfs/sysfs/system_cpu.go

Lines 273 to 275 in 9eed744

if os.IsNotExist(err) || os.IsPermission(err) {
continue
}

For these cases I saw that we were skipping over silently in other parts of the codebase, and kept the norm here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, makes sense

} else {
cpuinfoFrequencyTransitionsTotal = &cpuinfoFrequencyTransitionsTotalUint
}

// "time_in_state" is the total time spent at each frequency.
var cpuinfoFrequencyDuration *map[uint64]uint64 = nil
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
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
54 changes: 39 additions & 15 deletions sysfs/system_cpu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,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,6 +150,15 @@ 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,
},
}

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