]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
perf tp_pmu: Add event APIs
authorIan Rogers <irogers@google.com>
Fri, 25 Jul 2025 18:51:51 +0000 (11:51 -0700)
committerNamhyung Kim <namhyung@kernel.org>
Sat, 26 Jul 2025 23:31:43 +0000 (16:31 -0700)
Add event APIs for the tracepoint PMU allowing things like perf list
to function using it. For perf list add the tracepoint format in the
long description (shown with -v).

  $ sudo perf list -v tracepoint

  List of pre-defined events (to be used in -e or -M):

    alarmtimer:alarmtimer_cancel                       [Tracepoint event]
         [name: alarmtimer_cancel
          ID: 416
          format:
          field:unsigned short common_type; offset:0; size:2; signed:0;
          field:unsigned char common_flags; offset:2; size:1; signed:0;
          field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
          field:int common_pid; offset:4; size:4; signed:1;
          field:void * alarm; offset:8; size:8; signed:0;
          field:unsigned char alarm_type; offset:16; size:1; signed:0;
          field:s64 expires; offset:24; size:8; signed:1;
          field:s64 now; offset:32; size:8; signed:1;
          print fmt: "alarmtimer:%p type:%s expires:%llu now:%llu",REC->alarm,__print_flags((1 << REC->alarm_type)," | ",{ 1 << 0,
          "REALTIME" },{ 1 << 1,"BOOTTIME" },{ 1 << 3,"REALTIME Freezer" },{ 1 << 4,"BOOTTIME Freezer" }),REC->expires,REC->now
          . Unit: tracepoint]
    alarmtimer:alarmtimer_fired                        [Tracepoint event]
         [name: alarmtimer_fired
          ID: 418
          ...

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-6-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/pmu.c
tools/perf/util/tp_pmu.c
tools/perf/util/tp_pmu.h

index f3da6e27bfcb7772f07159d1dfbbe57cb07e8170..5a291f1380edf8136bbdc10c2d99fdcb4077a78a 100644 (file)
@@ -24,6 +24,7 @@
 #include "hwmon_pmu.h"
 #include "pmus.h"
 #include "tool_pmu.h"
+#include "tp_pmu.h"
 #include <util/pmu-bison.h>
 #include <util/pmu-flex.h>
 #include "parse-events.h"
@@ -1983,6 +1984,8 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
                return false;
        if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(name))
                return false;
+       if (perf_pmu__is_tracepoint(pmu))
+               return tp_pmu__have_event(pmu, name);
        if (perf_pmu__is_hwmon(pmu))
                return hwmon_pmu__have_event(pmu, name);
        if (perf_pmu__is_drm(pmu))
@@ -1998,6 +2001,8 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
 {
        size_t nr;
 
+       if (perf_pmu__is_tracepoint(pmu))
+               return tp_pmu__num_events(pmu);
        if (perf_pmu__is_hwmon(pmu))
                return hwmon_pmu__num_events(pmu);
        if (perf_pmu__is_drm(pmu))
@@ -2068,6 +2073,8 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
        struct hashmap_entry *entry;
        size_t bkt;
 
+       if (perf_pmu__is_tracepoint(pmu))
+               return tp_pmu__for_each_event(pmu, state, cb);
        if (perf_pmu__is_hwmon(pmu))
                return hwmon_pmu__for_each_event(pmu, state, cb);
        if (perf_pmu__is_drm(pmu))
index 42bd967a4530cb72b3911d51be959dd4357cbf00..e7534a973247b2d2cdb74b885b5e1bbe9491b103 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
 #include "tp_pmu.h"
+#include "pmus.h"
 #include <api/fs/fs.h>
 #include <api/fs/tracing_path.h>
 #include <api/io_dir.h>
@@ -93,3 +94,117 @@ int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb)
        close(events_dir.dirfd);
        return ret;
 }
+
+bool perf_pmu__is_tracepoint(const struct perf_pmu *pmu)
+{
+       return pmu->type == PERF_TYPE_TRACEPOINT;
+}
+
+struct for_each_event_args {
+       void *state;
+       pmu_event_callback cb;
+       const struct perf_pmu *pmu;
+};
+
+static int for_each_event_cb(void *state, const char *sys_name, const char *evt_name)
+{
+       struct for_each_event_args *args = state;
+       char name[2 * FILENAME_MAX + 2];
+       /* 16 possible hex digits and 22 other characters and \0. */
+       char encoding[16 + 22];
+       char *format = NULL;
+       size_t format_size;
+       struct pmu_event_info info = {
+               .pmu = args->pmu,
+               .pmu_name = args->pmu->name,
+               .event_type_desc = "Tracepoint event",
+       };
+       char *tp_dir = get_events_file(sys_name);
+       char path[PATH_MAX];
+       int id, err;
+
+       if (!tp_dir)
+               return -1;
+
+       scnprintf(path, sizeof(path), "%s/%s/id", tp_dir, evt_name);
+       err = filename__read_int(path, &id);
+       if (err == 0) {
+               snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%x/", id);
+               info.encoding_desc = encoding;
+       }
+
+       scnprintf(path, sizeof(path), "%s/%s/format", tp_dir, evt_name);
+       put_events_file(tp_dir);
+       err = filename__read_str(path, &format, &format_size);
+       if (err == 0) {
+               info.long_desc = format;
+               for (size_t i = 0 ; i < format_size; i++) {
+                       /* Swap tabs to spaces due to some rendering issues. */
+                       if (format[i] == '\t')
+                               format[i] = ' ';
+               }
+       }
+       snprintf(name, sizeof(name), "%s:%s", sys_name, evt_name);
+       info.name = name;
+       err = args->cb(args->state, &info);
+       free(format);
+       return err;
+}
+
+static int for_each_event_sys_cb(void *state, const char *sys_name)
+{
+       return tp_pmu__for_each_tp_event(sys_name, state, for_each_event_cb);
+}
+
+int tp_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb)
+{
+       struct for_each_event_args args = {
+               .state = state,
+               .cb = cb,
+               .pmu = pmu,
+       };
+
+       return tp_pmu__for_each_tp_sys(&args, for_each_event_sys_cb);
+}
+
+static int num_events_cb(void *state, const char *sys_name __maybe_unused,
+                        const char *evt_name __maybe_unused)
+{
+       size_t *count = state;
+
+       (*count)++;
+       return 0;
+}
+
+static int num_events_sys_cb(void *state, const char *sys_name)
+{
+       return tp_pmu__for_each_tp_event(sys_name, state, num_events_cb);
+}
+
+size_t tp_pmu__num_events(struct perf_pmu *pmu __maybe_unused)
+{
+       size_t count = 0;
+
+       tp_pmu__for_each_tp_sys(&count, num_events_sys_cb);
+       return count;
+}
+
+bool tp_pmu__have_event(struct perf_pmu *pmu __maybe_unused, const char *name)
+{
+       char *dup_name, *colon;
+       int id;
+
+       colon = strchr(name, ':');
+       if (colon == NULL)
+               return false;
+
+       dup_name = strdup(name);
+       if (!dup_name)
+               return false;
+
+       colon = dup_name + (colon - name);
+       *colon = '\0';
+       id = tp_pmu__id(dup_name, colon + 1);
+       free(dup_name);
+       return id >= 0;
+}
index 49537303bd73af0a70b9d95c5f3edaae06fd4ae3..30456bd6943d425f59284c7b29fab36dfb58d8f8 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __TP_PMU_H
 #define __TP_PMU_H
 
+#include "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);
 
@@ -9,4 +11,9 @@ 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);
 
+bool perf_pmu__is_tracepoint(const struct perf_pmu *pmu);
+int tp_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb);
+size_t tp_pmu__num_events(struct perf_pmu *pmu);
+bool tp_pmu__have_event(struct perf_pmu *pmu, const char *name);
+
 #endif /* __TP_PMU_H */