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: Ian Rogers <irogers@google.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Link: https://lore.kernel.org/r/20250725185202.68671-5-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
@@ -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
@@ -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 @@ out_err:
|
||||
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;
|
||||
|
||||
@@ -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)
|
||||
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;
|
||||
};
|
||||
|
||||
static int add_tracepoint_multi_event_cb(void *state, const char *sys_name, const char *evt_name)
|
||||
{
|
||||
char *evt_path;
|
||||
struct io_dirent64 *evt_ent;
|
||||
struct io_dir evt_dir;
|
||||
int ret = 0, found = 0;
|
||||
struct add_tracepoint_multi_args *args = state;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!strglobmatch(evt_name, args->evt_glob))
|
||||
return 0;
|
||||
|
||||
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;
|
||||
args->found++;
|
||||
ret = add_tracepoint(args->parse_state, args->list, sys_name, evt_name,
|
||||
args->err, args->head_config, args->loc);
|
||||
|
||||
if (!strglobmatch(evt_ent->d_name, evt_name))
|
||||
continue;
|
||||
|
||||
found++;
|
||||
|
||||
ret = add_tracepoint(parse_state, list, sys_name, evt_ent->d_name,
|
||||
err, head_config, loc);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
tracepoint_error(err, ENOENT, sys_name, evt_name, loc->first_column);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
put_events_file(evt_path);
|
||||
close(evt_dir.dirfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_event(struct add_tracepoint_multi_args *args, 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);
|
||||
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);
|
||||
}
|
||||
|
||||
return tp_pmu__for_each_tp_event(sys_name, args, add_tracepoint_multi_event_cb);
|
||||
}
|
||||
|
||||
static int add_tracepoint_multi_sys_cb(void *state, const char *sys_name)
|
||||
{
|
||||
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);
|
||||
return add_tracepoint_multi_sys(parse_state, list, sys, event,
|
||||
err, head_config, loc);
|
||||
}
|
||||
|
||||
static int __parse_events_add_numeric(struct parse_events_state *parse_state,
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* 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 */
|
||||
Reference in New Issue
Block a user