From: Namhyung Kim <namhyung....@lge.com>

Detect leaf functions and print them in a same line.

Note that it only converts leaf-functions that doesn't have any other
records between entry and exit even in other cpus.  I left other leaf
functions as is.

Cc: Steven Rostedt <rost...@goodmis.org>
Cc: Frederic Weisbecker <fweis...@gmail.com>
Signed-off-by: Namhyung Kim <namhy...@kernel.org>
---
 tools/perf/builtin-ftrace.c | 87 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 76 insertions(+), 11 deletions(-)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 2a7acdbd6985..94f911946ef8 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -893,34 +893,77 @@ function_handler(struct trace_seq *s, struct 
pevent_record *record,
 
 #define TRACE_GRAPH_INDENT  2
 
+static struct pevent_record *peek_ordered_record(struct perf_ftrace *ftrace);
+static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace);
+
+static struct event_format *fgraph_exit_event;
+
 static int
 fgraph_ent_handler(struct trace_seq *s, struct pevent_record *record,
-                  struct event_format *event, void *context __maybe_unused)
+                  struct event_format *event, void *context)
 {
        unsigned long long depth;
        unsigned long long val;
        const char *func;
+       struct perf_ftrace *ftrace = context;
+       struct pevent_record *next;
+       bool is_leaf = false;
+       bool needs_free = false;
+       void *data;
+       int ret = -1;
        int i;
 
+       /*
+        * record->data can be invalidated after calling peek_ordered_record()
+        * because it can unmap the current kbuffer page.  Make a copy.
+        */
+       data = malloc(record->size);
+       if (data == NULL)
+               goto nested;
+
+       memcpy(data, record->data, record->size);
+       record->data = data;
+       needs_free = true;
+
+       /* detect leaf function and make it one-liner */
+       next = peek_ordered_record(ftrace);
+       if (next && next->cpu == record->cpu &&
+           pevent_data_type(event->pevent, next) == fgraph_exit_event->id) {
+               is_leaf = true;
+               /* consume record */
+               get_ordered_record(ftrace);
+               free(next);
+       }
+
+nested:
        if (pevent_get_field_val(s, event, "depth", record, &depth, 1))
-               return trace_seq_putc(s, '!');
+               goto out;
 
        /* Function */
        for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
                trace_seq_putc(s, ' ');
 
        if (pevent_get_field_val(s, event, "func", record, &val, 1))
-               return trace_seq_putc(s, '!');
+               goto out;
 
        func = pevent_find_function(event->pevent, val);
 
        if (func)
-               trace_seq_printf(s, "%s() {", func);
+               trace_seq_printf(s, "%s()", func);
        else
-               trace_seq_printf(s, "%llx() {", val);
+               trace_seq_printf(s, "%llx()", val);
 
-       trace_seq_putc(s, '\n');
-       return 0;
+       if (is_leaf)
+               trace_seq_puts(s, ";\n");
+       else
+               trace_seq_puts(s, " {\n");
+
+       ret = 0;
+out:
+       if (needs_free)
+               free(record->data);
+
+       return ret;
 }
 
 static int
@@ -1122,7 +1165,8 @@ get_ftrace_event_record(struct perf_ftrace *ftrace,
        return fra->record;
 }
 
-static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace)
+static struct ftrace_report_arg *
+__get_ordered_record(struct perf_ftrace *ftrace)
 {
        struct ftrace_report_arg *fra = NULL;
        struct ftrace_report_arg *tmp;
@@ -1136,9 +1180,26 @@ static struct pevent_record *get_ordered_record(struct 
perf_ftrace *ftrace)
                        fra = tmp;
                }
        }
+       return fra;
+}
+
+static struct pevent_record *peek_ordered_record(struct perf_ftrace *ftrace)
+{
+       struct ftrace_report_arg *fra = __get_ordered_record(ftrace);
+
+       if (fra)
+               return fra->record;
+
+       return NULL;
+}
+
+static struct pevent_record *get_ordered_record(struct perf_ftrace *ftrace)
+{
+       struct ftrace_report_arg *fra = __get_ordered_record(ftrace);
 
        if (fra) {
-               record = fra->record;
+               struct pevent_record *record = fra->record;
+
                fra->record = NULL;
                return record;
        }
@@ -1194,10 +1255,10 @@ static int do_ftrace_show(struct perf_ftrace *ftrace)
                                      function_handler, NULL);
        pevent_register_event_handler(ftrace->pevent, -1,
                                      "ftrace", "funcgraph_entry",
-                                     fgraph_ent_handler, NULL);
+                                     fgraph_ent_handler, ftrace);
        pevent_register_event_handler(ftrace->pevent, -1,
                                      "ftrace", "funcgraph_exit",
-                                     fgraph_ret_handler, NULL);
+                                     fgraph_ret_handler, ftrace);
 
        if (perf_session__process_events(session, &show.tool) < 0) {
                pr_err("failed to process events\n");
@@ -1205,6 +1266,10 @@ static int do_ftrace_show(struct perf_ftrace *ftrace)
                goto out;
        }
 
+       fgraph_exit_event = pevent_find_event_by_name(ftrace->pevent, "ftrace",
+                                                    "funcgraph_exit");
+       BUG_ON(fgraph_exit_event == NULL);
+
        trace_seq_init(&seq);
 
        record = get_ordered_record(ftrace);
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to