Commit 2c15f5eb authored by Chris Phlipot's avatar Chris Phlipot Committed by Arnaldo Carvalho de Melo

perf script: Expose usage of the callchain db export via the python api

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: default avatarChris Phlipot <cphlipot0@gmail.com>
Acked-by: default avatarAdrian 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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 568850ea
......@@ -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()
......
......@@ -25,19 +25,6 @@
#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
/**
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment