* [PATCH 2/4] libtracefs: New API for getting dynamic event
2021-11-30 5:00 [PATCH 0/4] New tracefs APIs Tzvetomir Stoyanov (VMware)
2021-11-30 5:00 ` [PATCH 1/4] libtracefs: Reuse logic for loading events inside the library Tzvetomir Stoyanov (VMware)
@ 2021-11-30 5:00 ` Tzvetomir Stoyanov (VMware)
2021-12-01 21:04 ` Steven Rostedt
2021-11-30 5:00 ` [PATCH 3/4] libtracefs: Unit test for tracefs_dynevent_get_event() Tzvetomir Stoyanov (VMware)
2021-11-30 5:00 ` [PATCH 4/4] libtracefs: New API for applying filter on event Tzvetomir Stoyanov (VMware)
3 siblings, 1 reply; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-11-30 5:00 UTC (permalink / raw)
To: rostedt, y.karadz; +Cc: linux-trace-devel
A new API is proposed, to get tep event describing given dynamic event:
tracefs_dynevent_get_event()
The API detects any newly created dynamic events, but does not detect
the deletion.
Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
Documentation/libtracefs-dynevents.txt | 14 +++++++++++--
include/tracefs.h | 2 ++
src/tracefs-dynevents.c | 29 ++++++++++++++++++++++++++
3 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/Documentation/libtracefs-dynevents.txt b/Documentation/libtracefs-dynevents.txt
index a374651..7de06be 100644
--- a/Documentation/libtracefs-dynevents.txt
+++ b/Documentation/libtracefs-dynevents.txt
@@ -4,8 +4,8 @@ libtracefs(3)
NAME
----
tracefs_dynevent_create, tracefs_dynevent_destroy, tracefs_dynevent_destroy_all,
-tracefs_dynevent_free, tracefs_dynevent_list_free, tracefs_dynevent_get_all, tracefs_dynevent_info -
-Create, destroy, free and get dynamic events.
+tracefs_dynevent_free, tracefs_dynevent_list_free, tracefs_dynevent_get_all, tracefs_dynevent_info,
+tracefs_dynevent_get_event - Create, destroy, free and get dynamic events.
SYNOPSIS
--------
@@ -23,6 +23,7 @@ void *tracefs_dynevent_list_free*(struct tracefs_dynevent pass:[*]pass:[*]_event
struct tracefs_dynevent pass:[*]*tracefs_dynevent_get*(enum tracefs_dynevent_type _type_, const char pass:[*]_system_, const char pass:[*]_event_);
struct tracefs_dynevent pass:[*]pass:[*]*tracefs_dynevent_get_all*(unsigned int _types_, const char pass:[*]_system_);
enum tracefs_dynevent_type *tracefs_dynevent_info*(struct tracefs_dynevent pass:[*]_dynevent_, char pass:[*]pass:[*]_system_, char pass:[*]pass:[*]_event_, char pass:[*]pass:[*]_prefix_, char pass:[*]pass:[*]_addr_, char pass:[*]pass:[*]_format_);
+struct tep_event pass:[*]*tracefs_dynevent_get_event*(struct tep_handle pass:[*]_tep_, struct tracefs_dynevent pass:[*]_dynevent_);
--
DESCRIPTION
@@ -68,6 +69,11 @@ if relevant for this event type. If _format_ is non NULL, it will hold the forma
dynamic event. Note, that the content in _group_, _event_, _prefix_, _addr_, and _format_ must be
freed with free(3) if they are set.
+The *tracefs_dynevent_get_event*() function returns tep event, describing the given dynamic event.
+If the dynamic event is newly created and not yet loaded in the @tep, the dynamic event system is
+rescanned for any new events. The returned pointer to tep event is controlled by @tep and must not
+be freed.
+
RETURN VALUE
------------
@@ -88,6 +94,10 @@ in case of an error or in case there are no events in the system. That array mus
on error. If _system_, _event_, _prefix_, _addr_, or _format_ are non NULL, they will contain
allocated strings that must be freed by free(3).
+The *tracefs_dynevent_get_event*() function returns pointer to tep event or NULL in case of an error
+or if the requested dynamic event is missing. The returned pointer to tep event is controlled by
+@tep and must not be freed.
+
ERRORS
------
The following errors are for all the above calls:
diff --git a/include/tracefs.h b/include/tracefs.h
index 9662603..fbd7d31 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -262,6 +262,8 @@ tracefs_dynevent_get(enum tracefs_dynevent_type type, const char *system, const
enum tracefs_dynevent_type
tracefs_dynevent_info(struct tracefs_dynevent *dynevent, char **system,
char **event, char **prefix, char **addr, char **format);
+struct tep_event *
+tracefs_dynevent_get_event(struct tep_handle *tep, struct tracefs_dynevent *dynevent);
struct tracefs_dynevent *
tracefs_eprobe_alloc(const char *system, const char *event,
diff --git a/src/tracefs-dynevents.c b/src/tracefs-dynevents.c
index ea07d13..2ff3c87 100644
--- a/src/tracefs-dynevents.c
+++ b/src/tracefs-dynevents.c
@@ -752,3 +752,32 @@ error:
return TRACEFS_DYNEVENT_UNKNOWN;
}
+
+/**
+ * tracefs_dynevent_get_event - return tep event, representing the given dynamic event
+ * @tep: a handle to the trace event parser context, that holds the events
+ * @dynevent: a dynamic event context, describing given dynamic event.
+ *
+ * Returns pointer to tep event, describing the given dynamic event. The pointer
+ * is managed by @tep handle and must not be freed. In case of an error, or in case
+ * the requested dynamic event is missing in the @tep handler - NULL is returned.
+ */
+struct tep_event *
+tracefs_dynevent_get_event(struct tep_handle *tep, struct tracefs_dynevent *dynevent)
+{
+ struct tep_event *event;
+
+ if (!tep || !dynevent || !dynevent->event)
+ return NULL;
+
+ /* If the dynamic event is already loaded in the tep, return it */
+ event = tep_find_event_by_name(tep, dynevent->system, dynevent->event);
+ if (event)
+ return event;
+
+ /* Try to load any new events from the given system */
+ if (trace_load_events(tep, NULL, dynevent->system))
+ return NULL;
+
+ return tep_find_event_by_name(tep, dynevent->system, dynevent->event);
+}
--
2.33.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 3/4] libtracefs: Unit test for tracefs_dynevent_get_event()
2021-11-30 5:00 [PATCH 0/4] New tracefs APIs Tzvetomir Stoyanov (VMware)
2021-11-30 5:00 ` [PATCH 1/4] libtracefs: Reuse logic for loading events inside the library Tzvetomir Stoyanov (VMware)
2021-11-30 5:00 ` [PATCH 2/4] libtracefs: New API for getting dynamic event Tzvetomir Stoyanov (VMware)
@ 2021-11-30 5:00 ` Tzvetomir Stoyanov (VMware)
2021-11-30 5:00 ` [PATCH 4/4] libtracefs: New API for applying filter on event Tzvetomir Stoyanov (VMware)
3 siblings, 0 replies; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-11-30 5:00 UTC (permalink / raw)
To: rostedt, y.karadz; +Cc: linux-trace-devel
Unit tests for dynamic events are extended to test the newly introduced
tracefs_dynevent_get_event() API.
Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
Documentation/libtracefs-dynevents.txt | 5 ++-
utest/tracefs-utest.c | 58 +++++++++++++++++---------
2 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/Documentation/libtracefs-dynevents.txt b/Documentation/libtracefs-dynevents.txt
index 7de06be..bd18f5b 100644
--- a/Documentation/libtracefs-dynevents.txt
+++ b/Documentation/libtracefs-dynevents.txt
@@ -71,8 +71,9 @@ freed with free(3) if they are set.
The *tracefs_dynevent_get_event*() function returns tep event, describing the given dynamic event.
If the dynamic event is newly created and not yet loaded in the @tep, the dynamic event system is
-rescanned for any new events. The returned pointer to tep event is controlled by @tep and must not
-be freed.
+rescanned for any new events. If the dynamic event is deleted from the system, any subsequent calls
+to *tracefs_dynevent_get_event*() may return a tep event, as the deletion is not detected by the API.
+The returned pointer to tep event is controlled by @tep and must not be freed.
RETURN VALUE
------------
diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
index 3a01f38..c555b06 100644
--- a/utest/tracefs-utest.c
+++ b/utest/tracefs-utest.c
@@ -567,9 +567,10 @@ struct probe_test {
static bool check_probes(struct probe_test *probes, int count,
struct tracefs_dynevent **devents, bool in_system,
- struct tracefs_instance *instance)
+ struct tracefs_instance *instance, struct tep_handle *tep)
{
enum tracefs_dynevent_type type;
+ struct tep_event *tevent;
char *ename;
char *address;
char *event;
@@ -615,6 +616,15 @@ static bool check_probes(struct probe_test *probes, int count,
CU_TEST(ret != 0);
}
+ if (in_system) {
+ tevent = tracefs_dynevent_get_event(tep, devents[i]);
+ CU_TEST(tevent != NULL);
+ if (tevent) {
+ CU_TEST(strcmp(tevent->name, event) == 0);
+ CU_TEST(strcmp(tevent->system, system) == 0);
+ }
+ }
+
found++;
break;
}
@@ -649,10 +659,14 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
struct tracefs_dynevent **dkretprobe;
struct tracefs_dynevent **dkprobe;
struct tracefs_dynevent **devents;
+ struct tep_handle *tep;
char *tmp;
int ret;
int i;
+ tep = tep_alloc();
+ CU_TEST(tep != NULL);
+
dkprobe = calloc(kprobe_count + 1, sizeof(*dkprobe));
dkretprobe = calloc(kretprobe_count + 1, sizeof(*dkretprobe));
@@ -676,7 +690,7 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
}
dkprobe[i] = NULL;
get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
- CU_TEST(check_probes(ktests, kprobe_count, dkprobe, false, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, dkprobe, false, instance, tep));
for (i = 0; i < kretprobe_count; i++) {
dkretprobe[i] = tracefs_kretprobe_alloc(kretests[i].system, kretests[i].event,
@@ -685,15 +699,15 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
}
dkretprobe[i] = NULL;
get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
- CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance));
+ CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
for (i = 0; i < kprobe_count; i++) {
CU_TEST(tracefs_dynevent_create(dkprobe[i]) == 0);
}
devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
kprobe_count);
- CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance));
- CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
+ CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -702,8 +716,8 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
}
devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
kprobe_count + kretprobe_count);
- CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance));
- CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
+ CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -712,8 +726,8 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
}
devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
kprobe_count);
- CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance));
- CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
+ CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -721,8 +735,8 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
CU_TEST(tracefs_dynevent_destroy(dkprobe[i], false) == 0);
}
get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
- CU_TEST(check_probes(ktests, kprobe_count, dkprobe, false, instance));
- CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, dkprobe, false, instance, tep));
+ CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -743,7 +757,7 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
}
devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, kprobe_count);
- CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -754,19 +768,19 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
}
devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE, kprobe_count);
- CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
devents = get_dynevents_check(TRACEFS_DYNEVENT_KRETPROBE, kretprobe_count);
- CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance));
+ CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
kprobe_count + kretprobe_count);
- CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance));
- CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance));
+ CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
+ CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -775,6 +789,7 @@ static void test_kprobes_instance(struct tracefs_instance *instance)
get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
free(dkretprobe);
free(dkprobe);
+ tep_free(tep);
}
static void test_kprobes(void)
@@ -793,11 +808,15 @@ static void test_eprobes_instance(struct tracefs_instance *instance)
int count = sizeof(etests) / sizeof((etests)[0]);
struct tracefs_dynevent **deprobes;
struct tracefs_dynevent **devents;
+ struct tep_handle *tep;
char *tsys, *tevent;
char *tmp, *sav;
int ret;
int i;
+ tep = tep_alloc();
+ CU_TEST(tep != NULL);
+
deprobes = calloc(count + 1, sizeof(*deprobes));
/* Invalid parameters */
@@ -821,14 +840,14 @@ static void test_eprobes_instance(struct tracefs_instance *instance)
deprobes[i] = NULL;
get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0);
- CU_TEST(check_probes(etests, count, deprobes, false, instance));
+ CU_TEST(check_probes(etests, count, deprobes, false, instance, tep));
for (i = 0; i < count; i++) {
CU_TEST(tracefs_dynevent_create(deprobes[i]) == 0);
}
devents = get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, count);
- CU_TEST(check_probes(etests, count, devents, true, instance));
+ CU_TEST(check_probes(etests, count, devents, true, instance, tep));
tracefs_dynevent_list_free(devents);
devents = NULL;
@@ -836,12 +855,13 @@ static void test_eprobes_instance(struct tracefs_instance *instance)
CU_TEST(tracefs_dynevent_destroy(deprobes[i], false) == 0);
}
get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0);
- CU_TEST(check_probes(etests, count, deprobes, false, instance));
+ CU_TEST(check_probes(etests, count, deprobes, false, instance, tep));
for (i = 0; i < count; i++)
tracefs_dynevent_free(deprobes[i]);
free(deprobes);
+ tep_free(tep);
}
static void test_eprobes(void)
--
2.33.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 4/4] libtracefs: New API for applying filter on event.
2021-11-30 5:00 [PATCH 0/4] New tracefs APIs Tzvetomir Stoyanov (VMware)
` (2 preceding siblings ...)
2021-11-30 5:00 ` [PATCH 3/4] libtracefs: Unit test for tracefs_dynevent_get_event() Tzvetomir Stoyanov (VMware)
@ 2021-11-30 5:00 ` Tzvetomir Stoyanov (VMware)
2021-12-01 19:55 ` Steven Rostedt
3 siblings, 1 reply; 8+ messages in thread
From: Tzvetomir Stoyanov (VMware) @ 2021-11-30 5:00 UTC (permalink / raw)
To: rostedt, y.karadz; +Cc: linux-trace-devel
There is no API for applying a filter string on event. Existing APIs
only constructs and verifies the filter string. Even though the actual
applying is just writing into the event's filter file, it is good to
have a dedicated API for that:
tracefs_event_apply_filter()
Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
---
Documentation/libtracefs-filter.txt | 11 ++++++++++-
include/tracefs.h | 3 +++
src/tracefs-filter.c | 19 +++++++++++++++++++
3 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/Documentation/libtracefs-filter.txt b/Documentation/libtracefs-filter.txt
index 7e167bc..7532c96 100644
--- a/Documentation/libtracefs-filter.txt
+++ b/Documentation/libtracefs-filter.txt
@@ -3,7 +3,8 @@ libtracefs(3)
NAME
----
-tracefs_event_append_filter, tracefs_event_verify_filter - Add and verify event filters
+tracefs_event_append_filter, tracefs_event_verify_filter tracefs_event_apply_filter -
+Add, verify and apply event filters
SYNOPSIS
--------
@@ -15,6 +16,7 @@ int tracefs_event_append_filter(struct tep_event pass:[*]event, char pass:[**] f
struct tracefs_filter type, const char pass:[*]field,
enum tracefs_synth_compare compare, const char pass:[*]val);
int tracefs_event_verify_filter(struct tep_event pass:[*]event, const char pass:[*]filter, char pass:[**]err);
+int tracefs_event_apply_filter(struct tracefs_instance pass:[*]instance, struct tep_event pass:[*]event, const char pass:[*]filter);
--
@@ -66,6 +68,8 @@ error in the syntax, and _err_ is not NULL, then it will be allocated with an
error message stating what was found wrong with the filter. _err_ must be freed
with *free*().
+*tracefs_event_apply_filter*() applies given _filter_ string on _event_ in given _instance_.
+
RETURN VALUE
------------
*tracefs_event_append_filter*() returns 0 on success and -1 on error.
@@ -75,6 +79,8 @@ is an error, and _errno_ is not *ENOMEM*, then _err_ is allocated and will
contain a string describing what was found wrong with _filter_. _err_ must be
freed with *free*().
+*tracefs_event_apply_filter*() returns 0 on success and -1 on error.
+
EXAMPLE
-------
[source,c]
@@ -269,6 +275,9 @@ int main (int argc, char **argv)
}
}
+ if (tracefs_event_apply_filter(NULL, event, new_filter))
+ fprintf(stderr, "Failed to apply filter on event");
+
tep_free(tep);
printf("Created new filter: '%s'\n", new_filter);
diff --git a/include/tracefs.h b/include/tracefs.h
index fbd7d31..8ac9694 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -475,6 +475,9 @@ int tracefs_event_append_filter(struct tep_event *event, char **filter,
const char *val);
int tracefs_event_verify_filter(struct tep_event *event, const char *filter,
char **err);
+int tracefs_event_apply_filter(struct tracefs_instance *instance,
+ struct tep_event *event, const char *filter);
+
#define TRACEFS_TIMESTAMP "common_timestamp"
#define TRACEFS_TIMESTAMP_USECS "common_timestamp.usecs"
diff --git a/src/tracefs-filter.c b/src/tracefs-filter.c
index def8f68..43683d0 100644
--- a/src/tracefs-filter.c
+++ b/src/tracefs-filter.c
@@ -745,3 +745,22 @@ int tracefs_event_verify_filter(struct tep_event *event, const char *filter,
free(str);
return 0;
}
+
+/**
+ * tracefs_event_apply_filter - apply given filter on event in given instance
+ * @instance: The instance in which the filter will be applied (NULL for toplevel).
+ * @event: The event to apply the filter on.
+ * @filter: The filter to apply.
+ *
+ * Apply the @filter to given @event in givem @instance. The @filter string
+ * should be created with tracefs_event_append_filter().
+ *
+ * Returns 0 on succes and -1 on error.
+ */
+int tracefs_event_apply_filter(struct tracefs_instance *instance,
+ struct tep_event *event, const char *filter)
+{
+ return tracefs_event_file_append(instance, event->system, event->name,
+ "filter", filter);
+}
+
--
2.33.1
^ permalink raw reply related [flat|nested] 8+ messages in thread