perf script: Expose usage of the callchain db export via the python api
authorChris Phlipot <cphlipot0@gmail.com>
Thu, 28 Apr 2016 08:19:10 +0000 (01:19 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 6 May 2016 16:00:54 +0000 (13:00 -0300)
This change allows python scripts to be able to utilize the recent
changes to the db export api allowing the export of call_paths derived
from sampled callchains. These call paths are also now associated with
the samples from which they were derived.

- This feature is enabled by setting "perf_db_export_callchains" to true

- When enabled, samples that have callchain information will have the
  callchains exported via call_path_table

- The call_path_id field is added to sample_table to enable association of
  samples with the corresponding callchain stored in the call paths
  table. A call_path_id of 0 will be exported if there is no
  corresponding callchain.

- When "perf_db_export_callchains" and "perf_db_export_calls" are both
  set to True, the call path root data structure will be shared. This
  prevents duplicating of data and call path ids that would result from
  building two separate call path trees in memory.

- The call_return_processor structure definition was relocated to the header
  file to make its contents visible to db-export.c. This enables the
  sharing of call path trees between the two features, as mentioned
  above.

This change is visible to python scripts using the python db export api.

The change is backwards compatible with scripts written against the
previous API, assuming that the scripts model the sample_table function
after the one in export-to-postgresql.py script by allowing for
additional arguments to be added in the future. ie. using *x as the
final argument of the sample_table function.

Signed-off-by: Chris Phlipot <cphlipot0@gmail.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1461831551-12213-6-git-send-email-cphlipot0@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/thread-stack.c
tools/perf/util/thread-stack.h

index 7bb8592022495a6e7222160199ad8b29f2a50080..091bce67844cb9c4dc7e051994ea0222f1c62722 100644 (file)
@@ -682,7 +682,7 @@ static int python_export_sample(struct db_export *dbe,
        struct tables *tables = container_of(dbe, struct tables, dbe);
        PyObject *t;
 
-       t = tuple_new(21);
+       t = tuple_new(22);
 
        tuple_set_u64(t, 0, es->db_id);
        tuple_set_u64(t, 1, es->evsel->db_id);
@@ -705,6 +705,7 @@ static int python_export_sample(struct db_export *dbe,
        tuple_set_u64(t, 18, es->sample->data_src);
        tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK);
        tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX));
+       tuple_set_u64(t, 21, es->call_path_id);
 
        call_object(tables->sample_handler, t, "sample_table");
 
@@ -999,8 +1000,10 @@ static void set_table_handlers(struct tables *tables)
 {
        const char *perf_db_export_mode = "perf_db_export_mode";
        const char *perf_db_export_calls = "perf_db_export_calls";
-       PyObject *db_export_mode, *db_export_calls;
+       const char *perf_db_export_callchains = "perf_db_export_callchains";
+       PyObject *db_export_mode, *db_export_calls, *db_export_callchains;
        bool export_calls = false;
+       bool export_callchains = false;
        int ret;
 
        memset(tables, 0, sizeof(struct tables));
@@ -1017,6 +1020,7 @@ static void set_table_handlers(struct tables *tables)
        if (!ret)
                return;
 
+       /* handle export calls */
        tables->dbe.crp = NULL;
        db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls);
        if (db_export_calls) {
@@ -1034,6 +1038,33 @@ static void set_table_handlers(struct tables *tables)
                        Py_FatalError("failed to create calls processor");
        }
 
+       /* handle export callchains */
+       tables->dbe.cpr = NULL;
+       db_export_callchains = PyDict_GetItemString(main_dict,
+                                                   perf_db_export_callchains);
+       if (db_export_callchains) {
+               ret = PyObject_IsTrue(db_export_callchains);
+               if (ret == -1)
+                       handler_call_die(perf_db_export_callchains);
+               export_callchains = !!ret;
+       }
+
+       if (export_callchains) {
+               /*
+                * Attempt to use the call path root from the call return
+                * processor, if the call return processor is in use. Otherwise,
+                * we allocate a new call path root. This prevents exporting
+                * duplicate call path ids when both are in use simultaniously.
+                */
+               if (tables->dbe.crp)
+                       tables->dbe.cpr = tables->dbe.crp->cpr;
+               else
+                       tables->dbe.cpr = call_path_root__new();
+
+               if (!tables->dbe.cpr)
+                       Py_FatalError("failed to create calls processor");
+       }
+
        tables->db_export_mode = true;
        /*
         * Reserve per symbol space for symbol->db_id via symbol__priv()
index fc419a59c88bac62c764275dd13c54e8bc4f30a1..825086aa9a08685303c08cddb36823620fa65c9e 100644 (file)
 #include "call-path.h"
 #include "thread-stack.h"
 
-/**
- * struct call_return_processor - provides a call-back to consume call-return
- *                                information.
- * @cpr: call path root
- * @process: call-back that accepts call/return information
- * @data: anonymous data for call-back
- */
-struct call_return_processor {
-       struct call_path_root *cpr;
-       int (*process)(struct call_return *cr, void *data);
-       void *data;
-};
-
 #define STACK_GROWTH 2048
 
 /**
index ec9beddfdbabc574de4ded32e7fe92d618aeb4fe..ad44c7944b8e72bbdbd931983cf972d3a598799e 100644 (file)
@@ -25,7 +25,6 @@ struct comm;
 struct ip_callchain;
 struct symbol;
 struct dso;
-struct call_return_processor;
 struct comm;
 struct perf_sample;
 struct addr_location;
@@ -68,6 +67,19 @@ struct call_return {
        u32 flags;
 };
 
+/**
+ * struct call_return_processor - provides a call-back to consume call-return
+ *                                information.
+ * @cpr: call path root
+ * @process: call-back that accepts call/return information
+ * @data: anonymous data for call-back
+ */
+struct call_return_processor {
+       struct call_path_root *cpr;
+       int (*process)(struct call_return *cr, void *data);
+       void *data;
+};
+
 int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
                        u64 to_ip, u16 insn_len, u64 trace_nr);
 void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);