Commit d002aab8 authored by Ian Rogers's avatar Ian Rogers Committed by Namhyung Kim
Browse files

perf tp_pmu: Factor existing tracepoint logic to new file



Start the creation of a tracepoint PMU abstraction. Tracepoint events
don't follow the regular sysfs perf conventions. Eventually the new
PMU abstraction will bridge the gap so tracepoint events look more
like regular perf ones.

Signed-off-by: default avatarIan Rogers <irogers@google.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/r/20250725185202.68671-5-irogers@google.com


Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
parent 6e9fa413
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ perf-util-y += pmu-bison.o
perf-util-y += drm_pmu.o
perf-util-y += hwmon_pmu.o
perf-util-y += tool_pmu.o
perf-util-y += tp_pmu.o
perf-util-y += svghelper.o
perf-util-y += trace-event-info.o
perf-util-y += trace-event-scripting.o
+2 −19
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@
#include "drm_pmu.h"
#include "hwmon_pmu.h"
#include "tool_pmu.h"
#include "tp_pmu.h"
#include "rlimit.h"
#include "../perf-sys.h"
#include "util/parse-branch-options.h"
@@ -572,24 +573,6 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
	return NULL;
}

static int trace_event__id(const char *sys, const char *name)
{
	char *tp_dir = get_events_file(sys);
	char path[PATH_MAX];
	int id, err;

	if (!tp_dir)
		return -1;

	scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name);
	put_events_file(tp_dir);
	err = filename__read_int(path, &id);
	if (err)
		return err;

	return id;
}

/*
 * Returns pointer with encoded error via <linux/err.h> interface.
 */
@@ -623,7 +606,7 @@ struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx, bool
	event_attr_init(&attr);

	if (format) {
		id = trace_event__id(sys, name);
		id = tp_pmu__id(sys, name);
		if (id < 0) {
			err = id;
			goto out_free;
+60 −87
Original line number Diff line number Diff line
@@ -17,13 +17,12 @@
#include "string2.h"
#include "strbuf.h"
#include "debug.h"
#include <api/fs/tracing_path.h>
#include <api/io_dir.h>
#include <perf/cpumap.h>
#include <util/parse-events-bison.h>
#include <util/parse-events-flex.h>
#include "pmu.h"
#include "pmus.h"
#include "tp_pmu.h"
#include "asm/bug.h"
#include "ui/ui.h"
#include "util/parse-branch-options.h"
@@ -33,6 +32,7 @@
#include "util/stat.h"
#include "util/util.h"
#include "tracepoint.h"
#include <api/fs/tracing_path.h>

#define MAX_NAME_LEN 100

@@ -599,105 +599,82 @@ static int add_tracepoint(struct parse_events_state *parse_state,
	return 0;
}

static int add_tracepoint_multi_event(struct parse_events_state *parse_state,
				      struct list_head *list,
				      const char *sys_name, const char *evt_name,
				      struct parse_events_error *err,
				      struct parse_events_terms *head_config, YYLTYPE *loc)
{
	char *evt_path;
	struct io_dirent64 *evt_ent;
	struct io_dir evt_dir;
	int ret = 0, found = 0;

	evt_path = get_events_file(sys_name);
	if (!evt_path) {
		tracepoint_error(err, errno, sys_name, evt_name, loc->first_column);
		return -1;
	}
	io_dir__init(&evt_dir, open(evt_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
	if (evt_dir.dirfd < 0) {
		put_events_file(evt_path);
		tracepoint_error(err, errno, sys_name, evt_name, loc->first_column);
		return -1;
	}
struct add_tracepoint_multi_args {
	struct parse_events_state *parse_state;
	struct list_head *list;
	const char *sys_glob;
	const char *evt_glob;
	struct parse_events_error *err;
	struct parse_events_terms *head_config;
	YYLTYPE *loc;
	int found;
};

	while (!ret && (evt_ent = io_dir__readdir(&evt_dir))) {
		if (!strcmp(evt_ent->d_name, ".")
		    || !strcmp(evt_ent->d_name, "..")
		    || !strcmp(evt_ent->d_name, "enable")
		    || !strcmp(evt_ent->d_name, "filter"))
			continue;
static int add_tracepoint_multi_event_cb(void *state, const char *sys_name, const char *evt_name)
{
	struct add_tracepoint_multi_args *args = state;
	int ret;

		if (!strglobmatch(evt_ent->d_name, evt_name))
			continue;
	if (!strglobmatch(evt_name, args->evt_glob))
		return 0;

		found++;
	args->found++;
	ret = add_tracepoint(args->parse_state, args->list, sys_name, evt_name,
			     args->err, args->head_config, args->loc);

		ret = add_tracepoint(parse_state, list, sys_name, evt_ent->d_name,
				     err, head_config, loc);
	return ret;
}

	if (!found) {
		tracepoint_error(err, ENOENT, sys_name, evt_name, loc->first_column);
		ret = -1;
static int add_tracepoint_multi_event(struct add_tracepoint_multi_args *args, const char *sys_name)
{
	if (strpbrk(args->evt_glob, "*?") == NULL) {
		/* Not a glob. */
		args->found++;
		return add_tracepoint(args->parse_state, args->list, sys_name, args->evt_glob,
				      args->err, args->head_config, args->loc);
	}

	put_events_file(evt_path);
	close(evt_dir.dirfd);
	return ret;
	return tp_pmu__for_each_tp_event(sys_name, args, add_tracepoint_multi_event_cb);
}

static int add_tracepoint_event(struct parse_events_state *parse_state,
				struct list_head *list,
				const char *sys_name, const char *evt_name,
				struct parse_events_error *err,
				struct parse_events_terms *head_config, YYLTYPE *loc)
static int add_tracepoint_multi_sys_cb(void *state, const char *sys_name)
{
	return strpbrk(evt_name, "*?") ?
		add_tracepoint_multi_event(parse_state, list, sys_name, evt_name,
					   err, head_config, loc) :
		add_tracepoint(parse_state, list, sys_name, evt_name,
			       err, head_config, loc);
	struct add_tracepoint_multi_args *args = state;

	if (!strglobmatch(sys_name, args->sys_glob))
		return 0;

	return add_tracepoint_multi_event(args, sys_name);
}

static int add_tracepoint_multi_sys(struct parse_events_state *parse_state,
				    struct list_head *list,
				    const char *sys_name, const char *evt_name,
				    const char *sys_glob, const char *evt_glob,
				    struct parse_events_error *err,
				    struct parse_events_terms *head_config, YYLTYPE *loc)
{
	struct io_dirent64 *events_ent;
	struct io_dir events_dir;
	int ret = 0;
	char *events_dir_path = get_tracing_file("events");
	struct add_tracepoint_multi_args args = {
		.parse_state = parse_state,
		.list = list,
		.sys_glob = sys_glob,
		.evt_glob = evt_glob,
		.err = err,
		.head_config = head_config,
		.loc = loc,
		.found = 0,
	};
	int ret;

	if (!events_dir_path) {
		tracepoint_error(err, errno, sys_name, evt_name, loc->first_column);
		return -1;
	if (strpbrk(sys_glob, "*?") == NULL) {
		/* Not a glob. */
		ret = add_tracepoint_multi_event(&args, sys_glob);
	} else {
		ret = tp_pmu__for_each_tp_sys(&args, add_tracepoint_multi_sys_cb);
	}
	io_dir__init(&events_dir, open(events_dir_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
	put_events_file(events_dir_path);
	if (events_dir.dirfd < 0) {
		tracepoint_error(err, errno, sys_name, evt_name, loc->first_column);
		return -1;
	if (args.found == 0) {
		tracepoint_error(err, ENOENT, sys_glob, evt_glob, loc->first_column);
		return -ENOENT;
	}

	while (!ret && (events_ent = io_dir__readdir(&events_dir))) {
		if (!strcmp(events_ent->d_name, ".")
		    || !strcmp(events_ent->d_name, "..")
		    || !strcmp(events_ent->d_name, "enable")
		    || !strcmp(events_ent->d_name, "header_event")
		    || !strcmp(events_ent->d_name, "header_page"))
			continue;

		if (!strglobmatch(events_ent->d_name, sys_name))
			continue;

		ret = add_tracepoint_event(parse_state, list, events_ent->d_name,
					   evt_name, err, head_config, loc);
	}
	close(events_dir.dirfd);
	return ret;
}

@@ -1406,12 +1383,8 @@ int parse_events_add_tracepoint(struct parse_events_state *parse_state,
			return -EINVAL;
	}

	if (strpbrk(sys, "*?"))
	return add_tracepoint_multi_sys(parse_state, list, sys, event,
					err, head_config, loc);
	else
		return add_tracepoint_event(parse_state, list, sys, event,
					    err, head_config, loc);
}

static int __parse_events_add_numeric(struct parse_events_state *parse_state,
+95 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
#include "tp_pmu.h"
#include <api/fs/fs.h>
#include <api/fs/tracing_path.h>
#include <api/io_dir.h>
#include <linux/kernel.h>
#include <errno.h>
#include <string.h>

int tp_pmu__id(const char *sys, const char *name)
{
	char *tp_dir = get_events_file(sys);
	char path[PATH_MAX];
	int id, err;

	if (!tp_dir)
		return -1;

	scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name);
	put_events_file(tp_dir);
	err = filename__read_int(path, &id);
	if (err)
		return err;

	return id;
}


int tp_pmu__for_each_tp_event(const char *sys, void *state, tp_event_callback cb)
{
	char *evt_path;
	struct io_dirent64 *evt_ent;
	struct io_dir evt_dir;
	int ret = 0;

	evt_path = get_events_file(sys);
	if (!evt_path)
		return -errno;

	io_dir__init(&evt_dir, open(evt_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
	if (evt_dir.dirfd < 0) {
		ret = -errno;
		put_events_file(evt_path);
		return ret;
	}
	put_events_file(evt_path);

	while (!ret && (evt_ent = io_dir__readdir(&evt_dir))) {
		if (!strcmp(evt_ent->d_name, ".")
		    || !strcmp(evt_ent->d_name, "..")
		    || !strcmp(evt_ent->d_name, "enable")
		    || !strcmp(evt_ent->d_name, "filter"))
			continue;

		ret = cb(state, sys, evt_ent->d_name);
		if (ret)
			break;
	}
	close(evt_dir.dirfd);
	return ret;
}

int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb)
{
	struct io_dirent64 *events_ent;
	struct io_dir events_dir;
	int ret = 0;
	char *events_dir_path = get_tracing_file("events");

	if (!events_dir_path)
		return -errno;

	io_dir__init(&events_dir, open(events_dir_path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
	if (events_dir.dirfd < 0) {
		ret = -errno;
		put_events_file(events_dir_path);
		return ret;
	}
	put_events_file(events_dir_path);

	while (!ret && (events_ent = io_dir__readdir(&events_dir))) {
		if (!strcmp(events_ent->d_name, ".") ||
		    !strcmp(events_ent->d_name, "..") ||
		    !strcmp(events_ent->d_name, "enable") ||
		    !strcmp(events_ent->d_name, "header_event") ||
		    !strcmp(events_ent->d_name, "header_page"))
			continue;

		ret = cb(state, events_ent->d_name);
		if (ret)
			break;
	}
	close(events_dir.dirfd);
	return ret;
}
+12 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __TP_PMU_H
#define __TP_PMU_H

typedef int (*tp_sys_callback)(void *state, const char *sys_name);
typedef int (*tp_event_callback)(void *state, const char *sys_name, const char *evt_name);

int tp_pmu__id(const char *sys, const char *name);
int tp_pmu__for_each_tp_event(const char *sys, void *state, tp_event_callback cb);
int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb);

#endif /* __TP_PMU_H */