License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 15:07:57 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2012-03-15 20:09:17 +01:00
|
|
|
#include <linux/list.h>
|
2015-06-10 00:25:07 -07:00
|
|
|
#include <linux/compiler.h>
|
2019-06-26 11:42:03 -03:00
|
|
|
#include <linux/string.h>
|
2019-07-04 11:32:27 -03:00
|
|
|
#include <linux/zalloc.h>
|
2021-07-01 14:42:53 +08:00
|
|
|
#include <linux/ctype.h>
|
2012-03-15 20:09:17 +01:00
|
|
|
#include <sys/types.h>
|
2017-09-11 10:50:26 -03:00
|
|
|
#include <fcntl.h>
|
2017-04-19 20:57:47 -03:00
|
|
|
#include <sys/stat.h>
|
2012-03-15 20:09:17 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
2014-07-31 09:00:49 +03:00
|
|
|
#include <stdbool.h>
|
2012-03-15 20:09:17 +01:00
|
|
|
#include <dirent.h>
|
2013-12-09 17:14:24 +01:00
|
|
|
#include <api/fs/fs.h>
|
2024-12-05 20:40:32 -08:00
|
|
|
#include <api/io.h>
|
2025-02-21 22:10:08 -08:00
|
|
|
#include <api/io_dir.h>
|
2013-11-12 17:58:49 +01:00
|
|
|
#include <locale.h>
|
2021-07-01 14:42:53 +08:00
|
|
|
#include <fnmatch.h>
|
2023-01-17 15:29:25 +08:00
|
|
|
#include <math.h>
|
2019-08-22 10:48:31 -03:00
|
|
|
#include "debug.h"
|
2020-04-01 13:16:09 +03:00
|
|
|
#include "evsel.h"
|
2012-03-15 20:09:17 +01:00
|
|
|
#include "pmu.h"
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
#include "drm_pmu.h"
|
2024-11-08 16:37:57 -08:00
|
|
|
#include "hwmon_pmu.h"
|
2022-12-06 10:02:36 +05:30
|
|
|
#include "pmus.h"
|
2024-10-01 20:20:07 -07:00
|
|
|
#include "tool_pmu.h"
|
perf tp_pmu: Add event APIs
Add event APIs for the tracepoint PMU allowing things like perf list
to function using it. For perf list add the tracepoint format in the
long description (shown with -v).
$ sudo perf list -v tracepoint
List of pre-defined events (to be used in -e or -M):
alarmtimer:alarmtimer_cancel [Tracepoint event]
[name: alarmtimer_cancel
ID: 416
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:void * alarm; offset:8; size:8; signed:0;
field:unsigned char alarm_type; offset:16; size:1; signed:0;
field:s64 expires; offset:24; size:8; signed:1;
field:s64 now; offset:32; size:8; signed:1;
print fmt: "alarmtimer:%p type:%s expires:%llu now:%llu",REC->alarm,__print_flags((1 << REC->alarm_type)," | ",{ 1 << 0,
"REALTIME" },{ 1 << 1,"BOOTTIME" },{ 1 << 3,"REALTIME Freezer" },{ 1 << 4,"BOOTTIME Freezer" }),REC->expires,REC->now
. Unit: tracepoint]
alarmtimer:alarmtimer_fired [Tracepoint event]
[name: alarmtimer_fired
ID: 418
...
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/r/20250725185202.68671-6-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-07-25 11:51:51 -07:00
|
|
|
#include "tp_pmu.h"
|
2023-07-27 19:24:47 -07:00
|
|
|
#include <util/pmu-bison.h>
|
|
|
|
#include <util/pmu-flex.h>
|
2012-03-15 20:09:17 +01:00
|
|
|
#include "parse-events.h"
|
perf list: Reorganize to use callbacks to allow honouring command line options
Rather than controlling the list output with passed flags, add
callbacks that are called when an event or metric are
encountered. State is passed to the callback so that command line
options can be respected, alternatively the callbacks can be changed.
Fix a few bugs:
- wordwrap to columns metric descriptions and expressions;
- remove unnecessary whitespace after PMU event names;
- the metric filter is a glob but matched using strstr which will
always fail, switch to using a proper globmatch,
- the detail flag gives details for extra kernel PMU events like
branch-instructions.
In metricgroup.c switch from struct mep being a rbtree of metricgroups
containing a list of metrics, to the tree directly containing all the
metrics. In general the alias for a name is passed to the print
routine rather than being contained in the name with OR.
Committer notes:
Check the asprint() return to address this on fedora 36:
util/print-events.c: In function ‘print_sdt_events’:
util/print-events.c:183:33: error: ignoring return value of ‘asprintf’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
183 | asprintf(&evt_name, "%s@%s(%.12s)", sdt_name->s, path, bid);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
$ gcc --version | head -1
gcc (GCC) 12.2.1 20220819 (Red Hat 12.2.1-2)
$
Fix ps.pmu_glob setting when dealing with *:* events, it was being left
with a freed pointer that then at the end of cmd_list() would be double
freed.
Check if pmu_name is NULL in default_print_event() before calling
strglobmatch(pmu_name, ...) to avoid a segfault.
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Xin Gao <gaoxin@cdjrlc.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: http://lore.kernel.org/lkml/20221114210723.2749751-10-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-11-14 13:07:22 -08:00
|
|
|
#include "print-events.h"
|
2025-05-12 12:46:21 -07:00
|
|
|
#include "hashmap.h"
|
2016-09-15 15:24:40 -07:00
|
|
|
#include "header.h"
|
2017-04-17 16:51:59 -03:00
|
|
|
#include "string2.h"
|
2019-08-30 12:52:25 -03:00
|
|
|
#include "strbuf.h"
|
2019-11-20 16:15:11 -08:00
|
|
|
#include "fncache.h"
|
2023-04-24 14:47:42 +01:00
|
|
|
#include "util/evsel_config.h"
|
2023-09-27 13:59:45 +08:00
|
|
|
#include <regex.h>
|
2012-03-15 20:09:17 +01:00
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
#define UNIT_MAX_LEN 31 /* max length for event unit name */
|
|
|
|
|
2024-05-10 17:36:01 -07:00
|
|
|
enum event_source {
|
2025-02-19 14:40:56 +01:00
|
|
|
/* An event loaded from /sys/bus/event_source/devices/<pmu>/events. */
|
2024-05-10 17:36:01 -07:00
|
|
|
EVENT_SRC_SYSFS,
|
|
|
|
/* An event loaded from a CPUID matched json file. */
|
|
|
|
EVENT_SRC_CPU_JSON,
|
|
|
|
/*
|
2025-02-19 14:40:56 +01:00
|
|
|
* An event loaded from a /sys/bus/event_source/devices/<pmu>/identifier matched json
|
2024-05-10 17:36:01 -07:00
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
EVENT_SRC_SYS_JSON,
|
|
|
|
};
|
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
/**
|
|
|
|
* struct perf_pmu_alias - An event either read from sysfs or builtin in
|
|
|
|
* pmu-events.c, created by parsing the pmu-events json files.
|
|
|
|
*/
|
|
|
|
struct perf_pmu_alias {
|
|
|
|
/** @name: Name of the event like "mem-loads". */
|
|
|
|
char *name;
|
|
|
|
/** @desc: Optional short description of the event. */
|
|
|
|
char *desc;
|
|
|
|
/** @long_desc: Optional long description. */
|
|
|
|
char *long_desc;
|
|
|
|
/**
|
|
|
|
* @topic: Optional topic such as cache or pipeline, particularly for
|
|
|
|
* json events.
|
|
|
|
*/
|
|
|
|
char *topic;
|
|
|
|
/** @terms: Owned list of the original parsed parameters. */
|
2023-09-01 16:39:49 -07:00
|
|
|
struct parse_events_terms terms;
|
2023-08-23 21:13:27 -07:00
|
|
|
/**
|
|
|
|
* @pmu_name: The name copied from the json struct pmu_event. This can
|
|
|
|
* differ from the PMU name as it won't have suffixes.
|
|
|
|
*/
|
|
|
|
char *pmu_name;
|
2023-08-23 21:13:14 -07:00
|
|
|
/** @unit: Units for the event, such as bytes or cache lines. */
|
|
|
|
char unit[UNIT_MAX_LEN+1];
|
|
|
|
/** @scale: Value to scale read counter values by. */
|
|
|
|
double scale;
|
2025-04-14 10:41:33 -07:00
|
|
|
/** @retirement_latency_mean: Value to be given for unsampled retirement latency mean. */
|
|
|
|
double retirement_latency_mean;
|
|
|
|
/** @retirement_latency_min: Value to be given for unsampled retirement latency min. */
|
|
|
|
double retirement_latency_min;
|
|
|
|
/** @retirement_latency_max: Value to be given for unsampled retirement latency max. */
|
|
|
|
double retirement_latency_max;
|
2023-08-23 21:13:14 -07:00
|
|
|
/**
|
|
|
|
* @per_pkg: Does the file
|
|
|
|
* <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.per-pkg or
|
|
|
|
* equivalent json value exist and have the value 1.
|
|
|
|
*/
|
|
|
|
bool per_pkg;
|
|
|
|
/**
|
|
|
|
* @snapshot: Does the file
|
|
|
|
* <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.snapshot
|
|
|
|
* exist and have the value 1.
|
|
|
|
*/
|
|
|
|
bool snapshot;
|
|
|
|
/**
|
|
|
|
* @deprecated: Is the event hidden and so not shown in perf list by
|
|
|
|
* default.
|
|
|
|
*/
|
|
|
|
bool deprecated;
|
2023-08-23 21:13:27 -07:00
|
|
|
/** @from_sysfs: Was the alias from sysfs or a json event? */
|
|
|
|
bool from_sysfs;
|
|
|
|
/** @info_loaded: Have the scale, unit and other values been read from disk? */
|
|
|
|
bool info_loaded;
|
2023-08-23 21:13:14 -07:00
|
|
|
};
|
|
|
|
|
2022-11-14 13:07:15 -08:00
|
|
|
/**
|
|
|
|
* struct perf_pmu_format - Values from a format file read from
|
|
|
|
* <sysfs>/devices/cpu/format/ held in struct perf_pmu.
|
|
|
|
*
|
|
|
|
* For example, the contents of <sysfs>/devices/cpu/format/event may be
|
|
|
|
* "config:0-7" and will be represented here as name="event",
|
|
|
|
* value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set.
|
|
|
|
*/
|
2013-01-18 17:05:09 -03:00
|
|
|
struct perf_pmu_format {
|
2023-08-23 21:13:13 -07:00
|
|
|
/** @list: Element on list within struct perf_pmu. */
|
|
|
|
struct list_head list;
|
|
|
|
/** @bits: Which config bits are set by this format value. */
|
|
|
|
DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
|
2022-11-14 13:07:15 -08:00
|
|
|
/** @name: The modifier/file name. */
|
2013-01-18 17:05:09 -03:00
|
|
|
char *name;
|
2022-11-14 13:07:15 -08:00
|
|
|
/**
|
|
|
|
* @value : Which config value the format relates to. Supported values
|
|
|
|
* are from PERF_PMU_FORMAT_VALUE_CONFIG to
|
|
|
|
* PERF_PMU_FORMAT_VALUE_CONFIG_END.
|
|
|
|
*/
|
2023-08-23 21:13:13 -07:00
|
|
|
u16 value;
|
|
|
|
/** @loaded: Has the contents been loaded/parsed. */
|
|
|
|
bool loaded;
|
2013-01-18 17:05:09 -03:00
|
|
|
};
|
|
|
|
|
2023-08-23 21:13:28 -07:00
|
|
|
static int pmu_aliases_parse(struct perf_pmu *pmu);
|
|
|
|
|
2023-08-23 21:13:13 -07:00
|
|
|
static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
|
|
|
|
{
|
|
|
|
struct perf_pmu_format *format;
|
|
|
|
|
|
|
|
format = zalloc(sizeof(*format));
|
|
|
|
if (!format)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
format->name = strdup(name);
|
|
|
|
if (!format->name) {
|
|
|
|
free(format);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
list_add_tail(&format->list, list);
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called at the end of parsing a format. */
|
|
|
|
void perf_pmu_format__set_value(void *vformat, int config, unsigned long *bits)
|
|
|
|
{
|
|
|
|
struct perf_pmu_format *format = vformat;
|
|
|
|
|
|
|
|
format->value = config;
|
|
|
|
memcpy(format->bits, bits, sizeof(format->bits));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __perf_pmu_format__load(struct perf_pmu_format *format, FILE *file)
|
|
|
|
{
|
|
|
|
void *scanner;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = perf_pmu_lex_init(&scanner);
|
|
|
|
if (ret)
|
|
|
|
return;
|
|
|
|
|
|
|
|
perf_pmu_set_in(file, scanner);
|
|
|
|
ret = perf_pmu_parse(format, scanner);
|
|
|
|
perf_pmu_lex_destroy(scanner);
|
|
|
|
format->loaded = true;
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:43 -07:00
|
|
|
static void perf_pmu_format__load(const struct perf_pmu *pmu, struct perf_pmu_format *format)
|
2023-08-23 21:13:13 -07:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
FILE *file = NULL;
|
|
|
|
|
|
|
|
if (format->loaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, "format"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
assert(strlen(path) + strlen(format->name) + 2 < sizeof(path));
|
|
|
|
strcat(path, "/");
|
|
|
|
strcat(path, format->name);
|
|
|
|
|
|
|
|
file = fopen(path, "r");
|
|
|
|
if (!file)
|
|
|
|
return;
|
|
|
|
__perf_pmu_format__load(format, file);
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
|
2012-03-15 20:09:17 +01:00
|
|
|
/*
|
|
|
|
* Parse & process all the sysfs attributes located under
|
|
|
|
* the directory specified in 'dir' parameter.
|
|
|
|
*/
|
2024-05-02 14:35:04 -07:00
|
|
|
static int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
2025-02-21 22:10:08 -08:00
|
|
|
struct io_dirent64 *evt_ent;
|
|
|
|
struct io_dir format_dir;
|
2012-03-15 20:09:17 +01:00
|
|
|
int ret = 0;
|
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
io_dir__init(&format_dir, dirfd);
|
2012-03-15 20:09:17 +01:00
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
while ((evt_ent = io_dir__readdir(&format_dir)) != NULL) {
|
2023-08-23 21:13:13 -07:00
|
|
|
struct perf_pmu_format *format;
|
2012-03-15 20:09:17 +01:00
|
|
|
char *name = evt_ent->d_name;
|
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
if (io_dir__is_dir(&format_dir, evt_ent))
|
2012-03-15 20:09:17 +01:00
|
|
|
continue;
|
|
|
|
|
2023-08-23 21:13:13 -07:00
|
|
|
format = perf_pmu__new_format(&pmu->format, name);
|
|
|
|
if (!format) {
|
|
|
|
ret = -ENOMEM;
|
2023-04-05 23:52:23 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:13 -07:00
|
|
|
if (eager_load) {
|
|
|
|
FILE *file;
|
|
|
|
int fd = openat(dirfd, name, O_RDONLY);
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
ret = -errno;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
file = fdopen(fd, "r");
|
|
|
|
if (!file) {
|
|
|
|
close(fd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
__perf_pmu_format__load(format, file);
|
2023-04-05 23:52:23 -07:00
|
|
|
fclose(file);
|
|
|
|
}
|
2012-03-15 20:09:17 +01:00
|
|
|
}
|
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
close(format_dir.dirfd);
|
2012-03-15 20:09:17 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reading/parsing the default pmu format definition, which should be
|
|
|
|
* located at:
|
|
|
|
* /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
|
|
|
|
*/
|
2024-05-02 14:35:04 -07:00
|
|
|
static int pmu_format(struct perf_pmu *pmu, int dirfd, const char *name, bool eager_load)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
perf pmu: Use relative path for sysfs scan
The PMU information is in the kernel sysfs so it needs to scan the
directory to get the whole information like event aliases, formats and
so on. During the traversal, it opens a lot of files and directories
like below:
dir = opendir("/sys/bus/event_source/devices");
while (dentry = readdir(dir)) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s",
"/sys/bus/event_source/devices", dentry->d_name);
fd = open(buf, O_RDONLY);
...
}
But this is not good since it needs to copy the string to build the
absolute pathname, and it makes redundant pathname walk (from the /sys)
unnecessarily. We can use openat(2) to open the file in the given
directory. While it's not a problem ususally, it can be a problem when
the kernel has contentions on the sysfs.
Add a couple of new helper to return the file descriptor of PMU
directory so that it can use it with relative paths.
* perf_pmu__event_source_devices_fd()
- returns a fd for the PMU root ("/sys/bus/event_source/devices")
* perf_pmu__pathname_fd()
- returns a fd for "<pmu>/<file>" under the PMU root
Now the above code can be converted something like below:
dirfd = perf_pmu__event_source_devices_fd();
dir = fdopendir(dirfd);
while (dentry = readdir(dir)) {
fd = openat(dirfd, dentry->d_name, O_RDONLY);
...
}
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-03-31 13:29:45 -07:00
|
|
|
int fd;
|
2012-03-15 20:09:17 +01:00
|
|
|
|
perf pmu: Use relative path for sysfs scan
The PMU information is in the kernel sysfs so it needs to scan the
directory to get the whole information like event aliases, formats and
so on. During the traversal, it opens a lot of files and directories
like below:
dir = opendir("/sys/bus/event_source/devices");
while (dentry = readdir(dir)) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s",
"/sys/bus/event_source/devices", dentry->d_name);
fd = open(buf, O_RDONLY);
...
}
But this is not good since it needs to copy the string to build the
absolute pathname, and it makes redundant pathname walk (from the /sys)
unnecessarily. We can use openat(2) to open the file in the given
directory. While it's not a problem ususally, it can be a problem when
the kernel has contentions on the sysfs.
Add a couple of new helper to return the file descriptor of PMU
directory so that it can use it with relative paths.
* perf_pmu__event_source_devices_fd()
- returns a fd for the PMU root ("/sys/bus/event_source/devices")
* perf_pmu__pathname_fd()
- returns a fd for "<pmu>/<file>" under the PMU root
Now the above code can be converted something like below:
dirfd = perf_pmu__event_source_devices_fd();
dir = fdopendir(dirfd);
while (dentry = readdir(dir)) {
fd = openat(dirfd, dentry->d_name, O_RDONLY);
...
}
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-03-31 13:29:45 -07:00
|
|
|
fd = perf_pmu__pathname_fd(dirfd, name, "format", O_DIRECTORY);
|
|
|
|
if (fd < 0)
|
2019-11-20 16:15:11 -08:00
|
|
|
return 0;
|
2012-03-15 20:09:17 +01:00
|
|
|
|
perf pmu: Use relative path for sysfs scan
The PMU information is in the kernel sysfs so it needs to scan the
directory to get the whole information like event aliases, formats and
so on. During the traversal, it opens a lot of files and directories
like below:
dir = opendir("/sys/bus/event_source/devices");
while (dentry = readdir(dir)) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s",
"/sys/bus/event_source/devices", dentry->d_name);
fd = open(buf, O_RDONLY);
...
}
But this is not good since it needs to copy the string to build the
absolute pathname, and it makes redundant pathname walk (from the /sys)
unnecessarily. We can use openat(2) to open the file in the given
directory. While it's not a problem ususally, it can be a problem when
the kernel has contentions on the sysfs.
Add a couple of new helper to return the file descriptor of PMU
directory so that it can use it with relative paths.
* perf_pmu__event_source_devices_fd()
- returns a fd for the PMU root ("/sys/bus/event_source/devices")
* perf_pmu__pathname_fd()
- returns a fd for "<pmu>/<file>" under the PMU root
Now the above code can be converted something like below:
dirfd = perf_pmu__event_source_devices_fd();
dir = fdopendir(dirfd);
while (dentry = readdir(dir)) {
fd = openat(dirfd, dentry->d_name, O_RDONLY);
...
}
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-03-31 13:29:45 -07:00
|
|
|
/* it'll close the fd */
|
2024-05-02 14:35:04 -07:00
|
|
|
if (perf_pmu__format_parse(pmu, fd, eager_load))
|
2012-03-15 20:09:17 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2025-04-14 10:41:33 -07:00
|
|
|
static int parse_double(const char *scale, char **end, double *sval)
|
2013-11-12 17:58:49 +01:00
|
|
|
{
|
2016-03-08 19:42:30 +01:00
|
|
|
char *lc;
|
2017-01-03 07:08:23 -08:00
|
|
|
int ret = 0;
|
2015-05-31 11:36:23 +05:30
|
|
|
|
2013-11-12 17:58:49 +01:00
|
|
|
/*
|
|
|
|
* save current locale
|
|
|
|
*/
|
|
|
|
lc = setlocale(LC_NUMERIC, NULL);
|
|
|
|
|
perf tools: Fix locale handling in pmu parsing
Ingo reported regression on display format of big numbers, which is
missing separators (in default perf stat output).
triton:~/tip> perf stat -a sleep 1
...
127008602 cycles # 0.011 GHz
279538533 stalled-cycles-frontend # 220.09% frontend cycles idle
119213269 instructions # 0.94 insn per cycle
This is caused by recent change:
perf stat: Check existence of frontend/backed stalled cycles
that added call to pmu_have_event, that subsequently calls
perf_pmu__parse_scale, which has a bug in locale handling.
The lc string returned from setlocale, that we use to store old locale
value, may be allocated in static storage. Getting a dynamic copy to
make it survive another setlocale call.
$ perf stat ls
...
2,360,602 cycles # 3.080 GHz
2,703,090 instructions # 1.15 insn per cycle
546,031 branches # 712.511 M/sec
Committer note:
Since the patch introducing the regression didn't made to perf/core,
move it to just before where the regression was introduced, so that we
don't break bisection for this feature.
Reported-by: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20160303095348.GA24511@krava.redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-03-03 10:53:48 +01:00
|
|
|
/*
|
|
|
|
* The lc string may be allocated in static storage,
|
|
|
|
* so get a dynamic copy to make it survive setlocale
|
|
|
|
* call below.
|
|
|
|
*/
|
|
|
|
lc = strdup(lc);
|
|
|
|
if (!lc) {
|
|
|
|
ret = -ENOMEM;
|
2017-01-03 07:08:23 -08:00
|
|
|
goto out;
|
perf tools: Fix locale handling in pmu parsing
Ingo reported regression on display format of big numbers, which is
missing separators (in default perf stat output).
triton:~/tip> perf stat -a sleep 1
...
127008602 cycles # 0.011 GHz
279538533 stalled-cycles-frontend # 220.09% frontend cycles idle
119213269 instructions # 0.94 insn per cycle
This is caused by recent change:
perf stat: Check existence of frontend/backed stalled cycles
that added call to pmu_have_event, that subsequently calls
perf_pmu__parse_scale, which has a bug in locale handling.
The lc string returned from setlocale, that we use to store old locale
value, may be allocated in static storage. Getting a dynamic copy to
make it survive another setlocale call.
$ perf stat ls
...
2,360,602 cycles # 3.080 GHz
2,703,090 instructions # 1.15 insn per cycle
546,031 branches # 712.511 M/sec
Committer note:
Since the patch introducing the regression didn't made to perf/core,
move it to just before where the regression was introduced, so that we
don't break bisection for this feature.
Reported-by: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20160303095348.GA24511@krava.redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-03-03 10:53:48 +01:00
|
|
|
}
|
|
|
|
|
2013-11-12 17:58:49 +01:00
|
|
|
/*
|
|
|
|
* force to C locale to ensure kernel
|
|
|
|
* scale string is converted correctly.
|
|
|
|
* kernel uses default C locale.
|
|
|
|
*/
|
|
|
|
setlocale(LC_NUMERIC, "C");
|
|
|
|
|
2017-01-03 07:08:23 -08:00
|
|
|
*sval = strtod(scale, end);
|
2013-11-12 17:58:49 +01:00
|
|
|
|
2017-01-03 07:08:23 -08:00
|
|
|
out:
|
2013-11-12 17:58:49 +01:00
|
|
|
/* restore locale */
|
|
|
|
setlocale(LC_NUMERIC, lc);
|
2016-03-08 19:42:30 +01:00
|
|
|
free(lc);
|
2017-01-03 07:08:23 -08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2025-04-14 10:41:33 -07:00
|
|
|
int perf_pmu__convert_scale(const char *scale, char **end, double *sval)
|
|
|
|
{
|
|
|
|
return parse_double(scale, end, sval);
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
static int perf_pmu__parse_scale(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
|
2017-01-03 07:08:23 -08:00
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
ssize_t sret;
|
2023-08-23 21:13:27 -07:00
|
|
|
size_t len;
|
2017-01-03 07:08:23 -08:00
|
|
|
char scale[128];
|
|
|
|
int fd, ret = -1;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
|
|
|
|
if (!len)
|
|
|
|
return 0;
|
2023-09-20 12:23:49 +00:00
|
|
|
scnprintf(path + len, sizeof(path) - len, "%s/events/%s.scale", pmu->name, alias->name);
|
2017-01-03 07:08:23 -08:00
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
fd = open(path, O_RDONLY);
|
2017-01-03 07:08:23 -08:00
|
|
|
if (fd == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (fstat(fd, &st) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
sret = read(fd, scale, sizeof(scale)-1);
|
|
|
|
if (sret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (scale[sret - 1] == '\n')
|
|
|
|
scale[sret - 1] = '\0';
|
|
|
|
else
|
|
|
|
scale[sret] = '\0';
|
perf tools: Fix locale handling in pmu parsing
Ingo reported regression on display format of big numbers, which is
missing separators (in default perf stat output).
triton:~/tip> perf stat -a sleep 1
...
127008602 cycles # 0.011 GHz
279538533 stalled-cycles-frontend # 220.09% frontend cycles idle
119213269 instructions # 0.94 insn per cycle
This is caused by recent change:
perf stat: Check existence of frontend/backed stalled cycles
that added call to pmu_have_event, that subsequently calls
perf_pmu__parse_scale, which has a bug in locale handling.
The lc string returned from setlocale, that we use to store old locale
value, may be allocated in static storage. Getting a dynamic copy to
make it survive another setlocale call.
$ perf stat ls
...
2,360,602 cycles # 3.080 GHz
2,703,090 instructions # 1.15 insn per cycle
546,031 branches # 712.511 M/sec
Committer note:
Since the patch introducing the regression didn't made to perf/core,
move it to just before where the regression was introduced, so that we
don't break bisection for this feature.
Reported-by: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20160303095348.GA24511@krava.redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-03-03 10:53:48 +01:00
|
|
|
|
2019-08-28 13:59:29 +08:00
|
|
|
ret = perf_pmu__convert_scale(scale, NULL, &alias->scale);
|
2013-11-12 17:58:49 +01:00
|
|
|
error:
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
static int perf_pmu__parse_unit(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
|
2013-11-12 17:58:49 +01:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
2023-08-23 21:13:27 -07:00
|
|
|
size_t len;
|
2013-11-12 17:58:49 +01:00
|
|
|
ssize_t sret;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
|
|
|
|
if (!len)
|
|
|
|
return 0;
|
2023-09-20 12:23:49 +00:00
|
|
|
scnprintf(path + len, sizeof(path) - len, "%s/events/%s.unit", pmu->name, alias->name);
|
2023-08-23 21:13:27 -07:00
|
|
|
|
|
|
|
fd = open(path, O_RDONLY);
|
2013-11-12 17:58:49 +01:00
|
|
|
if (fd == -1)
|
|
|
|
return -1;
|
|
|
|
|
2015-12-14 16:44:40 +01:00
|
|
|
sret = read(fd, alias->unit, UNIT_MAX_LEN);
|
2013-11-12 17:58:49 +01:00
|
|
|
if (sret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
2015-05-31 11:36:23 +05:30
|
|
|
if (alias->unit[sret - 1] == '\n')
|
|
|
|
alias->unit[sret - 1] = '\0';
|
|
|
|
else
|
|
|
|
alias->unit[sret] = '\0';
|
2013-11-12 17:58:49 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
close(fd);
|
|
|
|
alias->unit[0] = '\0';
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-07-17 17:30:20 -07:00
|
|
|
static bool perf_pmu__parse_event_source_bool(const char *pmu_name, const char *event_name,
|
|
|
|
const char *suffix)
|
2014-11-21 10:31:12 +01:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
2023-08-23 21:13:27 -07:00
|
|
|
size_t len;
|
2014-11-21 10:31:12 +01:00
|
|
|
int fd;
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
|
|
|
|
if (!len)
|
2024-07-17 17:30:20 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
scnprintf(path + len, sizeof(path) - len, "%s/events/%s.%s", pmu_name, event_name, suffix);
|
2014-11-21 10:31:12 +01:00
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
fd = open(path, O_RDONLY);
|
2014-11-21 10:31:12 +01:00
|
|
|
if (fd == -1)
|
2024-07-17 17:30:20 -07:00
|
|
|
return false;
|
2014-11-21 10:31:12 +01:00
|
|
|
|
2024-07-17 17:30:20 -07:00
|
|
|
#ifndef NDEBUG
|
|
|
|
{
|
|
|
|
char buf[8];
|
2014-11-21 10:31:12 +01:00
|
|
|
|
2024-07-17 17:30:20 -07:00
|
|
|
len = read(fd, buf, sizeof(buf));
|
|
|
|
assert(len == 1 || len == 2);
|
|
|
|
assert(buf[0] == '1');
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return true;
|
2014-11-21 10:31:12 +01:00
|
|
|
}
|
|
|
|
|
2024-07-17 17:30:20 -07:00
|
|
|
static void perf_pmu__parse_per_pkg(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
|
2014-11-21 10:31:13 +01:00
|
|
|
{
|
2024-07-17 17:30:20 -07:00
|
|
|
alias->per_pkg = perf_pmu__parse_event_source_bool(pmu->name, alias->name, "per-pkg");
|
|
|
|
}
|
2014-11-21 10:31:13 +01:00
|
|
|
|
2024-07-17 17:30:20 -07:00
|
|
|
static void perf_pmu__parse_snapshot(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
|
|
|
|
{
|
|
|
|
alias->snapshot = perf_pmu__parse_event_source_bool(pmu->name, alias->name, "snapshot");
|
2014-11-21 10:31:13 +01:00
|
|
|
}
|
|
|
|
|
2018-06-15 12:11:05 +02:00
|
|
|
/* Delete an alias entry. */
|
2025-05-12 12:46:21 -07:00
|
|
|
static void perf_pmu_free_alias(struct perf_pmu_alias *alias)
|
2018-06-15 12:11:05 +02:00
|
|
|
{
|
2025-05-12 12:46:21 -07:00
|
|
|
if (!alias)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zfree(&alias->name);
|
|
|
|
zfree(&alias->desc);
|
|
|
|
zfree(&alias->long_desc);
|
|
|
|
zfree(&alias->topic);
|
|
|
|
zfree(&alias->pmu_name);
|
|
|
|
parse_events_terms__exit(&alias->terms);
|
|
|
|
free(alias);
|
2018-06-15 12:11:05 +02:00
|
|
|
}
|
|
|
|
|
2023-03-31 13:29:43 -07:00
|
|
|
static void perf_pmu__del_aliases(struct perf_pmu *pmu)
|
|
|
|
{
|
2025-05-12 12:46:21 -07:00
|
|
|
struct hashmap_entry *entry;
|
|
|
|
size_t bkt;
|
2023-03-31 13:29:43 -07:00
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
if (!pmu->aliases)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hashmap__for_each_entry(pmu->aliases, entry, bkt)
|
|
|
|
perf_pmu_free_alias(entry->pvalue);
|
|
|
|
|
|
|
|
hashmap__free(pmu->aliases);
|
|
|
|
pmu->aliases = NULL;
|
2023-03-31 13:29:43 -07:00
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:28 -07:00
|
|
|
static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu,
|
|
|
|
const char *name,
|
|
|
|
bool load)
|
2018-06-15 12:11:05 +02:00
|
|
|
{
|
2023-08-23 21:13:23 -07:00
|
|
|
struct perf_pmu_alias *alias;
|
2025-05-12 12:46:21 -07:00
|
|
|
bool has_sysfs_event;
|
2025-07-17 08:08:54 -07:00
|
|
|
char event_file_name[NAME_MAX + 8];
|
2018-06-15 12:11:05 +02:00
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
if (hashmap__find(pmu->aliases, name, &alias))
|
|
|
|
return alias;
|
2023-08-23 21:13:28 -07:00
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
if (!load || pmu->sysfs_aliases_loaded)
|
|
|
|
return NULL;
|
2024-05-02 14:35:07 -07:00
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
/*
|
|
|
|
* Test if alias/event 'name' exists in the PMU's sysfs/events
|
|
|
|
* directory. If not skip parsing the sysfs aliases. Sysfs event
|
|
|
|
* name must be all lower or all upper case.
|
|
|
|
*/
|
|
|
|
scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name);
|
|
|
|
for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
|
|
|
|
event_file_name[i] = tolower(event_file_name[i]);
|
2024-05-02 14:35:07 -07:00
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
|
|
|
|
if (!has_sysfs_event) {
|
|
|
|
for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
|
|
|
|
event_file_name[i] = toupper(event_file_name[i]);
|
2024-05-02 14:35:07 -07:00
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
|
2024-05-02 14:35:07 -07:00
|
|
|
}
|
2025-05-12 12:46:21 -07:00
|
|
|
if (has_sysfs_event) {
|
|
|
|
pmu_aliases_parse(pmu);
|
|
|
|
if (hashmap__find(pmu->aliases, name, &alias))
|
2023-08-23 21:13:23 -07:00
|
|
|
return alias;
|
2018-06-15 12:11:05 +02:00
|
|
|
}
|
2025-05-12 12:46:21 -07:00
|
|
|
|
2023-08-23 21:13:23 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool assign_str(const char *name, const char *field, char **old_str,
|
|
|
|
const char *new_str)
|
|
|
|
{
|
|
|
|
if (!*old_str && new_str) {
|
|
|
|
*old_str = strdup(new_str);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!new_str || !strcasecmp(*old_str, new_str))
|
|
|
|
return false; /* Nothing to update. */
|
|
|
|
|
|
|
|
pr_debug("alias %s differs in field '%s' ('%s' != '%s')\n",
|
|
|
|
name, field, *old_str, new_str);
|
|
|
|
zfree(old_str);
|
|
|
|
*old_str = strdup(new_str);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
static void read_alias_info(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
|
|
|
|
{
|
|
|
|
if (!alias->from_sysfs || alias->info_loaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* load unit name and scale if available
|
|
|
|
*/
|
|
|
|
perf_pmu__parse_unit(pmu, alias);
|
|
|
|
perf_pmu__parse_scale(pmu, alias);
|
|
|
|
perf_pmu__parse_per_pkg(pmu, alias);
|
|
|
|
perf_pmu__parse_snapshot(pmu, alias);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct update_alias_data {
|
|
|
|
struct perf_pmu *pmu;
|
|
|
|
struct perf_pmu_alias *alias;
|
|
|
|
};
|
|
|
|
|
2023-08-23 21:13:23 -07:00
|
|
|
static int update_alias(const struct pmu_event *pe,
|
|
|
|
const struct pmu_events_table *table __maybe_unused,
|
|
|
|
void *vdata)
|
|
|
|
{
|
2023-08-23 21:13:27 -07:00
|
|
|
struct update_alias_data *data = vdata;
|
2023-08-23 21:13:23 -07:00
|
|
|
int ret = 0;
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
read_alias_info(data->pmu, data->alias);
|
|
|
|
assign_str(pe->name, "desc", &data->alias->desc, pe->desc);
|
|
|
|
assign_str(pe->name, "long_desc", &data->alias->long_desc, pe->long_desc);
|
|
|
|
assign_str(pe->name, "topic", &data->alias->topic, pe->topic);
|
|
|
|
data->alias->per_pkg = pe->perpkg;
|
2023-08-30 00:07:53 -07:00
|
|
|
if (pe->event) {
|
2023-09-01 16:39:49 -07:00
|
|
|
parse_events_terms__exit(&data->alias->terms);
|
2023-08-23 21:13:27 -07:00
|
|
|
ret = parse_events_terms(&data->alias->terms, pe->event, /*input=*/NULL);
|
2023-08-23 21:13:23 -07:00
|
|
|
}
|
|
|
|
if (!ret && pe->unit) {
|
|
|
|
char *unit;
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
ret = perf_pmu__convert_scale(pe->unit, &unit, &data->alias->scale);
|
2023-08-23 21:13:23 -07:00
|
|
|
if (!ret)
|
2023-08-23 21:13:27 -07:00
|
|
|
snprintf(data->alias->unit, sizeof(data->alias->unit), "%s", unit);
|
2023-08-23 21:13:23 -07:00
|
|
|
}
|
2025-04-14 10:41:33 -07:00
|
|
|
if (!ret && pe->retirement_latency_mean) {
|
|
|
|
ret = parse_double(pe->retirement_latency_mean, NULL,
|
|
|
|
&data->alias->retirement_latency_mean);
|
|
|
|
}
|
|
|
|
if (!ret && pe->retirement_latency_min) {
|
|
|
|
ret = parse_double(pe->retirement_latency_min, NULL,
|
|
|
|
&data->alias->retirement_latency_min);
|
|
|
|
}
|
|
|
|
if (!ret && pe->retirement_latency_max) {
|
|
|
|
ret = parse_double(pe->retirement_latency_max, NULL,
|
|
|
|
&data->alias->retirement_latency_max);
|
|
|
|
}
|
2023-08-23 21:13:23 -07:00
|
|
|
return ret;
|
2018-06-15 12:11:05 +02:00
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
|
2023-08-23 21:13:21 -07:00
|
|
|
const char *desc, const char *val, FILE *val_fd,
|
2024-05-10 17:36:01 -07:00
|
|
|
const struct pmu_event *pe, enum event_source src)
|
2012-06-15 14:31:41 +08:00
|
|
|
{
|
2025-05-12 12:46:21 -07:00
|
|
|
struct perf_pmu_alias *alias, *old_alias;
|
2025-04-14 10:41:33 -07:00
|
|
|
int ret = 0;
|
2023-04-06 16:52:54 -07:00
|
|
|
const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
|
2023-02-19 01:28:03 -08:00
|
|
|
bool deprecated = false, perpkg = false;
|
2021-04-27 15:01:16 +08:00
|
|
|
|
2023-08-23 21:13:28 -07:00
|
|
|
if (perf_pmu__find_alias(pmu, name, /*load=*/ false)) {
|
2023-08-23 21:13:23 -07:00
|
|
|
/* Alias was already created/loaded. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-27 15:01:16 +08:00
|
|
|
if (pe) {
|
2023-04-06 16:52:54 -07:00
|
|
|
long_desc = pe->long_desc;
|
|
|
|
topic = pe->topic;
|
|
|
|
unit = pe->unit;
|
2023-02-19 01:28:03 -08:00
|
|
|
perpkg = pe->perpkg;
|
2023-02-19 01:28:02 -08:00
|
|
|
deprecated = pe->deprecated;
|
2024-03-07 16:19:11 -08:00
|
|
|
if (pe->pmu && strcmp(pe->pmu, "default_core"))
|
|
|
|
pmu_name = pe->pmu;
|
2021-04-27 15:01:16 +08:00
|
|
|
}
|
2012-06-15 14:31:41 +08:00
|
|
|
|
2023-09-13 19:24:25 -07:00
|
|
|
alias = zalloc(sizeof(*alias));
|
2012-06-15 14:31:41 +08:00
|
|
|
if (!alias)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2023-09-01 16:39:49 -07:00
|
|
|
parse_events_terms__init(&alias->terms);
|
2013-11-12 17:58:49 +01:00
|
|
|
alias->scale = 1.0;
|
|
|
|
alias->unit[0] = '\0';
|
2023-02-19 01:28:03 -08:00
|
|
|
alias->per_pkg = perpkg;
|
2016-01-06 19:50:01 +01:00
|
|
|
alias->snapshot = false;
|
2023-02-19 01:28:02 -08:00
|
|
|
alias->deprecated = deprecated;
|
2025-04-14 10:41:33 -07:00
|
|
|
alias->retirement_latency_mean = 0.0;
|
|
|
|
alias->retirement_latency_min = 0.0;
|
|
|
|
alias->retirement_latency_max = 0.0;
|
|
|
|
|
|
|
|
if (!ret && pe && pe->retirement_latency_mean) {
|
|
|
|
ret = parse_double(pe->retirement_latency_mean, NULL,
|
|
|
|
&alias->retirement_latency_mean);
|
|
|
|
}
|
|
|
|
if (!ret && pe && pe->retirement_latency_min) {
|
|
|
|
ret = parse_double(pe->retirement_latency_min, NULL,
|
|
|
|
&alias->retirement_latency_min);
|
|
|
|
}
|
|
|
|
if (!ret && pe && pe->retirement_latency_max) {
|
|
|
|
ret = parse_double(pe->retirement_latency_max, NULL,
|
|
|
|
&alias->retirement_latency_max);
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2013-11-12 17:58:49 +01:00
|
|
|
|
2023-08-23 21:13:21 -07:00
|
|
|
ret = parse_events_terms(&alias->terms, val, val_fd);
|
2012-06-15 14:31:41 +08:00
|
|
|
if (ret) {
|
2015-06-10 00:25:08 -07:00
|
|
|
pr_err("Cannot parse alias %s: %d\n", val, ret);
|
2012-06-15 14:31:41 +08:00
|
|
|
free(alias);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
alias->name = strdup(name);
|
2016-09-15 15:24:43 -07:00
|
|
|
alias->desc = desc ? strdup(desc) : NULL;
|
2025-07-10 16:51:21 -07:00
|
|
|
alias->long_desc = long_desc ? strdup(long_desc) : NULL;
|
2016-09-15 15:24:50 -07:00
|
|
|
alias->topic = topic ? strdup(topic) : NULL;
|
2023-08-23 21:13:23 -07:00
|
|
|
alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL;
|
2017-01-27 18:03:37 -08:00
|
|
|
if (unit) {
|
2023-08-23 21:13:23 -07:00
|
|
|
if (perf_pmu__convert_scale(unit, (char **)&unit, &alias->scale) < 0) {
|
|
|
|
perf_pmu_free_alias(alias);
|
2017-01-27 18:03:37 -08:00
|
|
|
return -1;
|
2023-08-23 21:13:23 -07:00
|
|
|
}
|
2017-01-27 18:03:37 -08:00
|
|
|
snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
|
|
|
|
}
|
2024-05-10 17:36:01 -07:00
|
|
|
switch (src) {
|
|
|
|
default:
|
|
|
|
case EVENT_SRC_SYSFS:
|
2023-08-23 21:13:27 -07:00
|
|
|
alias->from_sysfs = true;
|
2023-08-23 21:13:24 -07:00
|
|
|
if (pmu->events_table) {
|
2024-05-10 17:36:01 -07:00
|
|
|
/* Update an event from sysfs with json data. */
|
|
|
|
struct update_alias_data data = {
|
|
|
|
.pmu = pmu,
|
|
|
|
.alias = alias,
|
|
|
|
};
|
2023-08-23 21:13:25 -07:00
|
|
|
if (pmu_events_table__find_event(pmu->events_table, pmu, name,
|
2023-08-23 21:13:27 -07:00
|
|
|
update_alias, &data) == 0)
|
2025-02-26 10:41:01 +00:00
|
|
|
pmu->cpu_common_json_aliases++;
|
2023-08-23 21:13:24 -07:00
|
|
|
}
|
2023-08-23 21:13:25 -07:00
|
|
|
pmu->sysfs_aliases++;
|
2024-05-10 17:36:01 -07:00
|
|
|
break;
|
|
|
|
case EVENT_SRC_CPU_JSON:
|
|
|
|
pmu->cpu_json_aliases++;
|
|
|
|
break;
|
|
|
|
case EVENT_SRC_SYS_JSON:
|
|
|
|
pmu->sys_json_aliases++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
2025-05-12 12:46:21 -07:00
|
|
|
hashmap__set(pmu->aliases, alias->name, alias, /*old_key=*/ NULL, &old_alias);
|
|
|
|
perf_pmu_free_alias(old_alias);
|
2012-06-15 14:31:41 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:42 -07:00
|
|
|
static inline bool pmu_alias_info_file(const char *name)
|
2014-09-24 15:04:06 +01:00
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(name);
|
|
|
|
if (len > 5 && !strcmp(name + len - 5, ".unit"))
|
|
|
|
return true;
|
|
|
|
if (len > 6 && !strcmp(name + len - 6, ".scale"))
|
|
|
|
return true;
|
2014-11-21 10:31:12 +01:00
|
|
|
if (len > 8 && !strcmp(name + len - 8, ".per-pkg"))
|
|
|
|
return true;
|
2014-11-21 10:31:13 +01:00
|
|
|
if (len > 9 && !strcmp(name + len - 9, ".snapshot"))
|
|
|
|
return true;
|
2014-09-24 15:04:06 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-06-15 14:31:41 +08:00
|
|
|
/*
|
2023-08-23 21:13:28 -07:00
|
|
|
* Reading the pmu event aliases definition, which should be located at:
|
|
|
|
* /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
|
2012-06-15 14:31:41 +08:00
|
|
|
*/
|
2024-05-02 14:35:05 -07:00
|
|
|
static int __pmu_aliases_parse(struct perf_pmu *pmu, int events_dir_fd)
|
2012-06-15 14:31:41 +08:00
|
|
|
{
|
2025-02-21 22:10:08 -08:00
|
|
|
struct io_dirent64 *evt_ent;
|
|
|
|
struct io_dir event_dir;
|
2023-08-23 21:13:28 -07:00
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
io_dir__init(&event_dir, events_dir_fd);
|
2012-06-15 14:31:41 +08:00
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
while ((evt_ent = io_dir__readdir(&event_dir))) {
|
2012-06-15 14:31:41 +08:00
|
|
|
char *name = evt_ent->d_name;
|
2024-05-02 14:35:05 -07:00
|
|
|
int fd;
|
2012-06-15 14:31:41 +08:00
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
|
|
continue;
|
|
|
|
|
2013-11-12 17:58:49 +01:00
|
|
|
/*
|
2014-09-24 15:04:06 +01:00
|
|
|
* skip info files parsed in perf_pmu__new_alias()
|
2013-11-12 17:58:49 +01:00
|
|
|
*/
|
2014-09-24 15:04:06 +01:00
|
|
|
if (pmu_alias_info_file(name))
|
2013-11-12 17:58:49 +01:00
|
|
|
continue;
|
|
|
|
|
2024-05-02 14:35:05 -07:00
|
|
|
fd = openat(events_dir_fd, name, O_RDONLY);
|
2023-04-05 23:52:24 -07:00
|
|
|
if (fd == -1) {
|
|
|
|
pr_debug("Cannot open %s\n", name);
|
|
|
|
continue;
|
|
|
|
}
|
perf pmu: Use relative path for sysfs scan
The PMU information is in the kernel sysfs so it needs to scan the
directory to get the whole information like event aliases, formats and
so on. During the traversal, it opens a lot of files and directories
like below:
dir = opendir("/sys/bus/event_source/devices");
while (dentry = readdir(dir)) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s",
"/sys/bus/event_source/devices", dentry->d_name);
fd = open(buf, O_RDONLY);
...
}
But this is not good since it needs to copy the string to build the
absolute pathname, and it makes redundant pathname walk (from the /sys)
unnecessarily. We can use openat(2) to open the file in the given
directory. While it's not a problem ususally, it can be a problem when
the kernel has contentions on the sysfs.
Add a couple of new helper to return the file descriptor of PMU
directory so that it can use it with relative paths.
* perf_pmu__event_source_devices_fd()
- returns a fd for the PMU root ("/sys/bus/event_source/devices")
* perf_pmu__pathname_fd()
- returns a fd for "<pmu>/<file>" under the PMU root
Now the above code can be converted something like below:
dirfd = perf_pmu__event_source_devices_fd();
dir = fdopendir(dirfd);
while (dentry = readdir(dir)) {
fd = openat(dirfd, dentry->d_name, O_RDONLY);
...
}
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-03-31 13:29:45 -07:00
|
|
|
file = fdopen(fd, "r");
|
2016-02-17 14:44:55 -08:00
|
|
|
if (!file) {
|
2023-04-05 23:52:24 -07:00
|
|
|
close(fd);
|
2016-02-17 14:44:55 -08:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-12 17:58:49 +01:00
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
if (perf_pmu__new_alias(pmu, name, /*desc=*/ NULL,
|
2024-05-10 17:36:01 -07:00
|
|
|
/*val=*/ NULL, file, /*pe=*/ NULL,
|
|
|
|
EVENT_SRC_SYSFS) < 0)
|
2016-02-17 14:44:55 -08:00
|
|
|
pr_debug("Cannot set up %s\n", name);
|
2012-06-15 14:31:41 +08:00
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:28 -07:00
|
|
|
pmu->sysfs_aliases_loaded = true;
|
2012-06-15 14:31:41 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-05-02 14:35:05 -07:00
|
|
|
static int pmu_aliases_parse(struct perf_pmu *pmu)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
size_t len;
|
|
|
|
int events_dir_fd, ret;
|
|
|
|
|
|
|
|
if (pmu->sysfs_aliases_loaded)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
|
|
|
|
if (!len)
|
|
|
|
return 0;
|
|
|
|
scnprintf(path + len, sizeof(path) - len, "%s/events", pmu->name);
|
|
|
|
|
|
|
|
events_dir_fd = open(path, O_DIRECTORY);
|
|
|
|
if (events_dir_fd == -1) {
|
|
|
|
pmu->sysfs_aliases_loaded = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = __pmu_aliases_parse(pmu, events_dir_fd);
|
|
|
|
close(events_dir_fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pmu_aliases_parse_eager(struct perf_pmu *pmu, int sysfs_fd)
|
|
|
|
{
|
2025-07-17 08:08:54 -07:00
|
|
|
char path[NAME_MAX + 8];
|
2024-05-02 14:35:05 -07:00
|
|
|
int ret, events_dir_fd;
|
|
|
|
|
|
|
|
scnprintf(path, sizeof(path), "%s/events", pmu->name);
|
|
|
|
events_dir_fd = openat(sysfs_fd, path, O_DIRECTORY, 0);
|
|
|
|
if (events_dir_fd == -1) {
|
|
|
|
pmu->sysfs_aliases_loaded = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = __pmu_aliases_parse(pmu, events_dir_fd);
|
|
|
|
close(events_dir_fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-31 05:49:39 -08:00
|
|
|
static int pmu_alias_terms(struct perf_pmu_alias *alias, int err_loc, struct list_head *terms)
|
2012-06-15 14:31:41 +08:00
|
|
|
{
|
2014-04-16 20:49:02 +02:00
|
|
|
struct parse_events_term *term, *cloned;
|
2023-09-01 16:39:49 -07:00
|
|
|
struct parse_events_terms clone_terms;
|
|
|
|
|
|
|
|
parse_events_terms__init(&clone_terms);
|
|
|
|
list_for_each_entry(term, &alias->terms.terms, list) {
|
|
|
|
int ret = parse_events_term__clone(&cloned, term);
|
2012-06-15 14:31:41 +08:00
|
|
|
|
|
|
|
if (ret) {
|
2023-09-01 16:39:49 -07:00
|
|
|
parse_events_terms__exit(&clone_terms);
|
2012-06-15 14:31:41 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2017-10-20 13:27:55 -07:00
|
|
|
/*
|
|
|
|
* Weak terms don't override command line options,
|
|
|
|
* which we don't want for implicit terms in aliases.
|
|
|
|
*/
|
|
|
|
cloned->weak = true;
|
2024-01-31 05:49:39 -08:00
|
|
|
cloned->err_term = cloned->err_val = err_loc;
|
2023-09-01 16:39:49 -07:00
|
|
|
list_add_tail(&cloned->list, &clone_terms.terms);
|
2012-06-15 14:31:41 +08:00
|
|
|
}
|
2023-09-01 16:39:49 -07:00
|
|
|
list_splice_init(&clone_terms.terms, terms);
|
|
|
|
parse_events_terms__exit(&clone_terms);
|
2012-06-15 14:31:41 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
Currently, perf record is broken on arm/arm64 systems when the PMU is
specified explicitly as part of the event, e.g.
$ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
In such cases, perf record fails to open events unless
perf_event_paranoid is set to -1, even if the PMU in question supports
mode exclusion. Further, even when perf_event_paranoid is toggled, no
samples are recorded.
This is an unintended side effect of commit:
e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
... which assumes that if a PMU has an associated cpu_map, it is an
uncore PMU, and forces events for such PMUs to be system-wide.
This is not true for arm/arm64 systems, which can have heterogeneous
CPUs. To account for this, multiple CPU PMUs are exposed, each with a
"cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM
PMUs do not have a "cpumask" file, and only have a "cpus" file. For the
gory details as to why, see commit:
7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
Given all of this, we can instead identify uncore PMUs by explicitly
checking for a "cpumask" file, and restore arm/arm64 PMU support back to
a working state. This patch does so, adding a new perf_pmu::is_uncore
field, and splitting the existing cpumask parsing so that it can be
reused.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by Will Deacon <will.deacon@arm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: 4.12+ <stable@vger.kernel.org>
Fixes: e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
Link: http://lkml.kernel.org/r/1507315102-5942-1-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-10-06 19:38:22 +01:00
|
|
|
/*
|
|
|
|
* Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
|
|
|
|
* may have a "cpus" file.
|
|
|
|
*/
|
2024-12-05 20:40:32 -08:00
|
|
|
static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *pmu_name, bool is_core)
|
2012-09-10 15:53:50 +08:00
|
|
|
{
|
perf pmu: Support alternative sysfs cpumask
The perf tools can read a cpumask file for a PMU, describing a subset of
CPUs which that PMU covers. So far this has only been used to cater for
uncore PMUs, which in practice happen to only have a single CPU
described in the mask.
Until recently, the perf tools only correctly handled cpumask containing
a single CPU, and only when monitoring in system-wide mode. For example,
prior to commit 00e727bb389359c8 ("perf stat: Balance opening and
reading events"), a mask with more than a single CPU could cause perf
stat to hang. When a CPU PMU covers a subset of CPUs, but lacks a
cpumask, perf record will fail to open events (on the cores the PMU does
not support), and gives up.
For systems with heterogeneous CPUs such as ARM big.LITTLE systems, this
presents a problem. We have a PMU for each microarchitecture (e.g. a big
PMU and a little PMU), and would like to expose a cpumask for each (so
as to allow perf record and other tools to do the right thing). However,
doing so kernel-side will cause old perf binaries to not function (e.g.
hitting the issue solved by 00e727bb389359c8), and thus commits the
cardinal sin of breaking (existing) userspace.
To address this chicken-and-egg problem, this patch adds support got a
new file, cpus, which is largely identical to the existing cpumask file.
A kernel can expose this file, knowing that new perf binaries will
correctly support it, while old perf binaries will not look for it (and
thus will not be broken).
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Link: http://lkml.kernel.org/r/1473330112-28528-8-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-09-08 11:21:52 +01:00
|
|
|
const char *templates[] = {
|
2023-01-20 14:36:55 +00:00
|
|
|
"cpumask",
|
|
|
|
"cpus",
|
perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
Currently, perf record is broken on arm/arm64 systems when the PMU is
specified explicitly as part of the event, e.g.
$ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
In such cases, perf record fails to open events unless
perf_event_paranoid is set to -1, even if the PMU in question supports
mode exclusion. Further, even when perf_event_paranoid is toggled, no
samples are recorded.
This is an unintended side effect of commit:
e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
... which assumes that if a PMU has an associated cpu_map, it is an
uncore PMU, and forces events for such PMUs to be system-wide.
This is not true for arm/arm64 systems, which can have heterogeneous
CPUs. To account for this, multiple CPU PMUs are exposed, each with a
"cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM
PMUs do not have a "cpumask" file, and only have a "cpus" file. For the
gory details as to why, see commit:
7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
Given all of this, we can instead identify uncore PMUs by explicitly
checking for a "cpumask" file, and restore arm/arm64 PMU support back to
a working state. This patch does so, adding a new perf_pmu::is_uncore
field, and splitting the existing cpumask parsing so that it can be
reused.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by Will Deacon <will.deacon@arm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: 4.12+ <stable@vger.kernel.org>
Fixes: e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
Link: http://lkml.kernel.org/r/1507315102-5942-1-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-10-06 19:38:22 +01:00
|
|
|
NULL
|
perf pmu: Support alternative sysfs cpumask
The perf tools can read a cpumask file for a PMU, describing a subset of
CPUs which that PMU covers. So far this has only been used to cater for
uncore PMUs, which in practice happen to only have a single CPU
described in the mask.
Until recently, the perf tools only correctly handled cpumask containing
a single CPU, and only when monitoring in system-wide mode. For example,
prior to commit 00e727bb389359c8 ("perf stat: Balance opening and
reading events"), a mask with more than a single CPU could cause perf
stat to hang. When a CPU PMU covers a subset of CPUs, but lacks a
cpumask, perf record will fail to open events (on the cores the PMU does
not support), and gives up.
For systems with heterogeneous CPUs such as ARM big.LITTLE systems, this
presents a problem. We have a PMU for each microarchitecture (e.g. a big
PMU and a little PMU), and would like to expose a cpumask for each (so
as to allow perf record and other tools to do the right thing). However,
doing so kernel-side will cause old perf binaries to not function (e.g.
hitting the issue solved by 00e727bb389359c8), and thus commits the
cardinal sin of breaking (existing) userspace.
To address this chicken-and-egg problem, this patch adds support got a
new file, cpus, which is largely identical to the existing cpumask file.
A kernel can expose this file, knowing that new perf binaries will
correctly support it, while old perf binaries will not look for it (and
thus will not be broken).
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Link: http://lkml.kernel.org/r/1473330112-28528-8-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-09-08 11:21:52 +01:00
|
|
|
};
|
|
|
|
const char **template;
|
2012-09-10 15:53:50 +08:00
|
|
|
|
perf pmu: Support alternative sysfs cpumask
The perf tools can read a cpumask file for a PMU, describing a subset of
CPUs which that PMU covers. So far this has only been used to cater for
uncore PMUs, which in practice happen to only have a single CPU
described in the mask.
Until recently, the perf tools only correctly handled cpumask containing
a single CPU, and only when monitoring in system-wide mode. For example,
prior to commit 00e727bb389359c8 ("perf stat: Balance opening and
reading events"), a mask with more than a single CPU could cause perf
stat to hang. When a CPU PMU covers a subset of CPUs, but lacks a
cpumask, perf record will fail to open events (on the cores the PMU does
not support), and gives up.
For systems with heterogeneous CPUs such as ARM big.LITTLE systems, this
presents a problem. We have a PMU for each microarchitecture (e.g. a big
PMU and a little PMU), and would like to expose a cpumask for each (so
as to allow perf record and other tools to do the right thing). However,
doing so kernel-side will cause old perf binaries to not function (e.g.
hitting the issue solved by 00e727bb389359c8), and thus commits the
cardinal sin of breaking (existing) userspace.
To address this chicken-and-egg problem, this patch adds support got a
new file, cpus, which is largely identical to the existing cpumask file.
A kernel can expose this file, knowing that new perf binaries will
correctly support it, while old perf binaries will not look for it (and
thus will not be broken).
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Link: http://lkml.kernel.org/r/1473330112-28528-8-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-09-08 11:21:52 +01:00
|
|
|
for (template = templates; *template; template++) {
|
2024-12-05 20:40:32 -08:00
|
|
|
struct io io;
|
|
|
|
char buf[128];
|
|
|
|
char *cpumask = NULL;
|
|
|
|
size_t cpumask_len;
|
|
|
|
ssize_t ret;
|
|
|
|
struct perf_cpu_map *cpus;
|
|
|
|
|
|
|
|
io.fd = perf_pmu__pathname_fd(dirfd, pmu_name, *template, O_RDONLY);
|
|
|
|
if (io.fd < 0)
|
2023-01-20 14:36:55 +00:00
|
|
|
continue;
|
2024-12-05 20:40:32 -08:00
|
|
|
|
|
|
|
io__init(&io, io.fd, buf, sizeof(buf));
|
|
|
|
ret = io__getline(&io, &cpumask, &cpumask_len);
|
|
|
|
close(io.fd);
|
|
|
|
if (ret < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cpus = perf_cpu_map__new(cpumask);
|
|
|
|
free(cpumask);
|
perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
Currently, perf record is broken on arm/arm64 systems when the PMU is
specified explicitly as part of the event, e.g.
$ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
In such cases, perf record fails to open events unless
perf_event_paranoid is set to -1, even if the PMU in question supports
mode exclusion. Further, even when perf_event_paranoid is toggled, no
samples are recorded.
This is an unintended side effect of commit:
e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
... which assumes that if a PMU has an associated cpu_map, it is an
uncore PMU, and forces events for such PMUs to be system-wide.
This is not true for arm/arm64 systems, which can have heterogeneous
CPUs. To account for this, multiple CPU PMUs are exposed, each with a
"cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM
PMUs do not have a "cpumask" file, and only have a "cpus" file. For the
gory details as to why, see commit:
7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
Given all of this, we can instead identify uncore PMUs by explicitly
checking for a "cpumask" file, and restore arm/arm64 PMU support back to
a working state. This patch does so, adding a new perf_pmu::is_uncore
field, and splitting the existing cpumask parsing so that it can be
reused.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by Will Deacon <will.deacon@arm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: 4.12+ <stable@vger.kernel.org>
Fixes: e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
Link: http://lkml.kernel.org/r/1507315102-5942-1-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-10-06 19:38:22 +01:00
|
|
|
if (cpus)
|
|
|
|
return cpus;
|
perf pmu: Support alternative sysfs cpumask
The perf tools can read a cpumask file for a PMU, describing a subset of
CPUs which that PMU covers. So far this has only been used to cater for
uncore PMUs, which in practice happen to only have a single CPU
described in the mask.
Until recently, the perf tools only correctly handled cpumask containing
a single CPU, and only when monitoring in system-wide mode. For example,
prior to commit 00e727bb389359c8 ("perf stat: Balance opening and
reading events"), a mask with more than a single CPU could cause perf
stat to hang. When a CPU PMU covers a subset of CPUs, but lacks a
cpumask, perf record will fail to open events (on the cores the PMU does
not support), and gives up.
For systems with heterogeneous CPUs such as ARM big.LITTLE systems, this
presents a problem. We have a PMU for each microarchitecture (e.g. a big
PMU and a little PMU), and would like to expose a cpumask for each (so
as to allow perf record and other tools to do the right thing). However,
doing so kernel-side will cause old perf binaries to not function (e.g.
hitting the issue solved by 00e727bb389359c8), and thus commits the
cardinal sin of breaking (existing) userspace.
To address this chicken-and-egg problem, this patch adds support got a
new file, cpus, which is largely identical to the existing cpumask file.
A kernel can expose this file, knowing that new perf binaries will
correctly support it, while old perf binaries will not look for it (and
thus will not be broken).
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Link: http://lkml.kernel.org/r/1473330112-28528-8-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-09-08 11:21:52 +01:00
|
|
|
}
|
2012-09-10 15:53:50 +08:00
|
|
|
|
2023-06-22 21:38:43 -07:00
|
|
|
/* Nothing found, for core PMUs assume this means all CPUs. */
|
2025-03-18 10:19:14 -07:00
|
|
|
return is_core ? cpu_map__online() : NULL;
|
perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
Currently, perf record is broken on arm/arm64 systems when the PMU is
specified explicitly as part of the event, e.g.
$ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
In such cases, perf record fails to open events unless
perf_event_paranoid is set to -1, even if the PMU in question supports
mode exclusion. Further, even when perf_event_paranoid is toggled, no
samples are recorded.
This is an unintended side effect of commit:
e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
... which assumes that if a PMU has an associated cpu_map, it is an
uncore PMU, and forces events for such PMUs to be system-wide.
This is not true for arm/arm64 systems, which can have heterogeneous
CPUs. To account for this, multiple CPU PMUs are exposed, each with a
"cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM
PMUs do not have a "cpumask" file, and only have a "cpus" file. For the
gory details as to why, see commit:
7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
Given all of this, we can instead identify uncore PMUs by explicitly
checking for a "cpumask" file, and restore arm/arm64 PMU support back to
a working state. This patch does so, adding a new perf_pmu::is_uncore
field, and splitting the existing cpumask parsing so that it can be
reused.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by Will Deacon <will.deacon@arm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: 4.12+ <stable@vger.kernel.org>
Fixes: e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
Link: http://lkml.kernel.org/r/1507315102-5942-1-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-10-06 19:38:22 +01:00
|
|
|
}
|
2012-09-10 15:53:50 +08:00
|
|
|
|
2023-03-31 13:29:48 -07:00
|
|
|
static bool pmu_is_uncore(int dirfd, const char *name)
|
perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
Currently, perf record is broken on arm/arm64 systems when the PMU is
specified explicitly as part of the event, e.g.
$ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
In such cases, perf record fails to open events unless
perf_event_paranoid is set to -1, even if the PMU in question supports
mode exclusion. Further, even when perf_event_paranoid is toggled, no
samples are recorded.
This is an unintended side effect of commit:
e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
... which assumes that if a PMU has an associated cpu_map, it is an
uncore PMU, and forces events for such PMUs to be system-wide.
This is not true for arm/arm64 systems, which can have heterogeneous
CPUs. To account for this, multiple CPU PMUs are exposed, each with a
"cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM
PMUs do not have a "cpumask" file, and only have a "cpus" file. For the
gory details as to why, see commit:
7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
Given all of this, we can instead identify uncore PMUs by explicitly
checking for a "cpumask" file, and restore arm/arm64 PMU support back to
a working state. This patch does so, adding a new perf_pmu::is_uncore
field, and splitting the existing cpumask parsing so that it can be
reused.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by Will Deacon <will.deacon@arm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: 4.12+ <stable@vger.kernel.org>
Fixes: e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
Link: http://lkml.kernel.org/r/1507315102-5942-1-git-send-email-mark.rutland@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-10-06 19:38:22 +01:00
|
|
|
{
|
2023-03-31 13:29:48 -07:00
|
|
|
int fd;
|
2012-09-10 15:53:50 +08:00
|
|
|
|
2023-03-31 13:29:48 -07:00
|
|
|
fd = perf_pmu__pathname_fd(dirfd, name, "cpumask", O_PATH);
|
|
|
|
if (fd < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return true;
|
2012-09-10 15:53:50 +08:00
|
|
|
}
|
|
|
|
|
2020-12-04 19:10:09 +08:00
|
|
|
static char *pmu_id(const char *name)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX], *str;
|
|
|
|
size_t len;
|
|
|
|
|
2023-01-20 14:36:56 +00:00
|
|
|
perf_pmu__pathname_scnprintf(path, sizeof(path), name, "identifier");
|
2020-12-04 19:10:09 +08:00
|
|
|
|
2023-01-20 14:36:56 +00:00
|
|
|
if (filename__read_str(path, &str, &len) < 0)
|
2020-12-04 19:10:09 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
str[len - 1] = 0; /* remove line feed */
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2023-05-27 00:21:40 -07:00
|
|
|
/**
|
|
|
|
* is_sysfs_pmu_core() - PMU CORE devices have different name other than cpu in
|
|
|
|
* sysfs on some platforms like ARM or Intel hybrid. Looking for
|
|
|
|
* possible the cpus file in sysfs files to identify whether this is a
|
|
|
|
* core device.
|
|
|
|
* @name: The PMU name such as "cpu_atom".
|
2017-08-24 16:30:58 +05:30
|
|
|
*/
|
2023-05-27 00:21:40 -07:00
|
|
|
static int is_sysfs_pmu_core(const char *name)
|
2017-08-24 16:30:58 +05:30
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
2023-01-20 14:36:54 +00:00
|
|
|
if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpus"))
|
2017-08-24 16:30:58 +05:30
|
|
|
return 0;
|
2019-11-20 16:15:11 -08:00
|
|
|
return file_available(path);
|
2017-08-24 16:30:58 +05:30
|
|
|
}
|
|
|
|
|
2024-06-26 15:54:46 +01:00
|
|
|
/**
|
|
|
|
* Return the length of the PMU name not including the suffix for uncore PMUs.
|
|
|
|
*
|
|
|
|
* We want to deduplicate many similar uncore PMUs by stripping their suffixes,
|
|
|
|
* but there are never going to be too many core PMUs and the suffixes might be
|
|
|
|
* interesting. "arm_cortex_a53" vs "arm_cortex_a57" or "cpum_cf" for example.
|
|
|
|
*
|
|
|
|
* @skip_duplicate_pmus: False in verbose mode so all uncore PMUs are visible
|
|
|
|
*/
|
|
|
|
static size_t pmu_deduped_name_len(const struct perf_pmu *pmu, const char *name,
|
|
|
|
bool skip_duplicate_pmus)
|
|
|
|
{
|
|
|
|
return skip_duplicate_pmus && !pmu->is_core
|
|
|
|
? pmu_name_len_no_suffix(name)
|
|
|
|
: strlen(name);
|
|
|
|
}
|
|
|
|
|
2023-04-06 16:52:55 -07:00
|
|
|
/**
|
2025-01-31 23:43:18 -08:00
|
|
|
* perf_pmu__match_wildcard - Does the pmu_name start with tok and is then only
|
|
|
|
* followed by nothing or a suffix? tok may contain
|
|
|
|
* part of a suffix.
|
2023-04-06 16:52:55 -07:00
|
|
|
* @pmu_name: The pmu_name with possible suffix.
|
2025-01-31 23:43:18 -08:00
|
|
|
* @tok: The wildcard argument to match.
|
2021-07-20 23:10:19 +08:00
|
|
|
*/
|
2025-01-31 23:43:18 -08:00
|
|
|
static bool perf_pmu__match_wildcard(const char *pmu_name, const char *tok)
|
2021-07-01 14:42:53 +08:00
|
|
|
{
|
2024-05-14 23:01:13 -07:00
|
|
|
const char *p, *suffix;
|
|
|
|
bool has_hex = false;
|
2025-01-31 23:43:18 -08:00
|
|
|
size_t tok_len = strlen(tok);
|
2021-07-01 14:42:53 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
/* Check start of pmu_name for equality. */
|
|
|
|
if (strncmp(pmu_name, tok, tok_len))
|
2021-07-01 14:42:53 +08:00
|
|
|
return false;
|
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
suffix = p = pmu_name + tok_len;
|
2021-07-01 14:42:53 +08:00
|
|
|
if (*p == 0)
|
|
|
|
return true;
|
|
|
|
|
2024-05-14 23:01:13 -07:00
|
|
|
if (*p == '_') {
|
2021-07-20 23:10:19 +08:00
|
|
|
++p;
|
2024-05-14 23:01:13 -07:00
|
|
|
++suffix;
|
|
|
|
}
|
2021-07-01 14:42:53 +08:00
|
|
|
|
2021-07-20 23:10:19 +08:00
|
|
|
/* Ensure we end in a number */
|
|
|
|
while (1) {
|
2024-05-14 23:01:13 -07:00
|
|
|
if (!isxdigit(*p))
|
2021-07-20 23:10:19 +08:00
|
|
|
return false;
|
2024-05-14 23:01:13 -07:00
|
|
|
if (!has_hex)
|
|
|
|
has_hex = !isdigit(*p);
|
2021-07-20 23:10:19 +08:00
|
|
|
if (*(++p) == 0)
|
|
|
|
break;
|
|
|
|
}
|
2021-07-01 14:42:53 +08:00
|
|
|
|
2024-05-14 23:01:13 -07:00
|
|
|
if (has_hex)
|
|
|
|
return (p - suffix) > 2;
|
|
|
|
|
2021-07-01 14:42:53 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-04-06 16:52:55 -07:00
|
|
|
/**
|
2025-01-31 23:43:18 -08:00
|
|
|
* perf_pmu__match_ignoring_suffix_uncore - Does the pmu_name match tok ignoring
|
|
|
|
* any trailing suffix on pmu_name and
|
|
|
|
* tok? The Suffix must be in form
|
|
|
|
* tok_{digits}, or tok{digits}.
|
|
|
|
* @pmu_name: The pmu_name with possible suffix.
|
|
|
|
* @tok: The possible match to pmu_name.
|
|
|
|
*/
|
|
|
|
static bool perf_pmu__match_ignoring_suffix_uncore(const char *pmu_name, const char *tok)
|
|
|
|
{
|
|
|
|
size_t pmu_name_len, tok_len;
|
|
|
|
|
|
|
|
/* For robustness, check for NULL. */
|
|
|
|
if (pmu_name == NULL)
|
|
|
|
return tok == NULL;
|
|
|
|
|
|
|
|
/* uncore_ prefixes are ignored. */
|
|
|
|
if (!strncmp(pmu_name, "uncore_", 7))
|
|
|
|
pmu_name += 7;
|
|
|
|
if (!strncmp(tok, "uncore_", 7))
|
|
|
|
tok += 7;
|
|
|
|
|
|
|
|
pmu_name_len = pmu_name_len_no_suffix(pmu_name);
|
|
|
|
tok_len = pmu_name_len_no_suffix(tok);
|
|
|
|
if (pmu_name_len != tok_len)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return strncmp(pmu_name, tok, pmu_name_len) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* perf_pmu__match_wildcard_uncore - does to_match match the PMU's name?
|
|
|
|
* @pmu_name: The pmu->name or pmu->alias to match against.
|
|
|
|
* @to_match: the json struct pmu_event name. This may lack a suffix (which
|
2023-04-06 16:52:55 -07:00
|
|
|
* matches) or be of the form "socket,pmuname" which will match
|
|
|
|
* "socketX_pmunameY".
|
|
|
|
*/
|
2025-01-31 23:43:18 -08:00
|
|
|
static bool perf_pmu__match_wildcard_uncore(const char *pmu_name, const char *to_match)
|
2019-06-28 22:35:49 +08:00
|
|
|
{
|
2025-01-31 23:43:18 -08:00
|
|
|
char *mutable_to_match, *tok, *tmp;
|
2023-04-06 16:52:55 -07:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (!pmu_name)
|
2019-06-28 22:35:49 +08:00
|
|
|
return false;
|
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
/* uncore_ prefixes are ignored. */
|
|
|
|
if (!strncmp(pmu_name, "uncore_", 7))
|
|
|
|
pmu_name += 7;
|
|
|
|
if (!strncmp(to_match, "uncore_", 7))
|
|
|
|
to_match += 7;
|
2019-06-28 22:35:49 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (strchr(to_match, ',') == NULL)
|
|
|
|
return perf_pmu__match_wildcard(pmu_name, to_match);
|
2021-07-20 23:10:19 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
/* Process comma separated list of PMU name components. */
|
|
|
|
mutable_to_match = strdup(to_match);
|
|
|
|
if (!mutable_to_match)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
tok = strtok_r(mutable_to_match, ",", &tmp);
|
|
|
|
while (tok) {
|
|
|
|
size_t tok_len = strlen(tok);
|
|
|
|
|
|
|
|
if (strncmp(pmu_name, tok, tok_len)) {
|
|
|
|
/* Mismatch between part of pmu_name and tok. */
|
|
|
|
free(mutable_to_match);
|
|
|
|
return false;
|
2019-06-28 22:35:49 +08:00
|
|
|
}
|
2025-01-31 23:43:18 -08:00
|
|
|
/* Move pmu_name forward over tok and suffix. */
|
|
|
|
pmu_name += tok_len;
|
|
|
|
while (*pmu_name != '\0' && isdigit(*pmu_name))
|
|
|
|
pmu_name++;
|
|
|
|
if (*pmu_name == '_')
|
|
|
|
pmu_name++;
|
|
|
|
|
|
|
|
tok = strtok_r(NULL, ",", &tmp);
|
2019-06-28 22:35:49 +08:00
|
|
|
}
|
2025-01-31 23:43:18 -08:00
|
|
|
free(mutable_to_match);
|
|
|
|
return *pmu_name == '\0';
|
2019-06-28 22:35:49 +08:00
|
|
|
}
|
|
|
|
|
2023-09-27 13:59:45 +08:00
|
|
|
bool pmu_uncore_identifier_match(const char *compat, const char *id)
|
|
|
|
{
|
|
|
|
regex_t re;
|
|
|
|
regmatch_t pmatch[1];
|
|
|
|
int match;
|
|
|
|
|
|
|
|
if (regcomp(&re, compat, REG_EXTENDED) != 0) {
|
|
|
|
/* Warn unable to generate match particular string. */
|
|
|
|
pr_info("Invalid regular expression %s\n", compat);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
match = !regexec(&re, id, 1, pmatch, 0);
|
|
|
|
if (match) {
|
|
|
|
/* Ensure a full match. */
|
|
|
|
match = pmatch[0].rm_so == 0 && (size_t)pmatch[0].rm_eo == strlen(id);
|
|
|
|
}
|
|
|
|
regfree(&re);
|
|
|
|
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
2022-08-12 16:09:45 -07:00
|
|
|
static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
|
2022-08-12 16:09:46 -07:00
|
|
|
const struct pmu_events_table *table __maybe_unused,
|
2022-08-12 16:09:45 -07:00
|
|
|
void *vdata)
|
|
|
|
{
|
2023-08-23 21:13:22 -07:00
|
|
|
struct perf_pmu *pmu = vdata;
|
2022-08-12 16:09:45 -07:00
|
|
|
|
2024-05-10 17:36:01 -07:00
|
|
|
perf_pmu__new_alias(pmu, pe->name, pe->desc, pe->event, /*val_fd=*/ NULL,
|
|
|
|
pe, EVENT_SRC_CPU_JSON);
|
2022-08-12 16:09:45 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-31 12:40:30 -07:00
|
|
|
/*
|
2023-06-22 21:38:42 -07:00
|
|
|
* From the pmu_events_table, find the events that correspond to the given
|
|
|
|
* PMU and add them to the list 'head'.
|
2017-08-31 12:40:30 -07:00
|
|
|
*/
|
2023-08-23 01:08:11 -07:00
|
|
|
void pmu_add_cpu_aliases_table(struct perf_pmu *pmu, const struct pmu_events_table *table)
|
2017-08-31 12:40:30 -07:00
|
|
|
{
|
2023-08-23 21:13:22 -07:00
|
|
|
pmu_events_table__for_each_event(table, pmu, pmu_add_cpu_aliases_map_callback, pmu);
|
2016-09-15 15:24:40 -07:00
|
|
|
}
|
|
|
|
|
2023-08-23 01:08:11 -07:00
|
|
|
static void pmu_add_cpu_aliases(struct perf_pmu *pmu)
|
2020-03-17 19:02:15 +08:00
|
|
|
{
|
2023-08-23 21:13:24 -07:00
|
|
|
if (!pmu->events_table)
|
2020-03-17 19:02:15 +08:00
|
|
|
return;
|
|
|
|
|
2023-08-23 21:13:25 -07:00
|
|
|
if (pmu->cpu_aliases_added)
|
|
|
|
return;
|
|
|
|
|
2023-08-23 21:13:24 -07:00
|
|
|
pmu_add_cpu_aliases_table(pmu, pmu->events_table);
|
2023-08-23 21:13:25 -07:00
|
|
|
pmu->cpu_aliases_added = true;
|
2020-03-17 19:02:15 +08:00
|
|
|
}
|
|
|
|
|
2022-08-12 16:09:42 -07:00
|
|
|
static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
|
2022-08-12 16:09:46 -07:00
|
|
|
const struct pmu_events_table *table __maybe_unused,
|
2023-08-23 21:13:22 -07:00
|
|
|
void *vdata)
|
2020-12-04 19:10:10 +08:00
|
|
|
{
|
2023-08-23 21:13:22 -07:00
|
|
|
struct perf_pmu *pmu = vdata;
|
2020-12-04 19:10:10 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (!pe->compat || !pe->pmu) {
|
|
|
|
/* No data to match. */
|
2020-12-04 19:10:10 +08:00
|
|
|
return 0;
|
2025-01-31 23:43:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!perf_pmu__match_wildcard_uncore(pmu->name, pe->pmu) &&
|
|
|
|
!perf_pmu__match_wildcard_uncore(pmu->alias_name, pe->pmu)) {
|
|
|
|
/* PMU name/alias_name don't match. */
|
|
|
|
return 0;
|
|
|
|
}
|
2020-12-04 19:10:10 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (pmu_uncore_identifier_match(pe->compat, pmu->id)) {
|
|
|
|
/* Id matched. */
|
2023-08-23 21:13:27 -07:00
|
|
|
perf_pmu__new_alias(pmu,
|
2023-08-23 21:13:21 -07:00
|
|
|
pe->name,
|
|
|
|
pe->desc,
|
|
|
|
pe->event,
|
|
|
|
/*val_fd=*/ NULL,
|
2024-05-10 17:36:01 -07:00
|
|
|
pe,
|
|
|
|
EVENT_SRC_SYS_JSON);
|
2020-12-04 19:10:10 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-08-23 01:08:11 -07:00
|
|
|
void pmu_add_sys_aliases(struct perf_pmu *pmu)
|
2020-12-04 19:10:10 +08:00
|
|
|
{
|
|
|
|
if (!pmu->id)
|
|
|
|
return;
|
|
|
|
|
2023-08-23 21:13:22 -07:00
|
|
|
pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, pmu);
|
2020-12-04 19:10:10 +08:00
|
|
|
}
|
|
|
|
|
2023-09-24 23:23:23 -07:00
|
|
|
static char *pmu_find_alias_name(struct perf_pmu *pmu, int dirfd)
|
perf pmu: Add PMU alias support
A perf uncore PMU may have two PMU names, a real name and an alias. The
alias is exported at /sys/bus/event_source/devices/uncore_*/alias.
The perf tool should support the alias as well.
Add alias_name in the struct perf_pmu to store the alias. For the PMU
which doesn't have an alias. It's NULL.
Introduce two X86 specific functions to retrieve the real name and the
alias separately.
Only go through the sysfs to retrieve the mapping between the real name
and the alias once. The result is cached in a list, uncore_pmu_list.
Nothing changed for the other ARCHs.
With the patch, the perf tool can monitor the PMU with either the real
name or the alias.
Use the real name,
$ perf stat -e uncore_cha_2/event=1/ -x,
4044879584,,uncore_cha_2/event=1/,2528059205,100.00,,
Use the alias,
$ perf stat -e uncore_type_0_2/event=1/ -x,
3659675336,,uncore_type_0_2/event=1/,2287306455,100.00,,
Committer notes:
Rename 'struct perf_pmu_alias_name' to 'pmu_alias', the 'perf_' prefix
should be used for libperf, things inside just tools/perf/ are being
moved away from that prefix.
Also 'pmu_alias' is shorter and reflects the abstraction.
Also don't use 'pmu' as the name for variables for that type, we should
use that for the 'struct perf_pmu' variables, avoiding confusion. Use
'pmu_alias' for 'struct pmu_alias' variables.
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Co-developed-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Link: http://lore.kernel.org/lkml/20210902065955.1299-2-yao.jin@linux.intel.com
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-02 14:59:54 +08:00
|
|
|
{
|
2023-09-24 23:23:23 -07:00
|
|
|
FILE *file = perf_pmu__open_file_at(pmu, dirfd, "alias");
|
|
|
|
char *line = NULL;
|
|
|
|
size_t line_len = 0;
|
|
|
|
ssize_t ret;
|
perf pmu: Add PMU alias support
A perf uncore PMU may have two PMU names, a real name and an alias. The
alias is exported at /sys/bus/event_source/devices/uncore_*/alias.
The perf tool should support the alias as well.
Add alias_name in the struct perf_pmu to store the alias. For the PMU
which doesn't have an alias. It's NULL.
Introduce two X86 specific functions to retrieve the real name and the
alias separately.
Only go through the sysfs to retrieve the mapping between the real name
and the alias once. The result is cached in a list, uncore_pmu_list.
Nothing changed for the other ARCHs.
With the patch, the perf tool can monitor the PMU with either the real
name or the alias.
Use the real name,
$ perf stat -e uncore_cha_2/event=1/ -x,
4044879584,,uncore_cha_2/event=1/,2528059205,100.00,,
Use the alias,
$ perf stat -e uncore_type_0_2/event=1/ -x,
3659675336,,uncore_type_0_2/event=1/,2287306455,100.00,,
Committer notes:
Rename 'struct perf_pmu_alias_name' to 'pmu_alias', the 'perf_' prefix
should be used for libperf, things inside just tools/perf/ are being
moved away from that prefix.
Also 'pmu_alias' is shorter and reflects the abstraction.
Also don't use 'pmu' as the name for variables for that type, we should
use that for the 'struct perf_pmu' variables, avoiding confusion. Use
'pmu_alias' for 'struct pmu_alias' variables.
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Co-developed-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Link: http://lore.kernel.org/lkml/20210902065955.1299-2-yao.jin@linux.intel.com
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-02 14:59:54 +08:00
|
|
|
|
2023-09-24 23:23:23 -07:00
|
|
|
if (!file)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = getline(&line, &line_len, file);
|
|
|
|
if (ret < 0) {
|
|
|
|
fclose(file);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Remove trailing newline. */
|
|
|
|
if (ret > 0 && line[ret - 1] == '\n')
|
|
|
|
line[--ret] = '\0';
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
return line;
|
perf pmu: Add PMU alias support
A perf uncore PMU may have two PMU names, a real name and an alias. The
alias is exported at /sys/bus/event_source/devices/uncore_*/alias.
The perf tool should support the alias as well.
Add alias_name in the struct perf_pmu to store the alias. For the PMU
which doesn't have an alias. It's NULL.
Introduce two X86 specific functions to retrieve the real name and the
alias separately.
Only go through the sysfs to retrieve the mapping between the real name
and the alias once. The result is cached in a list, uncore_pmu_list.
Nothing changed for the other ARCHs.
With the patch, the perf tool can monitor the PMU with either the real
name or the alias.
Use the real name,
$ perf stat -e uncore_cha_2/event=1/ -x,
4044879584,,uncore_cha_2/event=1/,2528059205,100.00,,
Use the alias,
$ perf stat -e uncore_type_0_2/event=1/ -x,
3659675336,,uncore_type_0_2/event=1/,2287306455,100.00,,
Committer notes:
Rename 'struct perf_pmu_alias_name' to 'pmu_alias', the 'perf_' prefix
should be used for libperf, things inside just tools/perf/ are being
moved away from that prefix.
Also 'pmu_alias' is shorter and reflects the abstraction.
Also don't use 'pmu' as the name for variables for that type, we should
use that for the 'struct perf_pmu' variables, avoiding confusion. Use
'pmu_alias' for 'struct pmu_alias' variables.
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Co-developed-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Link: http://lore.kernel.org/lkml/20210902065955.1299-2-yao.jin@linux.intel.com
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-02 14:59:54 +08:00
|
|
|
}
|
|
|
|
|
2023-03-31 13:29:48 -07:00
|
|
|
static int pmu_max_precise(int dirfd, struct perf_pmu *pmu)
|
2019-03-05 16:25:32 +01:00
|
|
|
{
|
|
|
|
int max_precise = -1;
|
|
|
|
|
2023-03-31 13:29:48 -07:00
|
|
|
perf_pmu__scan_file_at(pmu, dirfd, "caps/max_precise", "%d", &max_precise);
|
2019-03-05 16:25:32 +01:00
|
|
|
return max_precise;
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:39 -07:00
|
|
|
void __weak
|
2024-01-23 10:50:30 -08:00
|
|
|
perf_pmu__arch_init(struct perf_pmu *pmu)
|
2023-10-12 10:56:39 -07:00
|
|
|
{
|
2024-01-23 10:50:30 -08:00
|
|
|
if (pmu->is_core)
|
|
|
|
pmu->mem_events = perf_mem_events;
|
2023-10-12 10:56:39 -07:00
|
|
|
}
|
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
/* Variant of str_hash that does tolower on each character. */
|
|
|
|
static size_t aliases__hash(long key, void *ctx __maybe_unused)
|
|
|
|
{
|
|
|
|
const char *s = (const char *)key;
|
|
|
|
size_t h = 0;
|
|
|
|
|
|
|
|
while (*s) {
|
|
|
|
h = h * 31 + tolower(*s);
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool aliases__equal(long key1, long key2, void *ctx __maybe_unused)
|
|
|
|
{
|
|
|
|
return strcasecmp((const char *)key1, (const char *)key2) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name)
|
|
|
|
{
|
|
|
|
pmu->type = type;
|
|
|
|
INIT_LIST_HEAD(&pmu->format);
|
|
|
|
INIT_LIST_HEAD(&pmu->caps);
|
|
|
|
|
|
|
|
pmu->name = strdup(name);
|
|
|
|
if (!pmu->name)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
pmu->aliases = hashmap__new(aliases__hash, aliases__equal, /*ctx=*/ NULL);
|
|
|
|
if (!pmu->aliases)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2025-07-10 16:51:17 -07:00
|
|
|
static __u32 wellknown_pmu_type(const char *pmu_name)
|
|
|
|
{
|
|
|
|
struct {
|
|
|
|
const char *pmu_name;
|
|
|
|
__u32 type;
|
|
|
|
} wellknown_pmus[] = {
|
|
|
|
{
|
|
|
|
"software",
|
|
|
|
PERF_TYPE_SOFTWARE
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"tracepoint",
|
|
|
|
PERF_TYPE_TRACEPOINT
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"breakpoint",
|
|
|
|
PERF_TYPE_BREAKPOINT
|
|
|
|
},
|
|
|
|
};
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(wellknown_pmus); i++) {
|
|
|
|
if (!strcmp(wellknown_pmus[i].pmu_name, pmu_name))
|
|
|
|
return wellknown_pmus[i].type;
|
|
|
|
}
|
|
|
|
return PERF_TYPE_MAX;
|
|
|
|
}
|
|
|
|
|
2024-05-02 14:35:04 -07:00
|
|
|
struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name,
|
|
|
|
bool eager_load)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
|
|
|
struct perf_pmu *pmu;
|
2021-07-08 09:36:58 +08:00
|
|
|
|
2023-08-23 01:08:11 -07:00
|
|
|
pmu = zalloc(sizeof(*pmu));
|
|
|
|
if (!pmu)
|
|
|
|
return NULL;
|
|
|
|
|
2025-05-12 12:46:21 -07:00
|
|
|
if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, name) != 0) {
|
|
|
|
perf_pmu__delete(pmu);
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-08-23 21:13:26 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Read type early to fail fast if a lookup name isn't a PMU. Ensure
|
|
|
|
* that type value is successfully assigned (return 1).
|
|
|
|
*/
|
2025-05-12 12:46:21 -07:00
|
|
|
if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &pmu->type) != 1) {
|
2025-07-10 16:51:17 -07:00
|
|
|
/* Double check the PMU's name isn't wellknown. */
|
|
|
|
pmu->type = wellknown_pmu_type(name);
|
|
|
|
if (pmu->type == PERF_TYPE_MAX) {
|
|
|
|
perf_pmu__delete(pmu);
|
|
|
|
return NULL;
|
|
|
|
}
|
2025-05-12 12:46:21 -07:00
|
|
|
}
|
2023-08-23 21:13:26 -07:00
|
|
|
|
2012-03-15 20:09:17 +01:00
|
|
|
/*
|
|
|
|
* The pmu data we store & need consists of the pmu
|
|
|
|
* type value and format definitions. Load both right
|
|
|
|
* now.
|
|
|
|
*/
|
2025-05-12 12:46:21 -07:00
|
|
|
if (pmu_format(pmu, dirfd, name, eager_load)) {
|
|
|
|
perf_pmu__delete(pmu);
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-08-26 23:32:45 +02:00
|
|
|
|
2023-06-22 21:38:43 -07:00
|
|
|
pmu->is_core = is_pmu_core(name);
|
|
|
|
pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core);
|
perf pmu: Add PMU alias support
A perf uncore PMU may have two PMU names, a real name and an alias. The
alias is exported at /sys/bus/event_source/devices/uncore_*/alias.
The perf tool should support the alias as well.
Add alias_name in the struct perf_pmu to store the alias. For the PMU
which doesn't have an alias. It's NULL.
Introduce two X86 specific functions to retrieve the real name and the
alias separately.
Only go through the sysfs to retrieve the mapping between the real name
and the alias once. The result is cached in a list, uncore_pmu_list.
Nothing changed for the other ARCHs.
With the patch, the perf tool can monitor the PMU with either the real
name or the alias.
Use the real name,
$ perf stat -e uncore_cha_2/event=1/ -x,
4044879584,,uncore_cha_2/event=1/,2528059205,100.00,,
Use the alias,
$ perf stat -e uncore_type_0_2/event=1/ -x,
3659675336,,uncore_type_0_2/event=1/,2287306455,100.00,,
Committer notes:
Rename 'struct perf_pmu_alias_name' to 'pmu_alias', the 'perf_' prefix
should be used for libperf, things inside just tools/perf/ are being
moved away from that prefix.
Also 'pmu_alias' is shorter and reflects the abstraction.
Also don't use 'pmu' as the name for variables for that type, we should
use that for the 'struct perf_pmu' variables, avoiding confusion. Use
'pmu_alias' for 'struct pmu_alias' variables.
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Co-developed-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Link: http://lore.kernel.org/lkml/20210902065955.1299-2-yao.jin@linux.intel.com
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-02 14:59:54 +08:00
|
|
|
|
2023-03-31 13:29:48 -07:00
|
|
|
pmu->is_uncore = pmu_is_uncore(dirfd, name);
|
2020-12-04 19:10:09 +08:00
|
|
|
if (pmu->is_uncore)
|
|
|
|
pmu->id = pmu_id(name);
|
2023-03-31 13:29:48 -07:00
|
|
|
pmu->max_precise = pmu_max_precise(dirfd, pmu);
|
2023-09-24 23:23:23 -07:00
|
|
|
pmu->alias_name = pmu_find_alias_name(pmu, dirfd);
|
2023-08-23 21:13:24 -07:00
|
|
|
pmu->events_table = perf_pmu__find_events_table(pmu);
|
2024-05-10 17:36:01 -07:00
|
|
|
/*
|
|
|
|
* Load the sys json events/aliases when loading the PMU as each event
|
|
|
|
* may have a different compat regular expression. We therefore can't
|
|
|
|
* know the number of sys json events/aliases without computing the
|
|
|
|
* regular expressions for them all.
|
|
|
|
*/
|
2023-08-23 01:08:11 -07:00
|
|
|
pmu_add_sys_aliases(pmu);
|
2023-05-27 00:22:03 -07:00
|
|
|
list_add_tail(&pmu->list, pmus);
|
2014-07-31 09:00:49 +03:00
|
|
|
|
2023-10-12 10:56:39 -07:00
|
|
|
perf_pmu__arch_init(pmu);
|
2014-07-31 09:00:49 +03:00
|
|
|
|
2024-05-02 14:35:05 -07:00
|
|
|
if (eager_load)
|
|
|
|
pmu_aliases_parse_eager(pmu, dirfd);
|
|
|
|
|
2012-03-15 20:09:17 +01:00
|
|
|
return pmu;
|
|
|
|
}
|
|
|
|
|
2023-06-27 11:28:34 -07:00
|
|
|
/* Creates the PMU when sysfs scanning fails. */
|
|
|
|
struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus)
|
|
|
|
{
|
|
|
|
struct perf_pmu *pmu = zalloc(sizeof(*pmu));
|
|
|
|
|
|
|
|
if (!pmu)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
pmu->name = strdup("cpu");
|
|
|
|
if (!pmu->name) {
|
|
|
|
free(pmu);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pmu->is_core = true;
|
|
|
|
pmu->type = PERF_TYPE_RAW;
|
|
|
|
pmu->cpus = cpu_map__online();
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&pmu->format);
|
2025-05-12 12:46:21 -07:00
|
|
|
pmu->aliases = hashmap__new(aliases__hash, aliases__equal, /*ctx=*/ NULL);
|
2023-06-27 11:28:34 -07:00
|
|
|
INIT_LIST_HEAD(&pmu->caps);
|
|
|
|
list_add_tail(&pmu->list, core_pmus);
|
|
|
|
return pmu;
|
|
|
|
}
|
|
|
|
|
2024-09-26 15:48:35 +01:00
|
|
|
bool perf_pmu__is_fake(const struct perf_pmu *pmu)
|
2024-09-06 22:08:17 -07:00
|
|
|
{
|
|
|
|
return pmu->type == PERF_PMU_TYPE_FAKE;
|
|
|
|
}
|
|
|
|
|
2022-10-04 14:12:35 -05:00
|
|
|
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
|
|
|
|
{
|
|
|
|
struct perf_pmu_format *format;
|
|
|
|
|
2023-05-31 19:36:43 -07:00
|
|
|
if (pmu->formats_checked)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pmu->formats_checked = true;
|
|
|
|
|
2022-10-04 14:12:35 -05:00
|
|
|
/* fake pmu doesn't have format list */
|
2024-09-06 22:08:17 -07:00
|
|
|
if (perf_pmu__is_fake(pmu))
|
2022-10-04 14:12:35 -05:00
|
|
|
return;
|
|
|
|
|
2023-08-23 21:13:13 -07:00
|
|
|
list_for_each_entry(format, &pmu->format, list) {
|
|
|
|
perf_pmu_format__load(pmu, format);
|
2022-10-04 14:12:35 -05:00
|
|
|
if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) {
|
|
|
|
pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'"
|
|
|
|
"which is not supported by this version of perf!\n",
|
|
|
|
pmu->name, format->name, format->value);
|
|
|
|
return;
|
|
|
|
}
|
2023-08-23 21:13:13 -07:00
|
|
|
}
|
2022-10-04 14:12:35 -05:00
|
|
|
}
|
|
|
|
|
2023-03-11 18:15:37 -08:00
|
|
|
bool evsel__is_aux_event(const struct evsel *evsel)
|
2020-04-01 13:16:09 +03:00
|
|
|
{
|
2024-07-15 19:07:05 +03:00
|
|
|
struct perf_pmu *pmu;
|
|
|
|
|
|
|
|
if (evsel->needs_auxtrace_mmap)
|
|
|
|
return true;
|
2020-04-01 13:16:09 +03:00
|
|
|
|
2024-07-15 19:07:05 +03:00
|
|
|
pmu = evsel__find_pmu(evsel);
|
2020-04-01 13:16:09 +03:00
|
|
|
return pmu && pmu->auxtrace;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:47:42 +01:00
|
|
|
/*
|
|
|
|
* Set @config_name to @val as long as the user hasn't already set or cleared it
|
|
|
|
* by passing a config term on the command line.
|
|
|
|
*
|
|
|
|
* @val is the value to put into the bits specified by @config_name rather than
|
|
|
|
* the bit pattern. It is shifted into position by this function, so to set
|
|
|
|
* something to true, pass 1 for val rather than a pre shifted value.
|
|
|
|
*/
|
|
|
|
#define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask))
|
|
|
|
void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
|
|
|
|
const char *config_name, u64 val)
|
|
|
|
{
|
|
|
|
u64 user_bits = 0, bits;
|
|
|
|
struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
|
|
|
|
|
|
|
|
if (term)
|
|
|
|
user_bits = term->val.cfg_chg;
|
|
|
|
|
2023-08-23 01:08:10 -07:00
|
|
|
bits = perf_pmu__format_bits(pmu, config_name);
|
2023-04-24 14:47:42 +01:00
|
|
|
|
|
|
|
/* Do nothing if the user changed the value */
|
|
|
|
if (bits & user_bits)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Otherwise replace it */
|
|
|
|
evsel->core.attr.config &= ~bits;
|
|
|
|
evsel->core.attr.config |= field_prep(bits, val);
|
|
|
|
}
|
|
|
|
|
2013-01-18 16:54:00 -03:00
|
|
|
static struct perf_pmu_format *
|
2023-10-12 10:56:43 -07:00
|
|
|
pmu_find_format(const struct list_head *formats, const char *name)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
2013-01-18 16:54:00 -03:00
|
|
|
struct perf_pmu_format *format;
|
2012-03-15 20:09:17 +01:00
|
|
|
|
|
|
|
list_for_each_entry(format, formats, list)
|
|
|
|
if (!strcmp(format->name, name))
|
|
|
|
return format;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-08-23 01:08:10 -07:00
|
|
|
__u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name)
|
2015-07-17 19:33:49 +03:00
|
|
|
{
|
2023-08-23 01:08:10 -07:00
|
|
|
struct perf_pmu_format *format = pmu_find_format(&pmu->format, name);
|
2015-07-17 19:33:49 +03:00
|
|
|
__u64 bits = 0;
|
|
|
|
int fbit;
|
|
|
|
|
|
|
|
if (!format)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS)
|
|
|
|
bits |= 1ULL << fbit;
|
|
|
|
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2023-08-23 01:08:09 -07:00
|
|
|
int perf_pmu__format_type(struct perf_pmu *pmu, const char *name)
|
2019-11-15 14:42:22 +02:00
|
|
|
{
|
2023-08-23 01:08:09 -07:00
|
|
|
struct perf_pmu_format *format = pmu_find_format(&pmu->format, name);
|
2019-11-15 14:42:22 +02:00
|
|
|
|
|
|
|
if (!format)
|
|
|
|
return -1;
|
|
|
|
|
2023-08-23 21:13:13 -07:00
|
|
|
perf_pmu_format__load(pmu, format);
|
2019-11-15 14:42:22 +02:00
|
|
|
return format->value;
|
|
|
|
}
|
|
|
|
|
2012-03-15 20:09:17 +01:00
|
|
|
/*
|
2014-07-31 09:00:49 +03:00
|
|
|
* Sets value based on the format definition (format parameter)
|
2021-03-23 17:09:15 +01:00
|
|
|
* and unformatted value (value parameter).
|
2012-03-15 20:09:17 +01:00
|
|
|
*/
|
2014-07-31 09:00:49 +03:00
|
|
|
static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
|
|
|
|
bool zero)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
|
|
|
unsigned long fbit, vbit;
|
|
|
|
|
|
|
|
for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
|
|
|
|
|
|
|
|
if (!test_bit(fbit, format))
|
|
|
|
continue;
|
|
|
|
|
2014-07-31 09:00:49 +03:00
|
|
|
if (value & (1llu << vbit++))
|
|
|
|
*v |= (1llu << fbit);
|
|
|
|
else if (zero)
|
|
|
|
*v &= ~(1llu << fbit);
|
2012-03-15 20:09:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:50 +03:00
|
|
|
static __u64 pmu_format_max_value(const unsigned long *format)
|
|
|
|
{
|
Revert "perf tools: Fix PMU term format max value calculation"
This reverts commit ac0e2cd555373ae6f8f3a3ad3fbbf5b6d1e7aaaa.
Michael reported an issue with oversized terms values assignment
and I noticed there was actually a misunderstanding of the max
value check in the past.
The above commit's changelog says:
If bit 21 is set, there is parsing issues as below.
$ perf stat -a -e uncore_qpi_0/event=0x200002,umask=0x8/
event syntax error: '..pi_0/event=0x200002,umask=0x8/'
\___ value too big for format, maximum is 511
But there's no issue there, because the event value is distributed
along the value defined by the format. Even if the format defines
separated bit, the value is treated as a continual number, which
should follow the format definition.
In above case it's 9-bit value with last bit separated:
$ cat uncore_qpi_0/format/event
config:0-7,21
Hence the value 0x200002 is correctly reported as format violation,
because it exceeds 9 bits. It should have been 0x102 instead, which
sets the 9th bit - the bit 21 of the format.
$ perf stat -vv -a -e uncore_qpi_0/event=0x102,umask=0x8/
Using CPUID GenuineIntel-6-2D
...
------------------------------------------------------------
perf_event_attr:
type 10
size 112
config 0x200802
sample_type IDENTIFIER
...
Reported-by: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Fixes: ac0e2cd55537 ("perf tools: Fix PMU term format max value calculation")
Link: http://lkml.kernel.org/r/20181003072046.29276-1-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-10-03 09:20:46 +02:00
|
|
|
int w;
|
2016-03-30 12:16:15 -07:00
|
|
|
|
Revert "perf tools: Fix PMU term format max value calculation"
This reverts commit ac0e2cd555373ae6f8f3a3ad3fbbf5b6d1e7aaaa.
Michael reported an issue with oversized terms values assignment
and I noticed there was actually a misunderstanding of the max
value check in the past.
The above commit's changelog says:
If bit 21 is set, there is parsing issues as below.
$ perf stat -a -e uncore_qpi_0/event=0x200002,umask=0x8/
event syntax error: '..pi_0/event=0x200002,umask=0x8/'
\___ value too big for format, maximum is 511
But there's no issue there, because the event value is distributed
along the value defined by the format. Even if the format defines
separated bit, the value is treated as a continual number, which
should follow the format definition.
In above case it's 9-bit value with last bit separated:
$ cat uncore_qpi_0/format/event
config:0-7,21
Hence the value 0x200002 is correctly reported as format violation,
because it exceeds 9 bits. It should have been 0x102 instead, which
sets the 9th bit - the bit 21 of the format.
$ perf stat -vv -a -e uncore_qpi_0/event=0x102,umask=0x8/
Using CPUID GenuineIntel-6-2D
...
------------------------------------------------------------
perf_event_attr:
type 10
size 112
config 0x200802
sample_type IDENTIFIER
...
Reported-by: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Fixes: ac0e2cd55537 ("perf tools: Fix PMU term format max value calculation")
Link: http://lkml.kernel.org/r/20181003072046.29276-1-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-10-03 09:20:46 +02:00
|
|
|
w = bitmap_weight(format, PERF_PMU_FORMAT_BITS);
|
|
|
|
if (!w)
|
|
|
|
return 0;
|
|
|
|
if (w < 64)
|
|
|
|
return (1ULL << w) - 1;
|
|
|
|
return -1;
|
2015-07-17 19:33:50 +03:00
|
|
|
}
|
|
|
|
|
2015-01-07 17:13:50 -08:00
|
|
|
/*
|
|
|
|
* Term is a string term, and might be a param-term. Try to look up it's value
|
|
|
|
* in the remaining terms.
|
|
|
|
* - We have a term like "base-or-format-term=param-term",
|
|
|
|
* - We need to find the value supplied for "param-term" (with param-term named
|
|
|
|
* in a config string) later on in the term list.
|
|
|
|
*/
|
|
|
|
static int pmu_resolve_param_term(struct parse_events_term *term,
|
2023-09-01 16:39:49 -07:00
|
|
|
struct parse_events_terms *head_terms,
|
2015-01-07 17:13:50 -08:00
|
|
|
__u64 *value)
|
|
|
|
{
|
|
|
|
struct parse_events_term *t;
|
|
|
|
|
2023-09-01 16:39:49 -07:00
|
|
|
list_for_each_entry(t, &head_terms->terms, list) {
|
2020-03-25 09:40:22 -07:00
|
|
|
if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM &&
|
|
|
|
t->config && !strcmp(t->config, term->config)) {
|
|
|
|
t->used = true;
|
|
|
|
*value = t->val.num;
|
|
|
|
return 0;
|
2015-01-07 17:13:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:17:38 +09:00
|
|
|
if (verbose > 0)
|
2015-01-07 17:13:50 -08:00
|
|
|
printf("Required parameter '%s' not specified\n", term->config);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:43 -07:00
|
|
|
static char *pmu_formats_string(const struct list_head *formats)
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
{
|
|
|
|
struct perf_pmu_format *format;
|
2016-05-10 14:47:44 +09:00
|
|
|
char *str = NULL;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2022-08-17 01:41:09 +08:00
|
|
|
unsigned int i = 0;
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
|
perf tools: Show proper error message for wrong terms of hw/sw events
Show proper error message and show valid terms when wrong config terms
is specified for hw/sw type perf events.
This patch makes the original error format function formats_error_string()
more generic, which only outputs the static config terms for hw/sw perf
events, and prepends pmu formats for pmu events.
Before this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
invalid or unsupported event: 'cpu-clock/freqx=200/'
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
After this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
event syntax error: 'cpu-clock/freqx=200/'
\___ unknown term
valid terms: config,config1,config2,name,period,freq,branch_type,time,call-graph,stack-size
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: He Kuang <hekuang@huawei.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1443412336-120050-2-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-09-28 03:52:14 +00:00
|
|
|
if (!formats)
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* sysfs exported terms */
|
perf tools: Show proper error message for wrong terms of hw/sw events
Show proper error message and show valid terms when wrong config terms
is specified for hw/sw type perf events.
This patch makes the original error format function formats_error_string()
more generic, which only outputs the static config terms for hw/sw perf
events, and prepends pmu formats for pmu events.
Before this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
invalid or unsupported event: 'cpu-clock/freqx=200/'
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
After this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
event syntax error: 'cpu-clock/freqx=200/'
\___ unknown term
valid terms: config,config1,config2,name,period,freq,branch_type,time,call-graph,stack-size
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: He Kuang <hekuang@huawei.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1443412336-120050-2-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-09-28 03:52:14 +00:00
|
|
|
list_for_each_entry(format, formats, list)
|
2016-05-10 14:47:44 +09:00
|
|
|
if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0)
|
|
|
|
goto error;
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
|
perf tools: Show proper error message for wrong terms of hw/sw events
Show proper error message and show valid terms when wrong config terms
is specified for hw/sw type perf events.
This patch makes the original error format function formats_error_string()
more generic, which only outputs the static config terms for hw/sw perf
events, and prepends pmu formats for pmu events.
Before this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
invalid or unsupported event: 'cpu-clock/freqx=200/'
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
After this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
event syntax error: 'cpu-clock/freqx=200/'
\___ unknown term
valid terms: config,config1,config2,name,period,freq,branch_type,time,call-graph,stack-size
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: He Kuang <hekuang@huawei.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1443412336-120050-2-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-09-28 03:52:14 +00:00
|
|
|
str = strbuf_detach(&buf, NULL);
|
2016-05-10 14:47:44 +09:00
|
|
|
error:
|
perf tools: Show proper error message for wrong terms of hw/sw events
Show proper error message and show valid terms when wrong config terms
is specified for hw/sw type perf events.
This patch makes the original error format function formats_error_string()
more generic, which only outputs the static config terms for hw/sw perf
events, and prepends pmu formats for pmu events.
Before this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
invalid or unsupported event: 'cpu-clock/freqx=200/'
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
After this patch:
$ perf record -e 'cpu-clock/freqx=200/' -a sleep 1
event syntax error: 'cpu-clock/freqx=200/'
\___ unknown term
valid terms: config,config1,config2,name,period,freq,branch_type,time,call-graph,stack-size
Run 'perf list' for a list of valid events
usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: He Kuang <hekuang@huawei.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1443412336-120050-2-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-09-28 03:52:14 +00:00
|
|
|
strbuf_release(&buf);
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2012-03-15 20:09:17 +01:00
|
|
|
/*
|
|
|
|
* Setup one of config[12] attr members based on the
|
2014-01-08 08:43:51 -08:00
|
|
|
* user input data - term parameter.
|
2012-03-15 20:09:17 +01:00
|
|
|
*/
|
2023-10-12 10:56:43 -07:00
|
|
|
static int pmu_config_term(const struct perf_pmu *pmu,
|
2012-03-15 20:09:17 +01:00
|
|
|
struct perf_event_attr *attr,
|
2014-07-31 09:00:49 +03:00
|
|
|
struct parse_events_term *term,
|
2023-09-01 16:39:49 -07:00
|
|
|
struct parse_events_terms *head_terms,
|
2024-10-01 20:20:05 -07:00
|
|
|
bool zero, bool apply_hardcoded,
|
|
|
|
struct parse_events_error *err)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
2013-01-18 16:54:00 -03:00
|
|
|
struct perf_pmu_format *format;
|
2012-03-15 20:09:17 +01:00
|
|
|
__u64 *vp;
|
2015-07-17 19:33:50 +03:00
|
|
|
__u64 val, max_val;
|
2015-01-07 17:13:50 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is a parameter we've already used for parameterized-eval,
|
|
|
|
* skip it in normal eval.
|
|
|
|
*/
|
|
|
|
if (term->used)
|
|
|
|
return 0;
|
2012-03-15 20:09:17 +01:00
|
|
|
|
|
|
|
/*
|
2024-10-01 20:20:05 -07:00
|
|
|
* Hardcoded terms are generally handled in event parsing, which
|
|
|
|
* traditionally have had to handle not having a PMU. An alias may
|
|
|
|
* have hard coded config values, optionally apply them below.
|
2012-03-15 20:09:17 +01:00
|
|
|
*/
|
2024-10-01 20:20:05 -07:00
|
|
|
if (parse_events__is_hardcoded_term(term)) {
|
|
|
|
/* Config terms set all bits in the config. */
|
|
|
|
DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
|
|
|
|
|
|
|
|
if (!apply_hardcoded)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bitmap_fill(bits, PERF_PMU_FORMAT_BITS);
|
|
|
|
|
|
|
|
switch (term->type_term) {
|
|
|
|
case PARSE_EVENTS__TERM_TYPE_CONFIG:
|
|
|
|
assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
|
|
|
|
pmu_format_value(bits, term->val.num, &attr->config, zero);
|
|
|
|
break;
|
|
|
|
case PARSE_EVENTS__TERM_TYPE_CONFIG1:
|
|
|
|
assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
|
|
|
|
pmu_format_value(bits, term->val.num, &attr->config1, zero);
|
|
|
|
break;
|
|
|
|
case PARSE_EVENTS__TERM_TYPE_CONFIG2:
|
|
|
|
assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
|
|
|
|
pmu_format_value(bits, term->val.num, &attr->config2, zero);
|
|
|
|
break;
|
|
|
|
case PARSE_EVENTS__TERM_TYPE_CONFIG3:
|
|
|
|
assert(term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
|
|
|
|
pmu_format_value(bits, term->val.num, &attr->config3, zero);
|
|
|
|
break;
|
|
|
|
case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */
|
|
|
|
return -EINVAL;
|
perf parse-events: Add "cpu" term to set the CPU an event is recorded on
The -C option allows the CPUs for a list of events to be specified but
its not possible to set the CPU for a single event. Add a term to
allow this. The term isn't a general CPU list due to ',' already being
a special character in event parsing instead multiple cpu= terms may
be provided and they will be merged/unioned together.
An example of mixing different types of events counted on different CPUs:
```
$ perf stat -A -C 0,4-5,8 -e "instructions/cpu=0/,l1d-misses/cpu=4,cpu=5/,inst_retired.any/cpu=8/,cycles" -a sleep 0.1
Performance counter stats for 'system wide':
CPU0 6,979,225 instructions/cpu=0/ # 0.89 insn per cycle
CPU4 75,138 cpu/l1d-misses/
CPU5 1,418,939 cpu/l1d-misses/
CPU8 797,553 cpu/inst_retired.any,cpu=8/
CPU0 7,845,302 cycles
CPU4 6,546,859 cycles
CPU5 185,915,438 cycles
CPU8 2,065,668 cycles
0.112449242 seconds time elapsed
```
Committer testing:
root@number:~# grep -m1 "model name" /proc/cpuinfo
model name : AMD Ryzen 9 9950X3D 16-Core Processor
root@number:~# perf stat -A -e "instructions/cpu=0/,instructions,l1d-misses/cpu=4,cpu=5/,cycles" -a sleep 0.1
Performance counter stats for 'system wide':
CPU0 2,398,351 instructions/cpu=0/ # 0.44 insn per cycle
CPU0 2,398,152 instructions # 0.44 insn per cycle
CPU1 1,265,634 instructions # 0.49 insn per cycle
CPU2 606,087 instructions # 0.50 insn per cycle
CPU3 4,025,752 instructions # 0.52 insn per cycle
CPU4 4,236,810 instructions # 0.53 insn per cycle
CPU5 3,984,832 instructions # 0.66 insn per cycle
CPU6 434,132 instructions # 0.44 insn per cycle
CPU7 65,752 instructions # 0.41 insn per cycle
CPU8 459,083 instructions # 0.48 insn per cycle
CPU9 6,464,161 instructions # 1.31 insn per cycle
<SNIP>
root@number:~# perf stat -e "instructions/cpu=0/,instructions,l1d-misses/cpu=4,cpu=5/,cycles" -a sleep 0.
Performance counter stats for 'system wide':
144,822 instructions/cpu=0/ # 0.03 insn per cycle
4,666,114 instructions # 0.93 insn per cycle
2,583 l1d-misses
4,993,633 cycles
0.000868512 seconds time elapsed
root@number:~#
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Dominique Martinet <asmadeus@codewreck.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Link: https://lore.kernel.org/r/20250403194337.40202-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2025-04-03 12:43:37 -07:00
|
|
|
case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_CPU:
|
2024-10-01 20:20:05 -07:00
|
|
|
/* Skip non-config terms. */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2012-03-15 20:09:17 +01:00
|
|
|
return 0;
|
2024-10-01 20:20:05 -07:00
|
|
|
}
|
2012-03-15 20:09:17 +01:00
|
|
|
|
2023-08-23 01:08:08 -07:00
|
|
|
format = pmu_find_format(&pmu->format, term->config);
|
2015-01-07 17:13:50 -08:00
|
|
|
if (!format) {
|
2023-08-23 01:08:08 -07:00
|
|
|
char *pmu_term = pmu_formats_string(&pmu->format);
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
char *unknown_term;
|
|
|
|
char *help_msg;
|
|
|
|
|
|
|
|
if (asprintf(&unknown_term,
|
|
|
|
"unknown term '%s' for pmu '%s'",
|
2023-08-23 01:08:08 -07:00
|
|
|
term->config, pmu->name) < 0)
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
unknown_term = NULL;
|
|
|
|
help_msg = parse_events_formats_error_string(pmu_term);
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
if (err) {
|
2021-11-07 01:00:00 -08:00
|
|
|
parse_events_error__handle(err, term->err_term,
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
unknown_term,
|
|
|
|
help_msg);
|
|
|
|
} else {
|
|
|
|
pr_debug("%s (%s)\n", unknown_term, help_msg);
|
|
|
|
free(unknown_term);
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
}
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
free(pmu_term);
|
2012-03-15 20:09:17 +01:00
|
|
|
return -EINVAL;
|
2015-01-07 17:13:50 -08:00
|
|
|
}
|
2023-08-23 21:13:13 -07:00
|
|
|
perf_pmu_format__load(pmu, format);
|
2012-03-15 20:09:17 +01:00
|
|
|
switch (format->value) {
|
|
|
|
case PERF_PMU_FORMAT_VALUE_CONFIG:
|
|
|
|
vp = &attr->config;
|
|
|
|
break;
|
|
|
|
case PERF_PMU_FORMAT_VALUE_CONFIG1:
|
|
|
|
vp = &attr->config1;
|
|
|
|
break;
|
|
|
|
case PERF_PMU_FORMAT_VALUE_CONFIG2:
|
|
|
|
vp = &attr->config2;
|
|
|
|
break;
|
2023-02-17 16:32:11 -06:00
|
|
|
case PERF_PMU_FORMAT_VALUE_CONFIG3:
|
|
|
|
vp = &attr->config3;
|
|
|
|
break;
|
2012-03-15 20:09:17 +01:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2012-04-25 18:24:57 +02:00
|
|
|
/*
|
2015-01-07 17:13:50 -08:00
|
|
|
* Either directly use a numeric term, or try to translate string terms
|
|
|
|
* using event parameters.
|
2012-04-25 18:24:57 +02:00
|
|
|
*/
|
2017-02-17 15:00:56 +01:00
|
|
|
if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
|
|
|
|
if (term->no_value &&
|
|
|
|
bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) {
|
|
|
|
if (err) {
|
2021-11-07 01:00:00 -08:00
|
|
|
parse_events_error__handle(err, term->err_val,
|
perf parse: Add parse events handle error
Parse event error handling may overwrite one error string with another
creating memory leaks. Introduce a helper routine that warns about
multiple error messages as well as avoiding the memory leak.
A reproduction of this problem can be seen with:
perf stat -e c/c/
After this change this produces:
WARNING: multiple event parsing errors
event syntax error: 'c/c/'
\___ unknown term
valid terms: event,filter_rem,filter_opc0,edge,filter_isoc,filter_tid,filter_loc,filter_nc,inv,umask,filter_opc1,tid_en,thresh,filter_all_op,filter_not_nm,filter_state,filter_nm,config,config1,config2,name,period,percore
Run 'perf list' for a list of valid events
Usage: perf stat [<options>] [<command>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <songliubraving@fb.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: clang-built-linux@googlegroups.com
Cc: netdev@vger.kernel.org
Link: http://lore.kernel.org/lkml/20191030223448.12930-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-10-30 15:34:39 -07:00
|
|
|
strdup("no value assigned for term"),
|
|
|
|
NULL);
|
2017-02-17 15:00:56 +01:00
|
|
|
}
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-01-07 17:13:50 -08:00
|
|
|
val = term->val.num;
|
2017-02-17 15:00:56 +01:00
|
|
|
} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
|
2015-01-07 17:13:50 -08:00
|
|
|
if (strcmp(term->val.str, "?")) {
|
2017-02-17 17:17:38 +09:00
|
|
|
if (verbose > 0) {
|
2015-01-07 17:13:50 -08:00
|
|
|
pr_info("Invalid sysfs entry %s=%s\n",
|
|
|
|
term->config, term->val.str);
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
}
|
|
|
|
if (err) {
|
2021-11-07 01:00:00 -08:00
|
|
|
parse_events_error__handle(err, term->err_val,
|
perf parse: Add parse events handle error
Parse event error handling may overwrite one error string with another
creating memory leaks. Introduce a helper routine that warns about
multiple error messages as well as avoiding the memory leak.
A reproduction of this problem can be seen with:
perf stat -e c/c/
After this change this produces:
WARNING: multiple event parsing errors
event syntax error: 'c/c/'
\___ unknown term
valid terms: event,filter_rem,filter_opc0,edge,filter_isoc,filter_tid,filter_loc,filter_nc,inv,umask,filter_opc1,tid_en,thresh,filter_all_op,filter_not_nm,filter_state,filter_nm,config,config1,config2,name,period,percore
Run 'perf list' for a list of valid events
Usage: perf stat [<options>] [<command>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <songliubraving@fb.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: clang-built-linux@googlegroups.com
Cc: netdev@vger.kernel.org
Link: http://lore.kernel.org/lkml/20191030223448.12930-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-10-30 15:34:39 -07:00
|
|
|
strdup("expected numeric value"),
|
|
|
|
NULL);
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
}
|
2015-01-07 17:13:50 -08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pmu_resolve_param_term(term, head_terms, &val))
|
|
|
|
return -EINVAL;
|
|
|
|
} else
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-07-17 19:33:50 +03:00
|
|
|
max_val = pmu_format_max_value(format->bits);
|
|
|
|
if (val > max_val) {
|
|
|
|
if (err) {
|
perf parse: Add parse events handle error
Parse event error handling may overwrite one error string with another
creating memory leaks. Introduce a helper routine that warns about
multiple error messages as well as avoiding the memory leak.
A reproduction of this problem can be seen with:
perf stat -e c/c/
After this change this produces:
WARNING: multiple event parsing errors
event syntax error: 'c/c/'
\___ unknown term
valid terms: event,filter_rem,filter_opc0,edge,filter_isoc,filter_tid,filter_loc,filter_nc,inv,umask,filter_opc1,tid_en,thresh,filter_all_op,filter_not_nm,filter_state,filter_nm,config,config1,config2,name,period,percore
Run 'perf list' for a list of valid events
Usage: perf stat [<options>] [<command>]
-e, --event <event> event selector. use 'perf list' to list available events
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <songliubraving@fb.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: clang-built-linux@googlegroups.com
Cc: netdev@vger.kernel.org
Link: http://lore.kernel.org/lkml/20191030223448.12930-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-10-30 15:34:39 -07:00
|
|
|
char *err_str;
|
|
|
|
|
2024-10-01 20:20:04 -07:00
|
|
|
if (asprintf(&err_str,
|
|
|
|
"value too big for format (%s), maximum is %llu",
|
|
|
|
format->name, (unsigned long long)max_val) < 0) {
|
|
|
|
err_str = strdup("value too big for format");
|
|
|
|
}
|
|
|
|
parse_events_error__handle(err, term->err_val, err_str, /*help=*/NULL);
|
2015-07-17 19:33:50 +03:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Assume we don't care if !err, in which case the value will be
|
|
|
|
* silently truncated.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2015-01-07 17:13:50 -08:00
|
|
|
pmu_format_value(format->bits, val, vp, zero);
|
2012-03-15 20:09:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:43 -07:00
|
|
|
int perf_pmu__config_terms(const struct perf_pmu *pmu,
|
2012-11-10 01:46:50 +01:00
|
|
|
struct perf_event_attr *attr,
|
2023-09-01 16:39:49 -07:00
|
|
|
struct parse_events_terms *terms,
|
2024-10-01 20:20:05 -07:00
|
|
|
bool zero, bool apply_hardcoded,
|
|
|
|
struct parse_events_error *err)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
2013-01-18 16:29:49 -03:00
|
|
|
struct parse_events_term *term;
|
2012-03-15 20:09:17 +01:00
|
|
|
|
2024-11-08 16:37:57 -08:00
|
|
|
if (perf_pmu__is_hwmon(pmu))
|
|
|
|
return hwmon_pmu__config_terms(pmu, attr, terms, err);
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
if (perf_pmu__is_drm(pmu))
|
|
|
|
return drm_pmu__config_terms(pmu, attr, terms, err);
|
2024-11-08 16:37:57 -08:00
|
|
|
|
2023-09-01 16:39:49 -07:00
|
|
|
list_for_each_entry(term, &terms->terms, list) {
|
2024-10-01 20:20:05 -07:00
|
|
|
if (pmu_config_term(pmu, attr, term, terms, zero, apply_hardcoded, err))
|
2012-03-15 20:09:17 +01:00
|
|
|
return -EINVAL;
|
2015-01-07 17:13:50 -08:00
|
|
|
}
|
2012-03-15 20:09:17 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configures event's 'attr' parameter based on the:
|
|
|
|
* 1) users input - specified in terms parameter
|
|
|
|
* 2) pmu format definitions - specified by pmu parameter
|
|
|
|
*/
|
|
|
|
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
|
2023-09-01 16:39:49 -07:00
|
|
|
struct parse_events_terms *head_terms,
|
2024-10-01 20:20:05 -07:00
|
|
|
bool apply_hardcoded,
|
perf tools: Add term support for parse_events_error
Allowing event's term processing to report back error, like:
$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term
valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-04-22 21:10:21 +02:00
|
|
|
struct parse_events_error *err)
|
2012-03-15 20:09:17 +01:00
|
|
|
{
|
2023-10-12 10:56:45 -07:00
|
|
|
bool zero = !!pmu->perf_event_attr_init_default;
|
2014-07-31 09:00:49 +03:00
|
|
|
|
2024-09-06 22:08:17 -07:00
|
|
|
/* Fake PMU doesn't have proper terms so nothing to configure in attr. */
|
|
|
|
if (perf_pmu__is_fake(pmu))
|
|
|
|
return 0;
|
|
|
|
|
2024-10-01 20:20:05 -07:00
|
|
|
return perf_pmu__config_terms(pmu, attr, head_terms, zero, apply_hardcoded, err);
|
2012-03-15 20:09:17 +01:00
|
|
|
}
|
|
|
|
|
2013-01-18 16:54:00 -03:00
|
|
|
static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
|
|
|
|
struct parse_events_term *term)
|
2012-06-15 14:31:41 +08:00
|
|
|
{
|
2023-08-23 21:13:25 -07:00
|
|
|
struct perf_pmu_alias *alias;
|
2023-08-24 19:39:59 -07:00
|
|
|
const char *name;
|
2012-06-15 14:31:41 +08:00
|
|
|
|
|
|
|
if (parse_events__is_hardcoded_term(term))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
|
2023-08-31 00:14:21 -07:00
|
|
|
if (!term->no_value)
|
2012-06-15 14:31:41 +08:00
|
|
|
return NULL;
|
|
|
|
if (pmu_find_format(&pmu->format, term->config))
|
|
|
|
return NULL;
|
|
|
|
name = term->config;
|
2023-08-23 21:13:14 -07:00
|
|
|
|
2012-06-15 14:31:41 +08:00
|
|
|
} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
|
|
|
|
if (strcasecmp(term->config, "event"))
|
|
|
|
return NULL;
|
|
|
|
name = term->val.str;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:28 -07:00
|
|
|
alias = perf_pmu__find_alias(pmu, name, /*load=*/ true);
|
2023-08-23 21:13:25 -07:00
|
|
|
if (alias || pmu->cpu_aliases_added)
|
|
|
|
return alias;
|
|
|
|
|
|
|
|
/* Alias doesn't exist, try to get it from the json events. */
|
|
|
|
if (pmu->events_table &&
|
|
|
|
pmu_events_table__find_event(pmu->events_table, pmu, name,
|
|
|
|
pmu_add_cpu_aliases_map_callback,
|
|
|
|
pmu) == 0) {
|
2023-08-23 21:13:28 -07:00
|
|
|
alias = perf_pmu__find_alias(pmu, name, /*load=*/ false);
|
2023-08-23 21:13:25 -07:00
|
|
|
}
|
|
|
|
return alias;
|
2012-06-15 14:31:41 +08:00
|
|
|
}
|
|
|
|
|
2013-11-12 17:58:49 +01:00
|
|
|
|
2023-08-23 21:13:27 -07:00
|
|
|
static int check_info_data(struct perf_pmu *pmu,
|
|
|
|
struct perf_pmu_alias *alias,
|
2023-08-23 21:13:17 -07:00
|
|
|
struct perf_pmu_info *info,
|
|
|
|
struct parse_events_error *err,
|
|
|
|
int column)
|
2013-11-12 17:58:49 +01:00
|
|
|
{
|
2023-08-23 21:13:27 -07:00
|
|
|
read_alias_info(pmu, alias);
|
2013-11-12 17:58:49 +01:00
|
|
|
/*
|
|
|
|
* Only one term in event definition can
|
2014-11-21 10:31:13 +01:00
|
|
|
* define unit, scale and snapshot, fail
|
|
|
|
* if there's more than one.
|
2013-11-12 17:58:49 +01:00
|
|
|
*/
|
2023-08-23 21:13:17 -07:00
|
|
|
if (info->unit && alias->unit[0]) {
|
|
|
|
parse_events_error__handle(err, column,
|
|
|
|
strdup("Attempt to set event's unit twice"),
|
|
|
|
NULL);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (info->scale && alias->scale) {
|
|
|
|
parse_events_error__handle(err, column,
|
|
|
|
strdup("Attempt to set event's scale twice"),
|
|
|
|
NULL);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (info->snapshot && alias->snapshot) {
|
|
|
|
parse_events_error__handle(err, column,
|
|
|
|
strdup("Attempt to set event snapshot twice"),
|
|
|
|
NULL);
|
2013-11-12 17:58:49 +01:00
|
|
|
return -EINVAL;
|
2023-08-23 21:13:17 -07:00
|
|
|
}
|
2013-11-12 17:58:49 +01:00
|
|
|
|
2017-02-15 10:06:20 -03:00
|
|
|
if (alias->unit[0])
|
2014-11-21 10:31:13 +01:00
|
|
|
info->unit = alias->unit;
|
2013-11-12 17:58:49 +01:00
|
|
|
|
|
|
|
if (alias->scale)
|
2014-11-21 10:31:13 +01:00
|
|
|
info->scale = alias->scale;
|
|
|
|
|
|
|
|
if (alias->snapshot)
|
|
|
|
info->snapshot = alias->snapshot;
|
2013-11-12 17:58:49 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-15 14:31:41 +08:00
|
|
|
/*
|
|
|
|
* Find alias in the terms list and replace it with the terms
|
|
|
|
* defined for the alias
|
|
|
|
*/
|
2023-09-01 16:39:49 -07:00
|
|
|
int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,
|
perf parse-events: Make legacy events lower priority than sysfs/JSON
The perf tool has previously made legacy events the priority so with
or without a PMU the legacy event would be opened:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
After aliases, add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 833967 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
Fixes to make hybrid/BIG.little PMUs behave correctly, ie as core PMUs
capable of opening legacy events on each, removing hard coded "cpu_core"
and "cpu_atom" Intel PMU names, etc. caused a behavioral difference on
Apple/ARM due to latent issues in the PMU driver reported in:
https://lore.kernel.org/lkml/08f1f185-e259-4014-9ca4-6411d5c1bc65@marcan.st/
As part of that report Mark Rutland <mark.rutland@arm.com> requested
that legacy events not be higher in priority when a PMU is specified
reversing what has until this change been perf's default behavior. With
this change the above becomes:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
Attempt to add: cpu/cpu-cycles=0/
..after resolving event: cpu/event=0x3c/
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 827628 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 4 (PERF_TYPE_RAW)
size 136
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
So the second event has become a raw event as
/sys/devices/cpu/events/cpu-cycles exists.
A fix was necessary to config_term_pmu in parse-events.c as check_alias
expansion needs to happen after config_term_pmu, and config_term_pmu may
need calling a second time because of this.
config_term_pmu is updated to not use the legacy event when the PMU has
such a named event (either from JSON or sysfs).
The bulk of this change is updating all of the parse-events test
expectations so that if a sysfs/JSON event exists for a PMU the test
doesn't fail - a further sign, if it were needed, that the legacy event
priority was a known and tested behavior of the perf tool.
Reported-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Hector Martin <marcan@marcan.st>
Tested-by: Marc Zyngier <maz@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20231123042922.834425-1-irogers@google.com
[ Initialize the 'alias_rewrote_terms' variable to false to address a clang warning ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-11-22 20:29:22 -08:00
|
|
|
struct perf_pmu_info *info, bool *rewrote_terms,
|
2024-09-26 15:48:32 +01:00
|
|
|
u64 *alternate_hw_config, struct parse_events_error *err)
|
2012-06-15 14:31:41 +08:00
|
|
|
{
|
2013-01-18 16:29:49 -03:00
|
|
|
struct parse_events_term *term, *h;
|
2013-01-18 16:54:00 -03:00
|
|
|
struct perf_pmu_alias *alias;
|
2012-06-15 14:31:41 +08:00
|
|
|
int ret;
|
|
|
|
|
perf parse-events: Make legacy events lower priority than sysfs/JSON
The perf tool has previously made legacy events the priority so with
or without a PMU the legacy event would be opened:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
After aliases, add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 833967 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
Fixes to make hybrid/BIG.little PMUs behave correctly, ie as core PMUs
capable of opening legacy events on each, removing hard coded "cpu_core"
and "cpu_atom" Intel PMU names, etc. caused a behavioral difference on
Apple/ARM due to latent issues in the PMU driver reported in:
https://lore.kernel.org/lkml/08f1f185-e259-4014-9ca4-6411d5c1bc65@marcan.st/
As part of that report Mark Rutland <mark.rutland@arm.com> requested
that legacy events not be higher in priority when a PMU is specified
reversing what has until this change been perf's default behavior. With
this change the above becomes:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
Attempt to add: cpu/cpu-cycles=0/
..after resolving event: cpu/event=0x3c/
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 827628 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 4 (PERF_TYPE_RAW)
size 136
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
So the second event has become a raw event as
/sys/devices/cpu/events/cpu-cycles exists.
A fix was necessary to config_term_pmu in parse-events.c as check_alias
expansion needs to happen after config_term_pmu, and config_term_pmu may
need calling a second time because of this.
config_term_pmu is updated to not use the legacy event when the PMU has
such a named event (either from JSON or sysfs).
The bulk of this change is updating all of the parse-events test
expectations so that if a sysfs/JSON event exists for a PMU the test
doesn't fail - a further sign, if it were needed, that the legacy event
priority was a known and tested behavior of the perf tool.
Reported-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Hector Martin <marcan@marcan.st>
Tested-by: Marc Zyngier <maz@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20231123042922.834425-1-irogers@google.com
[ Initialize the 'alias_rewrote_terms' variable to false to address a clang warning ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-11-22 20:29:22 -08:00
|
|
|
*rewrote_terms = false;
|
2014-11-21 10:31:12 +01:00
|
|
|
info->per_pkg = false;
|
|
|
|
|
2014-01-17 16:34:05 +01:00
|
|
|
/*
|
|
|
|
* Mark unit and scale as not set
|
|
|
|
* (different from default values, see below)
|
|
|
|
*/
|
2014-11-21 10:31:13 +01:00
|
|
|
info->unit = NULL;
|
|
|
|
info->scale = 0.0;
|
|
|
|
info->snapshot = false;
|
2025-04-14 10:41:33 -07:00
|
|
|
info->retirement_latency_mean = 0.0;
|
|
|
|
info->retirement_latency_min = 0.0;
|
|
|
|
info->retirement_latency_max = 0.0;
|
2013-11-12 17:58:49 +01:00
|
|
|
|
2024-11-08 16:37:57 -08:00
|
|
|
if (perf_pmu__is_hwmon(pmu)) {
|
|
|
|
ret = hwmon_pmu__check_alias(head_terms, info, err);
|
|
|
|
goto out;
|
|
|
|
}
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
if (perf_pmu__is_drm(pmu)) {
|
|
|
|
ret = drm_pmu__check_alias(pmu, head_terms, info, err);
|
|
|
|
goto out;
|
|
|
|
}
|
2024-11-08 16:37:57 -08:00
|
|
|
|
2024-10-01 20:20:12 -07:00
|
|
|
/* Fake PMU doesn't rewrite terms. */
|
|
|
|
if (perf_pmu__is_fake(pmu))
|
2024-09-06 22:08:17 -07:00
|
|
|
goto out;
|
|
|
|
|
2023-09-01 16:39:49 -07:00
|
|
|
list_for_each_entry_safe(term, h, &head_terms->terms, list) {
|
2012-06-15 14:31:41 +08:00
|
|
|
alias = pmu_find_alias(pmu, term);
|
|
|
|
if (!alias)
|
|
|
|
continue;
|
2024-01-31 05:49:39 -08:00
|
|
|
ret = pmu_alias_terms(alias, term->err_term, &term->list);
|
2023-08-23 21:13:17 -07:00
|
|
|
if (ret) {
|
|
|
|
parse_events_error__handle(err, term->err_term,
|
|
|
|
strdup("Failure to duplicate terms"),
|
|
|
|
NULL);
|
2012-06-15 14:31:41 +08:00
|
|
|
return ret;
|
2023-08-23 21:13:17 -07:00
|
|
|
}
|
2024-09-26 15:48:32 +01:00
|
|
|
|
perf parse-events: Make legacy events lower priority than sysfs/JSON
The perf tool has previously made legacy events the priority so with
or without a PMU the legacy event would be opened:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
After aliases, add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 833967 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
Fixes to make hybrid/BIG.little PMUs behave correctly, ie as core PMUs
capable of opening legacy events on each, removing hard coded "cpu_core"
and "cpu_atom" Intel PMU names, etc. caused a behavioral difference on
Apple/ARM due to latent issues in the PMU driver reported in:
https://lore.kernel.org/lkml/08f1f185-e259-4014-9ca4-6411d5c1bc65@marcan.st/
As part of that report Mark Rutland <mark.rutland@arm.com> requested
that legacy events not be higher in priority when a PMU is specified
reversing what has until this change been perf's default behavior. With
this change the above becomes:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
Attempt to add: cpu/cpu-cycles=0/
..after resolving event: cpu/event=0x3c/
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 827628 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 4 (PERF_TYPE_RAW)
size 136
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
So the second event has become a raw event as
/sys/devices/cpu/events/cpu-cycles exists.
A fix was necessary to config_term_pmu in parse-events.c as check_alias
expansion needs to happen after config_term_pmu, and config_term_pmu may
need calling a second time because of this.
config_term_pmu is updated to not use the legacy event when the PMU has
such a named event (either from JSON or sysfs).
The bulk of this change is updating all of the parse-events test
expectations so that if a sysfs/JSON event exists for a PMU the test
doesn't fail - a further sign, if it were needed, that the legacy event
priority was a known and tested behavior of the perf tool.
Reported-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Hector Martin <marcan@marcan.st>
Tested-by: Marc Zyngier <maz@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20231123042922.834425-1-irogers@google.com
[ Initialize the 'alias_rewrote_terms' variable to false to address a clang warning ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-11-22 20:29:22 -08:00
|
|
|
*rewrote_terms = true;
|
2023-08-23 21:13:27 -07:00
|
|
|
ret = check_info_data(pmu, alias, info, err, term->err_term);
|
2013-11-12 17:58:49 +01:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2014-11-21 10:31:12 +01:00
|
|
|
if (alias->per_pkg)
|
|
|
|
info->per_pkg = true;
|
|
|
|
|
2024-09-26 15:48:32 +01:00
|
|
|
if (term->alternate_hw_config)
|
|
|
|
*alternate_hw_config = term->val.num;
|
|
|
|
|
2025-04-14 10:41:33 -07:00
|
|
|
info->retirement_latency_mean = alias->retirement_latency_mean;
|
|
|
|
info->retirement_latency_min = alias->retirement_latency_min;
|
|
|
|
info->retirement_latency_max = alias->retirement_latency_max;
|
|
|
|
|
2019-07-04 12:13:46 -03:00
|
|
|
list_del_init(&term->list);
|
2019-10-30 15:34:47 -07:00
|
|
|
parse_events_term__delete(term);
|
2012-06-15 14:31:41 +08:00
|
|
|
}
|
2024-09-06 22:08:17 -07:00
|
|
|
out:
|
2014-01-17 16:34:05 +01:00
|
|
|
/*
|
2021-03-23 17:09:15 +01:00
|
|
|
* if no unit or scale found in aliases, then
|
2014-01-17 16:34:05 +01:00
|
|
|
* set defaults as for evsel
|
|
|
|
* unit cannot left to NULL
|
|
|
|
*/
|
2014-09-24 15:04:06 +01:00
|
|
|
if (info->unit == NULL)
|
|
|
|
info->unit = "";
|
2014-01-17 16:34:05 +01:00
|
|
|
|
2014-09-24 15:04:06 +01:00
|
|
|
if (info->scale == 0.0)
|
|
|
|
info->scale = 1.0;
|
2014-01-17 16:34:05 +01:00
|
|
|
|
2012-06-15 14:31:41 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
struct find_event_args {
|
|
|
|
const char *event;
|
|
|
|
void *state;
|
|
|
|
pmu_event_callback cb;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int find_event_callback(void *state, struct pmu_event_info *info)
|
2023-08-23 01:08:11 -07:00
|
|
|
{
|
2023-08-23 21:13:14 -07:00
|
|
|
struct find_event_args *args = state;
|
2023-08-23 01:08:11 -07:00
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
if (!strcmp(args->event, info->name))
|
|
|
|
return args->cb(args->state, info);
|
2023-08-23 01:08:11 -07:00
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
return 0;
|
2023-08-23 01:08:11 -07:00
|
|
|
}
|
2023-08-23 21:13:14 -07:00
|
|
|
|
|
|
|
int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb)
|
|
|
|
{
|
|
|
|
struct find_event_args args = {
|
|
|
|
.event = event,
|
|
|
|
.state = state,
|
|
|
|
.cb = cb,
|
|
|
|
};
|
|
|
|
|
2023-08-25 06:52:37 -07:00
|
|
|
/* Sub-optimal, but function is only used by tests. */
|
|
|
|
return perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/ false,
|
|
|
|
&args, find_event_callback);
|
2023-08-23 21:13:14 -07:00
|
|
|
}
|
|
|
|
|
2023-08-23 01:08:08 -07:00
|
|
|
static void perf_pmu__del_formats(struct list_head *formats)
|
2020-09-15 12:18:19 +09:00
|
|
|
{
|
|
|
|
struct perf_pmu_format *fmt, *tmp;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(fmt, tmp, formats, list) {
|
|
|
|
list_del(&fmt->list);
|
2023-04-12 09:50:08 -03:00
|
|
|
zfree(&fmt->name);
|
2020-09-15 12:18:19 +09:00
|
|
|
free(fmt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-06 11:37:05 -07:00
|
|
|
bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name)
|
|
|
|
{
|
|
|
|
struct perf_pmu_format *format;
|
|
|
|
|
|
|
|
list_for_each_entry(format, &pmu->format, list) {
|
|
|
|
if (!strcmp(format->name, name))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
perf list: Give more details about raw event encodings
List all the PMUs, not just the first core one, and list real format
specifiers with value ranges.
Before:
$ perf list
...
rNNN [Raw hardware event descriptor]
cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descriptor]
[(see 'man perf-list' on how to encode it)]
mem:<addr>[/len][:access] [Hardware breakpoint]
...
After:
$ perf list
...
rNNN [Raw event descriptor]
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
breakpoint//modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
intel_bts//modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
kprobe/retprobe/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
power/event=0..255/modifier [Raw event descriptor]
software//modifier [Raw event descriptor]
tracepoint//modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
mem:<addr>[/len][:access] [Hardware breakpoint]
...
With '--details' provide more details on the formats encoding:
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
cpu/event=0..255,pc,edge,offcore_rsp=0..0xffffffffffffffff,ldlat=0..0xffff,inv,
umask=0..255,frontend=0..0xffffff,cmask=0..255,config=0..0xffffffffffffffff,
config1=0..0xffffffffffffffff,config2=0..0xffffffffffffffff,config3=0..0xffffffffffffffff,
name=string,period=number,freq=number,branch_type=(u|k|hv|any|...),time,
call-graph=(fp|dwarf|lbr),stack-size=number,max-stack=number,nr=number,inherit,no-inherit,
overwrite,no-overwrite,percore,aux-output,aux-sample-size=number/modifier
breakpoint//modifier [Raw event descriptor]
breakpoint//modifier
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier
intel_bts//modifier [Raw event descriptor]
intel_bts//modifier
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,pt,notnt,branch,tsc,pwr_evt,fup_on_ptw,cyc,noretcomp,
mtc,psb_period=0..15,mtc_period=0..15/modifier
kprobe/retprobe/modifier [Raw event descriptor]
kprobe/retprobe/modifier
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier
power/event=0..255/modifier [Raw event descriptor]
power/event=0..255/modifier
software//modifier [Raw event descriptor]
software//modifier
tracepoint//modifier [Raw event descriptor]
tracepoint//modifier
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier
Committer notes:
Address this build error in various distros:
55 58.44 ubuntu:24.04 : FAIL gcc version 13.2.0 (Ubuntu 13.2.0-17ubuntu2)
util/pmu.c:1638:70: error: '_Static_assert' with no message is a C2x extension [-Werror,-Wc2x-extensions]
1638 | _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6);
| ^
| , ""
1 error generated.
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20240308001915.4060155-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2024-03-07 16:19:13 -08:00
|
|
|
int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb)
|
|
|
|
{
|
|
|
|
static const char *const terms[] = {
|
|
|
|
"config=0..0xffffffffffffffff",
|
|
|
|
"config1=0..0xffffffffffffffff",
|
|
|
|
"config2=0..0xffffffffffffffff",
|
|
|
|
"config3=0..0xffffffffffffffff",
|
|
|
|
"name=string",
|
|
|
|
"period=number",
|
|
|
|
"freq=number",
|
|
|
|
"branch_type=(u|k|hv|any|...)",
|
|
|
|
"time",
|
|
|
|
"call-graph=(fp|dwarf|lbr)",
|
|
|
|
"stack-size=number",
|
|
|
|
"max-stack=number",
|
|
|
|
"nr=number",
|
|
|
|
"inherit",
|
|
|
|
"no-inherit",
|
|
|
|
"overwrite",
|
|
|
|
"no-overwrite",
|
|
|
|
"percore",
|
|
|
|
"aux-output",
|
2024-12-16 09:02:38 +02:00
|
|
|
"aux-action=(pause|resume|start-paused)",
|
perf list: Give more details about raw event encodings
List all the PMUs, not just the first core one, and list real format
specifiers with value ranges.
Before:
$ perf list
...
rNNN [Raw hardware event descriptor]
cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descriptor]
[(see 'man perf-list' on how to encode it)]
mem:<addr>[/len][:access] [Hardware breakpoint]
...
After:
$ perf list
...
rNNN [Raw event descriptor]
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
breakpoint//modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
intel_bts//modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
kprobe/retprobe/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
power/event=0..255/modifier [Raw event descriptor]
software//modifier [Raw event descriptor]
tracepoint//modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
mem:<addr>[/len][:access] [Hardware breakpoint]
...
With '--details' provide more details on the formats encoding:
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
cpu/event=0..255,pc,edge,offcore_rsp=0..0xffffffffffffffff,ldlat=0..0xffff,inv,
umask=0..255,frontend=0..0xffffff,cmask=0..255,config=0..0xffffffffffffffff,
config1=0..0xffffffffffffffff,config2=0..0xffffffffffffffff,config3=0..0xffffffffffffffff,
name=string,period=number,freq=number,branch_type=(u|k|hv|any|...),time,
call-graph=(fp|dwarf|lbr),stack-size=number,max-stack=number,nr=number,inherit,no-inherit,
overwrite,no-overwrite,percore,aux-output,aux-sample-size=number/modifier
breakpoint//modifier [Raw event descriptor]
breakpoint//modifier
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier
intel_bts//modifier [Raw event descriptor]
intel_bts//modifier
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,pt,notnt,branch,tsc,pwr_evt,fup_on_ptw,cyc,noretcomp,
mtc,psb_period=0..15,mtc_period=0..15/modifier
kprobe/retprobe/modifier [Raw event descriptor]
kprobe/retprobe/modifier
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier
power/event=0..255/modifier [Raw event descriptor]
power/event=0..255/modifier
software//modifier [Raw event descriptor]
software//modifier
tracepoint//modifier [Raw event descriptor]
tracepoint//modifier
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier
Committer notes:
Address this build error in various distros:
55 58.44 ubuntu:24.04 : FAIL gcc version 13.2.0 (Ubuntu 13.2.0-17ubuntu2)
util/pmu.c:1638:70: error: '_Static_assert' with no message is a C2x extension [-Werror,-Wc2x-extensions]
1638 | _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6);
| ^
| , ""
1 error generated.
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20240308001915.4060155-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2024-03-07 16:19:13 -08:00
|
|
|
"aux-sample-size=number",
|
perf parse-events: Add "cpu" term to set the CPU an event is recorded on
The -C option allows the CPUs for a list of events to be specified but
its not possible to set the CPU for a single event. Add a term to
allow this. The term isn't a general CPU list due to ',' already being
a special character in event parsing instead multiple cpu= terms may
be provided and they will be merged/unioned together.
An example of mixing different types of events counted on different CPUs:
```
$ perf stat -A -C 0,4-5,8 -e "instructions/cpu=0/,l1d-misses/cpu=4,cpu=5/,inst_retired.any/cpu=8/,cycles" -a sleep 0.1
Performance counter stats for 'system wide':
CPU0 6,979,225 instructions/cpu=0/ # 0.89 insn per cycle
CPU4 75,138 cpu/l1d-misses/
CPU5 1,418,939 cpu/l1d-misses/
CPU8 797,553 cpu/inst_retired.any,cpu=8/
CPU0 7,845,302 cycles
CPU4 6,546,859 cycles
CPU5 185,915,438 cycles
CPU8 2,065,668 cycles
0.112449242 seconds time elapsed
```
Committer testing:
root@number:~# grep -m1 "model name" /proc/cpuinfo
model name : AMD Ryzen 9 9950X3D 16-Core Processor
root@number:~# perf stat -A -e "instructions/cpu=0/,instructions,l1d-misses/cpu=4,cpu=5/,cycles" -a sleep 0.1
Performance counter stats for 'system wide':
CPU0 2,398,351 instructions/cpu=0/ # 0.44 insn per cycle
CPU0 2,398,152 instructions # 0.44 insn per cycle
CPU1 1,265,634 instructions # 0.49 insn per cycle
CPU2 606,087 instructions # 0.50 insn per cycle
CPU3 4,025,752 instructions # 0.52 insn per cycle
CPU4 4,236,810 instructions # 0.53 insn per cycle
CPU5 3,984,832 instructions # 0.66 insn per cycle
CPU6 434,132 instructions # 0.44 insn per cycle
CPU7 65,752 instructions # 0.41 insn per cycle
CPU8 459,083 instructions # 0.48 insn per cycle
CPU9 6,464,161 instructions # 1.31 insn per cycle
<SNIP>
root@number:~# perf stat -e "instructions/cpu=0/,instructions,l1d-misses/cpu=4,cpu=5/,cycles" -a sleep 0.
Performance counter stats for 'system wide':
144,822 instructions/cpu=0/ # 0.03 insn per cycle
4,666,114 instructions # 0.93 insn per cycle
2,583 l1d-misses
4,993,633 cycles
0.000868512 seconds time elapsed
root@number:~#
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Dominique Martinet <asmadeus@codewreck.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Link: https://lore.kernel.org/r/20250403194337.40202-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2025-04-03 12:43:37 -07:00
|
|
|
"cpu=number",
|
perf list: Give more details about raw event encodings
List all the PMUs, not just the first core one, and list real format
specifiers with value ranges.
Before:
$ perf list
...
rNNN [Raw hardware event descriptor]
cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descriptor]
[(see 'man perf-list' on how to encode it)]
mem:<addr>[/len][:access] [Hardware breakpoint]
...
After:
$ perf list
...
rNNN [Raw event descriptor]
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
breakpoint//modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
intel_bts//modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
kprobe/retprobe/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
power/event=0..255/modifier [Raw event descriptor]
software//modifier [Raw event descriptor]
tracepoint//modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
mem:<addr>[/len][:access] [Hardware breakpoint]
...
With '--details' provide more details on the formats encoding:
cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor]
[(see 'man perf-list' or 'man perf-record' on how to encode it)]
cpu/event=0..255,pc,edge,offcore_rsp=0..0xffffffffffffffff,ldlat=0..0xffff,inv,
umask=0..255,frontend=0..0xffffff,cmask=0..255,config=0..0xffffffffffffffff,
config1=0..0xffffffffffffffff,config2=0..0xffffffffffffffff,config3=0..0xffffffffffffffff,
name=string,period=number,freq=number,branch_type=(u|k|hv|any|...),time,
call-graph=(fp|dwarf|lbr),stack-size=number,max-stack=number,nr=number,inherit,no-inherit,
overwrite,no-overwrite,percore,aux-output,aux-sample-size=number/modifier
breakpoint//modifier [Raw event descriptor]
breakpoint//modifier
cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_core/event=0..0xffffffffffffffff/modifier
cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
cstate_pkg/event=0..0xffffffffffffffff/modifier
i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor]
i915/i915_eventid=0..0x1fffff/modifier
intel_bts//modifier [Raw event descriptor]
intel_bts//modifier
intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor]
intel_pt/ptw,event,cyc_thresh=0..15,pt,notnt,branch,tsc,pwr_evt,fup_on_ptw,cyc,noretcomp,
mtc,psb_period=0..15,mtc_period=0..15/modifier
kprobe/retprobe/modifier [Raw event descriptor]
kprobe/retprobe/modifier
msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor]
msr/event=0..0xffffffffffffffff/modifier
power/event=0..255/modifier [Raw event descriptor]
power/event=0..255/modifier
software//modifier [Raw event descriptor]
software//modifier
tracepoint//modifier [Raw event descriptor]
tracepoint//modifier
uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_arb/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor]
uncore_cbox/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier
uncore_clock/event=0..255/modifier [Raw event descriptor]
uncore_clock/event=0..255/modifier
uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor]
uncore_imc_free_running/event=0..255,umask=0..255/modifier
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor]
uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier
Committer notes:
Address this build error in various distros:
55 58.44 ubuntu:24.04 : FAIL gcc version 13.2.0 (Ubuntu 13.2.0-17ubuntu2)
util/pmu.c:1638:70: error: '_Static_assert' with no message is a C2x extension [-Werror,-Wc2x-extensions]
1638 | _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6);
| ^
| , ""
1 error generated.
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20240308001915.4060155-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2024-03-07 16:19:13 -08:00
|
|
|
};
|
|
|
|
struct perf_pmu_format *format;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* max-events and driver-config are missing above as are the internal
|
|
|
|
* types user, metric-id, raw, legacy cache and hardware. Assert against
|
|
|
|
* the enum parse_events__term_type so they are kept in sync.
|
|
|
|
*/
|
|
|
|
_Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6,
|
|
|
|
"perf_pmu__for_each_format()'s terms must be kept in sync with enum parse_events__term_type");
|
|
|
|
list_for_each_entry(format, &pmu->format, list) {
|
|
|
|
perf_pmu_format__load(pmu, format);
|
|
|
|
ret = cb(state, format->name, (int)format->value, format->bits);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (!pmu->is_core)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(terms); i++) {
|
|
|
|
int config = PERF_PMU_FORMAT_VALUE_CONFIG;
|
|
|
|
|
|
|
|
if (i < PERF_PMU_FORMAT_VALUE_CONFIG_END)
|
|
|
|
config = i;
|
|
|
|
|
|
|
|
ret = cb(state, terms[i], config, /*bits=*/NULL);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-17 19:02:17 +08:00
|
|
|
bool is_pmu_core(const char *name)
|
|
|
|
{
|
2023-06-16 10:14:37 +02:00
|
|
|
return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name);
|
2023-05-27 00:21:40 -07:00
|
|
|
}
|
|
|
|
|
2023-05-02 15:38:30 -07:00
|
|
|
bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu)
|
|
|
|
{
|
2023-05-27 00:21:41 -07:00
|
|
|
return pmu->is_core;
|
2023-05-02 15:38:30 -07:00
|
|
|
}
|
|
|
|
|
2023-05-02 15:38:43 -07:00
|
|
|
bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu)
|
|
|
|
{
|
2023-06-25 22:30:48 -07:00
|
|
|
return !pmu->is_core || perf_pmus__num_core_pmus() == 1;
|
2023-05-02 15:38:43 -07:00
|
|
|
}
|
|
|
|
|
2023-08-23 21:13:25 -07:00
|
|
|
bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
|
2013-08-21 16:47:26 -07:00
|
|
|
{
|
perf parse-events: Make legacy events lower priority than sysfs/JSON
The perf tool has previously made legacy events the priority so with
or without a PMU the legacy event would be opened:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
After aliases, add event pmu 'cpu' with 'cpu-cycles,' that may result in non-fatal errors
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 833967 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
Fixes to make hybrid/BIG.little PMUs behave correctly, ie as core PMUs
capable of opening legacy events on each, removing hard coded "cpu_core"
and "cpu_atom" Intel PMU names, etc. caused a behavioral difference on
Apple/ARM due to latent issues in the PMU driver reported in:
https://lore.kernel.org/lkml/08f1f185-e259-4014-9ca4-6411d5c1bc65@marcan.st/
As part of that report Mark Rutland <mark.rutland@arm.com> requested
that legacy events not be higher in priority when a PMU is specified
reversing what has until this change been perf's default behavior. With
this change the above becomes:
$ perf stat -e cpu-cycles,cpu/cpu-cycles/ true
Using CPUID GenuineIntel-6-8D-1
Attempt to add: cpu/cpu-cycles=0/
..after resolving event: cpu/event=0x3c/
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 0 (PERF_TYPE_HARDWARE)
size 136
config 0 (PERF_COUNT_HW_CPU_CYCLES)
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid 827628 cpu -1 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 4 (PERF_TYPE_RAW)
size 136
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
enable_on_exec 1
exclude_guest 1
------------------------------------------------------------
...
So the second event has become a raw event as
/sys/devices/cpu/events/cpu-cycles exists.
A fix was necessary to config_term_pmu in parse-events.c as check_alias
expansion needs to happen after config_term_pmu, and config_term_pmu may
need calling a second time because of this.
config_term_pmu is updated to not use the legacy event when the PMU has
such a named event (either from JSON or sysfs).
The bulk of this change is updating all of the parse-events test
expectations so that if a sysfs/JSON event exists for a PMU the test
doesn't fail - a further sign, if it were needed, that the legacy event
priority was a known and tested behavior of the perf tool.
Reported-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Hector Martin <marcan@marcan.st>
Tested-by: Marc Zyngier <maz@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20231123042922.834425-1-irogers@google.com
[ Initialize the 'alias_rewrote_terms' variable to false to address a clang warning ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-11-22 20:29:22 -08:00
|
|
|
if (!name)
|
|
|
|
return false;
|
2024-10-01 20:20:12 -07:00
|
|
|
if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(name))
|
|
|
|
return false;
|
perf tp_pmu: Add event APIs
Add event APIs for the tracepoint PMU allowing things like perf list
to function using it. For perf list add the tracepoint format in the
long description (shown with -v).
$ sudo perf list -v tracepoint
List of pre-defined events (to be used in -e or -M):
alarmtimer:alarmtimer_cancel [Tracepoint event]
[name: alarmtimer_cancel
ID: 416
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:void * alarm; offset:8; size:8; signed:0;
field:unsigned char alarm_type; offset:16; size:1; signed:0;
field:s64 expires; offset:24; size:8; signed:1;
field:s64 now; offset:32; size:8; signed:1;
print fmt: "alarmtimer:%p type:%s expires:%llu now:%llu",REC->alarm,__print_flags((1 << REC->alarm_type)," | ",{ 1 << 0,
"REALTIME" },{ 1 << 1,"BOOTTIME" },{ 1 << 3,"REALTIME Freezer" },{ 1 << 4,"BOOTTIME Freezer" }),REC->expires,REC->now
. Unit: tracepoint]
alarmtimer:alarmtimer_fired [Tracepoint event]
[name: alarmtimer_fired
ID: 418
...
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/r/20250725185202.68671-6-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-07-25 11:51:51 -07:00
|
|
|
if (perf_pmu__is_tracepoint(pmu))
|
|
|
|
return tp_pmu__have_event(pmu, name);
|
2024-11-08 16:37:57 -08:00
|
|
|
if (perf_pmu__is_hwmon(pmu))
|
|
|
|
return hwmon_pmu__have_event(pmu, name);
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
if (perf_pmu__is_drm(pmu))
|
|
|
|
return drm_pmu__have_event(pmu, name);
|
2023-08-23 21:13:28 -07:00
|
|
|
if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
|
2023-08-23 21:13:25 -07:00
|
|
|
return true;
|
|
|
|
if (pmu->cpu_aliases_added || !pmu->events_table)
|
|
|
|
return false;
|
|
|
|
return pmu_events_table__find_event(pmu->events_table, pmu, name, NULL, NULL) == 0;
|
2023-08-23 21:13:14 -07:00
|
|
|
}
|
2013-08-21 16:47:26 -07:00
|
|
|
|
2023-08-23 21:13:25 -07:00
|
|
|
size_t perf_pmu__num_events(struct perf_pmu *pmu)
|
2023-08-23 21:13:14 -07:00
|
|
|
{
|
2023-08-23 21:13:28 -07:00
|
|
|
size_t nr;
|
|
|
|
|
perf tp_pmu: Add event APIs
Add event APIs for the tracepoint PMU allowing things like perf list
to function using it. For perf list add the tracepoint format in the
long description (shown with -v).
$ sudo perf list -v tracepoint
List of pre-defined events (to be used in -e or -M):
alarmtimer:alarmtimer_cancel [Tracepoint event]
[name: alarmtimer_cancel
ID: 416
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:void * alarm; offset:8; size:8; signed:0;
field:unsigned char alarm_type; offset:16; size:1; signed:0;
field:s64 expires; offset:24; size:8; signed:1;
field:s64 now; offset:32; size:8; signed:1;
print fmt: "alarmtimer:%p type:%s expires:%llu now:%llu",REC->alarm,__print_flags((1 << REC->alarm_type)," | ",{ 1 << 0,
"REALTIME" },{ 1 << 1,"BOOTTIME" },{ 1 << 3,"REALTIME Freezer" },{ 1 << 4,"BOOTTIME Freezer" }),REC->expires,REC->now
. Unit: tracepoint]
alarmtimer:alarmtimer_fired [Tracepoint event]
[name: alarmtimer_fired
ID: 418
...
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/r/20250725185202.68671-6-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-07-25 11:51:51 -07:00
|
|
|
if (perf_pmu__is_tracepoint(pmu))
|
|
|
|
return tp_pmu__num_events(pmu);
|
2024-11-08 16:37:57 -08:00
|
|
|
if (perf_pmu__is_hwmon(pmu))
|
|
|
|
return hwmon_pmu__num_events(pmu);
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
if (perf_pmu__is_drm(pmu))
|
|
|
|
return drm_pmu__num_events(pmu);
|
2024-11-08 16:37:57 -08:00
|
|
|
|
2024-05-02 14:35:07 -07:00
|
|
|
pmu_aliases_parse(pmu);
|
2024-06-28 13:30:49 +08:00
|
|
|
nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
|
2023-08-23 21:13:14 -07:00
|
|
|
|
2023-08-23 21:13:25 -07:00
|
|
|
if (pmu->cpu_aliases_added)
|
2024-05-10 17:36:01 -07:00
|
|
|
nr += pmu->cpu_json_aliases;
|
2023-08-23 21:13:25 -07:00
|
|
|
else if (pmu->events_table)
|
2025-02-26 10:41:01 +00:00
|
|
|
nr += pmu_events_table__num_events(pmu->events_table, pmu) -
|
|
|
|
pmu->cpu_common_json_aliases;
|
2024-05-10 17:36:01 -07:00
|
|
|
else
|
2025-02-26 10:41:01 +00:00
|
|
|
assert(pmu->cpu_json_aliases == 0 && pmu->cpu_common_json_aliases == 0);
|
2023-08-23 21:13:14 -07:00
|
|
|
|
2024-10-01 20:20:12 -07:00
|
|
|
if (perf_pmu__is_tool(pmu))
|
|
|
|
nr -= tool_pmu__num_skip_events();
|
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
return pmu->selectable ? nr + 1 : nr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sub_non_neg(int a, int b)
|
|
|
|
{
|
|
|
|
if (b > a)
|
|
|
|
return 0;
|
|
|
|
return a - b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
|
2023-08-25 06:52:37 -07:00
|
|
|
const struct perf_pmu_alias *alias, bool skip_duplicate_pmus)
|
2023-08-23 21:13:14 -07:00
|
|
|
{
|
|
|
|
struct parse_events_term *term;
|
2024-06-26 15:54:46 +01:00
|
|
|
size_t pmu_name_len = pmu_deduped_name_len(pmu, pmu->name,
|
|
|
|
skip_duplicate_pmus);
|
2024-05-14 23:01:13 -07:00
|
|
|
int used = snprintf(buf, len, "%.*s/%s", (int)pmu_name_len, pmu->name, alias->name);
|
2023-08-23 21:13:14 -07:00
|
|
|
|
2023-09-01 16:39:49 -07:00
|
|
|
list_for_each_entry(term, &alias->terms.terms, list) {
|
2023-08-23 21:13:14 -07:00
|
|
|
if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
|
|
|
|
used += snprintf(buf + used, sub_non_neg(len, used),
|
|
|
|
",%s=%s", term->config,
|
|
|
|
term->val.str);
|
2013-08-21 16:47:26 -07:00
|
|
|
}
|
2023-08-23 21:13:14 -07:00
|
|
|
|
|
|
|
if (sub_non_neg(len, used) > 0) {
|
|
|
|
buf[used] = '/';
|
|
|
|
used++;
|
|
|
|
}
|
|
|
|
if (sub_non_neg(len, used) > 0) {
|
|
|
|
buf[used] = '\0';
|
|
|
|
used++;
|
|
|
|
} else
|
|
|
|
buf[len - 1] = '\0';
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2023-08-25 06:52:37 -07:00
|
|
|
int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
|
|
|
|
void *state, pmu_event_callback cb)
|
2023-08-23 21:13:14 -07:00
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
struct pmu_event_info info = {
|
|
|
|
.pmu = pmu,
|
2024-09-06 22:08:19 -07:00
|
|
|
.event_type_desc = "Kernel PMU event",
|
2023-08-23 21:13:14 -07:00
|
|
|
};
|
|
|
|
int ret = 0;
|
2023-08-30 00:07:53 -07:00
|
|
|
struct strbuf sb;
|
2025-05-12 12:46:21 -07:00
|
|
|
struct hashmap_entry *entry;
|
|
|
|
size_t bkt;
|
2023-08-23 21:13:14 -07:00
|
|
|
|
perf tp_pmu: Add event APIs
Add event APIs for the tracepoint PMU allowing things like perf list
to function using it. For perf list add the tracepoint format in the
long description (shown with -v).
$ sudo perf list -v tracepoint
List of pre-defined events (to be used in -e or -M):
alarmtimer:alarmtimer_cancel [Tracepoint event]
[name: alarmtimer_cancel
ID: 416
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:void * alarm; offset:8; size:8; signed:0;
field:unsigned char alarm_type; offset:16; size:1; signed:0;
field:s64 expires; offset:24; size:8; signed:1;
field:s64 now; offset:32; size:8; signed:1;
print fmt: "alarmtimer:%p type:%s expires:%llu now:%llu",REC->alarm,__print_flags((1 << REC->alarm_type)," | ",{ 1 << 0,
"REALTIME" },{ 1 << 1,"BOOTTIME" },{ 1 << 3,"REALTIME Freezer" },{ 1 << 4,"BOOTTIME Freezer" }),REC->expires,REC->now
. Unit: tracepoint]
alarmtimer:alarmtimer_fired [Tracepoint event]
[name: alarmtimer_fired
ID: 418
...
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/r/20250725185202.68671-6-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-07-25 11:51:51 -07:00
|
|
|
if (perf_pmu__is_tracepoint(pmu))
|
|
|
|
return tp_pmu__for_each_event(pmu, state, cb);
|
2024-11-08 16:37:57 -08:00
|
|
|
if (perf_pmu__is_hwmon(pmu))
|
|
|
|
return hwmon_pmu__for_each_event(pmu, state, cb);
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
if (perf_pmu__is_drm(pmu))
|
|
|
|
return drm_pmu__for_each_event(pmu, state, cb);
|
2024-11-08 16:37:57 -08:00
|
|
|
|
2023-08-30 00:07:53 -07:00
|
|
|
strbuf_init(&sb, /*hint=*/ 0);
|
2024-05-02 14:35:07 -07:00
|
|
|
pmu_aliases_parse(pmu);
|
2023-08-23 21:13:25 -07:00
|
|
|
pmu_add_cpu_aliases(pmu);
|
2025-05-12 12:46:21 -07:00
|
|
|
hashmap__for_each_entry(pmu->aliases, entry, bkt) {
|
|
|
|
struct perf_pmu_alias *event = entry->pvalue;
|
2024-05-14 23:01:13 -07:00
|
|
|
size_t buf_used, pmu_name_len;
|
2023-08-23 21:13:14 -07:00
|
|
|
|
2024-10-01 20:20:12 -07:00
|
|
|
if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
|
|
|
|
continue;
|
|
|
|
|
2023-08-23 21:13:14 -07:00
|
|
|
info.pmu_name = event->pmu_name ?: pmu->name;
|
2024-06-26 15:54:46 +01:00
|
|
|
pmu_name_len = pmu_deduped_name_len(pmu, info.pmu_name,
|
|
|
|
skip_duplicate_pmus);
|
2023-08-23 21:13:14 -07:00
|
|
|
info.alias = NULL;
|
|
|
|
if (event->desc) {
|
|
|
|
info.name = event->name;
|
|
|
|
buf_used = 0;
|
|
|
|
} else {
|
2023-08-25 06:52:37 -07:00
|
|
|
info.name = format_alias(buf, sizeof(buf), pmu, event,
|
|
|
|
skip_duplicate_pmus);
|
2023-08-23 21:13:14 -07:00
|
|
|
if (pmu->is_core) {
|
|
|
|
info.alias = info.name;
|
|
|
|
info.name = event->name;
|
|
|
|
}
|
|
|
|
buf_used = strlen(buf) + 1;
|
|
|
|
}
|
|
|
|
info.scale_unit = NULL;
|
|
|
|
if (strlen(event->unit) || event->scale != 1.0) {
|
|
|
|
info.scale_unit = buf + buf_used;
|
|
|
|
buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
|
|
|
|
"%G%s", event->scale, event->unit) + 1;
|
|
|
|
}
|
|
|
|
info.desc = event->desc;
|
|
|
|
info.long_desc = event->long_desc;
|
|
|
|
info.encoding_desc = buf + buf_used;
|
2023-09-01 16:39:49 -07:00
|
|
|
parse_events_terms__to_strbuf(&event->terms, &sb);
|
2023-08-23 21:13:14 -07:00
|
|
|
buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
|
2024-05-14 23:01:13 -07:00
|
|
|
"%.*s/%s/", (int)pmu_name_len, info.pmu_name, sb.buf) + 1;
|
2023-08-23 21:13:14 -07:00
|
|
|
info.topic = event->topic;
|
2023-08-30 00:07:53 -07:00
|
|
|
info.str = sb.buf;
|
2023-08-23 21:13:14 -07:00
|
|
|
info.deprecated = event->deprecated;
|
|
|
|
ret = cb(state, &info);
|
|
|
|
if (ret)
|
2023-08-30 00:07:53 -07:00
|
|
|
goto out;
|
|
|
|
strbuf_setlen(&sb, /*len=*/ 0);
|
2023-08-23 21:13:14 -07:00
|
|
|
}
|
|
|
|
if (pmu->selectable) {
|
|
|
|
info.name = buf;
|
|
|
|
snprintf(buf, sizeof(buf), "%s//", pmu->name);
|
|
|
|
info.alias = NULL;
|
|
|
|
info.scale_unit = NULL;
|
|
|
|
info.desc = NULL;
|
|
|
|
info.long_desc = NULL;
|
|
|
|
info.encoding_desc = NULL;
|
|
|
|
info.topic = NULL;
|
|
|
|
info.pmu_name = pmu->name;
|
|
|
|
info.deprecated = false;
|
|
|
|
ret = cb(state, &info);
|
|
|
|
}
|
2023-08-30 00:07:53 -07:00
|
|
|
out:
|
|
|
|
strbuf_release(&sb);
|
2023-08-23 21:13:14 -07:00
|
|
|
return ret;
|
2013-08-21 16:47:26 -07:00
|
|
|
}
|
2014-07-31 09:00:50 +03:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
static bool perf_pmu___name_match(const struct perf_pmu *pmu, const char *to_match, bool wildcard)
|
2023-08-23 21:13:19 -07:00
|
|
|
{
|
2025-01-31 23:43:18 -08:00
|
|
|
const char *names[2] = {
|
|
|
|
pmu->name,
|
|
|
|
pmu->alias_name,
|
|
|
|
};
|
|
|
|
if (pmu->is_core) {
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
|
|
|
|
const char *name = names[i];
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strcmp(name, to_match)) {
|
|
|
|
/* Exact name match. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!strcmp(to_match, "default_core")) {
|
|
|
|
/*
|
|
|
|
* jevents and tests use default_core as a marker for any core
|
|
|
|
* PMU as the PMU name varies across architectures.
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!pmu->is_uncore) {
|
2023-08-25 23:22:03 -07:00
|
|
|
/*
|
2025-01-31 23:43:18 -08:00
|
|
|
* PMU isn't core or uncore, some kind of broken CPU mask
|
|
|
|
* situation. Only match exact name.
|
2023-08-25 23:22:03 -07:00
|
|
|
*/
|
2025-01-31 23:43:18 -08:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
|
|
|
|
const char *name = names[i];
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strcmp(name, to_match)) {
|
|
|
|
/* Exact name match. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
|
|
|
|
const char *name = names[i];
|
|
|
|
|
2025-05-27 14:50:35 -07:00
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (wildcard && perf_pmu__match_wildcard_uncore(name, to_match))
|
|
|
|
return true;
|
|
|
|
if (!wildcard && perf_pmu__match_ignoring_suffix_uncore(name, to_match))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* perf_pmu__name_wildcard_match - Called by the jevents generated code to see
|
|
|
|
* if pmu matches the json to_match string.
|
|
|
|
* @pmu: The pmu whose name/alias to match.
|
|
|
|
* @to_match: The possible match to pmu_name.
|
|
|
|
*/
|
|
|
|
bool perf_pmu__name_wildcard_match(const struct perf_pmu *pmu, const char *to_match)
|
|
|
|
{
|
|
|
|
return perf_pmu___name_match(pmu, to_match, /*wildcard=*/true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* perf_pmu__name_no_suffix_match - Does pmu's name match to_match ignoring any
|
|
|
|
* trailing suffix on the pmu_name and/or tok?
|
|
|
|
* @pmu: The pmu whose name/alias to match.
|
|
|
|
* @to_match: The possible match to pmu_name.
|
|
|
|
*/
|
|
|
|
bool perf_pmu__name_no_suffix_match(const struct perf_pmu *pmu, const char *to_match)
|
|
|
|
{
|
|
|
|
return perf_pmu___name_match(pmu, to_match, /*wildcard=*/false);
|
2023-08-23 21:13:19 -07:00
|
|
|
}
|
|
|
|
|
2023-06-01 01:29:53 -07:00
|
|
|
bool perf_pmu__is_software(const struct perf_pmu *pmu)
|
|
|
|
{
|
perf pmu: Treat the msr pmu as software
The msr PMU is a software one, meaning msr events may be grouped
with events in a hardware context. As the msr PMU isn't marked as a
software PMU by perf_pmu__is_software, groups with the msr PMU in
are broken and the msr events placed in a different group. This
may lead to multiplexing errors where a hardware event isn't
counted while the msr event, such as tsc, is. Fix all of this by
marking the msr PMU as software, which agrees with the driver.
Before:
```
$ perf stat -e '{slots,tsc}' -a true
WARNING: events were regrouped to match PMUs
Performance counter stats for 'system wide':
1,750,335 slots
4,243,557 tsc
0.001456717 seconds time elapsed
```
After:
```
$ perf stat -e '{slots,tsc}' -a true
Performance counter stats for 'system wide':
12,526,380 slots
3,415,163 tsc
0.001488360 seconds time elapsed
```
Fixes: 251aa040244a ("perf parse-events: Wildcard most "numeric" events")
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Cc: James Clark <james.clark@arm.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Edward Baker <edward.baker@intel.com>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Samantha Alt <samantha.alt@intel.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Link: https://lore.kernel.org/r/20240124234200.1510417-1-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2024-01-24 15:42:00 -08:00
|
|
|
const char *known_sw_pmus[] = {
|
|
|
|
"kprobe",
|
|
|
|
"msr",
|
|
|
|
"uprobe",
|
|
|
|
};
|
|
|
|
|
2023-06-01 01:29:53 -07:00
|
|
|
if (pmu->is_core || pmu->is_uncore || pmu->auxtrace)
|
|
|
|
return false;
|
|
|
|
switch (pmu->type) {
|
|
|
|
case PERF_TYPE_HARDWARE: return false;
|
|
|
|
case PERF_TYPE_SOFTWARE: return true;
|
|
|
|
case PERF_TYPE_TRACEPOINT: return true;
|
|
|
|
case PERF_TYPE_HW_CACHE: return false;
|
|
|
|
case PERF_TYPE_RAW: return false;
|
|
|
|
case PERF_TYPE_BREAKPOINT: return true;
|
2024-10-01 20:20:07 -07:00
|
|
|
case PERF_PMU_TYPE_TOOL: return true;
|
2023-06-01 01:29:53 -07:00
|
|
|
default: break;
|
|
|
|
}
|
perf pmu: Treat the msr pmu as software
The msr PMU is a software one, meaning msr events may be grouped
with events in a hardware context. As the msr PMU isn't marked as a
software PMU by perf_pmu__is_software, groups with the msr PMU in
are broken and the msr events placed in a different group. This
may lead to multiplexing errors where a hardware event isn't
counted while the msr event, such as tsc, is. Fix all of this by
marking the msr PMU as software, which agrees with the driver.
Before:
```
$ perf stat -e '{slots,tsc}' -a true
WARNING: events were regrouped to match PMUs
Performance counter stats for 'system wide':
1,750,335 slots
4,243,557 tsc
0.001456717 seconds time elapsed
```
After:
```
$ perf stat -e '{slots,tsc}' -a true
Performance counter stats for 'system wide':
12,526,380 slots
3,415,163 tsc
0.001488360 seconds time elapsed
```
Fixes: 251aa040244a ("perf parse-events: Wildcard most "numeric" events")
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Cc: James Clark <james.clark@arm.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Edward Baker <edward.baker@intel.com>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Samantha Alt <samantha.alt@intel.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Link: https://lore.kernel.org/r/20240124234200.1510417-1-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2024-01-24 15:42:00 -08:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(known_sw_pmus); i++) {
|
|
|
|
if (!strcmp(pmu->name, known_sw_pmus[i]))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2023-06-01 01:29:53 -07:00
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:42 -07:00
|
|
|
FILE *perf_pmu__open_file(const struct perf_pmu *pmu, const char *name)
|
2014-07-31 09:00:50 +03:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
2023-01-20 14:36:54 +00:00
|
|
|
if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name) ||
|
|
|
|
!file_available(path))
|
2014-07-31 09:00:50 +03:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return fopen(path, "r");
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:42 -07:00
|
|
|
FILE *perf_pmu__open_file_at(const struct perf_pmu *pmu, int dirfd, const char *name)
|
2023-03-31 13:29:48 -07:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = perf_pmu__pathname_fd(dirfd, pmu->name, name, O_RDONLY);
|
|
|
|
if (fd < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return fdopen(fd, "r");
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:42 -07:00
|
|
|
int perf_pmu__scan_file(const struct perf_pmu *pmu, const char *name, const char *fmt,
|
2014-07-31 09:00:50 +03:00
|
|
|
...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
FILE *file;
|
|
|
|
int ret = EOF;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
file = perf_pmu__open_file(pmu, name);
|
|
|
|
if (file) {
|
|
|
|
ret = vfscanf(file, fmt, args);
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
return ret;
|
|
|
|
}
|
2020-03-19 13:25:01 -07:00
|
|
|
|
2023-10-12 10:56:42 -07:00
|
|
|
int perf_pmu__scan_file_at(const struct perf_pmu *pmu, int dirfd, const char *name,
|
2023-03-31 13:29:48 -07:00
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
FILE *file;
|
|
|
|
int ret = EOF;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
file = perf_pmu__open_file_at(pmu, dirfd, name);
|
|
|
|
if (file) {
|
|
|
|
ret = vfscanf(file, fmt, args);
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-10-12 10:56:42 -07:00
|
|
|
bool perf_pmu__file_exists(const struct perf_pmu *pmu, const char *name)
|
2023-01-20 14:36:57 +00:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
|
|
|
if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return file_available(path);
|
|
|
|
}
|
|
|
|
|
2020-03-19 13:25:01 -07:00
|
|
|
static int perf_pmu__new_caps(struct list_head *list, char *name, char *value)
|
|
|
|
{
|
|
|
|
struct perf_pmu_caps *caps = zalloc(sizeof(*caps));
|
|
|
|
|
|
|
|
if (!caps)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
caps->name = strdup(name);
|
|
|
|
if (!caps->name)
|
|
|
|
goto free_caps;
|
|
|
|
caps->value = strndup(value, strlen(value) - 1);
|
|
|
|
if (!caps->value)
|
|
|
|
goto free_name;
|
|
|
|
list_add_tail(&caps->list, list);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_name:
|
2023-04-12 10:23:35 -03:00
|
|
|
zfree(&caps->name);
|
2020-03-19 13:25:01 -07:00
|
|
|
free_caps:
|
|
|
|
free(caps);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2023-03-31 13:29:43 -07:00
|
|
|
static void perf_pmu__del_caps(struct perf_pmu *pmu)
|
|
|
|
{
|
|
|
|
struct perf_pmu_caps *caps, *tmp;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(caps, tmp, &pmu->caps, list) {
|
|
|
|
list_del(&caps->list);
|
2023-04-12 09:50:08 -03:00
|
|
|
zfree(&caps->name);
|
|
|
|
zfree(&caps->value);
|
2023-03-31 13:29:43 -07:00
|
|
|
free(caps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-29 03:59:37 +00:00
|
|
|
struct perf_pmu_caps *perf_pmu__get_cap(struct perf_pmu *pmu, const char *name)
|
|
|
|
{
|
|
|
|
struct perf_pmu_caps *caps;
|
|
|
|
|
|
|
|
list_for_each_entry(caps, &pmu->caps, list) {
|
|
|
|
if (!strcmp(caps->name, name))
|
|
|
|
return caps;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-19 13:25:01 -07:00
|
|
|
/*
|
|
|
|
* Reading/parsing the given pmu capabilities, which should be located at:
|
|
|
|
* /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes.
|
|
|
|
* Return the number of capabilities
|
|
|
|
*/
|
|
|
|
int perf_pmu__caps_parse(struct perf_pmu *pmu)
|
|
|
|
{
|
|
|
|
char caps_path[PATH_MAX];
|
2025-02-21 22:10:08 -08:00
|
|
|
struct io_dir caps_dir;
|
|
|
|
struct io_dirent64 *evt_ent;
|
2023-03-31 13:29:46 -07:00
|
|
|
int caps_fd;
|
2022-06-04 10:15:13 +05:30
|
|
|
|
|
|
|
if (pmu->caps_initialized)
|
|
|
|
return pmu->nr_caps;
|
|
|
|
|
|
|
|
pmu->nr_caps = 0;
|
2020-03-19 13:25:01 -07:00
|
|
|
|
2023-01-20 14:36:54 +00:00
|
|
|
if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name, "caps"))
|
2020-03-19 13:25:01 -07:00
|
|
|
return -1;
|
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
caps_fd = open(caps_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
|
|
|
|
if (caps_fd == -1) {
|
2022-06-04 10:15:13 +05:30
|
|
|
pmu->caps_initialized = true;
|
2020-03-19 13:25:01 -07:00
|
|
|
return 0; /* no error if caps does not exist */
|
2022-06-04 10:15:13 +05:30
|
|
|
}
|
2020-03-19 13:25:01 -07:00
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
io_dir__init(&caps_dir, caps_fd);
|
2023-03-31 13:29:46 -07:00
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
while ((evt_ent = io_dir__readdir(&caps_dir)) != NULL) {
|
2020-03-19 13:25:01 -07:00
|
|
|
char *name = evt_ent->d_name;
|
|
|
|
char value[128];
|
|
|
|
FILE *file;
|
2023-03-31 13:29:46 -07:00
|
|
|
int fd;
|
2020-03-19 13:25:01 -07:00
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
if (io_dir__is_dir(&caps_dir, evt_ent))
|
2020-03-19 13:25:01 -07:00
|
|
|
continue;
|
|
|
|
|
2023-03-31 13:29:46 -07:00
|
|
|
fd = openat(caps_fd, name, O_RDONLY);
|
2023-04-05 23:52:24 -07:00
|
|
|
if (fd == -1)
|
|
|
|
continue;
|
2023-03-31 13:29:46 -07:00
|
|
|
file = fdopen(fd, "r");
|
2023-04-05 23:52:24 -07:00
|
|
|
if (!file) {
|
|
|
|
close(fd);
|
2020-03-19 13:25:01 -07:00
|
|
|
continue;
|
2023-04-05 23:52:24 -07:00
|
|
|
}
|
2020-03-19 13:25:01 -07:00
|
|
|
|
|
|
|
if (!fgets(value, sizeof(value), file) ||
|
|
|
|
(perf_pmu__new_caps(&pmu->caps, name, value) < 0)) {
|
|
|
|
fclose(file);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-06-04 10:15:13 +05:30
|
|
|
pmu->nr_caps++;
|
2020-03-19 13:25:01 -07:00
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
|
2025-02-21 22:10:08 -08:00
|
|
|
close(caps_fd);
|
2020-03-19 13:25:01 -07:00
|
|
|
|
2022-06-04 10:15:13 +05:30
|
|
|
pmu->caps_initialized = true;
|
|
|
|
return pmu->nr_caps;
|
2020-03-19 13:25:01 -07:00
|
|
|
}
|
2021-03-10 13:11:38 +08:00
|
|
|
|
2023-05-31 19:36:44 -07:00
|
|
|
static void perf_pmu__compute_config_masks(struct perf_pmu *pmu)
|
2021-03-10 13:11:38 +08:00
|
|
|
{
|
|
|
|
struct perf_pmu_format *format;
|
2023-05-31 19:36:44 -07:00
|
|
|
|
|
|
|
if (pmu->config_masks_computed)
|
|
|
|
return;
|
2021-03-10 13:11:38 +08:00
|
|
|
|
|
|
|
list_for_each_entry(format, &pmu->format, list) {
|
2023-05-31 19:36:44 -07:00
|
|
|
unsigned int i;
|
|
|
|
__u64 *mask;
|
|
|
|
|
|
|
|
if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END)
|
2021-03-10 13:11:38 +08:00
|
|
|
continue;
|
|
|
|
|
2023-05-31 19:36:44 -07:00
|
|
|
pmu->config_masks_present = true;
|
|
|
|
mask = &pmu->config_masks[format->value];
|
|
|
|
|
2021-03-10 13:11:38 +08:00
|
|
|
for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS)
|
2023-05-31 19:36:44 -07:00
|
|
|
*mask |= 1ULL << i;
|
2021-03-10 13:11:38 +08:00
|
|
|
}
|
2023-05-31 19:36:44 -07:00
|
|
|
pmu->config_masks_computed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
|
|
|
|
const char *name, int config_num,
|
|
|
|
const char *config_name)
|
|
|
|
{
|
|
|
|
__u64 bits;
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
perf_pmu__compute_config_masks(pmu);
|
2021-03-10 13:11:38 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Kernel doesn't export any valid format bits.
|
|
|
|
*/
|
2023-05-31 19:36:44 -07:00
|
|
|
if (!pmu->config_masks_present)
|
2021-03-10 13:11:38 +08:00
|
|
|
return;
|
|
|
|
|
2023-05-31 19:36:44 -07:00
|
|
|
bits = config & ~pmu->config_masks[config_num];
|
2021-03-10 13:11:38 +08:00
|
|
|
if (bits == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf));
|
|
|
|
|
2023-05-31 19:36:44 -07:00
|
|
|
pr_warning("WARNING: event '%s' not valid (bits %s of %s "
|
2021-03-10 13:11:38 +08:00
|
|
|
"'%llx' not supported by kernel)!\n",
|
2023-05-31 19:36:44 -07:00
|
|
|
name ?: "N/A", buf, config_name, config);
|
2021-03-10 13:11:38 +08:00
|
|
|
}
|
2021-04-27 15:01:19 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
bool perf_pmu__wildcard_match(const struct perf_pmu *pmu, const char *wildcard_to_match)
|
2021-07-01 14:42:53 +08:00
|
|
|
{
|
2025-01-31 23:43:18 -08:00
|
|
|
const char *names[2] = {
|
|
|
|
pmu->name,
|
|
|
|
pmu->alias_name,
|
|
|
|
};
|
|
|
|
bool need_fnmatch = strisglob(wildcard_to_match);
|
perf pmu: Add PMU alias support
A perf uncore PMU may have two PMU names, a real name and an alias. The
alias is exported at /sys/bus/event_source/devices/uncore_*/alias.
The perf tool should support the alias as well.
Add alias_name in the struct perf_pmu to store the alias. For the PMU
which doesn't have an alias. It's NULL.
Introduce two X86 specific functions to retrieve the real name and the
alias separately.
Only go through the sysfs to retrieve the mapping between the real name
and the alias once. The result is cached in a list, uncore_pmu_list.
Nothing changed for the other ARCHs.
With the patch, the perf tool can monitor the PMU with either the real
name or the alias.
Use the real name,
$ perf stat -e uncore_cha_2/event=1/ -x,
4044879584,,uncore_cha_2/event=1/,2528059205,100.00,,
Use the alias,
$ perf stat -e uncore_type_0_2/event=1/ -x,
3659675336,,uncore_type_0_2/event=1/,2287306455,100.00,,
Committer notes:
Rename 'struct perf_pmu_alias_name' to 'pmu_alias', the 'perf_' prefix
should be used for libperf, things inside just tools/perf/ are being
moved away from that prefix.
Also 'pmu_alias' is shorter and reflects the abstraction.
Also don't use 'pmu' as the name for variables for that type, we should
use that for the 'struct perf_pmu' variables, avoiding confusion. Use
'pmu_alias' for 'struct pmu_alias' variables.
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Co-developed-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Link: http://lore.kernel.org/lkml/20210902065955.1299-2-yao.jin@linux.intel.com
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-02 14:59:54 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (!strncmp(wildcard_to_match, "uncore_", 7))
|
|
|
|
wildcard_to_match += 7;
|
2021-07-01 14:42:53 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
|
|
|
|
const char *pmu_name = names[i];
|
2021-07-01 14:42:53 +08:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (!pmu_name)
|
|
|
|
continue;
|
2024-04-15 23:15:20 -07:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (!strncmp(pmu_name, "uncore_", 7))
|
|
|
|
pmu_name += 7;
|
2024-04-15 23:15:20 -07:00
|
|
|
|
2025-01-31 23:43:18 -08:00
|
|
|
if (perf_pmu__match_wildcard(pmu_name, wildcard_to_match) ||
|
|
|
|
(need_fnmatch && !fnmatch(wildcard_to_match, pmu_name, 0)))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2021-07-01 14:42:53 +08:00
|
|
|
}
|
perf tools: Enable on a list of CPUs for hybrid
The 'perf record' and 'perf stat' commands have supported the option
'-C/--cpus' to count or collect only on the list of CPUs provided. This
option needs to be supported for hybrid as well.
For hybrid support, it needs to check that the cpu list are available
on hybrid PMU. One example for AlderLake, cpu0-7 is 'cpu_core', cpu8-11
is 'cpu_atom'.
Before:
# perf stat -e cpu_core/cycles/ -C11 -- sleep 1
Performance counter stats for 'CPU(s) 11':
<not supported> cpu_core/cycles/
1.006179431 seconds time elapsed
The 'perf stat' command silently returned "<not supported>" without any
helpful information. It should error out pointing out that that cpu11
was not 'cpu_core'.
After:
# perf stat -e cpu_core/cycles/ -C11 -- sleep 1
WARNING: 11 isn't a 'cpu_core', please use a CPU list in the 'cpu_core' range (0-7)
failed to use cpu list 11
We also need to support the events without pmu prefix specified.
# perf stat -e cycles -C11 -- sleep 1
WARNING: 11 isn't a 'cpu_core', please use a CPU list in the 'cpu_core' range (0-7)
Performance counter stats for 'CPU(s) 11':
1,067,373 cpu_atom/cycles/
1.005544738 seconds time elapsed
The perf tool creates two cycles events automatically, cpu_core/cycles/ and
cpu_atom/cycles/. It checks that cpu11 is not 'cpu_core', then shows a warning
for cpu_core/cycles/ and only count the cpu_atom/cycles/.
If part of cpus are 'cpu_core' and part of cpus are 'cpu_atom', for example,
# perf stat -e cycles -C0,11 -- sleep 1
WARNING: use 0 in 'cpu_core' for 'cycles', skip other cpus in list.
WARNING: use 11 in 'cpu_atom' for 'cycles', skip other cpus in list.
Performance counter stats for 'CPU(s) 0,11':
1,914,704 cpu_core/cycles/
2,036,983 cpu_atom/cycles/
1.005815641 seconds time elapsed
It now automatically selects cpu0 for cpu_core/cycles/, selects cpu11 for
cpu_atom/cycles/, and output with some warnings.
Some more complex examples,
# perf stat -e cycles,instructions -C0,11 -- sleep 1
WARNING: use 0 in 'cpu_core' for 'cycles', skip other cpus in list.
WARNING: use 11 in 'cpu_atom' for 'cycles', skip other cpus in list.
WARNING: use 0 in 'cpu_core' for 'instructions', skip other cpus in list.
WARNING: use 11 in 'cpu_atom' for 'instructions', skip other cpus in list.
Performance counter stats for 'CPU(s) 0,11':
2,780,387 cpu_core/cycles/
1,583,432 cpu_atom/cycles/
3,957,277 cpu_core/instructions/
1,167,089 cpu_atom/instructions/
1.006005124 seconds time elapsed
# perf stat -e cycles,cpu_atom/instructions/ -C0,11 -- sleep 1
WARNING: use 0 in 'cpu_core' for 'cycles', skip other cpus in list.
WARNING: use 11 in 'cpu_atom' for 'cycles', skip other cpus in list.
WARNING: use 11 in 'cpu_atom' for 'cpu_atom/instructions/', skip other cpus in list.
Performance counter stats for 'CPU(s) 0,11':
3,290,301 cpu_core/cycles/
1,953,073 cpu_atom/cycles/
1,407,869 cpu_atom/instructions/
1.006260912 seconds time elapsed
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jin Yao <yao.jin@intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https //lore.kernel.org/r/20210723063433.7318-4-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-23 14:34:33 +08:00
|
|
|
|
2023-01-20 14:36:54 +00:00
|
|
|
int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size)
|
|
|
|
{
|
|
|
|
const char *sysfs = sysfs__mountpoint();
|
|
|
|
|
|
|
|
if (!sysfs)
|
|
|
|
return 0;
|
|
|
|
return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs);
|
|
|
|
}
|
|
|
|
|
perf pmu: Use relative path for sysfs scan
The PMU information is in the kernel sysfs so it needs to scan the
directory to get the whole information like event aliases, formats and
so on. During the traversal, it opens a lot of files and directories
like below:
dir = opendir("/sys/bus/event_source/devices");
while (dentry = readdir(dir)) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s",
"/sys/bus/event_source/devices", dentry->d_name);
fd = open(buf, O_RDONLY);
...
}
But this is not good since it needs to copy the string to build the
absolute pathname, and it makes redundant pathname walk (from the /sys)
unnecessarily. We can use openat(2) to open the file in the given
directory. While it's not a problem ususally, it can be a problem when
the kernel has contentions on the sysfs.
Add a couple of new helper to return the file descriptor of PMU
directory so that it can use it with relative paths.
* perf_pmu__event_source_devices_fd()
- returns a fd for the PMU root ("/sys/bus/event_source/devices")
* perf_pmu__pathname_fd()
- returns a fd for "<pmu>/<file>" under the PMU root
Now the above code can be converted something like below:
dirfd = perf_pmu__event_source_devices_fd();
dir = fdopendir(dirfd);
while (dentry = readdir(dir)) {
fd = openat(dirfd, dentry->d_name, O_RDONLY);
...
}
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-03-31 13:29:45 -07:00
|
|
|
int perf_pmu__event_source_devices_fd(void)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
const char *sysfs = sysfs__mountpoint();
|
|
|
|
|
|
|
|
if (!sysfs)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
scnprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs);
|
|
|
|
return open(path, O_DIRECTORY);
|
|
|
|
}
|
|
|
|
|
2023-01-20 14:36:54 +00:00
|
|
|
/*
|
|
|
|
* Fill 'buf' with the path to a file or folder in 'pmu_name' in
|
|
|
|
* sysfs. For example if pmu_name = "cs_etm" and 'filename' = "format"
|
|
|
|
* then pathname will be filled with
|
|
|
|
* "/sys/bus/event_source/devices/cs_etm/format"
|
|
|
|
*
|
2023-08-23 01:08:05 -07:00
|
|
|
* Return 0 if the sysfs mountpoint couldn't be found, if no characters were
|
|
|
|
* written or if the buffer size is exceeded.
|
2023-01-20 14:36:54 +00:00
|
|
|
*/
|
|
|
|
int perf_pmu__pathname_scnprintf(char *buf, size_t size,
|
|
|
|
const char *pmu_name, const char *filename)
|
|
|
|
{
|
2023-08-23 01:08:05 -07:00
|
|
|
size_t len;
|
2023-01-20 14:36:54 +00:00
|
|
|
|
2023-08-23 01:08:05 -07:00
|
|
|
len = perf_pmu__event_source_devices_scnprintf(buf, size);
|
|
|
|
if (!len || (len + strlen(pmu_name) + strlen(filename) + 1) >= size)
|
2023-01-20 14:36:54 +00:00
|
|
|
return 0;
|
2023-08-23 01:08:05 -07:00
|
|
|
|
|
|
|
return scnprintf(buf + len, size - len, "%s/%s", pmu_name, filename);
|
2023-01-20 14:36:54 +00:00
|
|
|
}
|
2023-03-31 13:29:43 -07:00
|
|
|
|
perf pmu: Use relative path for sysfs scan
The PMU information is in the kernel sysfs so it needs to scan the
directory to get the whole information like event aliases, formats and
so on. During the traversal, it opens a lot of files and directories
like below:
dir = opendir("/sys/bus/event_source/devices");
while (dentry = readdir(dir)) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s",
"/sys/bus/event_source/devices", dentry->d_name);
fd = open(buf, O_RDONLY);
...
}
But this is not good since it needs to copy the string to build the
absolute pathname, and it makes redundant pathname walk (from the /sys)
unnecessarily. We can use openat(2) to open the file in the given
directory. While it's not a problem ususally, it can be a problem when
the kernel has contentions on the sysfs.
Add a couple of new helper to return the file descriptor of PMU
directory so that it can use it with relative paths.
* perf_pmu__event_source_devices_fd()
- returns a fd for the PMU root ("/sys/bus/event_source/devices")
* perf_pmu__pathname_fd()
- returns a fd for "<pmu>/<file>" under the PMU root
Now the above code can be converted something like below:
dirfd = perf_pmu__event_source_devices_fd();
dir = fdopendir(dirfd);
while (dentry = readdir(dir)) {
fd = openat(dirfd, dentry->d_name, O_RDONLY);
...
}
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230331202949.810326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2023-03-31 13:29:45 -07:00
|
|
|
int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
|
|
|
scnprintf(path, sizeof(path), "%s/%s", pmu_name, filename);
|
|
|
|
return openat(dirfd, path, flags);
|
|
|
|
}
|
|
|
|
|
2023-05-27 00:22:03 -07:00
|
|
|
void perf_pmu__delete(struct perf_pmu *pmu)
|
2023-03-31 13:29:43 -07:00
|
|
|
{
|
2025-05-12 12:46:21 -07:00
|
|
|
if (!pmu)
|
|
|
|
return;
|
|
|
|
|
2024-11-08 16:37:57 -08:00
|
|
|
if (perf_pmu__is_hwmon(pmu))
|
|
|
|
hwmon_pmu__exit(pmu);
|
perf drm_pmu: Add a tool like PMU to expose DRM information
DRM clients expose information through usage stats as documented in
Documentation/gpu/drm-usage-stats.rst (available online at
https://docs.kernel.org/gpu/drm-usage-stats.html). Add a tool like
PMU, similar to the hwmon PMU, that exposes DRM information. For
example on a tigerlake laptop:
```
$ perf list drm
List of pre-defined events (to be used in -e or -M):
drm:
drm-active-stolen-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-active-system0
[Total memory active in one or more engines. Unit: drm_i915]
drm-engine-capacity-video
[Engine capacity. Unit: drm_i915]
drm-engine-copy
[Utilization in ns. Unit: drm_i915]
drm-engine-render
[Utilization in ns. Unit: drm_i915]
drm-engine-video
[Utilization in ns. Unit: drm_i915]
drm-engine-video-enhance
[Utilization in ns. Unit: drm_i915]
drm-purgeable-stolen-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-purgeable-system0
[Size of resident and purgeable memory bufers. Unit: drm_i915]
drm-resident-stolen-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-resident-system0
[Size of resident memory bufers. Unit: drm_i915]
drm-shared-stolen-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-shared-system0
[Size of shared memory bufers. Unit: drm_i915]
drm-total-stolen-system0
[Size of shared and private memory. Unit: drm_i915]
drm-total-system0
[Size of shared and private memory. Unit: drm_i915]
```
System wide data can be gathered:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0
1.000904910,0,bytes,drm-active-stolen-system0,1,100.00,,
1.000904910,0,bytes,drm-active-system0,1,100.00,,
1.000904910,36,capacity,drm-engine-capacity-video,1,100.00,,
1.000904910,0,ns,drm-engine-copy,1,100.00,,
1.000904910,1472970566175,ns,drm-engine-render,1,100.00,,
1.000904910,0,ns,drm-engine-video,1,100.00,,
1.000904910,0,ns,drm-engine-video-enhance,1,100.00,,
1.000904910,0,bytes,drm-purgeable-stolen-system0,1,100.00,,
1.000904910,38199296,bytes,drm-purgeable-system0,1,100.00,,
1.000904910,0,bytes,drm-resident-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-resident-system0,1,100.00,,
1.000904910,0,bytes,drm-shared-stolen-system0,1,100.00,,
1.000904910,1886871552,bytes,drm-shared-system0,1,100.00,,
1.000904910,0,bytes,drm-total-stolen-system0,1,100.00,,
1.000904910,4643196928,bytes,drm-total-system0,1,100.00,,
2.264426839,0,bytes,drm-active-stolen-system0,1,100.00,,
```
Or for a particular process:
```
$ perf stat -x, -I 1000 -e drm-active-stolen-system0,drm-active-system0,drm-engine-capacity-video,drm-engine-copy,drm-engine-render,drm-engine-video,drm-engine-video-enhance,drm-purgeable-stolen-system0,drm-purgeable-system0,drm-resident-stolen-system0,drm-resident-system0,drm-shared-stolen-system0,drm-shared-system0,drm-total-stolen-system0,drm-total-system0 -p 200027
1.001040274,0,bytes,drm-active-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-active-system0,6,100.00,,
1.001040274,12,capacity,drm-engine-capacity-video,6,100.00,,
1.001040274,0,ns,drm-engine-copy,6,100.00,,
1.001040274,1542300,ns,drm-engine-render,6,100.00,,
1.001040274,0,ns,drm-engine-video,6,100.00,,
1.001040274,0,ns,drm-engine-video-enhance,6,100.00,,
1.001040274,0,bytes,drm-purgeable-stolen-system0,6,100.00,,
1.001040274,13516800,bytes,drm-purgeable-system0,6,100.00,,
1.001040274,0,bytes,drm-resident-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-resident-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-stolen-system0,6,100.00,,
1.001040274,0,bytes,drm-shared-system0,6,100.00,,
1.001040274,0,bytes,drm-total-stolen-system0,6,100.00,,
1.001040274,27746304,bytes,drm-total-system0,6,100.00,,
2.016629075,0,bytes,drm-active-stolen-system0,6,100.00,,
```
As with the hwmon PMU, high numbered PMU types are used to encode
multiple possible "DRM" PMUs. The appropriate fdinfo is found by
scanning /proc and filtering which fdinfos to read with stat. To avoid
some unneeding scanning, events not starting with "drm-" are
ignored. The patch builds on commit 57e13264dcea ("perf pmus:
Restructure pmu_read_sysfs to scan fewer PMUs") and later so that only
if full wild carding is being done, the PMU starts with "drm_" or the
event starts with "drm-" will /proc be scanned. That is there should
be little to no cost in this PMU unless DRM events are requested.
Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624231837.179536-3-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-24 16:18:36 -07:00
|
|
|
else if (perf_pmu__is_drm(pmu))
|
|
|
|
drm_pmu__exit(pmu);
|
2024-11-08 16:37:57 -08:00
|
|
|
|
2023-03-31 13:29:43 -07:00
|
|
|
perf_pmu__del_formats(&pmu->format);
|
|
|
|
perf_pmu__del_aliases(pmu);
|
|
|
|
perf_pmu__del_caps(pmu);
|
|
|
|
|
|
|
|
perf_cpu_map__put(pmu->cpus);
|
|
|
|
|
2023-04-12 09:50:08 -03:00
|
|
|
zfree(&pmu->name);
|
|
|
|
zfree(&pmu->alias_name);
|
2023-08-24 19:40:00 -07:00
|
|
|
zfree(&pmu->id);
|
2023-03-31 13:29:43 -07:00
|
|
|
free(pmu);
|
|
|
|
}
|
2024-03-07 16:19:15 -08:00
|
|
|
|
|
|
|
const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config)
|
|
|
|
{
|
2025-05-12 12:46:21 -07:00
|
|
|
struct hashmap_entry *entry;
|
|
|
|
size_t bkt;
|
2024-03-07 16:19:15 -08:00
|
|
|
|
|
|
|
if (!pmu)
|
|
|
|
return NULL;
|
|
|
|
|
2024-05-02 14:35:07 -07:00
|
|
|
pmu_aliases_parse(pmu);
|
2024-03-07 16:19:15 -08:00
|
|
|
pmu_add_cpu_aliases(pmu);
|
2025-05-12 12:46:21 -07:00
|
|
|
hashmap__for_each_entry(pmu->aliases, entry, bkt) {
|
|
|
|
struct perf_pmu_alias *event = entry->pvalue;
|
2024-03-07 16:19:15 -08:00
|
|
|
struct perf_event_attr attr = {.config = 0,};
|
2024-10-01 20:20:05 -07:00
|
|
|
|
|
|
|
int ret = perf_pmu__config(pmu, &attr, &event->terms, /*apply_hardcoded=*/true,
|
|
|
|
/*err=*/NULL);
|
2024-03-07 16:19:15 -08:00
|
|
|
|
|
|
|
if (ret == 0 && config == attr.config)
|
|
|
|
return event->name;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|