OSDN Git Service

perf tsc: Add cpuinfo fall back for arch_get_tsc_freq()
authorIan Rogers <irogers@google.com>
Mon, 18 Jul 2022 16:43:11 +0000 (09:43 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 25 Jul 2022 15:29:07 +0000 (12:29 -0300)
The CPUID method of arch_get_tsc_freq fails for older Intel processors,
such as Skylake. Compute using /proc/cpuinfo.

Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kshipra Bopardikar <kshipra.bopardikar@intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20220718164312.3994191-3-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/arch/x86/util/tsc.c

index b69144f..eb2b519 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/types.h>
+#include <math.h>
 #include <string.h>
 
+#include "../../../util/debug.h"
 #include "../../../util/tsc.h"
 #include "cpuid.h"
 
@@ -14,6 +16,44 @@ u64 rdtsc(void)
        return low | ((u64)high) << 32;
 }
 
+/*
+ * Derive the TSC frequency in Hz from the /proc/cpuinfo, for example:
+ * ...
+ * model name      : Intel(R) Xeon(R) Gold 6154 CPU @ 3.00GHz
+ * ...
+ * will return 3000000000.
+ */
+static double cpuinfo_tsc_freq(void)
+{
+       double result = 0;
+       FILE *cpuinfo;
+       char *line = NULL;
+       size_t len = 0;
+
+       cpuinfo = fopen("/proc/cpuinfo", "r");
+       if (!cpuinfo) {
+               pr_err("Failed to read /proc/cpuinfo for TSC frequency");
+               return NAN;
+       }
+       while (getline(&line, &len, cpuinfo) > 0) {
+               if (!strncmp(line, "model name", 10)) {
+                       char *pos = strstr(line + 11, " @ ");
+
+                       if (pos && sscanf(pos, " @ %lfGHz", &result) == 1) {
+                               result *= 1000000000;
+                               goto out;
+                       }
+               }
+       }
+out:
+       if (fpclassify(result) == FP_ZERO)
+               pr_err("Failed to find TSC frequency in /proc/cpuinfo");
+
+       free(line);
+       fclose(cpuinfo);
+       return result;
+}
+
 double arch_get_tsc_freq(void)
 {
        unsigned int a, b, c, d, lvl;
@@ -33,13 +73,17 @@ double arch_get_tsc_freq(void)
         * Don't support Time Stamp Counter and
         * Nominal Core Crystal Clock Information Leaf.
         */
-       if (lvl < 0x15)
-               return 0;
+       if (lvl < 0x15) {
+               tsc = cpuinfo_tsc_freq();
+               return tsc;
+       }
 
        cpuid(0x15, 0, &a, &b, &c, &d);
        /* TSC frequency is not enumerated */
-       if (!a || !b || !c)
-               return 0;
+       if (!a || !b || !c) {
+               tsc = cpuinfo_tsc_freq();
+               return tsc;
+       }
 
        tsc = (double)c * (double)b / (double)a;
        return tsc;