]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf intel-tpebs: Separate evsel__tpebs_prepare() out of evsel__tpebs_open()
authorIan Rogers <irogers@google.com>
Mon, 14 Apr 2025 17:41:22 +0000 (10:41 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 25 Apr 2025 15:31:01 +0000 (12:31 -0300)
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.

Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Weilin Wang <weilin.wang@intel.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Andreas Färber <afaerber@suse.de>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Link: https://lore.kernel.org/r/20250414174134.3095492-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/intel-tpebs.c

index 566e0ddcad88406f4b6ae4e9eba284a1699a9d20..2186818b2c9bcb2a297beb534575fcddccc7f431 100644 (file)
@@ -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 @@ out:
                close(ack_fd[0]);
                close(ack_fd[1]);
        }
-err:
        if (ret)
                tpebs_delete();
        return ret;