Commit 06905723 authored by Ian Rogers's avatar Ian Rogers Committed by Namhyung Kim
Browse files

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: default avatarIan Rogers <irogers@google.com>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20241002032016.333748-8-irogers@google.com


Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
parent b8f1a1b0
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include "../../../util/header.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
#include "../../../util/tool_pmu.h"
#include <api/fs/fs.h>
#include <math.h>

@@ -24,7 +25,7 @@ const struct pmu_metrics_table *pmu_metrics_table__find(void)
	return NULL;
}

double perf_pmu__cpu_slots_per_cycle(void)
u64 tool_pmu__cpu_slots_per_cycle(void)
{
	char path[PATH_MAX];
	unsigned long long slots = 0;
@@ -41,5 +42,5 @@ double perf_pmu__cpu_slots_per_cycle(void)
		filename__read_ull(path, &slots);
	}

	return slots ? (double)slots : NAN;
	return slots;
}
+10 −8
Original line number Diff line number Diff line
@@ -24,9 +24,9 @@ u64 rdtsc(void)
 * ...
 * will return 3000000000.
 */
static double cpuinfo_tsc_freq(void)
static u64 cpuinfo_tsc_freq(void)
{
	double result = 0;
	u64 result = 0;
	FILE *cpuinfo;
	char *line = NULL;
	size_t len = 0;
@@ -34,20 +34,22 @@ static double cpuinfo_tsc_freq(void)
	cpuinfo = fopen("/proc/cpuinfo", "r");
	if (!cpuinfo) {
		pr_err("Failed to read /proc/cpuinfo for TSC frequency\n");
		return NAN;
		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", &result) == 1) {
				result *= 1000000000;
			if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) {
				float_result *= 1000000000;
				result = (u64)float_result;
				goto out;
			}
		}
	}
out:
	if (fpclassify(result) == FP_ZERO)
	if (result == 0)
		pr_err("Failed to find TSC frequency in /proc/cpuinfo\n");

	free(line);
@@ -55,7 +57,7 @@ static double cpuinfo_tsc_freq(void)
	return result;
}

double arch_get_tsc_freq(void)
u64 arch_get_tsc_freq(void)
{
	unsigned int a, b, c, d, lvl;
	static bool cached;
@@ -86,6 +88,6 @@ double arch_get_tsc_freq(void)
		return tsc;
	}

	tsc = (double)c * (double)b / (double)a;
	tsc = (u64)c * (u64)b / (u64)a;
	return tsc;
}
+13 −80
Original line number Diff line number Diff line
@@ -5,25 +5,22 @@
#include <stdlib.h>
#include <string.h>
#include "metricgroup.h"
#include "cpumap.h"
#include "cputopo.h"
#include "debug.h"
#include "evlist.h"
#include "expr.h"
#include "pmu.h"
#include "smt.h"
#include "tool_pmu.h"
#include <util/expr-bison.h>
#include <util/expr-flex.h>
#include "util/hashmap.h"
#include "util/header.h"
#include "util/pmu.h"
#include "smt.h"
#include "tsc.h"
#include <api/fs/fs.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/zalloc.h>
#include <ctype.h>
#include <math.h>
#include "pmu.h"

struct expr_id_data {
	union {
@@ -393,90 +390,26 @@ double expr_id_data__source_count(const struct expr_id_data *data)
	return data->val.source_count;
}

#if !defined(__i386__) && !defined(__x86_64__)
double arch_get_tsc_freq(void)
{
	return 0.0;
}
#endif

static double has_pmem(void)
{
	static bool has_pmem, cached;
	const char *sysfs = sysfs__mountpoint();
	char path[PATH_MAX];

	if (!cached) {
		snprintf(path, sizeof(path), "%s/firmware/acpi/tables/NFIT", sysfs);
		has_pmem = access(path, F_OK) == 0;
		cached = true;
	}
	return has_pmem ? 1.0 : 0.0;
}

double expr__get_literal(const char *literal, const struct expr_scanner_ctx *ctx)
{
	const struct cpu_topology *topology;
	double result = NAN;
	enum tool_pmu_event ev = tool_pmu__str_to_event(literal + 1);

	if (!strcmp("#num_cpus", literal)) {
		result = cpu__max_present_cpu().cpu;
		goto out;
	}
	if (!strcmp("#num_cpus_online", literal)) {
		struct perf_cpu_map *online = cpu_map__online();

		if (online)
			result = perf_cpu_map__nr(online);
		goto out;
	}
	if (ev != TOOL_PMU__EVENT_NONE) {
		u64 count;

	if (!strcasecmp("#system_tsc_freq", literal)) {
		result = arch_get_tsc_freq();
		goto out;
	}
		if (tool_pmu__read_event(ev, &count))
			result = count;
		else
			pr_err("Failure to read '%s'", literal);

	/*
	 * Assume that topology strings are consistent, such as CPUs "0-1"
	 * wouldn't be listed as "0,1", and so after deduplication the number of
	 * these strings gives an indication of the number of packages, dies,
	 * etc.
	 */
	if (!strcasecmp("#smt_on", literal)) {
		result = smt_on() ? 1.0 : 0.0;
		goto out;
	}
	if (!strcmp("#core_wide", literal)) {
	} else if (!strcmp("#core_wide", literal)) {
		result = core_wide(ctx->system_wide, ctx->user_requested_cpu_list)
			? 1.0 : 0.0;
		goto out;
	}
	if (!strcmp("#num_packages", literal)) {
		topology = online_topology();
		result = topology->package_cpus_lists;
		goto out;
	}
	if (!strcmp("#num_dies", literal)) {
		topology = online_topology();
		result = topology->die_cpus_lists;
		goto out;
	}
	if (!strcmp("#num_cores", literal)) {
		topology = online_topology();
		result = topology->core_cpus_lists;
		goto out;
	}
	if (!strcmp("#slots", literal)) {
		result = perf_pmu__cpu_slots_per_cycle();
		goto out;
	}
	if (!strcmp("#has_pmem", literal)) {
		result = has_pmem();
		goto out;
	} else {
		pr_err("Unrecognized literal '%s'", literal);
	}

	pr_err("Unrecognized literal '%s'", literal);
out:
	pr_debug2("literal: %s = %f\n", literal, result);
	return result;
}
+0 −5
Original line number Diff line number Diff line
@@ -2254,11 +2254,6 @@ bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok)
		(need_fnmatch && !fnmatch(tok, name, 0));
}

double __weak perf_pmu__cpu_slots_per_cycle(void)
{
	return NAN;
}

int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size)
{
	const char *sysfs = sysfs__mountpoint();
+0 −1
Original line number Diff line number Diff line
@@ -271,7 +271,6 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);

bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok);

double perf_pmu__cpu_slots_per_cycle(void);
int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size);
int perf_pmu__pathname_scnprintf(char *buf, size_t size,
				 const char *pmu_name, const char *filename);
Loading