Skip to content

Commit ec3d8b8

Browse files
committed
Merge branch 'pm-tools'
Merge power management utilities changes for 5.18-rc1: - Add tracer tool for the amd-pstate driver (Jinzhou Su). - Fix PC6 displaying in turbostat on some systems (Artem Bityutskiy). - Add AMD P-State support to the cpupower utility (Huang Rui). * pm-tools: Documentation: amd-pstate: add tracer tool introduction tools/power/x86/amd_pstate_tracer: Add tracer tool for AMD P-state tools/power/x86/intel_pstate_tracer: make tracer as a module cpufreq: amd-pstate: Add more tracepoint for AMD P-State module turbostat: fix PC6 displaying on some systems cpupower: Add "perf" option to print AMD P-State information cpupower: Add function to print AMD P-State performance capabilities cpupower: Move print_speed function into misc helper cpupower: Enable boost state support for AMD P-State module cpupower: Add AMD P-State sysfs definition and access helper cpupower: Introduce ACPI CPPC library cpupower: Add the function to get the sysfs value from specific table cpupower: Initial AMD P-State capability cpupower: Add the function to check AMD P-State enabled cpupower: Add AMD P-State capability flag tools/power/cpupower/{ToDo => TODO}: Rename the todo file tools: cpupower: fix typo in cpupower-idle-set(1) manpage
2 parents ac9f310 + b020771 commit ec3d8b8

20 files changed

Lines changed: 911 additions & 198 deletions

File tree

Documentation/admin-guide/pm/amd-pstate.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,32 @@ governor (for the policies it is attached to), or by the ``CPUFreq`` core (for t
369369
policies with other scaling governors).
370370

371371

372+
Tracer Tool
373+
-------------
374+
375+
``amd_pstate_tracer.py`` can record and parse ``amd-pstate`` trace log, then
376+
generate performance plots. This utility can be used to debug and tune the
377+
performance of ``amd-pstate`` driver. The tracer tool needs to import intel
378+
pstate tracer.
379+
380+
Tracer tool located in ``linux/tools/power/x86/amd_pstate_tracer``. It can be
381+
used in two ways. If trace file is available, then directly parse the file
382+
with command ::
383+
384+
./amd_pstate_trace.py [-c cpus] -t <trace_file> -n <test_name>
385+
386+
Or generate trace file with root privilege, then parse and plot with command ::
387+
388+
sudo ./amd_pstate_trace.py [-c cpus] -n <test_name> -i <interval> [-m kbytes]
389+
390+
The test result can be found in ``results/test_name``. Following is the example
391+
about part of the output. ::
392+
393+
common_cpu common_secs common_usecs min_perf des_perf max_perf freq mperf apef tsc load duration_ms sample_num elapsed_time common_comm
394+
CPU_005 712 116384 39 49 166 0.7565 9645075 2214891 38431470 25.1 11.646 469 2.496 kworker/5:0-40
395+
CPU_006 712 116408 39 49 166 0.6769 8950227 1839034 37192089 24.06 11.272 470 2.496 kworker/6:0-1264
396+
397+
372398
Reference
373399
===========
374400

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ L: linux-pm@vger.kernel.org
10021002
S: Supported
10031003
F: Documentation/admin-guide/pm/amd-pstate.rst
10041004
F: drivers/cpufreq/amd-pstate*
1005+
F: tools/power/x86/amd_pstate_tracer/amd_pstate_trace.py
10051006

10061007
AMD PTDMA DRIVER
10071008
M: Sanjay R Mehta <sanju.mehta@amd.com>

drivers/cpufreq/amd-pstate-trace.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ TRACE_EVENT(amd_pstate_perf,
2727
TP_PROTO(unsigned long min_perf,
2828
unsigned long target_perf,
2929
unsigned long capacity,
30+
u64 freq,
31+
u64 mperf,
32+
u64 aperf,
33+
u64 tsc,
3034
unsigned int cpu_id,
3135
bool changed,
3236
bool fast_switch
@@ -35,6 +39,10 @@ TRACE_EVENT(amd_pstate_perf,
3539
TP_ARGS(min_perf,
3640
target_perf,
3741
capacity,
42+
freq,
43+
mperf,
44+
aperf,
45+
tsc,
3846
cpu_id,
3947
changed,
4048
fast_switch
@@ -44,6 +52,10 @@ TRACE_EVENT(amd_pstate_perf,
4452
__field(unsigned long, min_perf)
4553
__field(unsigned long, target_perf)
4654
__field(unsigned long, capacity)
55+
__field(unsigned long long, freq)
56+
__field(unsigned long long, mperf)
57+
__field(unsigned long long, aperf)
58+
__field(unsigned long long, tsc)
4759
__field(unsigned int, cpu_id)
4860
__field(bool, changed)
4961
__field(bool, fast_switch)
@@ -53,15 +65,23 @@ TRACE_EVENT(amd_pstate_perf,
5365
__entry->min_perf = min_perf;
5466
__entry->target_perf = target_perf;
5567
__entry->capacity = capacity;
68+
__entry->freq = freq;
69+
__entry->mperf = mperf;
70+
__entry->aperf = aperf;
71+
__entry->tsc = tsc;
5672
__entry->cpu_id = cpu_id;
5773
__entry->changed = changed;
5874
__entry->fast_switch = fast_switch;
5975
),
6076

61-
TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu cpu_id=%u changed=%s fast_switch=%s",
77+
TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu freq=%llu mperf=%llu aperf=%llu tsc=%llu cpu_id=%u changed=%s fast_switch=%s",
6278
(unsigned long)__entry->min_perf,
6379
(unsigned long)__entry->target_perf,
6480
(unsigned long)__entry->capacity,
81+
(unsigned long long)__entry->freq,
82+
(unsigned long long)__entry->mperf,
83+
(unsigned long long)__entry->aperf,
84+
(unsigned long long)__entry->tsc,
6585
(unsigned int)__entry->cpu_id,
6686
(__entry->changed) ? "true" : "false",
6787
(__entry->fast_switch) ? "true" : "false"

drivers/cpufreq/amd-pstate.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ MODULE_PARM_DESC(shared_mem,
6565

6666
static struct cpufreq_driver amd_pstate_driver;
6767

68+
/**
69+
* struct amd_aperf_mperf
70+
* @aperf: actual performance frequency clock count
71+
* @mperf: maximum performance frequency clock count
72+
* @tsc: time stamp counter
73+
*/
74+
struct amd_aperf_mperf {
75+
u64 aperf;
76+
u64 mperf;
77+
u64 tsc;
78+
};
79+
6880
/**
6981
* struct amd_cpudata - private CPU data for AMD P-State
7082
* @cpu: CPU number
@@ -81,6 +93,9 @@ static struct cpufreq_driver amd_pstate_driver;
8193
* @min_freq: the frequency that mapped to lowest_perf
8294
* @nominal_freq: the frequency that mapped to nominal_perf
8395
* @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf
96+
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
97+
* @prev: Last Aperf/Mperf/tsc count value read from register
98+
* @freq: current cpu frequency value
8499
* @boost_supported: check whether the Processor or SBIOS supports boost mode
85100
*
86101
* The amd_cpudata is key private data for each CPU thread in AMD P-State, and
@@ -102,6 +117,10 @@ struct amd_cpudata {
102117
u32 nominal_freq;
103118
u32 lowest_nonlinear_freq;
104119

120+
struct amd_aperf_mperf cur;
121+
struct amd_aperf_mperf prev;
122+
123+
u64 freq;
105124
bool boost_supported;
106125
};
107126

@@ -211,6 +230,39 @@ static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata,
211230
max_perf, fast_switch);
212231
}
213232

233+
static inline bool amd_pstate_sample(struct amd_cpudata *cpudata)
234+
{
235+
u64 aperf, mperf, tsc;
236+
unsigned long flags;
237+
238+
local_irq_save(flags);
239+
rdmsrl(MSR_IA32_APERF, aperf);
240+
rdmsrl(MSR_IA32_MPERF, mperf);
241+
tsc = rdtsc();
242+
243+
if (cpudata->prev.mperf == mperf || cpudata->prev.tsc == tsc) {
244+
local_irq_restore(flags);
245+
return false;
246+
}
247+
248+
local_irq_restore(flags);
249+
250+
cpudata->cur.aperf = aperf;
251+
cpudata->cur.mperf = mperf;
252+
cpudata->cur.tsc = tsc;
253+
cpudata->cur.aperf -= cpudata->prev.aperf;
254+
cpudata->cur.mperf -= cpudata->prev.mperf;
255+
cpudata->cur.tsc -= cpudata->prev.tsc;
256+
257+
cpudata->prev.aperf = aperf;
258+
cpudata->prev.mperf = mperf;
259+
cpudata->prev.tsc = tsc;
260+
261+
cpudata->freq = div64_u64((cpudata->cur.aperf * cpu_khz), cpudata->cur.mperf);
262+
263+
return true;
264+
}
265+
214266
static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
215267
u32 des_perf, u32 max_perf, bool fast_switch)
216268
{
@@ -226,8 +278,11 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
226278
value &= ~AMD_CPPC_MAX_PERF(~0L);
227279
value |= AMD_CPPC_MAX_PERF(max_perf);
228280

229-
trace_amd_pstate_perf(min_perf, des_perf, max_perf,
230-
cpudata->cpu, (value != prev), fast_switch);
281+
if (trace_amd_pstate_perf_enabled() && amd_pstate_sample(cpudata)) {
282+
trace_amd_pstate_perf(min_perf, des_perf, max_perf, cpudata->freq,
283+
cpudata->cur.mperf, cpudata->cur.aperf, cpudata->cur.tsc,
284+
cpudata->cpu, (value != prev), fast_switch);
285+
}
231286

232287
if (value == prev)
233288
return;

tools/power/cpupower/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
143143
utils/helpers/bitmask.h \
144144
utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
145145

146-
LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h
147-
LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c
148-
LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o
146+
LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h
147+
LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
148+
LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
149149
LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
150150

151151
override CFLAGS += -pipe
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <stdio.h>
4+
#include <errno.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <sys/types.h>
8+
#include <sys/stat.h>
9+
#include <fcntl.h>
10+
#include <unistd.h>
11+
12+
#include "cpupower_intern.h"
13+
#include "acpi_cppc.h"
14+
15+
/* ACPI CPPC sysfs access ***********************************************/
16+
17+
static int acpi_cppc_read_file(unsigned int cpu, const char *fname,
18+
char *buf, size_t buflen)
19+
{
20+
char path[SYSFS_PATH_MAX];
21+
22+
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/acpi_cppc/%s",
23+
cpu, fname);
24+
return cpupower_read_sysfs(path, buf, buflen);
25+
}
26+
27+
static const char * const acpi_cppc_value_files[] = {
28+
[HIGHEST_PERF] = "highest_perf",
29+
[LOWEST_PERF] = "lowest_perf",
30+
[NOMINAL_PERF] = "nominal_perf",
31+
[LOWEST_NONLINEAR_PERF] = "lowest_nonlinear_perf",
32+
[LOWEST_FREQ] = "lowest_freq",
33+
[NOMINAL_FREQ] = "nominal_freq",
34+
[REFERENCE_PERF] = "reference_perf",
35+
[WRAPAROUND_TIME] = "wraparound_time"
36+
};
37+
38+
unsigned long acpi_cppc_get_data(unsigned int cpu, enum acpi_cppc_value which)
39+
{
40+
unsigned long long value;
41+
unsigned int len;
42+
char linebuf[MAX_LINE_LEN];
43+
char *endp;
44+
45+
if (which >= MAX_CPPC_VALUE_FILES)
46+
return 0;
47+
48+
len = acpi_cppc_read_file(cpu, acpi_cppc_value_files[which],
49+
linebuf, sizeof(linebuf));
50+
if (len == 0)
51+
return 0;
52+
53+
value = strtoull(linebuf, &endp, 0);
54+
55+
if (endp == linebuf || errno == ERANGE)
56+
return 0;
57+
58+
return value;
59+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __ACPI_CPPC_H__
4+
#define __ACPI_CPPC_H__
5+
6+
enum acpi_cppc_value {
7+
HIGHEST_PERF,
8+
LOWEST_PERF,
9+
NOMINAL_PERF,
10+
LOWEST_NONLINEAR_PERF,
11+
LOWEST_FREQ,
12+
NOMINAL_FREQ,
13+
REFERENCE_PERF,
14+
WRAPAROUND_TIME,
15+
MAX_CPPC_VALUE_FILES
16+
};
17+
18+
unsigned long acpi_cppc_get_data(unsigned int cpu,
19+
enum acpi_cppc_value which);
20+
21+
#endif /* _ACPI_CPPC_H */

tools/power/cpupower/lib/cpufreq.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,21 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
8383
[STATS_NUM_TRANSITIONS] = "stats/total_trans"
8484
};
8585

86-
87-
static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
88-
enum cpufreq_value which)
86+
unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
87+
const char **table,
88+
unsigned int index,
89+
unsigned int size)
8990
{
9091
unsigned long value;
9192
unsigned int len;
9293
char linebuf[MAX_LINE_LEN];
9394
char *endp;
9495

95-
if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
96+
if (!table || index >= size || !table[index])
9697
return 0;
9798

98-
len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
99-
linebuf, sizeof(linebuf));
99+
len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
100+
sizeof(linebuf));
100101

101102
if (len == 0)
102103
return 0;
@@ -109,6 +110,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
109110
return value;
110111
}
111112

113+
static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
114+
enum cpufreq_value which)
115+
{
116+
return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
117+
which,
118+
MAX_CPUFREQ_VALUE_READ_FILES);
119+
}
120+
112121
/* read access to files which contain one string */
113122

114123
enum cpufreq_string {
@@ -124,7 +133,7 @@ static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
124133

125134

126135
static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
127-
enum cpufreq_string which)
136+
enum cpufreq_string which)
128137
{
129138
char linebuf[MAX_LINE_LEN];
130139
char *result;

tools/power/cpupower/lib/cpufreq.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,18 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
203203
int cpufreq_set_frequency(unsigned int cpu,
204204
unsigned long target_frequency);
205205

206+
/*
207+
* get the sysfs value from specific table
208+
*
209+
* Read the value with the sysfs file name from specific table. Does
210+
* only work if the cpufreq driver has the specific sysfs interfaces.
211+
*/
212+
213+
unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
214+
const char **table,
215+
unsigned int index,
216+
unsigned int size);
217+
206218
#ifdef __cplusplus
207219
}
208220
#endif

0 commit comments

Comments
 (0)