From: Tzvetomir (VMware) Stoyanov <tz.stoyanov@xxxxxxxxx> 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@xxxxxxxxx> --- src/libkshark-tepdata.c | 122 ++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 30 deletions(-) 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. */ -- 2.26.2