perf intel-tpebs: Separate evsel__tpebs_prepare() out of evsel__tpebs_open()

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>
This commit is contained in:
Ian Rogers 2025-04-14 10:41:22 -07:00 committed by Arnaldo Carvalho de Melo
parent 2332f68254
commit b009b51eea

View 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 @@ int evsel__tpebs_open(struct evsel *evsel)
close(ack_fd[0]);
close(ack_fd[1]);
}
err:
if (ret)
tpebs_delete();
return ret;