* [PATCH v4 00/16] Intel TPEBS min/max/mean/last support
@ 2025-04-09 6:10 Ian Rogers
2025-04-09 6:10 ` [PATCH v4 01/16] perf intel-tpebs: Cleanup header Ian Rogers
` (16 more replies)
0 siblings, 17 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
The patches add support to computing the min, max, mean or last
retirement latency and then using that value as the basis for metrics.
When values aren't available, support is added to use the retirement
latency as recorded for an event in the perf json.
Support is added for reading the retirement latency from the forked
perf command more than once. To avoid killing the process commands are
sent through the control fd. Some name handling is changed to make it
more robust.
Rather than retirement latency events having issues with perf record,
make it so that the retirement latency modifier enables sample
weights.
v4: Don't use json min/max in retirement latency stats as they will
never update afterwards. Warn once if json data is used when TPEBS
recording was requested.
v3: Two fixes from Kan Liang. Ensure min/max statistics don't vary
when real samples are encountered.
v2: Addition of header cleanup patch originally posted:
https://lore.kernel.org/lkml/20241210191823.612631-1-irogers@google.com/
as there are no arch specific reasons not to build this code.
Fix bug in "perf pmu-events: Add retirement latency to JSON events
inside of perf" where "t->stats.n != 0" should have been
"t->stats.n == 0".
Add patch so that perf record of a retirement latency event
doesn't crash but instead enables sample weights for the event.
Ian Rogers (16):
perf intel-tpebs: Cleanup header
perf intel-tpebs: Simplify tpebs_cmd
perf intel-tpebs: Rename tpebs_start to evsel__tpebs_open
perf intel-tpebs: Separate evsel__tpebs_prepare out of
evsel__tpebs_open
perf intel-tpebs: Move cpumap_buf out of evsel__tpebs_open
perf intel-tpebs: Reduce scope of tpebs_events_size
perf intel-tpebs: Inline get_perf_record_args
perf intel-tpebs: Ensure events are opened, factor out finding
perf intel-tpebs: Refactor tpebs_results list
perf intel-tpebs: Add support for updating counts in evsel__tpebs_read
perf intel-tpebs: Add mutex for tpebs_results
perf intel-tpebs: Don't close record on read
perf intel-tpebs: Use stats for retirement latency statistics
perf stat: Add mean, min, max and last --tpebs-mode options
perf pmu-events: Add retirement latency to JSON events inside of perf
perf record: Retirement latency cleanup in evsel__config
tools/perf/Documentation/perf-stat.txt | 7 +
tools/perf/builtin-stat.c | 29 +-
tools/perf/pmu-events/empty-pmu-events.c | 216 +++----
tools/perf/pmu-events/jevents.py | 6 +
tools/perf/pmu-events/pmu-events.h | 3 +
tools/perf/util/Build | 2 +-
tools/perf/util/evlist.c | 1 -
tools/perf/util/evsel.c | 22 +-
tools/perf/util/evsel.h | 6 +
tools/perf/util/intel-tpebs.c | 682 ++++++++++++++---------
tools/perf/util/intel-tpebs.h | 40 +-
tools/perf/util/parse-events.c | 4 +
tools/perf/util/pmu.c | 52 +-
tools/perf/util/pmu.h | 3 +
14 files changed, 666 insertions(+), 407 deletions(-)
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 01/16] perf intel-tpebs: Cleanup header
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 02/16] perf intel-tpebs: Simplify tpebs_cmd Ian Rogers
` (15 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Remove arch conditional compilation. Arch conditional compilation
belongs in the arch/ directory.
Tidy header guards to match other files. Remove unneeded includes and
switch to forward declarations when necesary.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/Build | 2 +-
tools/perf/util/intel-tpebs.c | 1 +
tools/perf/util/intel-tpebs.h | 30 ++++++------------------------
3 files changed, 8 insertions(+), 25 deletions(-)
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 946bce6628f3..815274b199fd 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -161,7 +161,7 @@ perf-util-y += clockid.o
perf-util-y += list_sort.o
perf-util-y += mutex.o
perf-util-y += sharded_mutex.o
-perf-util-$(CONFIG_X86_64) += intel-tpebs.o
+perf-util-y += intel-tpebs.o
perf-util-$(CONFIG_LIBBPF) += bpf_map.o
perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_counter.o
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 2c421b475b3b..3503da28a12f 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -19,6 +19,7 @@
#include "tool.h"
#include "cpumap.h"
#include "metricgroup.h"
+#include "stat.h"
#include <sys/stat.h>
#include <sys/file.h>
#include <poll.h>
diff --git a/tools/perf/util/intel-tpebs.h b/tools/perf/util/intel-tpebs.h
index 766b3fbd79f1..63c16e759a71 100644
--- a/tools/perf/util/intel-tpebs.h
+++ b/tools/perf/util/intel-tpebs.h
@@ -2,34 +2,16 @@
/*
* intel_tpebs.h: Intel TEPBS support
*/
-#ifndef INCLUDE__PERF_INTEL_TPEBS_H__
-#define INCLUDE__PERF_INTEL_TPEBS_H__
+#ifndef __INTEL_TPEBS_H
+#define __INTEL_TPEBS_H
-#include "stat.h"
-#include "evsel.h"
-
-#ifdef HAVE_ARCH_X86_64_SUPPORT
+struct evlist;
+struct evsel;
extern bool tpebs_recording;
+
int tpebs_start(struct evlist *evsel_list);
void tpebs_delete(void);
int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread);
-#else
-
-static inline int tpebs_start(struct evlist *evsel_list __maybe_unused)
-{
- return 0;
-}
-
-static inline void tpebs_delete(void) {};
-
-static inline int tpebs_set_evsel(struct evsel *evsel __maybe_unused,
- int cpu_map_idx __maybe_unused,
- int thread __maybe_unused)
-{
- return 0;
-}
-
-#endif
-#endif
+#endif /* __INTEL_TPEBS_H */
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 02/16] perf intel-tpebs: Simplify tpebs_cmd
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
2025-04-09 6:10 ` [PATCH v4 01/16] perf intel-tpebs: Cleanup header Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 03/16] perf intel-tpebs: Rename tpebs_start to evsel__tpebs_open Ian Rogers
` (14 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
No need to dynamically allocate when there is 1. tpebs_pid duplicates
tpebs_cmd.pid, so remove. Use 0 as the uninitialized value (PID == 0
is reserved for the kernel) rather than -1.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 55 ++++++++++++-----------------------
1 file changed, 18 insertions(+), 37 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 3503da28a12f..74b43faab986 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -28,11 +28,10 @@
#define PERF_DATA "-"
bool tpebs_recording;
-static pid_t tpebs_pid = -1;
static size_t tpebs_event_size;
static LIST_HEAD(tpebs_results);
static pthread_t tpebs_reader_thread;
-static struct child_process *tpebs_cmd;
+static struct child_process tpebs_cmd;
struct tpebs_retire_lat {
struct list_head nd;
@@ -83,16 +82,6 @@ static int get_perf_record_args(const char **record_argv, char buf[],
return 0;
}
-static int prepare_run_command(const char **argv)
-{
- tpebs_cmd = zalloc(sizeof(struct child_process));
- if (!tpebs_cmd)
- return -ENOMEM;
- tpebs_cmd->argv = argv;
- tpebs_cmd->out = -1;
- return 0;
-}
-
static int start_perf_record(int control_fd[], int ack_fd[],
const char *cpumap_buf)
{
@@ -110,10 +99,10 @@ static int start_perf_record(int control_fd[], int ack_fd[],
if (ret)
goto out;
- ret = prepare_run_command(record_argv);
- if (ret)
- goto out;
- ret = start_command(tpebs_cmd);
+ assert(tpebs_cmd.pid == 0);
+ tpebs_cmd.argv = record_argv;
+ tpebs_cmd.out = -1;
+ ret = start_command(&tpebs_cmd);
out:
free(record_argv);
return ret;
@@ -156,14 +145,13 @@ static int process_feature_event(struct perf_session *session,
return 0;
}
-static void *__sample_reader(void *arg)
+static void *__sample_reader(void *arg __maybe_unused)
{
- struct child_process *child = arg;
struct perf_session *session;
struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
.path = PERF_DATA,
- .file.fd = child->out,
+ .file.fd = tpebs_cmd.out,
};
struct perf_tool tool;
@@ -189,12 +177,12 @@ static int tpebs_stop(void)
int ret = 0;
/* Like tpebs_start, we should only run tpebs_end once. */
- if (tpebs_pid != -1) {
- kill(tpebs_cmd->pid, SIGTERM);
- tpebs_pid = -1;
+ if (tpebs_cmd.pid != 0) {
+ kill(tpebs_cmd.pid, SIGTERM);
pthread_join(tpebs_reader_thread, NULL);
- close(tpebs_cmd->out);
- ret = finish_command(tpebs_cmd);
+ close(tpebs_cmd.out);
+ ret = finish_command(&tpebs_cmd);
+ tpebs_cmd.pid = 0;
if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
ret = 0;
}
@@ -219,7 +207,7 @@ int tpebs_start(struct evlist *evsel_list)
* We should only run tpebs_start when tpebs_recording is enabled.
* And we should only run it once with all the required events.
*/
- if (tpebs_pid != -1 || !tpebs_recording)
+ if (tpebs_cmd.pid != 0 || !tpebs_recording)
return 0;
cpu_map__snprint(evsel_list->core.user_requested_cpus, cpumap_buf, sizeof(cpumap_buf));
@@ -284,10 +272,11 @@ int tpebs_start(struct evlist *evsel_list)
ret = start_perf_record(control_fd, ack_fd, cpumap_buf);
if (ret)
goto out;
- tpebs_pid = tpebs_cmd->pid;
- if (pthread_create(&tpebs_reader_thread, NULL, __sample_reader, tpebs_cmd)) {
- kill(tpebs_cmd->pid, SIGTERM);
- close(tpebs_cmd->out);
+
+ if (pthread_create(&tpebs_reader_thread, /*attr=*/NULL, __sample_reader,
+ /*arg=*/NULL)) {
+ kill(tpebs_cmd.pid, SIGTERM);
+ close(tpebs_cmd.out);
pr_err("Could not create thread to process sample data.\n");
ret = -1;
goto out;
@@ -416,18 +405,10 @@ void tpebs_delete(void)
{
struct tpebs_retire_lat *r, *rtmp;
- if (tpebs_pid == -1)
- return;
-
tpebs_stop();
list_for_each_entry_safe(r, rtmp, &tpebs_results, nd) {
list_del_init(&r->nd);
tpebs_retire_lat__delete(r);
}
-
- if (tpebs_cmd) {
- free(tpebs_cmd);
- tpebs_cmd = NULL;
- }
}
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 03/16] perf intel-tpebs: Rename tpebs_start to evsel__tpebs_open
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
2025-04-09 6:10 ` [PATCH v4 01/16] perf intel-tpebs: Cleanup header Ian Rogers
2025-04-09 6:10 ` [PATCH v4 02/16] perf intel-tpebs: Simplify tpebs_cmd Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 04/16] perf intel-tpebs: Separate evsel__tpebs_prepare out of evsel__tpebs_open Ian Rogers
` (13 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Try to add more consistency to evsel by having tpebs_start renamed to
evsel__tpebs_open, passing the evsel that is being opened. The unusual
behavior of evsel__tpebs_open opening all events on the evlist is kept
and will be cleaned up further in later patches. The comments are
cleaned up as tpebs_start isn't called from evlist.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evsel.c | 2 +-
tools/perf/util/intel-tpebs.c | 33 ++++++++++++++++-----------------
tools/perf/util/intel-tpebs.h | 2 +-
3 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1974395492d7..121283f2f382 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -2595,7 +2595,7 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,
struct perf_cpu cpu;
if (evsel__is_retire_lat(evsel))
- return tpebs_start(evsel->evlist);
+ return evsel__tpebs_open(evsel);
err = __evsel__prepare_open(evsel, cpus, threads);
if (err)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 74b43faab986..566e0ddcad88 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -12,6 +12,7 @@
#include <linux/zalloc.h>
#include <linux/err.h>
#include "sample.h"
+#include "counts.h"
#include "debug.h"
#include "evlist.h"
#include "evsel.h"
@@ -189,18 +190,16 @@ static int tpebs_stop(void)
return ret;
}
-/*
- * tpebs_start - start tpebs execution.
- * @evsel_list: retire_latency evsels in this list will be selected and sampled
- * to get the average retire_latency value.
- *
- * This function will be called from evlist level later when evlist__open() is
- * called consistently.
+/**
+ * evsel__tpebs_open - starts tpebs execution.
+ * @evsel: retire_latency evsel, all evsels on its list will be selected. Each
+ * evsel is sampled to get the average retire_latency value.
*/
-int tpebs_start(struct evlist *evsel_list)
+int evsel__tpebs_open(struct evsel *evsel)
{
int ret = 0;
- struct evsel *evsel;
+ struct evsel *pos;
+ struct evlist *evsel_list = evsel->evlist;
char cpumap_buf[50];
/*
@@ -215,25 +214,25 @@ int tpebs_start(struct evlist *evsel_list)
* Prepare perf record for sampling event retire_latency before fork and
* prepare workload
*/
- evlist__for_each_entry(evsel_list, evsel) {
+ evlist__for_each_entry(evsel_list, pos) {
int i;
char *name;
struct tpebs_retire_lat *new;
- if (!evsel->retire_lat)
+ if (!pos->retire_lat)
continue;
- pr_debug("tpebs: Retire_latency of event %s is required\n", evsel->name);
- for (i = strlen(evsel->name) - 1; i > 0; i--) {
- if (evsel->name[i] == 'R')
+ pr_debug("tpebs: Retire_latency of event %s is required\n", pos->name);
+ for (i = strlen(pos->name) - 1; i > 0; i--) {
+ if (pos->name[i] == 'R')
break;
}
- if (i <= 0 || evsel->name[i] != 'R') {
+ if (i <= 0 || pos->name[i] != 'R') {
ret = -1;
goto err;
}
- name = strdup(evsel->name);
+ name = strdup(pos->name);
if (!name) {
ret = -ENOMEM;
goto err;
@@ -247,7 +246,7 @@ int tpebs_start(struct evlist *evsel_list)
goto err;
}
new->name = name;
- new->tpebs_name = evsel->name;
+ new->tpebs_name = pos->name;
list_add_tail(&new->nd, &tpebs_results);
tpebs_event_size += 1;
}
diff --git a/tools/perf/util/intel-tpebs.h b/tools/perf/util/intel-tpebs.h
index 63c16e759a71..cc98203719c8 100644
--- a/tools/perf/util/intel-tpebs.h
+++ b/tools/perf/util/intel-tpebs.h
@@ -10,7 +10,7 @@ struct evsel;
extern bool tpebs_recording;
-int tpebs_start(struct evlist *evsel_list);
+int evsel__tpebs_open(struct evsel *evsel);
void tpebs_delete(void);
int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread);
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 04/16] perf intel-tpebs: Separate evsel__tpebs_prepare out of evsel__tpebs_open
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (2 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 03/16] perf intel-tpebs: Rename tpebs_start to evsel__tpebs_open Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 05/16] perf intel-tpebs: Move cpumap_buf " Ian Rogers
` (12 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Separate the creation of the tpebs_retire_lat result out of the
opening step. This is in preparation for adding a prepare operation
for evlists.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 133 ++++++++++++++++++++++------------
1 file changed, 86 insertions(+), 47 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 566e0ddcad88..2186818b2c9b 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -37,7 +37,7 @@ static struct child_process tpebs_cmd;
struct tpebs_retire_lat {
struct list_head nd;
/* Event name */
- const char *name;
+ char *name;
/* Event name with the TPEBS modifier R */
const char *tpebs_name;
/* Count of retire_latency values found in sample data */
@@ -190,6 +190,82 @@ static int tpebs_stop(void)
return ret;
}
+static char *evsel__tpebs_name(struct evsel *evsel)
+{
+ char *name, *modifier;
+
+ name = strdup(evsel->name);
+ if (!name)
+ return NULL;
+
+ modifier = strrchr(name, 'R');
+ if (!modifier) {
+ pr_err("Tpebs event missing modifier '%s'\n", name);
+ free(name);
+ return NULL;
+ }
+
+ *modifier = 'p';
+ return name;
+}
+
+static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
+{
+ struct tpebs_retire_lat *result = zalloc(sizeof(*result));
+
+ if (!result)
+ return NULL;
+
+ result->tpebs_name = evsel->name;
+ result->name = evsel__tpebs_name(evsel);
+ if (!result->name) {
+ free(result);
+ return NULL;
+ }
+ list_add_tail(&result->nd, &tpebs_results);
+ tpebs_event_size++;
+ return result;
+}
+
+/**
+ * evsel__tpebs_prepare - create tpebs data structures ready for opening.
+ * @evsel: retire_latency evsel, all evsels on its list will be prepared.
+ */
+static int evsel__tpebs_prepare(struct evsel *evsel)
+{
+ struct evsel *pos;
+ struct tpebs_retire_lat *tpebs_event;
+
+ list_for_each_entry(tpebs_event, &tpebs_results, nd) {
+ if (!strcmp(tpebs_event->tpebs_name, evsel->name)) {
+ /*
+ * evsel, or an identically named one, was already
+ * prepared.
+ */
+ return 0;
+ }
+ }
+ tpebs_event = tpebs_retire_lat__new(evsel);
+ if (!tpebs_event)
+ return -ENOMEM;
+
+ /*
+ * Eagerly prepare all other evsels on the list to try to ensure that by
+ * open they are all known.
+ */
+ evlist__for_each_entry(evsel->evlist, pos) {
+ int ret;
+
+ if (pos == evsel || !pos->retire_lat)
+ continue;
+
+ ret = evsel__tpebs_prepare(pos);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
/**
* evsel__tpebs_open - starts tpebs execution.
* @evsel: retire_latency evsel, all evsels on its list will be selected. Each
@@ -197,10 +273,7 @@ static int tpebs_stop(void)
*/
int evsel__tpebs_open(struct evsel *evsel)
{
- int ret = 0;
- struct evsel *pos;
- struct evlist *evsel_list = evsel->evlist;
- char cpumap_buf[50];
+ int ret;
/*
* We should only run tpebs_start when tpebs_recording is enabled.
@@ -209,49 +282,13 @@ int evsel__tpebs_open(struct evsel *evsel)
if (tpebs_cmd.pid != 0 || !tpebs_recording)
return 0;
- cpu_map__snprint(evsel_list->core.user_requested_cpus, cpumap_buf, sizeof(cpumap_buf));
- /*
- * Prepare perf record for sampling event retire_latency before fork and
- * prepare workload
- */
- evlist__for_each_entry(evsel_list, pos) {
- int i;
- char *name;
- struct tpebs_retire_lat *new;
-
- if (!pos->retire_lat)
- continue;
-
- pr_debug("tpebs: Retire_latency of event %s is required\n", pos->name);
- for (i = strlen(pos->name) - 1; i > 0; i--) {
- if (pos->name[i] == 'R')
- break;
- }
- if (i <= 0 || pos->name[i] != 'R') {
- ret = -1;
- goto err;
- }
-
- name = strdup(pos->name);
- if (!name) {
- ret = -ENOMEM;
- goto err;
- }
- name[i] = 'p';
-
- new = zalloc(sizeof(*new));
- if (!new) {
- ret = -1;
- zfree(&name);
- goto err;
- }
- new->name = name;
- new->tpebs_name = pos->name;
- list_add_tail(&new->nd, &tpebs_results);
- tpebs_event_size += 1;
- }
+ ret = evsel__tpebs_prepare(evsel);
+ if (ret)
+ return ret;
if (tpebs_event_size > 0) {
+ struct evlist *evsel_list = evsel->evlist;
+ char cpumap_buf[50];
struct pollfd pollfd = { .events = POLLIN, };
int control_fd[2], ack_fd[2], len;
char ack_buf[8];
@@ -268,6 +305,9 @@ int evsel__tpebs_open(struct evsel *evsel)
goto out;
}
+ cpu_map__snprint(evsel_list->core.user_requested_cpus, cpumap_buf,
+ sizeof(cpumap_buf));
+
ret = start_perf_record(control_fd, ack_fd, cpumap_buf);
if (ret)
goto out;
@@ -321,7 +361,6 @@ int evsel__tpebs_open(struct evsel *evsel)
close(ack_fd[0]);
close(ack_fd[1]);
}
-err:
if (ret)
tpebs_delete();
return ret;
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 05/16] perf intel-tpebs: Move cpumap_buf out of evsel__tpebs_open
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (3 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 04/16] perf intel-tpebs: Separate evsel__tpebs_prepare out of evsel__tpebs_open Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 06/16] perf intel-tpebs: Reduce scope of tpebs_events_size Ian Rogers
` (11 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
The buffer holds the cpumap to pass to the perf record command, so
move it down to the perf record function. Make this function an evsel
function given the need for the evsel for the cpumap.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 2186818b2c9b..2b04deaf66ff 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -83,12 +83,15 @@ static int get_perf_record_args(const char **record_argv, char buf[],
return 0;
}
-static int start_perf_record(int control_fd[], int ack_fd[],
- const char *cpumap_buf)
+static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
{
const char **record_argv;
int ret;
char buf[32];
+ char cpumap_buf[50];
+
+ cpu_map__snprint(evsel->evlist->core.user_requested_cpus, cpumap_buf,
+ sizeof(cpumap_buf));
scnprintf(buf, sizeof(buf), "--control=fd:%d,%d", control_fd[0], ack_fd[1]);
@@ -287,8 +290,6 @@ int evsel__tpebs_open(struct evsel *evsel)
return ret;
if (tpebs_event_size > 0) {
- struct evlist *evsel_list = evsel->evlist;
- char cpumap_buf[50];
struct pollfd pollfd = { .events = POLLIN, };
int control_fd[2], ack_fd[2], len;
char ack_buf[8];
@@ -305,10 +306,7 @@ int evsel__tpebs_open(struct evsel *evsel)
goto out;
}
- cpu_map__snprint(evsel_list->core.user_requested_cpus, cpumap_buf,
- sizeof(cpumap_buf));
-
- ret = start_perf_record(control_fd, ack_fd, cpumap_buf);
+ ret = evsel__tpebs_start_perf_record(evsel, control_fd, ack_fd);
if (ret)
goto out;
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 06/16] perf intel-tpebs: Reduce scope of tpebs_events_size
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (4 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 05/16] perf intel-tpebs: Move cpumap_buf " Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 07/16] perf intel-tpebs: Inline get_perf_record_args Ian Rogers
` (10 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Moved to record argument computation rather than being global.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 2b04deaf66ff..e3bed86145b9 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -29,7 +29,6 @@
#define PERF_DATA "-"
bool tpebs_recording;
-static size_t tpebs_event_size;
static LIST_HEAD(tpebs_results);
static pthread_t tpebs_reader_thread;
static struct child_process tpebs_cmd;
@@ -86,15 +85,20 @@ static int get_perf_record_args(const char **record_argv, char buf[],
static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
{
const char **record_argv;
+ size_t tpebs_event_size = 0;
int ret;
char buf[32];
char cpumap_buf[50];
+ struct tpebs_retire_lat *t;
cpu_map__snprint(evsel->evlist->core.user_requested_cpus, cpumap_buf,
sizeof(cpumap_buf));
scnprintf(buf, sizeof(buf), "--control=fd:%d,%d", control_fd[0], ack_fd[1]);
+ list_for_each_entry(t, &tpebs_results, nd)
+ tpebs_event_size++;
+
record_argv = calloc(12 + 2 * tpebs_event_size, sizeof(char *));
if (!record_argv)
return -ENOMEM;
@@ -226,7 +230,6 @@ static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
return NULL;
}
list_add_tail(&result->nd, &tpebs_results);
- tpebs_event_size++;
return result;
}
@@ -289,7 +292,7 @@ int evsel__tpebs_open(struct evsel *evsel)
if (ret)
return ret;
- if (tpebs_event_size > 0) {
+ if (!list_empty(&tpebs_results)) {
struct pollfd pollfd = { .events = POLLIN, };
int control_fd[2], ack_fd[2], len;
char ack_buf[8];
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 07/16] perf intel-tpebs: Inline get_perf_record_args
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (5 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 06/16] perf intel-tpebs: Reduce scope of tpebs_events_size Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 08/16] perf intel-tpebs: Ensure events are opened, factor out finding Ian Rogers
` (9 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Code is short enough to be inlined and there are no error cases when
made inline. Make the implicit NULL pointer at the end of the argv
explicit. Move the fixed number of arguments before the variable
number of arguments. Correctly size the argv allocation and zero when
feeing to avoid a dangling pointer.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 75 +++++++++++++----------------------
1 file changed, 28 insertions(+), 47 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index e3bed86145b9..c4c818f32239 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -47,72 +47,53 @@ struct tpebs_retire_lat {
double val;
};
-static int get_perf_record_args(const char **record_argv, char buf[],
- const char *cpumap_buf)
+static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
{
- struct tpebs_retire_lat *e;
- int i = 0;
+ const char **record_argv;
+ int tpebs_event_size = 0, i = 0, ret;
+ char control_fd_buf[32];
+ char cpumap_buf[50];
+ struct tpebs_retire_lat *t;
+
+ list_for_each_entry(t, &tpebs_results, nd)
+ tpebs_event_size++;
- pr_debug("tpebs: Prepare perf record for retire_latency\n");
+ record_argv = malloc((10 + 2 * tpebs_event_size) * sizeof(*record_argv));
+ if (!record_argv)
+ return -ENOMEM;
record_argv[i++] = "perf";
record_argv[i++] = "record";
record_argv[i++] = "-W";
record_argv[i++] = "--synth=no";
- record_argv[i++] = buf;
- if (!cpumap_buf) {
- pr_err("tpebs: Require cpumap list to run sampling\n");
- return -ECANCELED;
- }
- /* Use -C when cpumap_buf is not "-1" */
- if (strcmp(cpumap_buf, "-1")) {
+ scnprintf(control_fd_buf, sizeof(control_fd_buf), "--control=fd:%d,%d",
+ control_fd[0], ack_fd[1]);
+ record_argv[i++] = control_fd_buf;
+
+ record_argv[i++] = "-o";
+ record_argv[i++] = PERF_DATA;
+
+ if (!perf_cpu_map__is_any_cpu_or_is_empty(evsel->evlist->core.user_requested_cpus)) {
+ cpu_map__snprint(evsel->evlist->core.user_requested_cpus, cpumap_buf,
+ sizeof(cpumap_buf));
record_argv[i++] = "-C";
record_argv[i++] = cpumap_buf;
}
- list_for_each_entry(e, &tpebs_results, nd) {
+ list_for_each_entry(t, &tpebs_results, nd) {
record_argv[i++] = "-e";
- record_argv[i++] = e->name;
+ record_argv[i++] = t->name;
}
-
- record_argv[i++] = "-o";
- record_argv[i++] = PERF_DATA;
-
- return 0;
-}
-
-static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
-{
- const char **record_argv;
- size_t tpebs_event_size = 0;
- int ret;
- char buf[32];
- char cpumap_buf[50];
- struct tpebs_retire_lat *t;
-
- cpu_map__snprint(evsel->evlist->core.user_requested_cpus, cpumap_buf,
- sizeof(cpumap_buf));
-
- scnprintf(buf, sizeof(buf), "--control=fd:%d,%d", control_fd[0], ack_fd[1]);
-
- list_for_each_entry(t, &tpebs_results, nd)
- tpebs_event_size++;
-
- record_argv = calloc(12 + 2 * tpebs_event_size, sizeof(char *));
- if (!record_argv)
- return -ENOMEM;
-
- ret = get_perf_record_args(record_argv, buf, cpumap_buf);
- if (ret)
- goto out;
+ record_argv[i++] = NULL;
+ assert(i == 10 + 2 * tpebs_event_size || i == 8 + 2 * tpebs_event_size);
+ /* Note, no workload given so system wide is implied. */
assert(tpebs_cmd.pid == 0);
tpebs_cmd.argv = record_argv;
tpebs_cmd.out = -1;
ret = start_command(&tpebs_cmd);
-out:
- free(record_argv);
+ zfree(&tpebs_cmd.argv);
return ret;
}
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 08/16] perf intel-tpebs: Ensure events are opened, factor out finding
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (6 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 07/16] perf intel-tpebs: Inline get_perf_record_args Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 09/16] perf intel-tpebs: Refactor tpebs_results list Ian Rogers
` (8 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Factor out finding an tpebs_retire_lat from an evsel. Don't blindly
return when ignoring an open request, which happens after the first
open request, ensure the event was started on a fork of perf record.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 61 +++++++++++++++++++++--------------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index c4c818f32239..e42f3ec39a64 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -45,6 +45,8 @@ struct tpebs_retire_lat {
int sum;
/* Average of retire_latency, val = sum / count */
double val;
+ /* Has the event been sent to perf record? */
+ bool started;
};
static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
@@ -94,6 +96,9 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
tpebs_cmd.out = -1;
ret = start_command(&tpebs_cmd);
zfree(&tpebs_cmd.argv);
+ list_for_each_entry(t, &tpebs_results, nd)
+ t->started = true;
+
return ret;
}
@@ -214,6 +219,19 @@ static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
return result;
}
+static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel)
+{
+ struct tpebs_retire_lat *t;
+
+ list_for_each_entry(t, &tpebs_results, nd) {
+ if (t->tpebs_name == evsel->name ||
+ !strcmp(t->tpebs_name, evsel->name) ||
+ (evsel->metric_id && !strcmp(t->tpebs_name, evsel->metric_id)))
+ return t;
+ }
+ return NULL;
+}
+
/**
* evsel__tpebs_prepare - create tpebs data structures ready for opening.
* @evsel: retire_latency evsel, all evsels on its list will be prepared.
@@ -221,16 +239,11 @@ static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
static int evsel__tpebs_prepare(struct evsel *evsel)
{
struct evsel *pos;
- struct tpebs_retire_lat *tpebs_event;
-
- list_for_each_entry(tpebs_event, &tpebs_results, nd) {
- if (!strcmp(tpebs_event->tpebs_name, evsel->name)) {
- /*
- * evsel, or an identically named one, was already
- * prepared.
- */
- return 0;
- }
+ struct tpebs_retire_lat *tpebs_event = tpebs_retire_lat__find(evsel);
+
+ if (tpebs_event) {
+ /* evsel, or an identically named one, was already prepared. */
+ return 0;
}
tpebs_event = tpebs_retire_lat__new(evsel);
if (!tpebs_event)
@@ -262,12 +275,19 @@ int evsel__tpebs_open(struct evsel *evsel)
{
int ret;
- /*
- * We should only run tpebs_start when tpebs_recording is enabled.
- * And we should only run it once with all the required events.
- */
- if (tpebs_cmd.pid != 0 || !tpebs_recording)
+ /* We should only run tpebs_start when tpebs_recording is enabled. */
+ if (!tpebs_recording)
return 0;
+ /* Only start the events once. */
+ if (tpebs_cmd.pid != 0) {
+ struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
+
+ if (!t || !t->started) {
+ /* Fail, as the event wasn't started. */
+ return -EBUSY;
+ }
+ return 0;
+ }
ret = evsel__tpebs_prepare(evsel);
if (ret)
@@ -352,7 +372,6 @@ int evsel__tpebs_open(struct evsel *evsel)
int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread)
{
__u64 val;
- bool found = false;
struct tpebs_retire_lat *t;
struct perf_counts_values *count;
@@ -367,19 +386,13 @@ int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread)
tpebs_stop();
count = perf_counts(evsel->counts, cpu_map_idx, thread);
- list_for_each_entry(t, &tpebs_results, nd) {
- if (t->tpebs_name == evsel->name ||
- (evsel->metric_id && !strcmp(t->tpebs_name, evsel->metric_id))) {
- found = true;
- break;
- }
- }
+ t = tpebs_retire_lat__find(evsel);
/* Set ena and run to non-zero */
count->ena = count->run = 1;
count->lost = 0;
- if (!found) {
+ if (!t) {
/*
* Set default value or 0 when retire_latency for this event is
* not found from sampling data (record_tpebs not set or 0
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 09/16] perf intel-tpebs: Refactor tpebs_results list
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (7 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 08/16] perf intel-tpebs: Ensure events are opened, factor out finding Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 10/16] perf intel-tpebs: Add support for updating counts in evsel__tpebs_read Ian Rogers
` (7 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
evsel names and metric-ids are used for matching but this can be
problematic, for example, multiple occurrences of the same retirement
latency event become a single event for the record. Change the name of
the record events so they are unique and reflect the evsel of the
retirement latency event that opens them (the retirement latency
event's evsel address is embedded within them). This allows an evsel
based close to close the event when the retirement latency event is
closed. This is important as perf stat has an evlist and the session
listen to the record events has an evlist, knowing which event should
remove the tpebs_retire_lat can't be tied to an evlist list as there
is more than 1, so closing which evlist should cause the tpebs to
stop? Using the evsel and the last one out doing the tpebs_stop is
cleaner.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-stat.c | 2 -
tools/perf/util/evlist.c | 1 -
tools/perf/util/evsel.c | 2 +-
tools/perf/util/intel-tpebs.c | 150 +++++++++++++++++++++-------------
tools/perf/util/intel-tpebs.h | 2 +-
5 files changed, 93 insertions(+), 64 deletions(-)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 68ea7589c143..80e491bd775b 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -681,8 +681,6 @@ static enum counter_recovery stat_handle_error(struct evsel *counter)
if (child_pid != -1)
kill(child_pid, SIGTERM);
- tpebs_delete();
-
return COUNTER_FATAL;
}
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c1a04141aed0..0a21da4f990f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -183,7 +183,6 @@ void evlist__delete(struct evlist *evlist)
if (evlist == NULL)
return;
- tpebs_delete();
evlist__free_stats(evlist);
evlist__munmap(evlist);
evlist__close(evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 121283f2f382..554252ed1aab 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -2759,7 +2759,7 @@ int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus,
void evsel__close(struct evsel *evsel)
{
if (evsel__is_retire_lat(evsel))
- tpebs_delete();
+ evsel__tpebs_close(evsel);
perf_evsel__close(&evsel->core);
perf_evsel__free_id(&evsel->core);
}
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index e42f3ec39a64..a723687e67f6 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -35,10 +35,10 @@ static struct child_process tpebs_cmd;
struct tpebs_retire_lat {
struct list_head nd;
- /* Event name */
- char *name;
- /* Event name with the TPEBS modifier R */
- const char *tpebs_name;
+ /** @evsel: The evsel that opened the retire_lat event. */
+ struct evsel *evsel;
+ /** @event: Event passed to perf record. */
+ char *event;
/* Count of retire_latency values found in sample data */
size_t count;
/* Sum of all the retire_latency values in sample data */
@@ -49,6 +49,8 @@ struct tpebs_retire_lat {
bool started;
};
+static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel);
+
static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
{
const char **record_argv;
@@ -85,7 +87,7 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
list_for_each_entry(t, &tpebs_results, nd) {
record_argv[i++] = "-e";
- record_argv[i++] = t->name;
+ record_argv[i++] = t->event;
}
record_argv[i++] = NULL;
assert(i == 10 + 2 * tpebs_event_size || i == 8 + 2 * tpebs_event_size);
@@ -108,27 +110,20 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
struct evsel *evsel,
struct machine *machine __maybe_unused)
{
- int ret = 0;
- const char *evname;
struct tpebs_retire_lat *t;
- evname = evsel__name(evsel);
-
+ t = tpebs_retire_lat__find(evsel);
+ if (!t)
+ return -EINVAL;
/*
* Need to handle per core results? We are assuming average retire
* latency value will be used. Save the number of samples and the sum of
* retire latency value for each event.
*/
- list_for_each_entry(t, &tpebs_results, nd) {
- if (!strcmp(evname, t->name)) {
- t->count += 1;
- t->sum += sample->retire_lat;
- t->val = (double) t->sum / t->count;
- break;
- }
- }
-
- return ret;
+ t->count += 1;
+ t->sum += sample->retire_lat;
+ t->val = (double) t->sum / t->count;
+ return 0;
}
static int process_feature_event(struct perf_session *session,
@@ -183,50 +178,98 @@ static int tpebs_stop(void)
return ret;
}
-static char *evsel__tpebs_name(struct evsel *evsel)
+/**
+ * evsel__tpebs_event() - Create string event encoding to pass to `perf record`.
+ */
+static int evsel__tpebs_event(struct evsel *evsel, char **event)
{
char *name, *modifier;
+ int ret;
name = strdup(evsel->name);
if (!name)
- return NULL;
+ return -ENOMEM;
modifier = strrchr(name, 'R');
if (!modifier) {
- pr_err("Tpebs event missing modifier '%s'\n", name);
- free(name);
- return NULL;
+ ret = -EINVAL;
+ goto out;
}
-
*modifier = 'p';
- return name;
+ modifier = strchr(name, ':');
+ if (!modifier)
+ modifier = strrchr(name, '/');
+ if (!modifier) {
+ ret = -EINVAL;
+ goto out;
+ }
+ *modifier = '\0';
+ if (asprintf(event, "%s/name=tpebs_event_%p/%s", name, evsel, modifier + 1) > 0)
+ ret = 0;
+ else
+ ret = -ENOMEM;
+out:
+ if (ret)
+ pr_err("Tpebs event modifier broken '%s'\n", evsel->name);
+ free(name);
+ return ret;
}
static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
{
struct tpebs_retire_lat *result = zalloc(sizeof(*result));
+ int ret;
if (!result)
return NULL;
- result->tpebs_name = evsel->name;
- result->name = evsel__tpebs_name(evsel);
- if (!result->name) {
+ ret = evsel__tpebs_event(evsel, &result->event);
+ if (ret) {
free(result);
return NULL;
}
+ result->evsel = evsel;
list_add_tail(&result->nd, &tpebs_results);
return result;
}
+static void tpebs_retire_lat__delete(struct tpebs_retire_lat *r)
+{
+ zfree(&r->event);
+ free(r);
+}
+
static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel)
{
struct tpebs_retire_lat *t;
+ uint64_t num;
+ const char *evsel_name;
+ /*
+ * Evsels will match for evlist with the retirement latency event. The
+ * name with "tpebs_event_" prefix will be present on events being read
+ * from `perf record`.
+ */
+ if (evsel__is_retire_lat(evsel)) {
+ list_for_each_entry(t, &tpebs_results, nd) {
+ if (t->evsel == evsel)
+ return t;
+ }
+ return NULL;
+ }
+ evsel_name = strstr(evsel->name, "tpebs_event_");
+ if (!evsel_name) {
+ /* Unexpected that the perf record should have other events. */
+ return NULL;
+ }
+ errno = 0;
+ num = strtoull(evsel_name + 12, NULL, 16);
+ if (errno) {
+ pr_err("Bad evsel for tpebs find '%s'\n", evsel->name);
+ return NULL;
+ }
list_for_each_entry(t, &tpebs_results, nd) {
- if (t->tpebs_name == evsel->name ||
- !strcmp(t->tpebs_name, evsel->name) ||
- (evsel->metric_id && !strcmp(t->tpebs_name, evsel->metric_id)))
+ if ((uint64_t)t->evsel == num)
return t;
}
return NULL;
@@ -363,8 +406,12 @@ int evsel__tpebs_open(struct evsel *evsel)
close(ack_fd[0]);
close(ack_fd[1]);
}
- if (ret)
- tpebs_delete();
+ if (ret) {
+ struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
+
+ list_del_init(&t->nd);
+ tpebs_retire_lat__delete(t);
+ }
return ret;
}
@@ -414,34 +461,19 @@ int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread)
return 0;
}
-static void tpebs_retire_lat__delete(struct tpebs_retire_lat *r)
-{
- zfree(&r->name);
- free(r);
-}
-
-
-/*
- * tpebs_delete - delete tpebs related data and stop the created thread and
- * process by calling tpebs_stop().
- *
- * This function is called from evlist_delete() and also from builtin-stat
- * stat_handle_error(). If tpebs_start() is called from places other then perf
- * stat, need to ensure tpebs_delete() is also called to safely free mem and
- * close the data read thread and the forked perf record process.
+/**
+ * evsel__tpebs_close() - delete tpebs related data. If the last event, stop the
+ * created thread and process by calling tpebs_stop().
*
- * This function is also called in evsel__close() to be symmetric with
- * tpebs_start() being called in evsel__open(). We will update this call site
- * when move tpebs_start() to evlist level.
+ * This function is called in evsel__close() to be symmetric with
+ * evsel__tpebs_open() being called in evsel__open().
*/
-void tpebs_delete(void)
+void evsel__tpebs_close(struct evsel *evsel)
{
- struct tpebs_retire_lat *r, *rtmp;
+ struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
- tpebs_stop();
+ tpebs_retire_lat__delete(t);
- list_for_each_entry_safe(r, rtmp, &tpebs_results, nd) {
- list_del_init(&r->nd);
- tpebs_retire_lat__delete(r);
- }
+ if (list_empty(&tpebs_results))
+ tpebs_stop();
}
diff --git a/tools/perf/util/intel-tpebs.h b/tools/perf/util/intel-tpebs.h
index cc98203719c8..5c671181ec60 100644
--- a/tools/perf/util/intel-tpebs.h
+++ b/tools/perf/util/intel-tpebs.h
@@ -11,7 +11,7 @@ struct evsel;
extern bool tpebs_recording;
int evsel__tpebs_open(struct evsel *evsel);
-void tpebs_delete(void);
+void evsel__tpebs_close(struct evsel *evsel);
int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread);
#endif /* __INTEL_TPEBS_H */
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 10/16] perf intel-tpebs: Add support for updating counts in evsel__tpebs_read
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (8 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 09/16] perf intel-tpebs: Refactor tpebs_results list Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results Ian Rogers
` (6 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Rename to reflect evsel argument and for consistency with other tpebs
functions. Update count from prev_raw_counts when
available. Eventually this will allow inteval mode support.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evsel.c | 11 ++------
tools/perf/util/intel-tpebs.c | 52 ++++++++++++++---------------------
tools/perf/util/intel-tpebs.h | 2 +-
3 files changed, 25 insertions(+), 40 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 554252ed1aab..1d343f51225b 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1718,11 +1718,6 @@ static int evsel__read_one(struct evsel *evsel, int cpu_map_idx, int thread)
return perf_evsel__read(&evsel->core, cpu_map_idx, thread, count);
}
-static int evsel__read_retire_lat(struct evsel *evsel, int cpu_map_idx, int thread)
-{
- return tpebs_set_evsel(evsel, cpu_map_idx, thread);
-}
-
static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
u64 val, u64 ena, u64 run, u64 lost)
{
@@ -1730,8 +1725,8 @@ static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
count = perf_counts(counter->counts, cpu_map_idx, thread);
- if (counter->retire_lat) {
- evsel__read_retire_lat(counter, cpu_map_idx, thread);
+ if (evsel__is_retire_lat(counter)) {
+ evsel__tpebs_read(counter, cpu_map_idx, thread);
perf_counts__set_loaded(counter->counts, cpu_map_idx, thread, true);
return;
}
@@ -1889,7 +1884,7 @@ int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread)
return evsel__hwmon_pmu_read(evsel, cpu_map_idx, thread);
if (evsel__is_retire_lat(evsel))
- return evsel__read_retire_lat(evsel, cpu_map_idx, thread);
+ return evsel__tpebs_read(evsel, cpu_map_idx, thread);
if (evsel->core.attr.read_format & PERF_FORMAT_GROUP)
return evsel__read_group(evsel, cpu_map_idx, thread);
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index a723687e67f6..f648fca17556 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -415,49 +415,39 @@ int evsel__tpebs_open(struct evsel *evsel)
return ret;
}
-
-int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread)
+int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
{
- __u64 val;
+ struct perf_counts_values *count, *old_count = NULL;
struct tpebs_retire_lat *t;
- struct perf_counts_values *count;
+ uint64_t val;
+
+ /* Only set retire_latency value to the first CPU and thread. */
+ if (cpu_map_idx != 0 || thread != 0)
+ return 0;
+
+ if (evsel->prev_raw_counts)
+ old_count = perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread);
- /* Non reitre_latency evsel should never enter this function. */
- if (!evsel__is_retire_lat(evsel))
- return -1;
+ count = perf_counts(evsel->counts, cpu_map_idx, thread);
/*
* Need to stop the forked record to ensure get sampled data from the
* PIPE to process and get non-zero retire_lat value for hybrid.
*/
tpebs_stop();
- count = perf_counts(evsel->counts, cpu_map_idx, thread);
t = tpebs_retire_lat__find(evsel);
-
- /* Set ena and run to non-zero */
- count->ena = count->run = 1;
- count->lost = 0;
-
- if (!t) {
- /*
- * Set default value or 0 when retire_latency for this event is
- * not found from sampling data (record_tpebs not set or 0
- * sample recorded).
- */
- count->val = 0;
- return 0;
+ val = rint(t->val);
+
+ if (old_count) {
+ count->val = old_count->val + val;
+ count->run = old_count->run + 1;
+ count->ena = old_count->ena + 1;
+ } else {
+ count->val = val;
+ count->run++;
+ count->ena++;
}
-
- /*
- * Only set retire_latency value to the first CPU and thread.
- */
- if (cpu_map_idx == 0 && thread == 0)
- val = rint(t->val);
- else
- val = 0;
-
- count->val = val;
return 0;
}
diff --git a/tools/perf/util/intel-tpebs.h b/tools/perf/util/intel-tpebs.h
index 5c671181ec60..218a82866cee 100644
--- a/tools/perf/util/intel-tpebs.h
+++ b/tools/perf/util/intel-tpebs.h
@@ -12,6 +12,6 @@ extern bool tpebs_recording;
int evsel__tpebs_open(struct evsel *evsel);
void evsel__tpebs_close(struct evsel *evsel);
-int tpebs_set_evsel(struct evsel *evsel, int cpu_map_idx, int thread);
+int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread);
#endif /* __INTEL_TPEBS_H */
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (9 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 10/16] perf intel-tpebs: Add support for updating counts in evsel__tpebs_read Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-11 22:54 ` Namhyung Kim
2025-04-09 6:10 ` [PATCH v4 12/16] perf intel-tpebs: Don't close record on read Ian Rogers
` (5 subsequent siblings)
16 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Ensure sample reader isn't racing with events being added/removed.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 51 ++++++++++++++++++++++++++++++-----
1 file changed, 44 insertions(+), 7 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index f648fca17556..c5ccdbc42dc6 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -16,6 +16,7 @@
#include "debug.h"
#include "evlist.h"
#include "evsel.h"
+#include "mutex.h"
#include "session.h"
#include "tool.h"
#include "cpumap.h"
@@ -32,6 +33,7 @@ bool tpebs_recording;
static LIST_HEAD(tpebs_results);
static pthread_t tpebs_reader_thread;
static struct child_process tpebs_cmd;
+static struct mutex tpebs_mtx;
struct tpebs_retire_lat {
struct list_head nd;
@@ -51,6 +53,19 @@ struct tpebs_retire_lat {
static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel);
+static void tpebs_mtx_init(void)
+{
+ mutex_init(&tpebs_mtx);
+}
+
+static struct mutex *tpebs_mtx_get(void)
+{
+ static pthread_once_t tpebs_mtx_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&tpebs_mtx_once, tpebs_mtx_init);
+ return &tpebs_mtx;
+}
+
static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
{
const char **record_argv;
@@ -59,13 +74,15 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
char cpumap_buf[50];
struct tpebs_retire_lat *t;
+ mutex_lock(tpebs_mtx_get());
list_for_each_entry(t, &tpebs_results, nd)
tpebs_event_size++;
record_argv = malloc((10 + 2 * tpebs_event_size) * sizeof(*record_argv));
- if (!record_argv)
+ if (!record_argv) {
+ mutex_unlock(tpebs_mtx_get());
return -ENOMEM;
-
+ }
record_argv[i++] = "perf";
record_argv[i++] = "record";
record_argv[i++] = "-W";
@@ -101,6 +118,7 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
list_for_each_entry(t, &tpebs_results, nd)
t->started = true;
+ mutex_unlock(tpebs_mtx_get());
return ret;
}
@@ -112,9 +130,12 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
{
struct tpebs_retire_lat *t;
+ mutex_lock(tpebs_mtx_get());
t = tpebs_retire_lat__find(evsel);
- if (!t)
+ if (!t) {
+ mutex_unlock(tpebs_mtx_get());
return -EINVAL;
+ }
/*
* Need to handle per core results? We are assuming average retire
* latency value will be used. Save the number of samples and the sum of
@@ -123,6 +144,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
t->count += 1;
t->sum += sample->retire_lat;
t->val = (double) t->sum / t->count;
+ mutex_unlock(tpebs_mtx_get());
return 0;
}
@@ -229,7 +251,6 @@ static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
return NULL;
}
result->evsel = evsel;
- list_add_tail(&result->nd, &tpebs_results);
return result;
}
@@ -282,16 +303,22 @@ static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel)
static int evsel__tpebs_prepare(struct evsel *evsel)
{
struct evsel *pos;
- struct tpebs_retire_lat *tpebs_event = tpebs_retire_lat__find(evsel);
+ struct tpebs_retire_lat *tpebs_event;
+ mutex_lock(tpebs_mtx_get());
+ tpebs_event = tpebs_retire_lat__find(evsel);
if (tpebs_event) {
/* evsel, or an identically named one, was already prepared. */
+ mutex_unlock(tpebs_mtx_get());
return 0;
}
tpebs_event = tpebs_retire_lat__new(evsel);
if (!tpebs_event)
return -ENOMEM;
+ list_add_tail(&tpebs_event->nd, &tpebs_results);
+ mutex_unlock(tpebs_mtx_get());
+
/*
* Eagerly prepare all other evsels on the list to try to ensure that by
* open they are all known.
@@ -317,6 +344,7 @@ static int evsel__tpebs_prepare(struct evsel *evsel)
int evsel__tpebs_open(struct evsel *evsel)
{
int ret;
+ bool tpebs_empty;
/* We should only run tpebs_start when tpebs_recording is enabled. */
if (!tpebs_recording)
@@ -336,7 +364,10 @@ int evsel__tpebs_open(struct evsel *evsel)
if (ret)
return ret;
- if (!list_empty(&tpebs_results)) {
+ mutex_lock(tpebs_mtx_get());
+ tpebs_empty = list_empty(&tpebs_results);
+ mutex_unlock(tpebs_mtx_get());
+ if (!tpebs_empty) {
struct pollfd pollfd = { .events = POLLIN, };
int control_fd[2], ack_fd[2], len;
char ack_buf[8];
@@ -436,8 +467,10 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
*/
tpebs_stop();
+ mutex_lock(tpebs_mtx_get());
t = tpebs_retire_lat__find(evsel);
val = rint(t->val);
+ mutex_unlock(tpebs_mtx_get());
if (old_count) {
count->val = old_count->val + val;
@@ -460,9 +493,13 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
*/
void evsel__tpebs_close(struct evsel *evsel)
{
- struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
+ struct tpebs_retire_lat *t;
+ mutex_lock(tpebs_mtx_get());
+ t = tpebs_retire_lat__find(evsel);
+ list_del_init(&t->nd);
tpebs_retire_lat__delete(t);
+ mutex_unlock(tpebs_mtx_get());
if (list_empty(&tpebs_results))
tpebs_stop();
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 12/16] perf intel-tpebs: Don't close record on read
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (10 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 13/16] perf intel-tpebs: Use stats for retirement latency statistics Ian Rogers
` (4 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Factor sending record control fd code into its own function. Rather
than killing the record process send it a ping when reading. Timeouts
were witnessed if done too frequently, so only ping for the first
tpebs events. Don't kill the record command send it a stop command. As
close isn't reliably called also close on evsel__exit. Add extra
checks on the record being terminated to avoid warnings. Adjust the
locking as needed and incorporate extra -Wthread-safety checks. Check
to do six 500ms poll timeouts when sending commands, rather than the
larger 3000ms, to allow the record process terminating to be better
witnessed.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evsel.c | 2 +
tools/perf/util/intel-tpebs.c | 205 +++++++++++++++++++++-------------
2 files changed, 132 insertions(+), 75 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1d343f51225b..661a07cbdb25 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1656,6 +1656,8 @@ void evsel__exit(struct evsel *evsel)
{
assert(list_empty(&evsel->core.node));
assert(evsel->evlist == NULL);
+ if (evsel__is_retire_lat(evsel))
+ evsel__tpebs_close(evsel);
bpf_counter__destroy(evsel);
perf_bpf_filter__destroy(evsel);
evsel__free_counts(evsel);
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index c5ccdbc42dc6..a9446e7a1c5c 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -33,6 +33,7 @@ bool tpebs_recording;
static LIST_HEAD(tpebs_results);
static pthread_t tpebs_reader_thread;
static struct child_process tpebs_cmd;
+static int control_fd[2], ack_fd[2];
static struct mutex tpebs_mtx;
struct tpebs_retire_lat {
@@ -51,8 +52,6 @@ struct tpebs_retire_lat {
bool started;
};
-static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel);
-
static void tpebs_mtx_init(void)
{
mutex_init(&tpebs_mtx);
@@ -66,7 +65,10 @@ static struct mutex *tpebs_mtx_get(void)
return &tpebs_mtx;
}
-static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
+static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel)
+ EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get());
+
+static int evsel__tpebs_start_perf_record(struct evsel *evsel)
{
const char **record_argv;
int tpebs_event_size = 0, i = 0, ret;
@@ -74,15 +76,13 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
char cpumap_buf[50];
struct tpebs_retire_lat *t;
- mutex_lock(tpebs_mtx_get());
list_for_each_entry(t, &tpebs_results, nd)
tpebs_event_size++;
record_argv = malloc((10 + 2 * tpebs_event_size) * sizeof(*record_argv));
- if (!record_argv) {
- mutex_unlock(tpebs_mtx_get());
+ if (!record_argv)
return -ENOMEM;
- }
+
record_argv[i++] = "perf";
record_argv[i++] = "record";
record_argv[i++] = "-W";
@@ -118,7 +118,6 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
list_for_each_entry(t, &tpebs_results, nd)
t->started = true;
- mutex_unlock(tpebs_mtx_get());
return ret;
}
@@ -131,6 +130,11 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
struct tpebs_retire_lat *t;
mutex_lock(tpebs_mtx_get());
+ if (tpebs_cmd.pid == 0) {
+ /* Record has terminated. */
+ mutex_unlock(tpebs_mtx_get());
+ return 0;
+ }
t = tpebs_retire_lat__find(evsel);
if (!t) {
mutex_unlock(tpebs_mtx_get());
@@ -180,17 +184,98 @@ static void *__sample_reader(void *arg __maybe_unused)
return NULL;
}
+static int tpebs_send_record_cmd(const char *msg) EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get())
+{
+ struct pollfd pollfd = { .events = POLLIN, };
+ int ret, len, retries = 0;
+ char ack_buf[8];
+
+ /* Check if the command exited before the send, done with the lock held. */
+ if (tpebs_cmd.pid == 0)
+ return 0;
+
+ /*
+ * Let go of the lock while sending/receiving as blocking can starve the
+ * sample reading thread.
+ */
+ mutex_unlock(tpebs_mtx_get());
+
+ /* Send perf record command.*/
+ len = strlen(msg);
+ ret = write(control_fd[1], msg, len);
+ if (ret != len) {
+ pr_err("perf record control write control message '%s' failed\n", msg);
+ ret = -EPIPE;
+ goto out;
+ }
+
+ if (!strcmp(msg, EVLIST_CTL_CMD_STOP_TAG)) {
+ ret = 0;
+ goto out;
+ }
+
+ /* Wait for an ack. */
+ pollfd.fd = ack_fd[0];
+
+ /*
+ * We need this poll to ensure the ack_fd PIPE will not hang
+ * when perf record failed for any reason. The timeout value
+ * 3000ms is an empirical selection.
+ */
+again:
+ if (!poll(&pollfd, 1, 500)) {
+ if (check_if_command_finished(&tpebs_cmd)) {
+ ret = 0;
+ goto out;
+ }
+
+ if (retries++ < 6)
+ goto again;
+ pr_err("tpebs failed: perf record ack timeout for '%s'\n", msg);
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ if (!(pollfd.revents & POLLIN)) {
+ if (check_if_command_finished(&tpebs_cmd)) {
+ ret = 0;
+ goto out;
+ }
+
+ pr_err("tpebs failed: did not received an ack for '%s'\n", msg);
+ ret = -EPIPE;
+ goto out;
+ }
+
+ ret = read(ack_fd[0], ack_buf, sizeof(ack_buf));
+ if (ret > 0)
+ ret = strcmp(ack_buf, EVLIST_CTL_CMD_ACK_TAG);
+ else
+ pr_err("tpebs: perf record control ack failed\n");
+out:
+ /* Re-take lock as expected by caller. */
+ mutex_lock(tpebs_mtx_get());
+ return ret;
+}
+
/*
* tpebs_stop - stop the sample data read thread and the perf record process.
*/
-static int tpebs_stop(void)
+static int tpebs_stop(void) EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get())
{
int ret = 0;
/* Like tpebs_start, we should only run tpebs_end once. */
if (tpebs_cmd.pid != 0) {
- kill(tpebs_cmd.pid, SIGTERM);
+ tpebs_send_record_cmd(EVLIST_CTL_CMD_STOP_TAG);
+ tpebs_cmd.pid = 0;
+ mutex_unlock(tpebs_mtx_get());
pthread_join(tpebs_reader_thread, NULL);
+ mutex_lock(tpebs_mtx_get());
+ close(control_fd[0]);
+ close(control_fd[1]);
+ close(ack_fd[0]);
+ close(ack_fd[1]);
close(tpebs_cmd.out);
ret = finish_command(&tpebs_cmd);
tpebs_cmd.pid = 0;
@@ -313,9 +398,10 @@ static int evsel__tpebs_prepare(struct evsel *evsel)
return 0;
}
tpebs_event = tpebs_retire_lat__new(evsel);
- if (!tpebs_event)
+ if (!tpebs_event) {
+ mutex_unlock(tpebs_mtx_get());
return -ENOMEM;
-
+ }
list_add_tail(&tpebs_event->nd, &tpebs_results);
mutex_unlock(tpebs_mtx_get());
@@ -351,13 +437,15 @@ int evsel__tpebs_open(struct evsel *evsel)
return 0;
/* Only start the events once. */
if (tpebs_cmd.pid != 0) {
- struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
+ struct tpebs_retire_lat *t;
+ bool valid;
- if (!t || !t->started) {
- /* Fail, as the event wasn't started. */
- return -EBUSY;
- }
- return 0;
+ mutex_lock(tpebs_mtx_get());
+ t = tpebs_retire_lat__find(evsel);
+ valid = t && t->started;
+ mutex_unlock(tpebs_mtx_get());
+ /* May fail as the event wasn't started. */
+ return valid ? 0 : -EBUSY;
}
ret = evsel__tpebs_prepare(evsel);
@@ -366,12 +454,7 @@ int evsel__tpebs_open(struct evsel *evsel)
mutex_lock(tpebs_mtx_get());
tpebs_empty = list_empty(&tpebs_results);
- mutex_unlock(tpebs_mtx_get());
if (!tpebs_empty) {
- struct pollfd pollfd = { .events = POLLIN, };
- int control_fd[2], ack_fd[2], len;
- char ack_buf[8];
-
/*Create control and ack fd for --control*/
if (pipe(control_fd) < 0) {
pr_err("tpebs: Failed to create control fifo");
@@ -384,7 +467,7 @@ int evsel__tpebs_open(struct evsel *evsel)
goto out;
}
- ret = evsel__tpebs_start_perf_record(evsel, control_fd, ack_fd);
+ ret = evsel__tpebs_start_perf_record(evsel);
if (ret)
goto out;
@@ -396,53 +479,16 @@ int evsel__tpebs_open(struct evsel *evsel)
ret = -1;
goto out;
}
- /* Wait for perf record initialization.*/
- len = strlen(EVLIST_CTL_CMD_ENABLE_TAG);
- ret = write(control_fd[1], EVLIST_CTL_CMD_ENABLE_TAG, len);
- if (ret != len) {
- pr_err("perf record control write control message failed\n");
- goto out;
- }
-
- /* wait for an ack */
- pollfd.fd = ack_fd[0];
-
- /*
- * We need this poll to ensure the ack_fd PIPE will not hang
- * when perf record failed for any reason. The timeout value
- * 3000ms is an empirical selection.
- */
- if (!poll(&pollfd, 1, 3000)) {
- pr_err("tpebs failed: perf record ack timeout\n");
- ret = -1;
- goto out;
- }
-
- if (!(pollfd.revents & POLLIN)) {
- pr_err("tpebs failed: did not received an ack\n");
- ret = -1;
- goto out;
- }
-
- ret = read(ack_fd[0], ack_buf, sizeof(ack_buf));
- if (ret > 0)
- ret = strcmp(ack_buf, EVLIST_CTL_CMD_ACK_TAG);
- else {
- pr_err("tpebs: perf record control ack failed\n");
- goto out;
- }
-out:
- close(control_fd[0]);
- close(control_fd[1]);
- close(ack_fd[0]);
- close(ack_fd[1]);
+ ret = tpebs_send_record_cmd(EVLIST_CTL_CMD_ENABLE_TAG);
}
+out:
if (ret) {
struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
list_del_init(&t->nd);
tpebs_retire_lat__delete(t);
}
+ mutex_unlock(tpebs_mtx_get());
return ret;
}
@@ -451,6 +497,7 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
struct perf_counts_values *count, *old_count = NULL;
struct tpebs_retire_lat *t;
uint64_t val;
+ int ret;
/* Only set retire_latency value to the first CPU and thread. */
if (cpu_map_idx != 0 || thread != 0)
@@ -461,14 +508,20 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
count = perf_counts(evsel->counts, cpu_map_idx, thread);
- /*
- * Need to stop the forked record to ensure get sampled data from the
- * PIPE to process and get non-zero retire_lat value for hybrid.
- */
- tpebs_stop();
-
mutex_lock(tpebs_mtx_get());
t = tpebs_retire_lat__find(evsel);
+ /*
+ * If reading the first tpebs result, send a ping to the record
+ * process. Allow the sample reader a chance to read by releasing and
+ * reacquiring the lock.
+ */
+ if (&t->nd == tpebs_results.next) {
+ ret = tpebs_send_record_cmd(EVLIST_CTL_CMD_PING_TAG);
+ mutex_unlock(tpebs_mtx_get());
+ if (ret)
+ return ret;
+ mutex_lock(tpebs_mtx_get());
+ }
val = rint(t->val);
mutex_unlock(tpebs_mtx_get());
@@ -497,10 +550,12 @@ void evsel__tpebs_close(struct evsel *evsel)
mutex_lock(tpebs_mtx_get());
t = tpebs_retire_lat__find(evsel);
- list_del_init(&t->nd);
- tpebs_retire_lat__delete(t);
- mutex_unlock(tpebs_mtx_get());
+ if (t) {
+ list_del_init(&t->nd);
+ tpebs_retire_lat__delete(t);
- if (list_empty(&tpebs_results))
- tpebs_stop();
+ if (list_empty(&tpebs_results))
+ tpebs_stop();
+ }
+ mutex_unlock(tpebs_mtx_get());
}
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 13/16] perf intel-tpebs: Use stats for retirement latency statistics
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (11 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 12/16] perf intel-tpebs: Don't close record on read Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 14/16] perf stat: Add mean, min, max and last --tpebs-mode options Ian Rogers
` (3 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
struct stats provides access to mean, min and max. It also provides
uniformity with statistics code used elsewhere in perf.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/intel-tpebs.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index a9446e7a1c5c..de9fea601964 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -18,6 +18,7 @@
#include "evsel.h"
#include "mutex.h"
#include "session.h"
+#include "stat.h"
#include "tool.h"
#include "cpumap.h"
#include "metricgroup.h"
@@ -42,12 +43,8 @@ struct tpebs_retire_lat {
struct evsel *evsel;
/** @event: Event passed to perf record. */
char *event;
- /* Count of retire_latency values found in sample data */
- size_t count;
- /* Sum of all the retire_latency values in sample data */
- int sum;
- /* Average of retire_latency, val = sum / count */
- double val;
+ /** @stats: Recorded retirement latency stats. */
+ struct stats stats;
/* Has the event been sent to perf record? */
bool started;
};
@@ -145,9 +142,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
* latency value will be used. Save the number of samples and the sum of
* retire latency value for each event.
*/
- t->count += 1;
- t->sum += sample->retire_lat;
- t->val = (double) t->sum / t->count;
+ update_stats(&t->stats, sample->retire_lat);
mutex_unlock(tpebs_mtx_get());
return 0;
}
@@ -522,7 +517,7 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
return ret;
mutex_lock(tpebs_mtx_get());
}
- val = rint(t->val);
+ val = rint(t->stats.mean);
mutex_unlock(tpebs_mtx_get());
if (old_count) {
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 14/16] perf stat: Add mean, min, max and last --tpebs-mode options
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (12 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 13/16] perf intel-tpebs: Use stats for retirement latency statistics Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 15/16] perf pmu-events: Add retirement latency to JSON events inside of perf Ian Rogers
` (2 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Add command line configuration option for how retirement latency
events are combined. The default "mean" gives the average of
retirement latency. "min" or "max" give the smallest or largest
retirment latency times respectively. "last" uses the last retirment
latency sample's time.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Documentation/perf-stat.txt | 7 +++++++
tools/perf/builtin-stat.c | 27 ++++++++++++++++++++++++++
tools/perf/util/intel-tpebs.c | 20 ++++++++++++++++++-
tools/perf/util/intel-tpebs.h | 8 ++++++++
4 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 2bc063672486..61d091670dee 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -506,6 +506,13 @@ this option is not set. The TPEBS hardware feature starts from Intel Granite
Rapids microarchitecture. This option only exists in X86_64 and is meaningful on
Intel platforms with TPEBS feature.
+--tpebs-mode=[mean|min|max|last]::
+Set how retirement latency events have their sample times
+combined. The default "mean" gives the average of retirement
+latency. "min" or "max" give the smallest or largest retirment latency
+times respectively. "last" uses the last retirment latency sample's
+time.
+
--td-level::
Print the top-down statistics that equal the input level. It allows
users to print the interested top-down metrics level instead of the
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 80e491bd775b..4adf2ae53b11 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2327,6 +2327,30 @@ static void setup_system_wide(int forks)
}
}
+static int parse_tpebs_mode(const struct option *opt, const char *str,
+ int unset __maybe_unused)
+{
+ enum tpebs_mode *mode = opt->value;
+
+ if (!strcasecmp("mean", str)) {
+ *mode = TPEBS_MODE__MEAN;
+ return 0;
+ }
+ if (!strcasecmp("min", str)) {
+ *mode = TPEBS_MODE__MIN;
+ return 0;
+ }
+ if (!strcasecmp("max", str)) {
+ *mode = TPEBS_MODE__MAX;
+ return 0;
+ }
+ if (!strcasecmp("last", str)) {
+ *mode = TPEBS_MODE__LAST;
+ return 0;
+ }
+ return -1;
+}
+
int cmd_stat(int argc, const char **argv)
{
struct opt_aggr_mode opt_mode = {};
@@ -2431,6 +2455,9 @@ int cmd_stat(int argc, const char **argv)
#ifdef HAVE_ARCH_X86_64_SUPPORT
OPT_BOOLEAN(0, "record-tpebs", &tpebs_recording,
"enable recording for tpebs when retire_latency required"),
+ OPT_CALLBACK(0, "tpebs-mode", &tpebs_mode, "tpebs-mode",
+ "Mode of TPEBS recording: mean, min or max",
+ parse_tpebs_mode),
#endif
OPT_UINTEGER(0, "td-level", &stat_config.topdown_level,
"Set the metrics level for the top-down statistics (0: max level)"),
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index de9fea601964..6b00bd5b0af1 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -31,6 +31,7 @@
#define PERF_DATA "-"
bool tpebs_recording;
+enum tpebs_mode tpebs_mode;
static LIST_HEAD(tpebs_results);
static pthread_t tpebs_reader_thread;
static struct child_process tpebs_cmd;
@@ -45,6 +46,8 @@ struct tpebs_retire_lat {
char *event;
/** @stats: Recorded retirement latency stats. */
struct stats stats;
+ /** @last: Last retirement latency read. */
+ uint64_t last;
/* Has the event been sent to perf record? */
bool started;
};
@@ -142,6 +145,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
* latency value will be used. Save the number of samples and the sum of
* retire latency value for each event.
*/
+ t->last = sample->retire_lat;
update_stats(&t->stats, sample->retire_lat);
mutex_unlock(tpebs_mtx_get());
return 0;
@@ -517,7 +521,21 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
return ret;
mutex_lock(tpebs_mtx_get());
}
- val = rint(t->stats.mean);
+ switch (tpebs_mode) {
+ case TPEBS_MODE__MIN:
+ val = rint(t->stats.min);
+ break;
+ case TPEBS_MODE__MAX:
+ val = rint(t->stats.max);
+ break;
+ case TPEBS_MODE__LAST:
+ val = t->last;
+ break;
+ default:
+ case TPEBS_MODE__MEAN:
+ val = rint(t->stats.mean);
+ break;
+ }
mutex_unlock(tpebs_mtx_get());
if (old_count) {
diff --git a/tools/perf/util/intel-tpebs.h b/tools/perf/util/intel-tpebs.h
index 218a82866cee..9475e2e6ea74 100644
--- a/tools/perf/util/intel-tpebs.h
+++ b/tools/perf/util/intel-tpebs.h
@@ -8,7 +8,15 @@
struct evlist;
struct evsel;
+enum tpebs_mode {
+ TPEBS_MODE__MEAN,
+ TPEBS_MODE__MIN,
+ TPEBS_MODE__MAX,
+ TPEBS_MODE__LAST,
+};
+
extern bool tpebs_recording;
+extern enum tpebs_mode tpebs_mode;
int evsel__tpebs_open(struct evsel *evsel);
void evsel__tpebs_close(struct evsel *evsel);
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 15/16] perf pmu-events: Add retirement latency to JSON events inside of perf
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (13 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 14/16] perf stat: Add mean, min, max and last --tpebs-mode options Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 16/16] perf record: Retirement latency cleanup in evsel__config Ian Rogers
2025-04-11 23:09 ` [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Namhyung Kim
16 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
The updated Intel vendor events add retirement latency for
graniterapids:
https://lore.kernel.org/lkml/20250322063403.364981-14-irogers@google.com/
This change makes those values available within an alias/event within
a PMU and saves them into the evsel at event parse time. When no TPEBS
data is available the default values are substituted in for TMA
metrics that are using retirement latency events - currently just
those on graniterapids.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/pmu-events/empty-pmu-events.c | 216 ++++++++++++-----------
tools/perf/pmu-events/jevents.py | 6 +
tools/perf/pmu-events/pmu-events.h | 3 +
tools/perf/util/evsel.h | 6 +
tools/perf/util/intel-tpebs.c | 52 ++++--
tools/perf/util/parse-events.c | 4 +
tools/perf/util/pmu.c | 52 +++++-
tools/perf/util/pmu.h | 3 +
8 files changed, 220 insertions(+), 122 deletions(-)
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 0cb7ba7912e8..0361bcc1eb58 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -20,73 +20,73 @@ struct pmu_table_entry {
static const char *const big_c_string =
/* offset=0 */ "tool\000"
-/* offset=5 */ "duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000"
-/* offset=78 */ "user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000"
-/* offset=145 */ "system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000"
-/* offset=210 */ "has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000"
-/* offset=283 */ "num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000"
-/* offset=425 */ "num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000"
-/* offset=525 */ "num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000"
-/* offset=639 */ "num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000"
-/* offset=712 */ "num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000"
-/* offset=795 */ "slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000"
-/* offset=902 */ "smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000"
-/* offset=1006 */ "system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000"
-/* offset=1102 */ "default_core\000"
-/* offset=1115 */ "bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000"
-/* offset=1174 */ "bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000"
-/* offset=1233 */ "l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000Attributable Level 3 cache access, read\000"
-/* offset=1328 */ "segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000"
-/* offset=1427 */ "dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000"
-/* offset=1557 */ "eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000"
-/* offset=1672 */ "hisi_sccl,ddrc\000"
-/* offset=1687 */ "uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000DDRC write commands\000"
-/* offset=1773 */ "uncore_cbox\000"
-/* offset=1785 */ "unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000"
-/* offset=2016 */ "event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000UNC_CBO_HYPHEN\000"
-/* offset=2081 */ "event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000UNC_CBO_TWO_HYPH\000"
-/* offset=2152 */ "hisi_sccl,l3c\000"
-/* offset=2166 */ "uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000Total read hits\000"
-/* offset=2246 */ "uncore_imc_free_running\000"
-/* offset=2270 */ "uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000Total cache misses\000"
-/* offset=2365 */ "uncore_imc\000"
-/* offset=2376 */ "uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000Total cache hits\000"
-/* offset=2454 */ "uncore_sys_ddr_pmu\000"
-/* offset=2473 */ "sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000"
-/* offset=2546 */ "uncore_sys_ccn_pmu\000"
-/* offset=2565 */ "sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000"
-/* offset=2639 */ "uncore_sys_cmn_pmu\000"
-/* offset=2658 */ "sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000"
-/* offset=2798 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000"
-/* offset=2820 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000"
-/* offset=2883 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000"
-/* offset=3049 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000"
-/* offset=3113 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000"
-/* offset=3180 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000"
-/* offset=3251 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000"
-/* offset=3345 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000"
-/* offset=3479 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000"
-/* offset=3543 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000"
-/* offset=3611 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000"
-/* offset=3681 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\00000"
-/* offset=3703 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\00000"
-/* offset=3725 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\00000"
-/* offset=3745 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000"
+/* offset=5 */ "duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000\000\000\000"
+/* offset=81 */ "user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000\000\000\000"
+/* offset=151 */ "system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000\000\000\000"
+/* offset=219 */ "has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000\000\000\000"
+/* offset=295 */ "num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000\000\000\000"
+/* offset=440 */ "num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000\000\000\000"
+/* offset=543 */ "num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000\000\000\000"
+/* offset=660 */ "num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000\000\000\000"
+/* offset=736 */ "num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000\000\000\000"
+/* offset=822 */ "slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000\000\000\000"
+/* offset=932 */ "smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000\000\000\000"
+/* offset=1039 */ "system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000\000\000\000"
+/* offset=1138 */ "default_core\000"
+/* offset=1151 */ "bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000\000\000\000"
+/* offset=1213 */ "bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000\000\000\000"
+/* offset=1275 */ "l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000\000\000\000Attributable Level 3 cache access, read\000"
+/* offset=1373 */ "segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000\000\000\000"
+/* offset=1475 */ "dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000\000\000\000"
+/* offset=1608 */ "eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000\000\000\000"
+/* offset=1726 */ "hisi_sccl,ddrc\000"
+/* offset=1741 */ "uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000\000\000\000DDRC write commands\000"
+/* offset=1830 */ "uncore_cbox\000"
+/* offset=1842 */ "unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000\000\000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000"
+/* offset=2076 */ "event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000\000\000\000UNC_CBO_HYPHEN\000"
+/* offset=2144 */ "event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000\000\000\000UNC_CBO_TWO_HYPH\000"
+/* offset=2218 */ "hisi_sccl,l3c\000"
+/* offset=2232 */ "uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000\000\000\000Total read hits\000"
+/* offset=2315 */ "uncore_imc_free_running\000"
+/* offset=2339 */ "uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000\000\000\000Total cache misses\000"
+/* offset=2437 */ "uncore_imc\000"
+/* offset=2448 */ "uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000\000\000\000Total cache hits\000"
+/* offset=2529 */ "uncore_sys_ddr_pmu\000"
+/* offset=2548 */ "sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000\000\000\000"
+/* offset=2624 */ "uncore_sys_ccn_pmu\000"
+/* offset=2643 */ "sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000\000\000\000"
+/* offset=2720 */ "uncore_sys_cmn_pmu\000"
+/* offset=2739 */ "sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000\000\000\000"
+/* offset=2882 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000"
+/* offset=2904 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000"
+/* offset=2967 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000"
+/* offset=3133 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000"
+/* offset=3197 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000"
+/* offset=3264 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000"
+/* offset=3335 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000"
+/* offset=3429 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000"
+/* offset=3563 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000"
+/* offset=3627 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000"
+/* offset=3695 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000"
+/* offset=3765 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\00000"
+/* offset=3787 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\00000"
+/* offset=3809 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\00000"
+/* offset=3829 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000"
;
static const struct compact_pmu_event pmu_events__common_tool[] = {
-{ 5 }, /* duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000 */
-{ 210 }, /* has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000 */
-{ 283 }, /* num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000 */
-{ 425 }, /* num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000 */
-{ 525 }, /* num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000 */
-{ 639 }, /* num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000 */
-{ 712 }, /* num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000 */
-{ 795 }, /* slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000 */
-{ 902 }, /* smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000 */
-{ 145 }, /* system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000 */
-{ 1006 }, /* system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000 */
-{ 78 }, /* user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000 */
+{ 5 }, /* duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000\000\000\000 */
+{ 219 }, /* has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000\000\000\000 */
+{ 295 }, /* num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000\000\000\000 */
+{ 440 }, /* num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000\000\000\000 */
+{ 543 }, /* num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000\000\000\000 */
+{ 660 }, /* num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000\000\000\000 */
+{ 736 }, /* num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000\000\000\000 */
+{ 822 }, /* slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000\000\000\000 */
+{ 932 }, /* smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000\000\000\000 */
+{ 151 }, /* system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000\000\000\000 */
+{ 1039 }, /* system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000\000\000\000 */
+{ 81 }, /* user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000\000\000\000 */
};
@@ -99,29 +99,29 @@ const struct pmu_table_entry pmu_events__common[] = {
};
static const struct compact_pmu_event pmu_events__test_soc_cpu_default_core[] = {
-{ 1115 }, /* bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000 */
-{ 1174 }, /* bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000 */
-{ 1427 }, /* dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000 */
-{ 1557 }, /* eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000 */
-{ 1233 }, /* l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000Attributable Level 3 cache access, read\000 */
-{ 1328 }, /* segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000 */
+{ 1151 }, /* bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000\000\000\000 */
+{ 1213 }, /* bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000\000\000\000 */
+{ 1475 }, /* dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000\000\000\000 */
+{ 1608 }, /* eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000\000\000\000 */
+{ 1275 }, /* l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000\000\000\000Attributable Level 3 cache access, read\000 */
+{ 1373 }, /* segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000\000\000\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_ddrc[] = {
-{ 1687 }, /* uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000DDRC write commands\000 */
+{ 1741 }, /* uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000\000\000\000DDRC write commands\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_l3c[] = {
-{ 2166 }, /* uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000Total read hits\000 */
+{ 2232 }, /* uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000\000\000\000Total read hits\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_cbox[] = {
-{ 2016 }, /* event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000UNC_CBO_HYPHEN\000 */
-{ 2081 }, /* event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000UNC_CBO_TWO_HYPH\000 */
-{ 1785 }, /* unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000 */
+{ 2076 }, /* event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000\000\000\000UNC_CBO_HYPHEN\000 */
+{ 2144 }, /* event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000\000\000\000UNC_CBO_TWO_HYPH\000 */
+{ 1842 }, /* unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000\000\000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc[] = {
-{ 2376 }, /* uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000Total cache hits\000 */
+{ 2448 }, /* uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000\000\000\000Total cache hits\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc_free_running[] = {
-{ 2270 }, /* uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000Total cache misses\000 */
+{ 2339 }, /* uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000\000\000\000Total cache misses\000 */
};
@@ -129,51 +129,51 @@ const struct pmu_table_entry pmu_events__test_soc_cpu[] = {
{
.entries = pmu_events__test_soc_cpu_default_core,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_default_core),
- .pmu_name = { 1102 /* default_core\000 */ },
+ .pmu_name = { 1138 /* default_core\000 */ },
},
{
.entries = pmu_events__test_soc_cpu_hisi_sccl_ddrc,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_ddrc),
- .pmu_name = { 1672 /* hisi_sccl,ddrc\000 */ },
+ .pmu_name = { 1726 /* hisi_sccl,ddrc\000 */ },
},
{
.entries = pmu_events__test_soc_cpu_hisi_sccl_l3c,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_l3c),
- .pmu_name = { 2152 /* hisi_sccl,l3c\000 */ },
+ .pmu_name = { 2218 /* hisi_sccl,l3c\000 */ },
},
{
.entries = pmu_events__test_soc_cpu_uncore_cbox,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_cbox),
- .pmu_name = { 1773 /* uncore_cbox\000 */ },
+ .pmu_name = { 1830 /* uncore_cbox\000 */ },
},
{
.entries = pmu_events__test_soc_cpu_uncore_imc,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc),
- .pmu_name = { 2365 /* uncore_imc\000 */ },
+ .pmu_name = { 2437 /* uncore_imc\000 */ },
},
{
.entries = pmu_events__test_soc_cpu_uncore_imc_free_running,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc_free_running),
- .pmu_name = { 2246 /* uncore_imc_free_running\000 */ },
+ .pmu_name = { 2315 /* uncore_imc_free_running\000 */ },
},
};
static const struct compact_pmu_event pmu_metrics__test_soc_cpu_default_core[] = {
-{ 2798 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000 */
-{ 3479 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000 */
-{ 3251 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000 */
-{ 3345 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000 */
-{ 3543 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000 */
-{ 3611 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000 */
-{ 2883 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000 */
-{ 2820 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000 */
-{ 3745 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000 */
-{ 3681 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\00000 */
-{ 3703 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\00000 */
-{ 3725 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\00000 */
-{ 3180 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000 */
-{ 3049 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */
-{ 3113 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */
+{ 2882 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000 */
+{ 3563 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000 */
+{ 3335 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000 */
+{ 3429 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000 */
+{ 3627 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000 */
+{ 3695 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000 */
+{ 2967 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000 */
+{ 2904 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000 */
+{ 3829 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000 */
+{ 3765 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\00000 */
+{ 3787 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\00000 */
+{ 3809 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\00000 */
+{ 3264 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000 */
+{ 3133 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */
+{ 3197 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */
};
@@ -181,18 +181,18 @@ const struct pmu_table_entry pmu_metrics__test_soc_cpu[] = {
{
.entries = pmu_metrics__test_soc_cpu_default_core,
.num_entries = ARRAY_SIZE(pmu_metrics__test_soc_cpu_default_core),
- .pmu_name = { 1102 /* default_core\000 */ },
+ .pmu_name = { 1138 /* default_core\000 */ },
},
};
static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ccn_pmu[] = {
-{ 2565 }, /* sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000 */
+{ 2643 }, /* sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000\000\000\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_cmn_pmu[] = {
-{ 2658 }, /* sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000 */
+{ 2739 }, /* sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000\000\000\000 */
};
static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ddr_pmu[] = {
-{ 2473 }, /* sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000 */
+{ 2548 }, /* sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000\000\000\000 */
};
@@ -200,17 +200,17 @@ const struct pmu_table_entry pmu_events__test_soc_sys[] = {
{
.entries = pmu_events__test_soc_sys_uncore_sys_ccn_pmu,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ccn_pmu),
- .pmu_name = { 2546 /* uncore_sys_ccn_pmu\000 */ },
+ .pmu_name = { 2624 /* uncore_sys_ccn_pmu\000 */ },
},
{
.entries = pmu_events__test_soc_sys_uncore_sys_cmn_pmu,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_cmn_pmu),
- .pmu_name = { 2639 /* uncore_sys_cmn_pmu\000 */ },
+ .pmu_name = { 2720 /* uncore_sys_cmn_pmu\000 */ },
},
{
.entries = pmu_events__test_soc_sys_uncore_sys_ddr_pmu,
.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ddr_pmu),
- .pmu_name = { 2454 /* uncore_sys_ddr_pmu\000 */ },
+ .pmu_name = { 2529 /* uncore_sys_ddr_pmu\000 */ },
},
};
@@ -316,6 +316,12 @@ static void decompress_event(int offset, struct pmu_event *pe)
p++;
pe->unit = (*p == '\0' ? NULL : p);
while (*p++);
+ pe->retirement_latency_mean = (*p == '\0' ? NULL : p);
+ while (*p++);
+ pe->retirement_latency_min = (*p == '\0' ? NULL : p);
+ while (*p++);
+ pe->retirement_latency_max = (*p == '\0' ? NULL : p);
+ while (*p++);
pe->long_desc = (*p == '\0' ? NULL : p);
}
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 7499a35bfadd..e3a55486c08e 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -47,6 +47,9 @@ _json_event_attributes = [
'event',
# Short things in alphabetical order.
'compat', 'deprecated', 'perpkg', 'unit',
+ # Retirement latency specific to Intel granite rapids currently.
+ 'retirement_latency_mean', 'retirement_latency_min',
+ 'retirement_latency_max',
# Longer things (the last won't be iterated over during decompress).
'long_desc'
]
@@ -341,6 +344,9 @@ class JsonEvent:
self.perpkg = jd.get('PerPkg')
self.aggr_mode = convert_aggr_mode(jd.get('AggregationMode'))
self.deprecated = jd.get('Deprecated')
+ self.retirement_latency_mean = jd.get('RetirementLatencyMean')
+ self.retirement_latency_min = jd.get('RetirementLatencyMin')
+ self.retirement_latency_max = jd.get('RetirementLatencyMax')
self.metric_name = jd.get('MetricName')
self.metric_group = jd.get('MetricGroup')
self.metricgroup_no_group = jd.get('MetricgroupNoGroup')
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 675562e6f770..a95fee561622 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -47,6 +47,9 @@ struct pmu_event {
const char *long_desc;
const char *pmu;
const char *unit;
+ const char *retirement_latency_mean;
+ const char *retirement_latency_min;
+ const char *retirement_latency_max;
bool perpkg;
bool deprecated;
};
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index aae431d63d64..42dcadfef8ce 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -177,6 +177,12 @@ struct evsel {
/* For tool events */
/* Beginning time subtracted when the counter is read. */
union {
+ /* Defaults for retirement latency events. */
+ struct _retirement_latency {
+ double mean;
+ double min;
+ double max;
+ } retirement_latency;
/* duration_time is a single global time. */
__u64 start_time;
/*
diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
index 6b00bd5b0af1..467d990d09ce 100644
--- a/tools/perf/util/intel-tpebs.c
+++ b/tools/perf/util/intel-tpebs.c
@@ -514,27 +514,49 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
* process. Allow the sample reader a chance to read by releasing and
* reacquiring the lock.
*/
- if (&t->nd == tpebs_results.next) {
+ if (t && &t->nd == tpebs_results.next) {
ret = tpebs_send_record_cmd(EVLIST_CTL_CMD_PING_TAG);
mutex_unlock(tpebs_mtx_get());
if (ret)
return ret;
mutex_lock(tpebs_mtx_get());
}
- switch (tpebs_mode) {
- case TPEBS_MODE__MIN:
- val = rint(t->stats.min);
- break;
- case TPEBS_MODE__MAX:
- val = rint(t->stats.max);
- break;
- case TPEBS_MODE__LAST:
- val = t->last;
- break;
- default:
- case TPEBS_MODE__MEAN:
- val = rint(t->stats.mean);
- break;
+ if (t == NULL || t->stats.n == 0) {
+ /* No sample data, use default. */
+ if (tpebs_recording) {
+ pr_warning_once(
+ "Using precomputed retirement latency data as no samples\n");
+ }
+ val = 0;
+ switch (tpebs_mode) {
+ case TPEBS_MODE__MIN:
+ val = rint(evsel->retirement_latency.min);
+ break;
+ case TPEBS_MODE__MAX:
+ val = rint(evsel->retirement_latency.max);
+ break;
+ default:
+ case TPEBS_MODE__LAST:
+ case TPEBS_MODE__MEAN:
+ val = rint(evsel->retirement_latency.mean);
+ break;
+ }
+ } else {
+ switch (tpebs_mode) {
+ case TPEBS_MODE__MIN:
+ val = t->stats.min;
+ break;
+ case TPEBS_MODE__MAX:
+ val = t->stats.max;
+ break;
+ case TPEBS_MODE__LAST:
+ val = t->last;
+ break;
+ default:
+ case TPEBS_MODE__MEAN:
+ val = rint(t->stats.mean);
+ break;
+ }
}
mutex_unlock(tpebs_mtx_get());
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5152fd5a6ead..89708d1769c8 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1539,6 +1539,10 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
evsel->scale = info.scale;
evsel->per_pkg = info.per_pkg;
evsel->snapshot = info.snapshot;
+ evsel->retirement_latency.mean = info.retirement_latency_mean;
+ evsel->retirement_latency.min = info.retirement_latency_min;
+ evsel->retirement_latency.max = info.retirement_latency_max;
+
return 0;
}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b7ebac5ab1d1..bbb906bb2159 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -77,6 +77,12 @@ struct perf_pmu_alias {
char unit[UNIT_MAX_LEN+1];
/** @scale: Value to scale read counter values by. */
double scale;
+ /** @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;
/**
* @per_pkg: Does the file
* <sysfs>/bus/event_source/devices/<pmu_name>/events/<name>.per-pkg or
@@ -257,7 +263,7 @@ static int pmu_format(struct perf_pmu *pmu, int dirfd, const char *name, bool ea
return 0;
}
-int perf_pmu__convert_scale(const char *scale, char **end, double *sval)
+static int parse_double(const char *scale, char **end, double *sval)
{
char *lc;
int ret = 0;
@@ -294,6 +300,11 @@ int perf_pmu__convert_scale(const char *scale, char **end, double *sval)
return ret;
}
+int perf_pmu__convert_scale(const char *scale, char **end, double *sval)
+{
+ return parse_double(scale, end, sval);
+}
+
static int perf_pmu__parse_scale(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
{
struct stat st;
@@ -525,6 +536,18 @@ static int update_alias(const struct pmu_event *pe,
if (!ret)
snprintf(data->alias->unit, sizeof(data->alias->unit), "%s", unit);
}
+ 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);
+ }
return ret;
}
@@ -533,7 +556,7 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
const struct pmu_event *pe, enum event_source src)
{
struct perf_pmu_alias *alias;
- int ret;
+ int ret = 0;
const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
bool deprecated = false, perpkg = false;
@@ -562,6 +585,24 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
alias->per_pkg = perpkg;
alias->snapshot = false;
alias->deprecated = deprecated;
+ 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;
ret = parse_events_terms(&alias->terms, val, val_fd);
if (ret) {
@@ -1678,6 +1719,9 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
info->unit = NULL;
info->scale = 0.0;
info->snapshot = false;
+ info->retirement_latency_mean = 0.0;
+ info->retirement_latency_min = 0.0;
+ info->retirement_latency_max = 0.0;
if (perf_pmu__is_hwmon(pmu)) {
ret = hwmon_pmu__check_alias(head_terms, info, err);
@@ -1711,6 +1755,10 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
if (term->alternate_hw_config)
*alternate_hw_config = term->val.num;
+ info->retirement_latency_mean = alias->retirement_latency_mean;
+ info->retirement_latency_min = alias->retirement_latency_min;
+ info->retirement_latency_max = alias->retirement_latency_max;
+
list_del_init(&term->list);
parse_events_term__delete(term);
}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index b93014cc3670..13dd3511f504 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -194,6 +194,9 @@ struct perf_pmu {
struct perf_pmu_info {
const char *unit;
double scale;
+ double retirement_latency_mean;
+ double retirement_latency_min;
+ double retirement_latency_max;
bool per_pkg;
bool snapshot;
};
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 16/16] perf record: Retirement latency cleanup in evsel__config
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (14 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 15/16] perf pmu-events: Add retirement latency to JSON events inside of perf Ian Rogers
@ 2025-04-09 6:10 ` Ian Rogers
2025-04-10 3:12 ` Wang, Weilin
2025-04-11 23:09 ` [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Namhyung Kim
16 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2025-04-09 6:10 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Weilin Wang, James Clark,
Xu Yang, John Garry, Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users, linux-kernel
Perf record will fail with retirement latency events as the open
doesn't do a perf_event_open system call. Use evsel__config to set up
such events for recording by removing the flag and enabling sample
weights - the sample weights containing the retirement latency.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/evsel.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 661a07cbdb25..6a84893e3c58 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1440,9 +1440,10 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
attr->branch_sample_type = opts->branch_stack;
}
- if (opts->sample_weight)
+ if (opts->sample_weight || evsel->retire_lat) {
arch_evsel__set_sample_weight(evsel);
-
+ evsel->retire_lat = false;
+ }
attr->task = track;
attr->mmap = track;
attr->mmap2 = track && !perf_missing_features.mmap2;
--
2.49.0.504.g3bcea36a83-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* RE: [PATCH v4 16/16] perf record: Retirement latency cleanup in evsel__config
2025-04-09 6:10 ` [PATCH v4 16/16] perf record: Retirement latency cleanup in evsel__config Ian Rogers
@ 2025-04-10 3:12 ` Wang, Weilin
0 siblings, 0 replies; 21+ messages in thread
From: Wang, Weilin @ 2025-04-10 3:12 UTC (permalink / raw)
To: Ian Rogers, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Hunter, Adrian, Kan Liang, James Clark, Xu Yang, John Garry,
Howard Chu, Levi Yun, Dominique Martinet,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Ian Rogers <irogers@google.com>
> Sent: Tuesday, April 8, 2025 11:11 PM
> To: Peter Zijlstra <peterz@infradead.org>; Ingo Molnar <mingo@redhat.com>;
> Arnaldo Carvalho de Melo <acme@kernel.org>; Namhyung Kim
> <namhyung@kernel.org>; Mark Rutland <mark.rutland@arm.com>;
> Alexander Shishkin <alexander.shishkin@linux.intel.com>; Jiri Olsa
> <jolsa@kernel.org>; Ian Rogers <irogers@google.com>; Hunter, Adrian
> <adrian.hunter@intel.com>; Kan Liang <kan.liang@linux.intel.com>; Wang,
> Weilin <weilin.wang@intel.com>; James Clark <james.clark@linaro.org>; Xu
> Yang <xu.yang_2@nxp.com>; John Garry <john.g.garry@oracle.com>; Howard
> Chu <howardchu95@gmail.com>; Levi Yun <yeoreum.yun@arm.com>;
> Dominique Martinet <asmadeus@codewreck.org>; linux-perf-
> users@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [PATCH v4 16/16] perf record: Retirement latency cleanup in
> evsel__config
>
> Perf record will fail with retirement latency events as the open
> doesn't do a perf_event_open system call. Use evsel__config to set up
> such events for recording by removing the flag and enabling sample
> weights - the sample weights containing the retirement latency.
>
> Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Weilin Wang <weilin.wang@intel.com>
> ---
> tools/perf/util/evsel.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 661a07cbdb25..6a84893e3c58 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -1440,9 +1440,10 @@ void evsel__config(struct evsel *evsel, struct
> record_opts *opts,
> attr->branch_sample_type = opts->branch_stack;
> }
>
> - if (opts->sample_weight)
> + if (opts->sample_weight || evsel->retire_lat) {
> arch_evsel__set_sample_weight(evsel);
> -
> + evsel->retire_lat = false;
> + }
> attr->task = track;
> attr->mmap = track;
> attr->mmap2 = track && !perf_missing_features.mmap2;
> --
> 2.49.0.504.g3bcea36a83-goog
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results
2025-04-09 6:10 ` [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results Ian Rogers
@ 2025-04-11 22:54 ` Namhyung Kim
2025-04-14 17:00 ` Ian Rogers
0 siblings, 1 reply; 21+ messages in thread
From: Namhyung Kim @ 2025-04-11 22:54 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Weilin Wang, James Clark, Xu Yang, John Garry,
Howard Chu, Levi Yun, Dominique Martinet, linux-perf-users,
linux-kernel
On Tue, Apr 08, 2025 at 11:10:38PM -0700, Ian Rogers wrote:
> Ensure sample reader isn't racing with events being added/removed.
>
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
> tools/perf/util/intel-tpebs.c | 51 ++++++++++++++++++++++++++++++-----
> 1 file changed, 44 insertions(+), 7 deletions(-)
>
> diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
> index f648fca17556..c5ccdbc42dc6 100644
> --- a/tools/perf/util/intel-tpebs.c
> +++ b/tools/perf/util/intel-tpebs.c
> @@ -16,6 +16,7 @@
> #include "debug.h"
> #include "evlist.h"
> #include "evsel.h"
> +#include "mutex.h"
> #include "session.h"
> #include "tool.h"
> #include "cpumap.h"
> @@ -32,6 +33,7 @@ bool tpebs_recording;
> static LIST_HEAD(tpebs_results);
> static pthread_t tpebs_reader_thread;
> static struct child_process tpebs_cmd;
> +static struct mutex tpebs_mtx;
>
> struct tpebs_retire_lat {
> struct list_head nd;
> @@ -51,6 +53,19 @@ struct tpebs_retire_lat {
>
> static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel);
>
> +static void tpebs_mtx_init(void)
> +{
> + mutex_init(&tpebs_mtx);
> +}
> +
> +static struct mutex *tpebs_mtx_get(void)
> +{
> + static pthread_once_t tpebs_mtx_once = PTHREAD_ONCE_INIT;
> +
> + pthread_once(&tpebs_mtx_once, tpebs_mtx_init);
> + return &tpebs_mtx;
> +}
> +
> static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
> {
> const char **record_argv;
> @@ -59,13 +74,15 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
> char cpumap_buf[50];
> struct tpebs_retire_lat *t;
>
> + mutex_lock(tpebs_mtx_get());
> list_for_each_entry(t, &tpebs_results, nd)
> tpebs_event_size++;
>
> record_argv = malloc((10 + 2 * tpebs_event_size) * sizeof(*record_argv));
> - if (!record_argv)
> + if (!record_argv) {
> + mutex_unlock(tpebs_mtx_get());
> return -ENOMEM;
> -
> + }
> record_argv[i++] = "perf";
> record_argv[i++] = "record";
> record_argv[i++] = "-W";
> @@ -101,6 +118,7 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
> list_for_each_entry(t, &tpebs_results, nd)
> t->started = true;
>
> + mutex_unlock(tpebs_mtx_get());
> return ret;
> }
>
> @@ -112,9 +130,12 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
> {
> struct tpebs_retire_lat *t;
>
> + mutex_lock(tpebs_mtx_get());
> t = tpebs_retire_lat__find(evsel);
> - if (!t)
> + if (!t) {
> + mutex_unlock(tpebs_mtx_get());
> return -EINVAL;
> + }
> /*
> * Need to handle per core results? We are assuming average retire
> * latency value will be used. Save the number of samples and the sum of
> @@ -123,6 +144,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
> t->count += 1;
> t->sum += sample->retire_lat;
> t->val = (double) t->sum / t->count;
> + mutex_unlock(tpebs_mtx_get());
> return 0;
> }
>
> @@ -229,7 +251,6 @@ static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
> return NULL;
> }
> result->evsel = evsel;
> - list_add_tail(&result->nd, &tpebs_results);
> return result;
> }
>
> @@ -282,16 +303,22 @@ static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel)
> static int evsel__tpebs_prepare(struct evsel *evsel)
> {
> struct evsel *pos;
> - struct tpebs_retire_lat *tpebs_event = tpebs_retire_lat__find(evsel);
> + struct tpebs_retire_lat *tpebs_event;
>
> + mutex_lock(tpebs_mtx_get());
> + tpebs_event = tpebs_retire_lat__find(evsel);
> if (tpebs_event) {
> /* evsel, or an identically named one, was already prepared. */
> + mutex_unlock(tpebs_mtx_get());
> return 0;
> }
> tpebs_event = tpebs_retire_lat__new(evsel);
> if (!tpebs_event)
> return -ENOMEM;
The mutex_unlock() is missing here.
Thanks,
Namhyung
>
> + list_add_tail(&tpebs_event->nd, &tpebs_results);
> + mutex_unlock(tpebs_mtx_get());
> +
> /*
> * Eagerly prepare all other evsels on the list to try to ensure that by
> * open they are all known.
> @@ -317,6 +344,7 @@ static int evsel__tpebs_prepare(struct evsel *evsel)
> int evsel__tpebs_open(struct evsel *evsel)
> {
> int ret;
> + bool tpebs_empty;
>
> /* We should only run tpebs_start when tpebs_recording is enabled. */
> if (!tpebs_recording)
> @@ -336,7 +364,10 @@ int evsel__tpebs_open(struct evsel *evsel)
> if (ret)
> return ret;
>
> - if (!list_empty(&tpebs_results)) {
> + mutex_lock(tpebs_mtx_get());
> + tpebs_empty = list_empty(&tpebs_results);
> + mutex_unlock(tpebs_mtx_get());
> + if (!tpebs_empty) {
> struct pollfd pollfd = { .events = POLLIN, };
> int control_fd[2], ack_fd[2], len;
> char ack_buf[8];
> @@ -436,8 +467,10 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
> */
> tpebs_stop();
>
> + mutex_lock(tpebs_mtx_get());
> t = tpebs_retire_lat__find(evsel);
> val = rint(t->val);
> + mutex_unlock(tpebs_mtx_get());
>
> if (old_count) {
> count->val = old_count->val + val;
> @@ -460,9 +493,13 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
> */
> void evsel__tpebs_close(struct evsel *evsel)
> {
> - struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
> + struct tpebs_retire_lat *t;
>
> + mutex_lock(tpebs_mtx_get());
> + t = tpebs_retire_lat__find(evsel);
> + list_del_init(&t->nd);
> tpebs_retire_lat__delete(t);
> + mutex_unlock(tpebs_mtx_get());
>
> if (list_empty(&tpebs_results))
> tpebs_stop();
> --
> 2.49.0.504.g3bcea36a83-goog
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 00/16] Intel TPEBS min/max/mean/last support
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
` (15 preceding siblings ...)
2025-04-09 6:10 ` [PATCH v4 16/16] perf record: Retirement latency cleanup in evsel__config Ian Rogers
@ 2025-04-11 23:09 ` Namhyung Kim
16 siblings, 0 replies; 21+ messages in thread
From: Namhyung Kim @ 2025-04-11 23:09 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Weilin Wang, James Clark, Xu Yang, John Garry,
Howard Chu, Levi Yun, Dominique Martinet, linux-perf-users,
linux-kernel
On Tue, Apr 08, 2025 at 11:10:27PM -0700, Ian Rogers wrote:
> The patches add support to computing the min, max, mean or last
> retirement latency and then using that value as the basis for metrics.
> When values aren't available, support is added to use the retirement
> latency as recorded for an event in the perf json.
>
> Support is added for reading the retirement latency from the forked
> perf command more than once. To avoid killing the process commands are
> sent through the control fd. Some name handling is changed to make it
> more robust.
>
> Rather than retirement latency events having issues with perf record,
> make it so that the retirement latency modifier enables sample
> weights.
>
> v4: Don't use json min/max in retirement latency stats as they will
> never update afterwards. Warn once if json data is used when TPEBS
> recording was requested.
>
> v3: Two fixes from Kan Liang. Ensure min/max statistics don't vary
> when real samples are encountered.
>
> v2: Addition of header cleanup patch originally posted:
> https://lore.kernel.org/lkml/20241210191823.612631-1-irogers@google.com/
> as there are no arch specific reasons not to build this code.
> Fix bug in "perf pmu-events: Add retirement latency to JSON events
> inside of perf" where "t->stats.n != 0" should have been
> "t->stats.n == 0".
> Add patch so that perf record of a retirement latency event
> doesn't crash but instead enables sample weights for the event.
>
> Ian Rogers (16):
> perf intel-tpebs: Cleanup header
> perf intel-tpebs: Simplify tpebs_cmd
> perf intel-tpebs: Rename tpebs_start to evsel__tpebs_open
> perf intel-tpebs: Separate evsel__tpebs_prepare out of
> evsel__tpebs_open
> perf intel-tpebs: Move cpumap_buf out of evsel__tpebs_open
> perf intel-tpebs: Reduce scope of tpebs_events_size
> perf intel-tpebs: Inline get_perf_record_args
> perf intel-tpebs: Ensure events are opened, factor out finding
> perf intel-tpebs: Refactor tpebs_results list
> perf intel-tpebs: Add support for updating counts in evsel__tpebs_read
> perf intel-tpebs: Add mutex for tpebs_results
> perf intel-tpebs: Don't close record on read
> perf intel-tpebs: Use stats for retirement latency statistics
> perf stat: Add mean, min, max and last --tpebs-mode options
> perf pmu-events: Add retirement latency to JSON events inside of perf
> perf record: Retirement latency cleanup in evsel__config
I have a nitpick but otherwise looks good to me.
Acked-by: Namhyung Kim <namhyung@kernel.org>
Thanks,
Namhyung
>
> tools/perf/Documentation/perf-stat.txt | 7 +
> tools/perf/builtin-stat.c | 29 +-
> tools/perf/pmu-events/empty-pmu-events.c | 216 +++----
> tools/perf/pmu-events/jevents.py | 6 +
> tools/perf/pmu-events/pmu-events.h | 3 +
> tools/perf/util/Build | 2 +-
> tools/perf/util/evlist.c | 1 -
> tools/perf/util/evsel.c | 22 +-
> tools/perf/util/evsel.h | 6 +
> tools/perf/util/intel-tpebs.c | 682 ++++++++++++++---------
> tools/perf/util/intel-tpebs.h | 40 +-
> tools/perf/util/parse-events.c | 4 +
> tools/perf/util/pmu.c | 52 +-
> tools/perf/util/pmu.h | 3 +
> 14 files changed, 666 insertions(+), 407 deletions(-)
>
> --
> 2.49.0.504.g3bcea36a83-goog
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results
2025-04-11 22:54 ` Namhyung Kim
@ 2025-04-14 17:00 ` Ian Rogers
0 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2025-04-14 17:00 UTC (permalink / raw)
To: Namhyung Kim
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Weilin Wang, James Clark, Xu Yang, John Garry,
Howard Chu, Levi Yun, Dominique Martinet, linux-perf-users,
linux-kernel
On Fri, Apr 11, 2025 at 3:54 PM Namhyung Kim <namhyung@kernel.org> wrote:
>
> On Tue, Apr 08, 2025 at 11:10:38PM -0700, Ian Rogers wrote:
> > Ensure sample reader isn't racing with events being added/removed.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> > tools/perf/util/intel-tpebs.c | 51 ++++++++++++++++++++++++++++++-----
> > 1 file changed, 44 insertions(+), 7 deletions(-)
> >
> > diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c
> > index f648fca17556..c5ccdbc42dc6 100644
> > --- a/tools/perf/util/intel-tpebs.c
> > +++ b/tools/perf/util/intel-tpebs.c
> > @@ -16,6 +16,7 @@
> > #include "debug.h"
> > #include "evlist.h"
> > #include "evsel.h"
> > +#include "mutex.h"
> > #include "session.h"
> > #include "tool.h"
> > #include "cpumap.h"
> > @@ -32,6 +33,7 @@ bool tpebs_recording;
> > static LIST_HEAD(tpebs_results);
> > static pthread_t tpebs_reader_thread;
> > static struct child_process tpebs_cmd;
> > +static struct mutex tpebs_mtx;
> >
> > struct tpebs_retire_lat {
> > struct list_head nd;
> > @@ -51,6 +53,19 @@ struct tpebs_retire_lat {
> >
> > static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel);
> >
> > +static void tpebs_mtx_init(void)
> > +{
> > + mutex_init(&tpebs_mtx);
> > +}
> > +
> > +static struct mutex *tpebs_mtx_get(void)
> > +{
> > + static pthread_once_t tpebs_mtx_once = PTHREAD_ONCE_INIT;
> > +
> > + pthread_once(&tpebs_mtx_once, tpebs_mtx_init);
> > + return &tpebs_mtx;
> > +}
> > +
> > static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[], int ack_fd[])
> > {
> > const char **record_argv;
> > @@ -59,13 +74,15 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
> > char cpumap_buf[50];
> > struct tpebs_retire_lat *t;
> >
> > + mutex_lock(tpebs_mtx_get());
> > list_for_each_entry(t, &tpebs_results, nd)
> > tpebs_event_size++;
> >
> > record_argv = malloc((10 + 2 * tpebs_event_size) * sizeof(*record_argv));
> > - if (!record_argv)
> > + if (!record_argv) {
> > + mutex_unlock(tpebs_mtx_get());
> > return -ENOMEM;
> > -
> > + }
> > record_argv[i++] = "perf";
> > record_argv[i++] = "record";
> > record_argv[i++] = "-W";
> > @@ -101,6 +118,7 @@ static int evsel__tpebs_start_perf_record(struct evsel *evsel, int control_fd[],
> > list_for_each_entry(t, &tpebs_results, nd)
> > t->started = true;
> >
> > + mutex_unlock(tpebs_mtx_get());
> > return ret;
> > }
> >
> > @@ -112,9 +130,12 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
> > {
> > struct tpebs_retire_lat *t;
> >
> > + mutex_lock(tpebs_mtx_get());
> > t = tpebs_retire_lat__find(evsel);
> > - if (!t)
> > + if (!t) {
> > + mutex_unlock(tpebs_mtx_get());
> > return -EINVAL;
> > + }
> > /*
> > * Need to handle per core results? We are assuming average retire
> > * latency value will be used. Save the number of samples and the sum of
> > @@ -123,6 +144,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
> > t->count += 1;
> > t->sum += sample->retire_lat;
> > t->val = (double) t->sum / t->count;
> > + mutex_unlock(tpebs_mtx_get());
> > return 0;
> > }
> >
> > @@ -229,7 +251,6 @@ static struct tpebs_retire_lat *tpebs_retire_lat__new(struct evsel *evsel)
> > return NULL;
> > }
> > result->evsel = evsel;
> > - list_add_tail(&result->nd, &tpebs_results);
> > return result;
> > }
> >
> > @@ -282,16 +303,22 @@ static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel)
> > static int evsel__tpebs_prepare(struct evsel *evsel)
> > {
> > struct evsel *pos;
> > - struct tpebs_retire_lat *tpebs_event = tpebs_retire_lat__find(evsel);
> > + struct tpebs_retire_lat *tpebs_event;
> >
> > + mutex_lock(tpebs_mtx_get());
> > + tpebs_event = tpebs_retire_lat__find(evsel);
> > if (tpebs_event) {
> > /* evsel, or an identically named one, was already prepared. */
> > + mutex_unlock(tpebs_mtx_get());
> > return 0;
> > }
> > tpebs_event = tpebs_retire_lat__new(evsel);
> > if (!tpebs_event)
> > return -ENOMEM;
>
> The mutex_unlock() is missing here.
Good catch, I'll fix in v5. Fwiw cleanups would have avoided this.
Thanks,
Ian
> Thanks,
> Namhyung
>
> >
> > + list_add_tail(&tpebs_event->nd, &tpebs_results);
> > + mutex_unlock(tpebs_mtx_get());
> > +
> > /*
> > * Eagerly prepare all other evsels on the list to try to ensure that by
> > * open they are all known.
> > @@ -317,6 +344,7 @@ static int evsel__tpebs_prepare(struct evsel *evsel)
> > int evsel__tpebs_open(struct evsel *evsel)
> > {
> > int ret;
> > + bool tpebs_empty;
> >
> > /* We should only run tpebs_start when tpebs_recording is enabled. */
> > if (!tpebs_recording)
> > @@ -336,7 +364,10 @@ int evsel__tpebs_open(struct evsel *evsel)
> > if (ret)
> > return ret;
> >
> > - if (!list_empty(&tpebs_results)) {
> > + mutex_lock(tpebs_mtx_get());
> > + tpebs_empty = list_empty(&tpebs_results);
> > + mutex_unlock(tpebs_mtx_get());
> > + if (!tpebs_empty) {
> > struct pollfd pollfd = { .events = POLLIN, };
> > int control_fd[2], ack_fd[2], len;
> > char ack_buf[8];
> > @@ -436,8 +467,10 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
> > */
> > tpebs_stop();
> >
> > + mutex_lock(tpebs_mtx_get());
> > t = tpebs_retire_lat__find(evsel);
> > val = rint(t->val);
> > + mutex_unlock(tpebs_mtx_get());
> >
> > if (old_count) {
> > count->val = old_count->val + val;
> > @@ -460,9 +493,13 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_idx, int thread)
> > */
> > void evsel__tpebs_close(struct evsel *evsel)
> > {
> > - struct tpebs_retire_lat *t = tpebs_retire_lat__find(evsel);
> > + struct tpebs_retire_lat *t;
> >
> > + mutex_lock(tpebs_mtx_get());
> > + t = tpebs_retire_lat__find(evsel);
> > + list_del_init(&t->nd);
> > tpebs_retire_lat__delete(t);
> > + mutex_unlock(tpebs_mtx_get());
> >
> > if (list_empty(&tpebs_results))
> > tpebs_stop();
> > --
> > 2.49.0.504.g3bcea36a83-goog
> >
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-04-14 17:00 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-09 6:10 [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Ian Rogers
2025-04-09 6:10 ` [PATCH v4 01/16] perf intel-tpebs: Cleanup header Ian Rogers
2025-04-09 6:10 ` [PATCH v4 02/16] perf intel-tpebs: Simplify tpebs_cmd Ian Rogers
2025-04-09 6:10 ` [PATCH v4 03/16] perf intel-tpebs: Rename tpebs_start to evsel__tpebs_open Ian Rogers
2025-04-09 6:10 ` [PATCH v4 04/16] perf intel-tpebs: Separate evsel__tpebs_prepare out of evsel__tpebs_open Ian Rogers
2025-04-09 6:10 ` [PATCH v4 05/16] perf intel-tpebs: Move cpumap_buf " Ian Rogers
2025-04-09 6:10 ` [PATCH v4 06/16] perf intel-tpebs: Reduce scope of tpebs_events_size Ian Rogers
2025-04-09 6:10 ` [PATCH v4 07/16] perf intel-tpebs: Inline get_perf_record_args Ian Rogers
2025-04-09 6:10 ` [PATCH v4 08/16] perf intel-tpebs: Ensure events are opened, factor out finding Ian Rogers
2025-04-09 6:10 ` [PATCH v4 09/16] perf intel-tpebs: Refactor tpebs_results list Ian Rogers
2025-04-09 6:10 ` [PATCH v4 10/16] perf intel-tpebs: Add support for updating counts in evsel__tpebs_read Ian Rogers
2025-04-09 6:10 ` [PATCH v4 11/16] perf intel-tpebs: Add mutex for tpebs_results Ian Rogers
2025-04-11 22:54 ` Namhyung Kim
2025-04-14 17:00 ` Ian Rogers
2025-04-09 6:10 ` [PATCH v4 12/16] perf intel-tpebs: Don't close record on read Ian Rogers
2025-04-09 6:10 ` [PATCH v4 13/16] perf intel-tpebs: Use stats for retirement latency statistics Ian Rogers
2025-04-09 6:10 ` [PATCH v4 14/16] perf stat: Add mean, min, max and last --tpebs-mode options Ian Rogers
2025-04-09 6:10 ` [PATCH v4 15/16] perf pmu-events: Add retirement latency to JSON events inside of perf Ian Rogers
2025-04-09 6:10 ` [PATCH v4 16/16] perf record: Retirement latency cleanup in evsel__config Ian Rogers
2025-04-10 3:12 ` Wang, Weilin
2025-04-11 23:09 ` [PATCH v4 00/16] Intel TPEBS min/max/mean/last support Namhyung Kim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).