* [PATCH 0/9] trace-cmd library: Add and use new helper functions
@ 2022-08-05 15:40 Steven Rostedt
2022-08-05 15:40 ` [PATCH 1/9] tracecmd: Use make variable instead of if statement for zlib test Steven Rostedt
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Add the following functions to the libtracecmd library:
tracecmd_set_private() - set private data to tracecmd_input handle
tracecmd_get_private() - get private data from tracecmd_input handle
tracecmd_iterate_events() - iterate all events for a single buffer in a
trace.dat file (can filter on CPUs)
tracecmd_iterate_events_multi() - iterate all events from multiple buffers
in a trace.dat file. (Does not filter on CPUs).
tracecmd_filter_add() - Add a filter to a tracecmd_input handle that will
filter the iterator funtions.
tracecmd_filter_match() - Will test a record against a given filter to see
if it matches or not.
As change trace-cmd to use these functions instead of doing the same thing
internally.
Steven Rostedt (Google) (9):
tracecmd: Use make variable instead of if statement for zlib test
tracecmd library: Add tracecmd_iterate_events()
tracecmd utest: Add test to test using the libraries to read
tracecmd library: Add tracecmd_iterate_events_multi()
trace-cmd library: Allow callers to save private data in
tracecmd_input handlers
trace-cmd report: Use tracecmd_iterate_events_multi()
trace-cmd library: Add filtering logic for iterating events
trace-cmd report: Make filter arguments match their files
trace-cmd report: Use library tracecmd_filter_*() logic
Makefile | 3 +
include/trace-cmd/trace-cmd.h | 29 ++
lib/trace-cmd/Makefile | 7 +-
lib/trace-cmd/include/trace-cmd-local.h | 5 +
lib/trace-cmd/trace-filter.c | 197 ++++++++++
lib/trace-cmd/trace-input.c | 197 ++++++++++
tracecmd/Makefile | 6 +-
tracecmd/trace-read.c | 466 ++++++++----------------
utest/Makefile | 4 +-
utest/tracecmd-utest.c | 53 ++-
10 files changed, 650 insertions(+), 317 deletions(-)
create mode 100644 lib/trace-cmd/trace-filter.c
--
2.35.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/9] tracecmd: Use make variable instead of if statement for zlib test
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 2/9] tracecmd library: Add tracecmd_iterate_events() Steven Rostedt
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Instead of adding a test in all the Makefiles that test ZLIB_INSTALLED,
just create a variable that has ZLIB_LDLAGS set to -lz when enabled and
pass that to the LIB flags. When it's not enabled, ZLIB_LDLAGS will be
empty.
(I guess LDLAGS should have been LDFLAGS but a typo appears to have gone
wild!)
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
Makefile | 3 +++
lib/trace-cmd/Makefile | 6 +-----
tracecmd/Makefile | 6 +-----
3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index 2cf66e0d5efc..437b7d5a7152 100644
--- a/Makefile
+++ b/Makefile
@@ -316,10 +316,13 @@ endif
ZLIB_INSTALLED := $(shell if (printf "$(pound)include <zlib.h>\n void main(){deflateInit(NULL, Z_BEST_COMPRESSION);}" | $(CC) -o /dev/null -x c - -lz >/dev/null 2>&1) ; then echo 1; else echo 0 ; fi)
ifeq ($(ZLIB_INSTALLED), 1)
export ZLIB_INSTALLED
+ZLIB_LDLAGS = -lz
CFLAGS += -DHAVE_ZLIB
$(info Have zlib compression support)
endif
+export ZLIB_LDLAGS
+
TEST_LIBZSTD = $(shell sh -c "$(PKG_CONFIG) --atleast-version 1.4.0 libzstd > /dev/null 2>&1 && echo y")
ifeq ("$(TEST_LIBZSTD)", "y")
diff --git a/lib/trace-cmd/Makefile b/lib/trace-cmd/Makefile
index 9374b163b5f3..a476e35b3762 100644
--- a/lib/trace-cmd/Makefile
+++ b/lib/trace-cmd/Makefile
@@ -51,11 +51,7 @@ $(DEPS): | $(bdir)
$(LIBTRACECMD_STATIC): $(OBJS)
$(Q)$(call do_build_static_lib)
-LIBS = $(LIBTRACEEVENT_LDLAGS) $(LIBTRACEFS_LDLAGS) $(LIBZSTD_LDLAGS) -lpthread
-
-ifeq ($(ZLIB_INSTALLED), 1)
-LIBS += -lz
-endif
+LIBS = $(LIBTRACEEVENT_LDLAGS) $(LIBTRACEFS_LDLAGS) $(ZLIB_LDLAGS) $(LIBZSTD_LDLAGS) -lpthread
$(LIBTRACECMD_SHARED_VERSION): $(LIBTRACECMD_SHARED)
@ln -sf $(<F) $@
diff --git a/tracecmd/Makefile b/tracecmd/Makefile
index 56be9a3b88d1..8207c54b4391 100644
--- a/tracecmd/Makefile
+++ b/tracecmd/Makefile
@@ -50,13 +50,9 @@ all_objs := $(sort $(ALL_OBJS))
all_deps := $(all_objs:$(bdir)/%.o=$(bdir)/.%.d)
CONFIG_INCLUDES =
-CONFIG_LIBS = -lrt -lpthread $(TRACE_LIBS) $(LIBZSTD_LDLAGS)
+CONFIG_LIBS = -lrt -lpthread $(TRACE_LIBS) $(ZLIB_LDLAGS) $(LIBZSTD_LDLAGS)
CONFIG_FLAGS =
-ifeq ($(ZLIB_INSTALLED), 1)
-CONFIG_LIBS += -lz
-endif
-
all: $(TARGETS)
$(bdir):
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/9] tracecmd library: Add tracecmd_iterate_events()
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
2022-08-05 15:40 ` [PATCH 1/9] tracecmd: Use make variable instead of if statement for zlib test Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 3/9] tracecmd utest: Add test to test using the libraries to read Steven Rostedt
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Add a helper function that will iterate over a list of events for a given
handle. Requires the handle to be opened and ready for reading.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
include/trace-cmd/trace-cmd.h | 7 ++++
lib/trace-cmd/trace-input.c | 70 +++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+)
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index 5d71e8bab186..b91235751d64 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -48,6 +48,13 @@ int tracecmd_buffer_instances(struct tracecmd_input *handle);
const char *tracecmd_buffer_instance_name(struct tracecmd_input *handle, int indx);
struct tracecmd_input *tracecmd_buffer_instance_handle(struct tracecmd_input *handle, int indx);
+int tracecmd_iterate_events(struct tracecmd_input *handle,
+ cpu_set_t *cpus, int cpu_size,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_record *,
+ int, void *),
+ void *callback_data);
+
void tracecmd_set_loglevel(enum tep_loglevel level);
#endif /* _TRACE_CMD_H */
diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index 0fef2ca7bb70..e990600ad6b1 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -2511,6 +2511,76 @@ tracecmd_read_next_data(struct tracecmd_input *handle, int *rec_cpu)
return tracecmd_read_data(handle, next_cpu);
}
+/**
+ * tracecmd_iterate_events - iterate events over a given handle
+ * @handle: The handle to iterate over
+ * @cpus: The CPU set to filter on (NULL for all CPUs)
+ * @cpu_size: The size of @cpus (ignored if @cpus is NULL)
+ * @callback: The callback function for each event
+ * @callback_data: The data to pass to the @callback.
+ *
+ * Will loop over all events in @handle (filtered by the given @cpus),
+ * and will call @callback for each event in order of the event's records
+ * timestamp.
+ *
+ * Returns the -1 on error, or the value of the callbacks.
+ */
+int tracecmd_iterate_events(struct tracecmd_input *handle,
+ cpu_set_t *cpus, int cpu_size,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_record *,
+ int, void *),
+ void *callback_data)
+{
+ struct tep_record **records;
+ struct tep_record *record;
+ unsigned long long last_timestamp = 0;
+ int next_cpu;
+ int cpu;
+ int ret = 0;
+
+ records = calloc(handle->max_cpu, sizeof(*records));
+ if (!records)
+ return -1;
+
+ for (cpu = 0; cpu < handle->max_cpu; cpu++) {
+ if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpus))
+ continue;
+
+ records[cpu] = tracecmd_peek_data(handle, cpu);
+ }
+
+ do {
+ next_cpu = -1;
+ for (cpu = 0; cpu < handle->max_cpu; cpu++) {
+ record = records[cpu];
+ if (!record)
+ continue;
+
+ if (next_cpu < 0 || record->ts < last_timestamp) {
+ next_cpu = cpu;
+ last_timestamp = record->ts;
+ }
+ }
+ if (next_cpu >= 0) {
+ /* Need to call read_data to increment to the next record */
+ record = tracecmd_read_data(handle, next_cpu);
+ records[next_cpu] = tracecmd_peek_data(handle, next_cpu);
+
+ ret = callback(handle, record, next_cpu, callback_data);
+ tracecmd_free_record(record);
+ }
+
+ } while (next_cpu >= 0 && ret >= 0);
+
+ for (cpu = 0; cpu < handle->max_cpu; cpu++)
+ tracecmd_free_record(records[cpu]);
+
+ free(records);
+
+ return ret;
+}
+
/**
* tracecmd_peek_next_data - return the next record
* @handle: input handle to the trace.dat file
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/9] tracecmd utest: Add test to test using the libraries to read
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
2022-08-05 15:40 ` [PATCH 1/9] tracecmd: Use make variable instead of if statement for zlib test Steven Rostedt
2022-08-05 15:40 ` [PATCH 2/9] tracecmd library: Add tracecmd_iterate_events() Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 4/9] tracecmd library: Add tracecmd_iterate_events_multi() Steven Rostedt
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Add a test that uses tracecmd_open() and tracecmd_iterate_events() to read
a trace.dat file.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
utest/Makefile | 4 +++-
utest/tracecmd-utest.c | 53 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/utest/Makefile b/utest/Makefile
index 2b8f85f21a24..d475bad5a0f9 100644
--- a/utest/Makefile
+++ b/utest/Makefile
@@ -10,7 +10,9 @@ OBJS =
OBJS += trace-utest.o
OBJS += tracecmd-utest.o
-LIBS += -lcunit $(LIBTRACEEVENT_LDLAGS) $(LIBTRACEFS_LDLAGS)
+LIBS += $(LIBTRACECMD_STATIC) -lcunit $(LIBTRACEEVENT_LDLAGS) $(LIBTRACEFS_LDLAGS)
+
+LIBS += $(ZLIB_LDLAGS) $(LIBZSTD_LDLAGS)
OBJS := $(OBJS:%.o=$(bdir)/%.o)
DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d)
diff --git a/utest/tracecmd-utest.c b/utest/tracecmd-utest.c
index 7db5999e17f5..e45b3537365c 100644
--- a/utest/tracecmd-utest.c
+++ b/utest/tracecmd-utest.c
@@ -17,7 +17,7 @@
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
-#include <tracefs.h>
+#include <trace-cmd.h>
#include "trace-utest.h"
@@ -244,6 +244,55 @@ static void test_trace_convert6(void)
CU_TEST(ret == 0);
}
+struct callback_data {
+ long counter;
+ struct trace_seq seq;
+};
+
+static int read_events(struct tracecmd_input *handle, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct tep_handle *tep = tracecmd_get_tep(handle);
+ struct callback_data *cd = data;
+ struct trace_seq *seq = &cd->seq;
+
+ cd->counter++;
+
+ trace_seq_reset(seq);
+ tep_print_event(tep, seq, record, "%6.1000d", TEP_PRINT_TIME);
+ trace_seq_printf(seq, " [%03d] ", cpu);
+ tep_print_event(tep, seq, record, "%s-%d %s %s\n",
+ TEP_PRINT_COMM, TEP_PRINT_PID,
+ TEP_PRINT_NAME, TEP_PRINT_INFO);
+ trace_seq_do_printf(seq);
+ return 0;
+}
+
+static void test_trace_library_read(void)
+{
+ struct tracecmd_input *handle;
+ struct callback_data data;
+ struct stat st;
+ int ret;
+
+ data.counter = 0;
+ trace_seq_init(&data.seq);
+
+ /* If the trace data is already created, just use it, otherwise make it again */
+ if (stat(TRACECMD_FILE, &st) < 0) {
+ ret = run_trace("record", TRACECMD_OUT, "-e", "sched", "sleep", "1", NULL);
+ CU_TEST(ret == 0);
+ }
+
+ handle = tracecmd_open(TRACECMD_FILE, 0);
+ CU_TEST(handle != NULL);
+ ret = tracecmd_iterate_events(handle, NULL, 0, read_events, &data);
+ CU_TEST(ret == 0);
+
+ CU_TEST(data.counter > 0);
+ trace_seq_destroy(&data.seq);
+}
+
static int test_suite_destroy(void)
{
unlink(TRACECMD_FILE);
@@ -292,4 +341,6 @@ void test_tracecmd_lib(void)
test_trace_record_report);
CU_add_test(suite, "Test convert from v7 to v6",
test_trace_convert6);
+ CU_add_test(suite, "Use libraries to read file",
+ test_trace_library_read);
}
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/9] tracecmd library: Add tracecmd_iterate_events_multi()
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
` (2 preceding siblings ...)
2022-08-05 15:40 ` [PATCH 3/9] tracecmd utest: Add test to test using the libraries to read Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 5/9] trace-cmd library: Allow callers to save private data in tracecmd_input handlers Steven Rostedt
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Add a helper function that takes an array of tracecmd_input handles and
calls the callback for each event in order of the record's timestamp for
each handle.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
include/trace-cmd/trace-cmd.h | 6 +++
lib/trace-cmd/trace-input.c | 91 +++++++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+)
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index b91235751d64..86a3486972cc 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -54,6 +54,12 @@ int tracecmd_iterate_events(struct tracecmd_input *handle,
struct tep_record *,
int, void *),
void *callback_data);
+int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
+ int nr_handles,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_record *,
+ int, void *),
+ void *callback_data);
void tracecmd_set_loglevel(enum tep_loglevel level);
diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index e990600ad6b1..5df10716013d 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -170,6 +170,7 @@ struct tracecmd_input {
int page_map_size;
int max_cpu;
int cpus;
+ int start_cpu;
int ref;
int nr_buffers; /* buffer instances */
bool use_trace_clock;
@@ -2581,6 +2582,96 @@ int tracecmd_iterate_events(struct tracecmd_input *handle,
return ret;
}
+struct record_handle {
+ struct tep_record *record;
+ struct tracecmd_input *handle;
+};
+
+/**
+ * tracecmd_iterate_events_multi - iterate events over multiple handles
+ * @handles: An array of handles to iterate over
+ * @nr_handles: The number of handles in the @handles array.
+ * @callback: The callback function for each event
+ * @callback_data: The data to pass to the @callback.
+ *
+ * Will loop over all CPUs for each handle in @handles and call the
+ * @callback in the order of the timestamp for each event's record
+ * for each handle.
+ *
+ * Returns the -1 on error, or the value of the callbacks.
+ */
+int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
+ int nr_handles,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_record *,
+ int, void *),
+ void *callback_data)
+{
+ struct tracecmd_input *handle;
+ struct record_handle *records;
+ struct tep_record *record;
+ unsigned long long last_timestamp = 0;
+ int next_cpu;
+ int cpus = 0;
+ int all_cpus = 0;
+ int cpu;
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < nr_handles; i++) {
+ handle = handles[i];
+ cpus += handle->max_cpu;
+ }
+
+ records = calloc(cpus, sizeof(*records));
+ if (!records)
+ return -1;
+
+ for (i = 0; i < nr_handles; i++) {
+ handle = handles[i];
+ handle->start_cpu = all_cpus;
+ for (cpu = 0; cpu < handle->max_cpu; cpu++) {
+ records[all_cpus + cpu].record = tracecmd_peek_data(handle, cpu);
+ records[all_cpus + cpu].handle = handle;
+ }
+ all_cpus += cpu;
+ }
+
+ do {
+ next_cpu = -1;
+ for (cpu = 0; cpu < all_cpus; cpu++) {
+ record = records[cpu].record;
+ if (!record)
+ continue;
+
+ if (next_cpu < 0 || record->ts < last_timestamp) {
+ next_cpu = cpu;
+ last_timestamp = record->ts;
+ }
+ }
+ if (next_cpu >= 0) {
+ record = records[next_cpu].record;
+ handle = records[next_cpu].handle;
+ cpu = next_cpu - handle->start_cpu;
+ /* Need to call read_data to increment to the next record */
+ record = tracecmd_read_data(handle, cpu);
+ records[next_cpu].record = tracecmd_peek_data(handle, cpu);
+
+ ret = callback(handle, record, cpu, callback_data);
+ tracecmd_free_record(record);
+ }
+
+ } while (next_cpu >= 0 && ret >= 0);
+
+ /*
+ * The records array contains only records that were taken via
+ * tracecmd_peek_data(), and do not need to be freed.
+ */
+ free(records);
+
+ return ret;
+}
+
/**
* tracecmd_peek_next_data - return the next record
* @handle: input handle to the trace.dat file
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/9] trace-cmd library: Allow callers to save private data in tracecmd_input handlers
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
` (3 preceding siblings ...)
2022-08-05 15:40 ` [PATCH 4/9] tracecmd library: Add tracecmd_iterate_events_multi() Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 6/9] trace-cmd report: Use tracecmd_iterate_events_multi() Steven Rostedt
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Add a private field for tracecmd_input handle where callers can set it via
tracecmd_set_private() and retrieve it with tracecmd_get_private(). This
will allow a way to find specific information about a handle for users of
tracecmd_iterate_events_multi().
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
include/trace-cmd/trace-cmd.h | 3 +++
lib/trace-cmd/trace-input.c | 12 ++++++++++++
2 files changed, 15 insertions(+)
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index 86a3486972cc..e8d72c76c02a 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -48,6 +48,9 @@ int tracecmd_buffer_instances(struct tracecmd_input *handle);
const char *tracecmd_buffer_instance_name(struct tracecmd_input *handle, int indx);
struct tracecmd_input *tracecmd_buffer_instance_handle(struct tracecmd_input *handle, int indx);
+void tracecmd_set_private(struct tracecmd_input *handle, void *data);
+void *tracecmd_get_private(struct tracecmd_input *handle);
+
int tracecmd_iterate_events(struct tracecmd_input *handle,
cpu_set_t *cpus, int cpu_size,
int (*callback)(struct tracecmd_input *handle,
diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index 5df10716013d..a3f17070c269 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -215,6 +215,8 @@ struct tracecmd_input {
/* For custom profilers. */
tracecmd_show_data_func show_data_func;
+
+ void *private;
};
__thread struct tracecmd_input *tracecmd_curr_thread_handle;
@@ -245,6 +247,16 @@ enum tracecmd_file_states tracecmd_get_file_state(struct tracecmd_input *handle)
return handle->file_state;
}
+void tracecmd_set_private(struct tracecmd_input *handle, void *data)
+{
+ handle->private = data;
+}
+
+void *tracecmd_get_private(struct tracecmd_input *handle)
+{
+ return handle->private;
+}
+
#if DEBUG_RECORD
static void remove_record(struct page *page, struct tep_record *record)
{
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/9] trace-cmd report: Use tracecmd_iterate_events_multi()
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
` (4 preceding siblings ...)
2022-08-05 15:40 ` [PATCH 5/9] trace-cmd library: Allow callers to save private data in tracecmd_input handlers Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 7/9] trace-cmd library: Add filtering logic for iterating events Steven Rostedt
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Use the new helper library function tracecmd_iterate_events_multi(). This
simplifies the code as well as shows an example of how to use it for other
applications.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
tracecmd/trace-read.c | 214 +++++++++++++++++-------------------------
1 file changed, 87 insertions(+), 127 deletions(-)
diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c
index 691450b05a39..8b3efae63f8e 100644
--- a/tracecmd/trace-read.c
+++ b/tracecmd/trace-read.c
@@ -56,11 +56,8 @@ struct handle_list {
struct tracecmd_input *handle;
const char *file;
int cpus;
- int done;
- struct tep_record *record;
struct filter *event_filters;
struct filter *event_filter_out;
- unsigned long long *last_timestamp;
};
static struct list_head handle_list;
@@ -1088,92 +1085,6 @@ test_stacktrace(struct handle_list *handles, struct tep_record *record,
return 0;
}
-static struct tep_record *get_next_record(struct handle_list *handles)
-{
- struct tep_record *record;
- struct tep_handle *pevent;
- int found = 0;
- int cpu;
- int ret;
-
- if (handles->record)
- return handles->record;
-
- if (handles->done)
- return NULL;
-
- pevent = tracecmd_get_tep(handles->handle);
-
- do {
- if (filter_cpus) {
- long long last_stamp = -1;
- struct tep_record *precord;
- int first_record = 1;
- int next_cpu = -1;
- int i;
-
- for (i = 0; (cpu = filter_cpus[i]) >= 0; i++) {
- precord = tracecmd_peek_data(handles->handle, cpu);
- if (precord &&
- (first_record || precord->ts < last_stamp)) {
- next_cpu = cpu;
- last_stamp = precord->ts;
- first_record = 0;
- }
- }
- if (!first_record)
- record = tracecmd_read_data(handles->handle, next_cpu);
- else
- record = NULL;
- } else
- record = tracecmd_read_next_data(handles->handle, &cpu);
-
- if (record) {
- ret = test_filters(pevent, handles->event_filters, record, 0);
- switch (ret) {
- case FILTER_NOEXIST:
- /* Stack traces may still filter this */
- if (stacktrace_id &&
- test_stacktrace(handles, record, 0))
- found = 1;
- else
- tracecmd_free_record(record);
- break;
- case FILTER_NONE:
- case FILTER_MATCH:
- /* Test the negative filters (-v) */
- ret = test_filters(pevent, handles->event_filter_out,
- record, 1);
- if (ret != FILTER_MATCH) {
- found = 1;
- break;
- }
- /* fall through */
- default:
- tracecmd_free_record(record);
- }
- }
- } while (record && !found);
-
- if (record && stacktrace_id)
- test_stacktrace(handles, record, 1);
-
- handles->record = record;
- if (!record)
- handles->done = 1;
-
- return record;
-}
-
-static void free_handle_record(struct handle_list *handles)
-{
- if (!handles->record)
- return;
-
- tracecmd_free_record(handles->record);
- handles->record = NULL;
-}
-
static void print_handle_file(struct handle_list *handles)
{
/* Only print file names if more than one file is read */
@@ -1198,6 +1109,75 @@ static void free_filters(struct filter *event_filter)
}
}
+static bool skip_record(struct handle_list *handles, struct tep_record *record, int cpu)
+{
+ struct tep_handle *tep;
+ bool found = false;
+ int ret;
+
+ tep = tracecmd_get_tep(handles->handle);
+
+ if (filter_cpus) {
+ int i;
+
+ for (i = 0; filter_cpus[i] >= 0; i++) {
+ if (filter_cpus[i] == cpu) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return true;
+ found = false;
+ }
+
+ ret = test_filters(tep, handles->event_filters, record, 0);
+ switch (ret) {
+ case FILTER_NOEXIST:
+ /* Stack traces may still filter this */
+ if (stacktrace_id &&
+ test_stacktrace(handles, record, 0))
+ found = true;
+ break;
+ case FILTER_NONE:
+ case FILTER_MATCH:
+ /* Test the negative filters (-v) */
+ ret = test_filters(tep, handles->event_filter_out,
+ record, 1);
+ if (ret != FILTER_MATCH) {
+ found = true;
+ break;
+ }
+ }
+
+ if (record && stacktrace_id)
+ test_stacktrace(handles, record, 1);
+
+ return !found;
+}
+
+static int process_record(struct tracecmd_input *handle, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct handle_list *handles = tracecmd_get_private(handle);
+ unsigned long long *last_timestamp = data;
+
+ if (skip_record(handles, record, cpu))
+ return 0;
+
+ if (tscheck && *last_timestamp > record->ts) {
+ errno = 0;
+ warning("WARNING: Record on cpu %d went backwards: %lld to %lld delta: -%lld\n",
+ cpu, *last_timestamp, record->ts, *last_timestamp - record->ts);
+ }
+ *last_timestamp = record->ts;
+
+ print_handle_file(handles);
+ trace_show_data(handle, record);
+ return 0;
+}
+
enum output_type {
OUTPUT_NORMAL,
OUTPUT_STAT_ONLY,
@@ -1210,17 +1190,19 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
{
unsigned long long ts, first_ts;
struct handle_list *handles;
- struct handle_list *last_handle;
- struct tep_record *record;
- struct tep_record *last_record;
+ struct tracecmd_input **handle_array;
struct tep_handle *pevent;
struct tep_event *event;
+ unsigned long long last_timestamp = 0;
+ int nr_handles = 0;
int first = 1;
int ret;
list_for_each_entry(handles, handle_list, list) {
int cpus;
+ nr_handles++;
+
if (!tracecmd_is_buffer_instance(handles->handle)) {
ret = tracecmd_init_data(handles->handle);
if (ret < 0)
@@ -1228,9 +1210,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
}
cpus = tracecmd_cpus(handles->handle);
handles->cpus = cpus;
- handles->last_timestamp = calloc(cpus, sizeof(*handles->last_timestamp));
- if (!handles->last_timestamp)
- die("allocating timestamps");
/* Don't process instances that we added here */
if (tracecmd_is_buffer_instance(handles->handle))
@@ -1315,38 +1294,20 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
}
}
- do {
- last_handle = NULL;
- last_record = NULL;
+ handle_array = calloc(nr_handles, sizeof(*handle_array));
+ if (!handle_array)
+ die("Could not allocate memory for handle list");
- list_for_each_entry(handles, handle_list, list) {
- record = get_next_record(handles);
- if (!record)
- continue;
- if (!last_record ||
- (record && record->ts < last_record->ts)) {
- last_record = record;
- last_handle = handles;
- }
- }
- if (last_record) {
- int cpu = last_record->cpu;
- if (cpu >= last_handle->cpus)
- die("cpu %d greater than %d\n", cpu, last_handle->cpus);
- if (tscheck &&
- last_handle->last_timestamp[cpu] > last_record->ts) {
- errno = 0;
- warning("WARNING: Record on cpu %d went backwards: %lld to %lld delta: -%lld\n",
- cpu, last_handle->last_timestamp[cpu],
- last_record->ts,
- last_handle->last_timestamp[cpu] - last_record->ts);
- }
- last_handle->last_timestamp[cpu] = last_record->ts;
- print_handle_file(last_handle);
- trace_show_data(last_handle->handle, last_record);
- free_handle_record(last_handle);
- }
- } while (last_record);
+ nr_handles = 0;
+ list_for_each_entry(handles, handle_list, list) {
+ tracecmd_set_private(handles->handle, handles);
+ handle_array[nr_handles++] = handles->handle;
+ }
+
+ tracecmd_iterate_events_multi(handle_array, nr_handles,
+ process_record, &last_timestamp);
+
+ free(handle_array);
if (profile)
do_trace_profile();
@@ -1354,7 +1315,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
list_for_each_entry(handles, handle_list, list) {
free_filters(handles->event_filters);
free_filters(handles->event_filter_out);
- free(handles->last_timestamp);
show_test(handles->handle);
}
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/9] trace-cmd library: Add filtering logic for iterating events
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
` (5 preceding siblings ...)
2022-08-05 15:40 ` [PATCH 6/9] trace-cmd report: Use tracecmd_iterate_events_multi() Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 8/9] trace-cmd report: Make filter arguments match their files Steven Rostedt
2022-08-05 15:40 ` [PATCH 9/9] trace-cmd report: Use library tracecmd_filter_*() logic Steven Rostedt
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Add tracecmd_filter_add() and tracecmd_filter_match() for filtering of
events during tracecmd_iterate_events() and
tracecmd_iterate_events_multi().
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
include/trace-cmd/trace-cmd.h | 13 ++
lib/trace-cmd/Makefile | 1 +
lib/trace-cmd/include/trace-cmd-local.h | 5 +
lib/trace-cmd/trace-filter.c | 197 ++++++++++++++++++++++++
lib/trace-cmd/trace-input.c | 28 +++-
5 files changed, 242 insertions(+), 2 deletions(-)
create mode 100644 lib/trace-cmd/trace-filter.c
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index e8d72c76c02a..4963f45dfe12 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -66,4 +66,17 @@ int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
void tracecmd_set_loglevel(enum tep_loglevel level);
+enum tracecmd_filters {
+ TRACECMD_FILTER_NONE = TEP_ERRNO__NO_FILTER,
+ TRACECMD_FILTER_NOT_FOUND = TEP_ERRNO__FILTER_NOT_FOUND,
+ TRACECMD_FILTER_MISS = TEP_ERRNO__FILTER_MISS,
+ TRACECMD_FILTER_MATCH = TEP_ERRNO__FILTER_MATCH,
+};
+
+struct tracecmd_filter;
+struct tracecmd_filter *tracecmd_filter_add(struct tracecmd_input *handle,
+ const char *filter_str, bool neg);
+enum tracecmd_filters tracecmd_filter_match(struct tracecmd_filter *filter,
+ struct tep_record *record);
+
#endif /* _TRACE_CMD_H */
diff --git a/lib/trace-cmd/Makefile b/lib/trace-cmd/Makefile
index a476e35b3762..81cde3def3a7 100644
--- a/lib/trace-cmd/Makefile
+++ b/lib/trace-cmd/Makefile
@@ -15,6 +15,7 @@ OBJS += trace-output.o
OBJS += trace-recorder.o
OBJS += trace-util.o
OBJS += trace-filter-hash.o
+OBJS += trace-filter.o
OBJS += trace-msg.o
OBJS += trace-plugin.o
ifeq ($(PERF_DEFINED), 1)
diff --git a/lib/trace-cmd/include/trace-cmd-local.h b/lib/trace-cmd/include/trace-cmd-local.h
index cfa3e97ae445..2a458133204b 100644
--- a/lib/trace-cmd/include/trace-cmd-local.h
+++ b/lib/trace-cmd/include/trace-cmd-local.h
@@ -97,4 +97,9 @@ unsigned int get_meta_strings_size(struct tracecmd_input *handle);
int trace_append_options(struct tracecmd_output *handle, void *buf, size_t len);
void *trace_get_options(struct tracecmd_output *handle, size_t *len);
+/* filters */
+struct tracecmd_filter *tracecmd_filter_get(struct tracecmd_input *handle);
+void tracecmd_filter_set(struct tracecmd_input *handle, struct tracecmd_filter *filter);
+void tracecmd_filter_free(struct tracecmd_filter *filter);
+
#endif /* _TRACE_CMD_LOCAL_H */
diff --git a/lib/trace-cmd/trace-filter.c b/lib/trace-cmd/trace-filter.c
new file mode 100644
index 000000000000..f7eb46c762d6
--- /dev/null
+++ b/lib/trace-cmd/trace-filter.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2022, Google Inc, Steven Rostedt <rostedt@goodmis.org>
+*/
+#include <stdlib.h>
+#include <trace-cmd.h>
+#include <trace-cmd-local.h>
+
+struct filter {
+ struct tep_event_filter *filter;
+};
+
+struct tracecmd_filter {
+ struct tep_handle *tep;
+ struct filter **event_filters;
+ struct filter **event_notrace;
+ bool *last_printed;
+ int nr_cpus;
+ int nr_filters;
+ int nr_notrace;
+ int kernel_stacktrace_id;
+ int user_stacktrace_id;
+};
+
+static bool test_stacktrace(struct tracecmd_filter *filter, struct tep_record *record,
+ int stacktrace_id)
+{
+ struct tep_handle *tep = filter->tep;
+ int id;
+
+ if (stacktrace_id < 0)
+ return false;
+
+ id = tep_data_type(tep, record);
+ if (id != stacktrace_id)
+ return false;
+
+ return filter->last_printed[record->cpu];
+}
+
+static bool test_stacktraces(struct tracecmd_filter *filter, struct tep_record *record)
+{
+ return test_stacktrace(filter, record, filter->kernel_stacktrace_id) ||
+ test_stacktrace(filter, record, filter->user_stacktrace_id);
+}
+
+enum tracecmd_filters tracecmd_filter_match(struct tracecmd_filter *filter,
+ struct tep_record *record)
+{
+ bool found = false;
+ int ret;
+ int i;
+
+ if (!filter)
+ return TRACECMD_FILTER_NONE;
+
+ /* Setup stack traces. If a event is shown, still show stack traces */
+ if (!filter->kernel_stacktrace_id) {
+ struct tep_handle *tep = filter->tep;
+ struct tep_event *event;
+
+ /* In case the below logic fails, do not do this again */
+ filter->kernel_stacktrace_id = -1;
+
+ event = tep_find_event_by_name(tep, "ftrace", "kernel_stack");
+ if (event)
+ filter->kernel_stacktrace_id = event->id;
+
+ event = tep_find_event_by_name(tep, "ftrace", "user_stack");
+ if (event)
+ filter->user_stacktrace_id = event->id;
+
+ filter->nr_cpus = tep_get_cpus(tep);
+ filter->last_printed = calloc(filter->nr_cpus, sizeof(*filter->last_printed));
+ if (!filter->last_printed) {
+ tracecmd_warning("Could not allocate last_printed array for stack trace filtering");
+ filter->kernel_stacktrace_id = -1;
+ filter->user_stacktrace_id = -1;
+ }
+ }
+
+ for (i = 0; i < filter->nr_filters; i++) {
+ ret = tep_filter_match(filter->event_filters[i]->filter, record);
+ switch (ret) {
+ case TRACECMD_FILTER_NONE:
+ case TRACECMD_FILTER_MATCH:
+ found = true;
+ }
+ if (found)
+ break;
+ }
+
+ if (!found && filter->nr_filters) {
+ /* If this is a stack trace and the last event was printed continue */
+ if (!test_stacktraces(filter, record))
+ return TRACECMD_FILTER_MISS;
+ }
+
+ found = false;
+ /* We need to test all negative filters */
+ for (i = 0; i < filter->nr_notrace; i++) {
+ ret = tep_filter_match(filter->event_notrace[i]->filter, record);
+ switch (ret) {
+ case TRACECMD_FILTER_NONE:
+ case TRACECMD_FILTER_MATCH:
+ found = true;
+ }
+ if (found)
+ break;
+ }
+
+ if (filter->last_printed)
+ filter->last_printed[record->cpu] = !found;
+
+ return found ? TRACECMD_FILTER_MISS : TRACECMD_FILTER_MATCH;
+}
+
+struct tracecmd_filter *tracecmd_filter_add(struct tracecmd_input *handle,
+ const char *filter_str, bool neg)
+{
+ struct tracecmd_filter *trace_filter;
+ struct tep_handle *tep;
+ struct filter ***filter_ptr;
+ struct filter **filters;
+ struct filter *filter;
+ int *nr;
+ int ret;
+
+ filter = calloc(1, sizeof(*filter));
+ if (!filter)
+ return NULL;
+
+ tep = tracecmd_get_tep(handle);
+
+ trace_filter = tracecmd_filter_get(handle);
+ if (!trace_filter) {
+ trace_filter = calloc(1, sizeof(*trace_filter));
+ if (!trace_filter)
+ goto fail;
+ tracecmd_filter_set(handle, trace_filter);
+ trace_filter->tep = tep;
+ }
+
+ filter->filter = tep_filter_alloc(tep);
+ if (!filter->filter)
+ goto fail;
+
+ ret = tep_filter_add_filter_str(filter->filter, filter_str);
+ if (ret < 0)
+ goto fail;
+
+ if (neg) {
+ filter_ptr = &trace_filter->event_notrace;
+ nr = &trace_filter->nr_notrace;
+ } else {
+ filter_ptr = &trace_filter->event_filters;
+ nr = &trace_filter->nr_filters;
+ }
+
+ filters = realloc(*filter_ptr, sizeof(*filters) * (*nr + 1));
+ if (!filters)
+ goto fail;
+
+ *filter_ptr = filters;
+ filters[*nr] = filter;
+ (*nr)++;
+ return trace_filter;
+ fail:
+ if (filter) {
+ tep_filter_free(filter->filter);
+ free(filter);
+ }
+ return NULL;
+}
+
+static void free_filters (struct filter **filter, int nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++) {
+ tep_filter_free(filter[i]->filter);
+ free(filter[i]);
+ }
+
+ free(filter);
+}
+
+__hidden void tracecmd_filter_free(struct tracecmd_filter *trace_filter)
+{
+ if (!trace_filter)
+ return;
+
+ free_filters(trace_filter->event_filters, trace_filter->nr_filters);
+ free_filters(trace_filter->event_notrace, trace_filter->nr_notrace);
+
+ free(trace_filter);
+}
diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index a3f17070c269..cdaa17bd69f9 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -160,6 +160,7 @@ struct tracecmd_input {
struct tep_handle *pevent;
struct tep_plugin_list *plugin_list;
struct tracecmd_input *parent;
+ struct tracecmd_filter *filter;
unsigned long file_state;
unsigned long long trace_id;
unsigned long long next_offset;
@@ -2580,7 +2581,10 @@ int tracecmd_iterate_events(struct tracecmd_input *handle,
record = tracecmd_read_data(handle, next_cpu);
records[next_cpu] = tracecmd_peek_data(handle, next_cpu);
- ret = callback(handle, record, next_cpu, callback_data);
+ if (!handle->filter ||
+ tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH)
+ ret = callback(handle, record, next_cpu, callback_data);
+
tracecmd_free_record(record);
}
@@ -2669,7 +2673,9 @@ int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
record = tracecmd_read_data(handle, cpu);
records[next_cpu].record = tracecmd_peek_data(handle, cpu);
- ret = callback(handle, record, cpu, callback_data);
+ if (!handle->filter ||
+ tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH)
+ ret = callback(handle, record, next_cpu, callback_data);
tracecmd_free_record(record);
}
@@ -4716,6 +4722,8 @@ void tracecmd_close(struct tracecmd_input *handle)
trace_tsync_offset_free(&handle->host);
trace_guests_free(handle);
+ tracecmd_filter_free(handle->filter);
+
if (handle->flags & TRACECMD_FL_BUFFER_INSTANCE)
tracecmd_close(handle->parent);
else {
@@ -6058,3 +6066,19 @@ int tracecmd_enable_tsync(struct tracecmd_input *handle, bool enable)
return 0;
}
+__hidden struct tracecmd_filter *tracecmd_filter_get(struct tracecmd_input *handle)
+{
+ return handle->filter;
+}
+
+__hidden void tracecmd_filter_set(struct tracecmd_input *handle,
+ struct tracecmd_filter *filter)
+{
+ /* This can be used to set filter to NULL though. */
+ if (handle->filter && filter) {
+ tracecmd_warning("Filter exists and setting a new one");
+ return;
+ }
+
+ handle->filter = filter;
+}
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 8/9] trace-cmd report: Make filter arguments match their files
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
` (6 preceding siblings ...)
2022-08-05 15:40 ` [PATCH 7/9] trace-cmd library: Add filtering logic for iterating events Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
2022-08-05 15:40 ` [PATCH 9/9] trace-cmd report: Use library tracecmd_filter_*() logic Steven Rostedt
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Currently the filter argument "-F" only affects the first file passed in,
and is ignored for the rest of the files passed in via '-i'. Also, buffers
ignore them as well.
Have the -F affect the last '-i file', with the exception that the -F
filter can be called before the first file. That is, the first -i file is
affected by any -F before it and directly after it but before another -i
file is added.
Also, have buffers within a file be affected by the filters given to the
file.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
tracecmd/trace-read.c | 119 ++++++++++++++++++++++++++++++------------
1 file changed, 85 insertions(+), 34 deletions(-)
diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c
index 8b3efae63f8e..99f3538646ee 100644
--- a/tracecmd/trace-read.c
+++ b/tracecmd/trace-read.c
@@ -51,9 +51,12 @@ struct event_str {
const char *event;
};
+struct input_files;
+
struct handle_list {
struct list_head list;
struct tracecmd_input *handle;
+ struct input_files *input_file;
const char *file;
int cpus;
struct filter *event_filters;
@@ -64,6 +67,8 @@ static struct list_head handle_list;
struct input_files {
struct list_head list;
const char *file;
+ struct filter_str *filter_str;
+ struct filter_str **filter_str_next;
long long tsoffset;
unsigned long long ts2secs;
};
@@ -336,29 +341,42 @@ static void test_save(struct tep_record *record, int cpu)
}
#endif
-static void add_input(const char *file)
+static void free_filter_strings(struct filter_str *filter_str)
+{
+ struct filter_str *filter;
+
+ while (filter_str) {
+ filter = filter_str;
+ filter_str = filter->next;
+ free(filter->filter);
+ free(filter);
+ }
+}
+
+static struct input_files *add_input(const char *file)
{
struct input_files *item;
- item = malloc(sizeof(*item));
+ item = calloc(1, sizeof(*item));
if (!item)
die("Failed to allocate for %s", file);
- memset(item, 0, sizeof(*item));
item->file = file;
+ item->filter_str_next = &item->filter_str;
list_add_tail(&item->list, &input_files);
last_input_file = item;
+ return item;
}
-static void add_handle(struct tracecmd_input *handle, const char *file)
+static void add_handle(struct tracecmd_input *handle, struct input_files *input_files)
{
struct handle_list *item;
+ const char *file = input_files ? input_files->file : input_file;
- item = malloc(sizeof(*item));
+ item = calloc(1, sizeof(*item));
if (!item)
die("Failed ot allocate for %s", file);
- memset(item, 0, sizeof(*item));
item->handle = handle;
- if (file) {
+ if (input_files) {
item->file = file + strlen(file);
/* we want just the base name */
while (item->file >= file && *item->file != '/')
@@ -366,6 +384,8 @@ static void add_handle(struct tracecmd_input *handle, const char *file)
item->file++;
if (strlen(item->file) > max_file_size)
max_file_size = strlen(item->file);
+
+ item->input_file = input_files;
}
list_add_tail(&item->list, &handle_list);
}
@@ -377,6 +397,7 @@ static void free_inputs(void)
while (!list_empty(&input_files)) {
item = container_of(input_files.next, struct input_files, list);
list_del(&item->list);
+ free_filter_strings(item->filter_str);
free(item);
}
}
@@ -392,7 +413,7 @@ static void free_handles(void)
}
}
-static void add_filter(const char *filter, int neg)
+static void add_filter(struct input_files *input_file, const char *filter, int neg)
{
struct filter_str *ftr;
@@ -406,8 +427,13 @@ static void add_filter(const char *filter, int neg)
ftr->neg = neg;
/* must maintain order of command line */
- *filter_next = ftr;
- filter_next = &ftr->next;
+ if (input_file) {
+ *input_file->filter_str_next = ftr;
+ input_file->filter_str_next = &ftr->next;
+ } else {
+ *filter_next = ftr;
+ filter_next = &ftr->next;
+ }
}
static void __add_filter(struct pid_list **head, const char *arg)
@@ -517,7 +543,8 @@ static void convert_comm_filter(struct tracecmd_input *handle)
}
}
-static void make_pid_filter(struct tracecmd_input *handle)
+static void make_pid_filter(struct tracecmd_input *handle,
+ struct input_files *input_files)
{
struct pid_list *list;
char *str = NULL;
@@ -532,7 +559,7 @@ static void make_pid_filter(struct tracecmd_input *handle)
str = append_pid_filter(str, list->pid);
}
- add_filter(str, 0);
+ add_filter(input_files, str, 0);
free(str);
while (pid_list) {
@@ -557,12 +584,14 @@ static void process_filters(struct handle_list *handles)
pevent = tracecmd_get_tep(handles->handle);
- make_pid_filter(handles->handle);
+ make_pid_filter(handles->handle, handles->input_file);
- while (filter_strings) {
+ if (handles->input_file)
+ filter = handles->input_file->filter_str;
+ else
filter = filter_strings;
- filter_strings = filter->next;
+ for (; filter; filter = filter->next) {
event_filter = malloc(sizeof(*event_filter));
if (!event_filter)
die("Failed to allocate for event filter");
@@ -587,8 +616,6 @@ static void process_filters(struct handle_list *handles)
filter_next = &event_filter->next;
}
filters++;
- free(filter->filter);
- free(filter);
}
if (filters && test_filters_mode)
exit(0);
@@ -1211,6 +1238,8 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
cpus = tracecmd_cpus(handles->handle);
handles->cpus = cpus;
+ process_filters(handles);
+
/* Don't process instances that we added here */
if (tracecmd_is_buffer_instance(handles->handle))
continue;
@@ -1262,15 +1291,17 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
if (profile)
trace_init_profile(handles->handle, hooks, global);
- process_filters(handles);
-
/* If this file has buffer instances, get the handles for them */
instances = tracecmd_buffer_instances(handles->handle);
if (instances) {
struct tracecmd_input *new_handle;
+ struct input_files *file_input;
+ const char *save_name;
const char *name;
int i;
+ file_input = handles->input_file;
+
for (i = 0; i < instances; i++) {
name = tracecmd_buffer_instance_name(handles->handle, i);
if (!name)
@@ -1280,7 +1311,16 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
warning("could not retrieve handle %s", name);
continue;
}
- add_handle(new_handle, name);
+ if (file_input) {
+ save_name = file_input->file;
+ file_input->file = name;
+ } else {
+ save_name = NULL;
+ file_input = add_input(name);
+ }
+ add_handle(new_handle, file_input);
+ if (save_name)
+ file_input->file = save_name;
}
}
}
@@ -1493,6 +1533,21 @@ static void add_hook(const char *arg)
last_hook = hook;
}
+static void add_first_input(const char *input_file, long long tsoffset)
+{
+ struct input_files *item;
+
+ /* Copy filter strings to this input file */
+ item = add_input(input_file);
+ item->filter_str = filter_strings;
+ if (filter_strings)
+ item->filter_str_next = filter_next;
+ else
+ item->filter_str_next = &item->filter_str;
+ /* Copy the tsoffset to this input file */
+ item->tsoffset = tsoffset;
+}
+
enum {
OPT_verbose = 234,
OPT_align_ts = 235,
@@ -1615,18 +1670,15 @@ void trace_report (int argc, char **argv)
break;
case 'i':
if (input_file) {
- if (!multi_inputs) {
- add_input(input_file);
- if (tsoffset)
- last_input_file->tsoffset = tsoffset;
- }
multi_inputs++;
add_input(optarg);
- } else
+ } else {
input_file = optarg;
+ add_first_input(input_file, tsoffset);
+ }
break;
case 'F':
- add_filter(optarg, neg);
+ add_filter(last_input_file, optarg, neg);
break;
case 'H':
add_hook(optarg);
@@ -1803,15 +1855,14 @@ void trace_report (int argc, char **argv)
if (input_file)
usage(argv);
input_file = argv[optind + 1];
+ add_first_input(input_file, tsoffset);
}
- if (!input_file)
- input_file = default_input_file;
-
if (!multi_inputs) {
- add_input(input_file);
- if (tsoffset)
- last_input_file->tsoffset = tsoffset;
+ if (!input_file) {
+ input_file = default_input_file;
+ add_first_input(input_file, tsoffset);
+ }
} else if (show_wakeup)
die("Wakeup tracing can only be done on a single input file");
@@ -1821,7 +1872,7 @@ void trace_report (int argc, char **argv)
die("error reading header for %s", inputs->file);
/* If used with instances, top instance will have no tag */
- add_handle(handle, multi_inputs ? inputs->file : NULL);
+ add_handle(handle, multi_inputs ? inputs : NULL);
if (no_date)
tracecmd_set_flag(handle, TRACECMD_FL_IGNORE_DATE);
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 9/9] trace-cmd report: Use library tracecmd_filter_*() logic
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
` (7 preceding siblings ...)
2022-08-05 15:40 ` [PATCH 8/9] trace-cmd report: Make filter arguments match their files Steven Rostedt
@ 2022-08-05 15:40 ` Steven Rostedt
8 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2022-08-05 15:40 UTC (permalink / raw)
To: linux-trace-devel; +Cc: Steven Rostedt (Google)
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Simplify trace-read.c by implementing the use of tracecmd_filter_add(),
tracecmd_filter_match(). And move the processing into the library.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
tracecmd/trace-read.c | 175 +++---------------------------------------
1 file changed, 10 insertions(+), 165 deletions(-)
diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c
index 99f3538646ee..5b4d88b1fca5 100644
--- a/tracecmd/trace-read.c
+++ b/tracecmd/trace-read.c
@@ -41,11 +41,6 @@ static struct filter_str {
} *filter_strings;
static struct filter_str **filter_next = &filter_strings;
-struct filter {
- struct filter *next;
- struct tep_event_filter *filter;
-};
-
struct event_str {
struct event_str *next;
const char *event;
@@ -59,8 +54,6 @@ struct handle_list {
struct input_files *input_file;
const char *file;
int cpus;
- struct filter *event_filters;
- struct filter *event_filter_out;
};
static struct list_head handle_list;
@@ -100,7 +93,6 @@ static int show_wakeup;
static int wakeup_id;
static int wakeup_new_id;
static int sched_id;
-static int stacktrace_id;
static int profile;
@@ -573,16 +565,9 @@ static void make_pid_filter(struct tracecmd_input *handle,
static void process_filters(struct handle_list *handles)
{
- struct filter **filter_next = &handles->event_filters;
- struct filter **filter_out_next = &handles->event_filter_out;
- struct filter *event_filter;
+ struct tracecmd_filter *trace_filter;
struct filter_str *filter;
- struct tep_handle *pevent;
- char errstr[200];
int filters = 0;
- int ret;
-
- pevent = tracecmd_get_tep(handles->handle);
make_pid_filter(handles->handle, handles->input_file);
@@ -592,29 +577,12 @@ static void process_filters(struct handle_list *handles)
filter = filter_strings;
for (; filter; filter = filter->next) {
- event_filter = malloc(sizeof(*event_filter));
- if (!event_filter)
- die("Failed to allocate for event filter");
- event_filter->next = NULL;
- event_filter->filter = tep_filter_alloc(pevent);
- if (!event_filter->filter)
- die("malloc");
-
- ret = tep_filter_add_filter_str(event_filter->filter,
- filter->filter);
- if (ret < 0) {
- tep_strerror(pevent, ret, errstr, sizeof(errstr));
- die("Error filtering: %s\n%s",
- filter->filter, errstr);
- }
-
- if (filter->neg) {
- *filter_out_next = event_filter;
- filter_out_next = &event_filter->next;
- } else {
- *filter_next = event_filter;
- filter_next = &event_filter->next;
- }
+ trace_filter = tracecmd_filter_add(handles->handle,
+ filter->filter,
+ filter->neg);
+ if (!trace_filter)
+ die("Failed to create event filter: %s", filter->filter);
+
filters++;
}
if (filters && test_filters_mode)
@@ -993,10 +961,8 @@ static void read_latency(struct tracecmd_input *handle)
}
static int
-test_filters(struct tep_handle *pevent, struct filter *event_filters,
- struct tep_record *record, int neg)
+test_filters(struct tep_handle *pevent, struct tep_record *record)
{
- int found = 0;
int ret = FILTER_NONE;
int flags;
@@ -1008,19 +974,6 @@ test_filters(struct tep_handle *pevent, struct filter *event_filters,
return FILTER_MISS;
}
- while (event_filters) {
- ret = tep_filter_match(event_filters->filter, record);
- switch (ret) {
- case FILTER_NONE:
- case FILTER_MATCH:
- found = 1;
- }
- /* We need to test all negative filters */
- if (!neg && found)
- break;
- event_filters = event_filters->next;
- }
-
return ret;
}
@@ -1033,85 +986,9 @@ struct stack_info {
struct stack_info *next;
struct handle_list *handles;
struct stack_info_cpu *cpus;
- int stacktrace_id;
int nr_cpus;
};
-static int
-test_stacktrace(struct handle_list *handles, struct tep_record *record,
- int last_printed)
-{
- static struct stack_info *infos;
- struct stack_info *info;
- struct stack_info_cpu *cpu_info;
- struct handle_list *h;
- struct tracecmd_input *handle;
- struct tep_handle *pevent;
- struct tep_event *event;
- static int init;
- int ret;
- int id;
-
- if (!init) {
- init = 1;
-
- list_for_each_entry(h, &handle_list, list) {
- info = malloc(sizeof(*info));
- if (!info)
- die("Failed to allocate handle");
- info->handles = h;
- info->nr_cpus = tracecmd_cpus(h->handle);
-
- info->cpus = malloc(sizeof(*info->cpus) * info->nr_cpus);
- if (!info->cpus)
- die("Failed to allocate for %d cpus", info->nr_cpus);
- memset(info->cpus, 0, sizeof(*info->cpus));
-
- pevent = tracecmd_get_tep(h->handle);
- event = tep_find_event_by_name(pevent, "ftrace",
- "kernel_stack");
- if (event)
- info->stacktrace_id = event->id;
- else
- info->stacktrace_id = 0;
-
- info->next = infos;
- infos = info;
- }
-
-
- }
-
- handle = handles->handle;
- pevent = tracecmd_get_tep(handle);
-
- for (info = infos; info; info = info->next)
- if (info->handles == handles)
- break;
-
- if (!info->stacktrace_id)
- return 0;
-
- cpu_info = &info->cpus[record->cpu];
-
- id = tep_data_type(pevent, record);
-
- /*
- * Print the stack trace if the previous event was printed.
- * But do not print the stack trace if it is explicitly
- * being filtered out.
- */
- if (id == info->stacktrace_id) {
- ret = test_filters(pevent, handles->event_filter_out, record, 1);
- if (ret != FILTER_MATCH)
- return cpu_info->last_printed;
- return 0;
- }
-
- cpu_info->last_printed = last_printed;
- return 0;
-}
-
static void print_handle_file(struct handle_list *handles)
{
/* Only print file names if more than one file is read */
@@ -1123,19 +1000,6 @@ static void print_handle_file(struct handle_list *handles)
printf("%*s ", max_file_size, "");
}
-static void free_filters(struct filter *event_filter)
-{
- struct filter *filter;
-
- while (event_filter) {
- filter = event_filter;
- event_filter = filter->next;
-
- tep_filter_free(filter->filter);
- free(filter);
- }
-}
-
static bool skip_record(struct handle_list *handles, struct tep_record *record, int cpu)
{
struct tep_handle *tep;
@@ -1159,28 +1023,20 @@ static bool skip_record(struct handle_list *handles, struct tep_record *record,
found = false;
}
- ret = test_filters(tep, handles->event_filters, record, 0);
+ ret = test_filters(tep, record);
switch (ret) {
case FILTER_NOEXIST:
- /* Stack traces may still filter this */
- if (stacktrace_id &&
- test_stacktrace(handles, record, 0))
- found = true;
break;
case FILTER_NONE:
case FILTER_MATCH:
/* Test the negative filters (-v) */
- ret = test_filters(tep, handles->event_filter_out,
- record, 1);
+ ret = test_filters(tep, record);
if (ret != FILTER_MATCH) {
found = true;
break;
}
}
- if (record && stacktrace_id)
- test_stacktrace(handles, record, 1);
-
return !found;
}
@@ -1218,8 +1074,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
unsigned long long ts, first_ts;
struct handle_list *handles;
struct tracecmd_input **handle_array;
- struct tep_handle *pevent;
- struct tep_event *event;
unsigned long long last_timestamp = 0;
int nr_handles = 0;
int first = 1;
@@ -1277,12 +1131,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
continue;
}
- /* Find the kernel_stacktrace if available */
- pevent = tracecmd_get_tep(handles->handle);
- event = tep_find_event_by_name(pevent, "ftrace", "kernel_stack");
- if (event)
- stacktrace_id = event->id;
-
init_wakeup(handles->handle);
if (last_hook)
last_hook->next = tracecmd_hooks(handles->handle);
@@ -1353,9 +1201,6 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
do_trace_profile();
list_for_each_entry(handles, handle_list, list) {
- free_filters(handles->event_filters);
- free_filters(handles->event_filter_out);
-
show_test(handles->handle);
}
}
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2022-08-05 15:40 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-05 15:40 [PATCH 0/9] trace-cmd library: Add and use new helper functions Steven Rostedt
2022-08-05 15:40 ` [PATCH 1/9] tracecmd: Use make variable instead of if statement for zlib test Steven Rostedt
2022-08-05 15:40 ` [PATCH 2/9] tracecmd library: Add tracecmd_iterate_events() Steven Rostedt
2022-08-05 15:40 ` [PATCH 3/9] tracecmd utest: Add test to test using the libraries to read Steven Rostedt
2022-08-05 15:40 ` [PATCH 4/9] tracecmd library: Add tracecmd_iterate_events_multi() Steven Rostedt
2022-08-05 15:40 ` [PATCH 5/9] trace-cmd library: Allow callers to save private data in tracecmd_input handlers Steven Rostedt
2022-08-05 15:40 ` [PATCH 6/9] trace-cmd report: Use tracecmd_iterate_events_multi() Steven Rostedt
2022-08-05 15:40 ` [PATCH 7/9] trace-cmd library: Add filtering logic for iterating events Steven Rostedt
2022-08-05 15:40 ` [PATCH 8/9] trace-cmd report: Make filter arguments match their files Steven Rostedt
2022-08-05 15:40 ` [PATCH 9/9] trace-cmd report: Use library tracecmd_filter_*() logic Steven Rostedt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).