linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).