]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
cpufreq: amd-pstate: Add more tracepoint for AMD P-State module
authorJinzhou Su <Jinzhou.Su@amd.com>
Wed, 9 Mar 2022 01:23:48 +0000 (09:23 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 9 Mar 2022 18:53:01 +0000 (19:53 +0100)
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>
drivers/cpufreq/amd-pstate-trace.h
drivers/cpufreq/amd-pstate.c

index 647505957d4f22d6d510fd186486dc3453af35f1..35f38ae67fb13d88a5cfcaeebf4c57a06aca38e2 100644 (file)
@@ -27,6 +27,10 @@ TRACE_EVENT(amd_pstate_perf,
        TP_PROTO(unsigned long min_perf,
                 unsigned long target_perf,
                 unsigned long capacity,
+                u64 freq,
+                u64 mperf,
+                u64 aperf,
+                u64 tsc,
                 unsigned int cpu_id,
                 bool changed,
                 bool fast_switch
@@ -35,6 +39,10 @@ TRACE_EVENT(amd_pstate_perf,
        TP_ARGS(min_perf,
                target_perf,
                capacity,
+               freq,
+               mperf,
+               aperf,
+               tsc,
                cpu_id,
                changed,
                fast_switch
@@ -44,6 +52,10 @@ TRACE_EVENT(amd_pstate_perf,
                __field(unsigned long, min_perf)
                __field(unsigned long, target_perf)
                __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(bool, changed)
                __field(bool, fast_switch)
@@ -53,15 +65,23 @@ TRACE_EVENT(amd_pstate_perf,
                __entry->min_perf = min_perf;
                __entry->target_perf = target_perf;
                __entry->capacity = capacity;
+               __entry->freq = freq;
+               __entry->mperf = mperf;
+               __entry->aperf = aperf;
+               __entry->tsc = tsc;
                __entry->cpu_id = cpu_id;
                __entry->changed = changed;
                __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->target_perf,
                  (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,
                  (__entry->changed) ? "true" : "false",
                  (__entry->fast_switch) ? "true" : "false"
index 9ce75ed11f8e832b6e209f178f916d34bb656147..7be38bc6a673b09c90d578413b38c731a135dc84 100644 (file)
@@ -65,6 +65,18 @@ MODULE_PARM_DESC(shared_mem,
 
 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
  * @cpu: CPU number
@@ -81,6 +93,9 @@ static struct cpufreq_driver amd_pstate_driver;
  * @min_freq: the frequency that mapped to lowest_perf
  * @nominal_freq: the frequency that mapped to nominal_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
  *
  * 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     lowest_nonlinear_freq;
 
+       struct amd_aperf_mperf cur;
+       struct amd_aperf_mperf prev;
+
+       u64 freq;
        bool    boost_supported;
 };
 
@@ -211,6 +230,39 @@ static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata,
                                            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,
                              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(max_perf);
 
-       trace_amd_pstate_perf(min_perf, des_perf, max_perf,
-                             cpudata->cpu, (value != prev), fast_switch);
+       if (trace_amd_pstate_perf_enabled() && amd_pstate_sample(cpudata)) {
+               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)
                return;