cpufreq: amd-pstate: Add more tracepoint for AMD P-State module

Add frequency, mperf, aperf and tsc in the trace. This can be used
to debug and tune the performance of AMD P-state driver.

Use the time difference between amd_pstate_update to calculate CPU
frequency. There could be sleep in arch_freq_get_on_cpu, so do not
use it here.

Signed-off-by: Jinzhou Su <Jinzhou.Su@amd.com>
Co-developed-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Jinzhou Su 2022-03-09 09:23:48 +08:00 committed by Rafael J. Wysocki
parent a1b6f487cb
commit 23c296fb7e
2 changed files with 78 additions and 3 deletions

View File

@ -27,6 +27,10 @@ TRACE_EVENT(amd_pstate_perf,
TP_PROTO(unsigned long min_perf, TP_PROTO(unsigned long min_perf,
unsigned long target_perf, unsigned long target_perf,
unsigned long capacity, unsigned long capacity,
u64 freq,
u64 mperf,
u64 aperf,
u64 tsc,
unsigned int cpu_id, unsigned int cpu_id,
bool changed, bool changed,
bool fast_switch bool fast_switch
@ -35,6 +39,10 @@ TRACE_EVENT(amd_pstate_perf,
TP_ARGS(min_perf, TP_ARGS(min_perf,
target_perf, target_perf,
capacity, capacity,
freq,
mperf,
aperf,
tsc,
cpu_id, cpu_id,
changed, changed,
fast_switch fast_switch
@ -44,6 +52,10 @@ TRACE_EVENT(amd_pstate_perf,
__field(unsigned long, min_perf) __field(unsigned long, min_perf)
__field(unsigned long, target_perf) __field(unsigned long, target_perf)
__field(unsigned long, capacity) __field(unsigned long, capacity)
__field(unsigned long long, freq)
__field(unsigned long long, mperf)
__field(unsigned long long, aperf)
__field(unsigned long long, tsc)
__field(unsigned int, cpu_id) __field(unsigned int, cpu_id)
__field(bool, changed) __field(bool, changed)
__field(bool, fast_switch) __field(bool, fast_switch)
@ -53,15 +65,23 @@ TRACE_EVENT(amd_pstate_perf,
__entry->min_perf = min_perf; __entry->min_perf = min_perf;
__entry->target_perf = target_perf; __entry->target_perf = target_perf;
__entry->capacity = capacity; __entry->capacity = capacity;
__entry->freq = freq;
__entry->mperf = mperf;
__entry->aperf = aperf;
__entry->tsc = tsc;
__entry->cpu_id = cpu_id; __entry->cpu_id = cpu_id;
__entry->changed = changed; __entry->changed = changed;
__entry->fast_switch = fast_switch; __entry->fast_switch = fast_switch;
), ),
TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu cpu_id=%u changed=%s fast_switch=%s", 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",
(unsigned long)__entry->min_perf, (unsigned long)__entry->min_perf,
(unsigned long)__entry->target_perf, (unsigned long)__entry->target_perf,
(unsigned long)__entry->capacity, (unsigned long)__entry->capacity,
(unsigned long long)__entry->freq,
(unsigned long long)__entry->mperf,
(unsigned long long)__entry->aperf,
(unsigned long long)__entry->tsc,
(unsigned int)__entry->cpu_id, (unsigned int)__entry->cpu_id,
(__entry->changed) ? "true" : "false", (__entry->changed) ? "true" : "false",
(__entry->fast_switch) ? "true" : "false" (__entry->fast_switch) ? "true" : "false"

View File

@ -65,6 +65,18 @@ MODULE_PARM_DESC(shared_mem,
static struct cpufreq_driver amd_pstate_driver; static struct cpufreq_driver amd_pstate_driver;
/**
* struct amd_aperf_mperf
* @aperf: actual performance frequency clock count
* @mperf: maximum performance frequency clock count
* @tsc: time stamp counter
*/
struct amd_aperf_mperf {
u64 aperf;
u64 mperf;
u64 tsc;
};
/** /**
* struct amd_cpudata - private CPU data for AMD P-State * struct amd_cpudata - private CPU data for AMD P-State
* @cpu: CPU number * @cpu: CPU number
@ -81,6 +93,9 @@ static struct cpufreq_driver amd_pstate_driver;
* @min_freq: the frequency that mapped to lowest_perf * @min_freq: the frequency that mapped to lowest_perf
* @nominal_freq: the frequency that mapped to nominal_perf * @nominal_freq: the frequency that mapped to nominal_perf
* @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf * @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
* @prev: Last Aperf/Mperf/tsc count value read from register
* @freq: current cpu frequency value
* @boost_supported: check whether the Processor or SBIOS supports boost mode * @boost_supported: check whether the Processor or SBIOS supports boost mode
* *
* The amd_cpudata is key private data for each CPU thread in AMD P-State, and * The amd_cpudata is key private data for each CPU thread in AMD P-State, and
@ -102,6 +117,10 @@ struct amd_cpudata {
u32 nominal_freq; u32 nominal_freq;
u32 lowest_nonlinear_freq; u32 lowest_nonlinear_freq;
struct amd_aperf_mperf cur;
struct amd_aperf_mperf prev;
u64 freq;
bool boost_supported; bool boost_supported;
}; };
@ -211,6 +230,39 @@ static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata,
max_perf, fast_switch); max_perf, fast_switch);
} }
static inline bool amd_pstate_sample(struct amd_cpudata *cpudata)
{
u64 aperf, mperf, tsc;
unsigned long flags;
local_irq_save(flags);
rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf);
tsc = rdtsc();
if (cpudata->prev.mperf == mperf || cpudata->prev.tsc == tsc) {
local_irq_restore(flags);
return false;
}
local_irq_restore(flags);
cpudata->cur.aperf = aperf;
cpudata->cur.mperf = mperf;
cpudata->cur.tsc = tsc;
cpudata->cur.aperf -= cpudata->prev.aperf;
cpudata->cur.mperf -= cpudata->prev.mperf;
cpudata->cur.tsc -= cpudata->prev.tsc;
cpudata->prev.aperf = aperf;
cpudata->prev.mperf = mperf;
cpudata->prev.tsc = tsc;
cpudata->freq = div64_u64((cpudata->cur.aperf * cpu_khz), cpudata->cur.mperf);
return true;
}
static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
u32 des_perf, u32 max_perf, bool fast_switch) u32 des_perf, u32 max_perf, bool fast_switch)
{ {
@ -226,8 +278,11 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
value &= ~AMD_CPPC_MAX_PERF(~0L); value &= ~AMD_CPPC_MAX_PERF(~0L);
value |= AMD_CPPC_MAX_PERF(max_perf); value |= AMD_CPPC_MAX_PERF(max_perf);
trace_amd_pstate_perf(min_perf, des_perf, max_perf, if (trace_amd_pstate_perf_enabled() && amd_pstate_sample(cpudata)) {
cpudata->cpu, (value != prev), fast_switch); trace_amd_pstate_perf(min_perf, des_perf, max_perf, cpudata->freq,
cpudata->cur.mperf, cpudata->cur.aperf, cpudata->cur.tsc,
cpudata->cpu, (value != prev), fast_switch);
}
if (value == prev) if (value == prev)
return; return;