diff mbox series

[4/5] KernelShark: Load trace.dat file with ftrace sub-buffers

Message ID 20200727071823.169962-5-tz.stoyanov@gmail.com (mailing list archive)
State New
Headers show
Series Add support for opening trace.dat files with multuiple buffers | expand

Commit Message

Tzvetomir Stoyanov (VMware) July 27, 2020, 7:18 a.m. UTC
From: Tzvetomir (VMware)  Stoyanov <tz.stoyanov@gmail.com>

Ftrace supports parallel tracing in isolated ring buffers. Trace-cmd
also supprts this ftrace functionality, it saves the data from all
buffers into single trace.dat file. When such file is opened by
KernelShark, it loads the tracing data only from the top biffer.
Support for loading data from all buffers, located in a single trace.dat
file, is added. Each buffer is loaded as different KernelShark session.

Signed-off-by: Tzvetomir (VMware)  Stoyanov <tz.stoyanov@gmail.com>
---
 src/libkshark-tepdata.c | 122 ++++++++++++++++++++++++++++++----------
 1 file changed, 92 insertions(+), 30 deletions(-)
diff mbox series

Patch

diff --git a/src/libkshark-tepdata.c b/src/libkshark-tepdata.c
index efd8c82..4b3a57d 100644
--- a/src/libkshark-tepdata.c
+++ b/src/libkshark-tepdata.c
@@ -1134,55 +1134,60 @@  out:
 	return peer_handle;
 }
 
-/** Initialize the FTRACE data input (from file). */
-int kshark_tep_init_input(struct kshark_data_stream *stream,
-			  const char *file)
+static int kshark_tep_init_stream(struct kshark_context *kshark_ctx,
+				  struct kshark_data_stream *stream,
+				  const char *file,
+				  struct kshark_data_stream *parent,
+				  int instance)
 {
-	struct kshark_context *kshark_ctx = NULL;
 	struct tepdata_handle *tep_handle;
-	struct kshark_plugin_list *plugin;
+	struct tepdata_handle *tep_parent;
 	struct tracecmd_input *merge_peer;
+	struct kshark_plugin_list *plugin;
 	struct tep_event *event;
 	int i, n_tep_plugins;
 	int ret;
-
-	if (!kshark_instance(&kshark_ctx) || !init_thread_seq())
-		return -EEXIST;
-
-	/*
-	 * Turn off function trace indent and turn on show parent
-	 * if possible.
-	 */
-	tep_plugin_add_option("ftrace:parent", "1");
-	tep_plugin_add_option("ftrace:indent", "0");
+	char *name;
 
 	tep_handle = calloc(1, sizeof(*tep_handle));
 	if (!tep_handle)
 		return -EFAULT;
 
-	/** Open the tracing file, parse headers and create trace input context */
-	tep_handle->input = tracecmd_open_head(file);
-	if (!tep_handle->input) {
-		free(tep_handle);
-		stream->interface.handle = NULL;
-		return -EEXIST;
+	if (!parent || instance < 0) {
+		/** Open the tracing file, parse headers and create trace input context */
+		tep_handle->input = tracecmd_open_head(file);
+		if (!tep_handle->input) {
+			free(tep_handle);
+			stream->interface.handle = NULL;
+			return -EEXIST;
+		}
+		/** Find a merge peer from the same tracing session */
+		merge_peer = kshark_tep_find_merge_peer(kshark_ctx, tep_handle->input);
+		if (merge_peer)
+			tracecmd_pair_peer(tep_handle->input, merge_peer);
+
+		/** Read the racing data from the file */
+		ret = tracecmd_init_data(tep_handle->input);
+		name = "top";
+	} else {
+		tep_parent = (struct tepdata_handle *)parent->interface.handle;
+		name = tracecmd_buffer_instance_name(tep_parent->input, instance);
+		stream->file = strdup(file);
+		asprintf(&stream->name, "%s:%s", stream->file, name);
+		tep_handle->input = tracecmd_buffer_instance_handle(tep_parent->input, instance);
+		tracecmd_print_stats(tep_handle->input);
+		if (!tep_handle->input)
+			ret = -1;
+		else
+			ret = 0;
 	}
 
-	/** Find a merge peer from the same tracing session */
-	merge_peer = kshark_tep_find_merge_peer(kshark_ctx, tep_handle->input);
-	if (merge_peer)
-		tracecmd_pair_peer(tep_handle->input, merge_peer);
-
-	/** Read the racing data from the file */
-	ret = tracecmd_init_data(tep_handle->input);
-
 	if (ret < 0) {
 		tracecmd_close(tep_handle->input);
 		free(tep_handle);
 		stream->interface.handle = NULL;
 		return -EEXIST;
 	}
-
 	tep_handle->tep = tracecmd_get_pevent(tep_handle->input);
 
 	tep_handle->sched_switch_event_id = -EINVAL;
@@ -1224,8 +1229,65 @@  int kshark_tep_init_input(struct kshark_data_stream *stream,
 	}
 
 	kshark_handle_all_dpis(stream, KSHARK_PLUGIN_INIT);
+	return 0;
+}
 
+/** Initialize the FTRACE data input (from file). */
+int kshark_tep_init_input(struct kshark_data_stream *stream,
+			  const char *file)
+{
+	struct kshark_context *kshark_ctx = NULL;
+	struct kshark_data_stream *child_stream;
+	struct tepdata_handle *tep_handle;
+	int count;
+	int ret;
+	int sd;
+	int i;
+
+	if (!kshark_instance(&kshark_ctx) || !init_thread_seq())
+		return -EEXIST;
+
+	/*
+	 * Turn off function trace indent and turn on show parent
+	 * if possible.
+	 */
+	tep_plugin_add_option("ftrace:parent", "1");
+	tep_plugin_add_option("ftrace:indent", "0");
+
+	ret = kshark_tep_init_stream(kshark_ctx, stream, file, NULL, -1);
+	if (ret < 0)
+		return ret;
+	tep_handle = (struct tepdata_handle *)stream->interface.handle;
+	count = tracecmd_buffer_instances(tep_handle->input);
+	for (i = 0; i < count; i++) {
+		sd = kshark_add_stream(kshark_ctx);
+		if (sd < 0) {
+			ret = sd;
+			goto error;
+		}
+		child_stream = kshark_ctx->stream[sd];
+		if (!child_stream) {
+			ret = -ENOMEM;
+			goto error;
+		}
+		if (pthread_mutex_init(&child_stream->input_mutex, NULL) != 0) {
+			ret = -EAGAIN;
+			goto error;
+		}
+		child_stream->format = KS_TEP_DATA;
+		ret = kshark_tep_init_stream(kshark_ctx, child_stream, file, stream, i);
+		if (ret < 0)
+			goto error;
+		kshark_ctx->n_streams++;
+	}
 	return 0;
+
+error:
+		tracecmd_close(tep_handle->input);
+		free(tep_handle);
+		stream->interface.handle = NULL;
+		return ret;
+
 }
 
 /** Initialize using the locally available tracing events. */