Commit b009b51e authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarKan Liang <kan.liang@linux.intel.com>
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Tested-by: default avatarWeilin Wang <weilin.wang@intel.com>
Acked-by: default avatarNamhyung 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 2332f682
Loading
Loading
Loading
Loading
+86 −47
Original line number Diff line number Diff line
@@ -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,68 +190,105 @@ 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_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.
 * evsel__tpebs_prepare - create tpebs data structures ready for opening.
 * @evsel: retire_latency evsel, all evsels on its list will be prepared.
 */
int evsel__tpebs_open(struct evsel *evsel)
static int evsel__tpebs_prepare(struct evsel *evsel)
{
	int ret = 0;
	struct evsel *pos;
	struct evlist *evsel_list = evsel->evlist;
	char cpumap_buf[50];
	struct tpebs_retire_lat *tpebs_event;

	list_for_each_entry(tpebs_event, &tpebs_results, nd) {
		if (!strcmp(tpebs_event->tpebs_name, evsel->name)) {
			/*
	 * We should only run tpebs_start when tpebs_recording is enabled.
	 * And we should only run it once with all the required events.
			 * evsel, or an identically named one, was already
			 * prepared.
			 */
	if (tpebs_cmd.pid != 0 || !tpebs_recording)
			return 0;
		}
	}
	tpebs_event = tpebs_retire_lat__new(evsel);
	if (!tpebs_event)
		return -ENOMEM;

	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
	 * Eagerly prepare all other evsels on the list to try to ensure that by
	 * open they are all known.
	 */
	evlist__for_each_entry(evsel_list, pos) {
		int i;
		char *name;
		struct tpebs_retire_lat *new;
	evlist__for_each_entry(evsel->evlist, pos) {
		int ret;

		if (!pos->retire_lat)
		if (pos == evsel || !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;
		ret = evsel__tpebs_prepare(pos);
		if (ret)
			return ret;
	}
		if (i <= 0 || pos->name[i] != 'R') {
			ret = -1;
			goto err;
	return 0;
}

		name = strdup(pos->name);
		if (!name) {
			ret = -ENOMEM;
			goto err;
		}
		name[i] = 'p';
/**
 * 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 evsel__tpebs_open(struct evsel *evsel)
{
	int ret;

		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;
	}
	/*
	 * 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)
		return 0;

	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;