linux/tools/perf/arch/x86/util/tsc.c
Ian Rogers 069057239a perf tool_pmu: Move expr literals to tool_pmu
Add the expr literals like "#smt_on" as tool events, this allows stat
events to give the values. On my laptop with hyperthreading enabled:

```
$ perf stat -e "has_pmem,num_cores,num_cpus,num_cpus_online,num_dies,num_packages,smt_on,system_tsc_freq" true

 Performance counter stats for 'true':

                 0      has_pmem
                 8      num_cores
                16      num_cpus
                16      num_cpus_online
                 1      num_dies
                 1      num_packages
                 1      smt_on
     2,496,000,000      system_tsc_freq

       0.001113637 seconds time elapsed

       0.001218000 seconds user
       0.000000000 seconds sys
```

And with hyperthreading disabled:
```
$ perf stat -e "has_pmem,num_cores,num_cpus,num_cpus_online,num_dies,num_packages,smt_on,system_tsc_freq" true

 Performance counter stats for 'true':

                 0      has_pmem
                 8      num_cores
                16      num_cpus
                 8      num_cpus_online
                 1      num_dies
                 1      num_packages
                 0      smt_on
     2,496,000,000      system_tsc_freq

       0.000802115 seconds time elapsed

       0.000000000 seconds user
       0.000806000 seconds sys
```

As zero matters for these values, in stat-display
should_skip_zero_counter only skip the zero value if it is not the
first aggregation index.

The tool event implementations are used in expr but not evaluated as
events for simplicity. Also core_wide isn't made a tool event as it
requires command line parameters.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20241002032016.333748-8-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2024-10-10 23:40:32 -07:00

93 lines
1.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <linux/types.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "../../../util/debug.h"
#include "../../../util/tsc.h"
#include "cpuid.h"
u64 rdtsc(void)
{
unsigned int low, high;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
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 u64 cpuinfo_tsc_freq(void)
{
u64 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\n");
return 0;
}
while (getline(&line, &len, cpuinfo) > 0) {
if (!strncmp(line, "model name", 10)) {
char *pos = strstr(line + 11, " @ ");
double float_result;
if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) {
float_result *= 1000000000;
result = (u64)float_result;
goto out;
}
}
}
out:
if (result == 0)
pr_err("Failed to find TSC frequency in /proc/cpuinfo\n");
free(line);
fclose(cpuinfo);
return result;
}
u64 arch_get_tsc_freq(void)
{
unsigned int a, b, c, d, lvl;
static bool cached;
static double tsc;
char vendor[16];
if (cached)
return tsc;
cached = true;
get_cpuid_0(vendor, &lvl);
if (!strstr(vendor, "Intel"))
return 0;
/*
* Don't support Time Stamp Counter and
* Nominal Core Crystal Clock Information Leaf.
*/
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) {
tsc = cpuinfo_tsc_freq();
return tsc;
}
tsc = (u64)c * (u64)b / (u64)a;
return tsc;
}