diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2019-02-28 08:00:24 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-03-01 12:50:47 -0500 |
commit | f435887ec0c941b97301bd6ed1f3e4b5200df409 (patch) | |
tree | e9a1be1b4803aa39ae58d93b000b9e773bbd35ef | |
parent | 076333870c2f5bdd9b6d31e7ca1909cf0c84cbfa (diff) |
perf db-export: Add calls parent_id to enable creation of call trees
The call_path can be used to find the parent symbol for a call but not
the exact parent call. To do that add parent_id to the call_return
export. This enables the creation of a call tree from the exported data.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lkml.kernel.org/n/tip-6j7tzdxo67cox6kan7k22oo6@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/db-export.c | 15 | ||||
-rw-r--r-- | tools/perf/util/db-export.h | 3 | ||||
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 8 | ||||
-rw-r--r-- | tools/perf/util/thread-stack.c | 16 | ||||
-rw-r--r-- | tools/perf/util/thread-stack.h | 6 |
5 files changed, 35 insertions, 13 deletions
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index de9b4769d06c..d7315a00c731 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c | |||
@@ -510,18 +510,23 @@ int db_export__call_path(struct db_export *dbe, struct call_path *cp) | |||
510 | return 0; | 510 | return 0; |
511 | } | 511 | } |
512 | 512 | ||
513 | int db_export__call_return(struct db_export *dbe, struct call_return *cr) | 513 | int db_export__call_return(struct db_export *dbe, struct call_return *cr, |
514 | u64 *parent_db_id) | ||
514 | { | 515 | { |
515 | int err; | 516 | int err; |
516 | 517 | ||
517 | if (cr->db_id) | ||
518 | return 0; | ||
519 | |||
520 | err = db_export__call_path(dbe, cr->cp); | 518 | err = db_export__call_path(dbe, cr->cp); |
521 | if (err) | 519 | if (err) |
522 | return err; | 520 | return err; |
523 | 521 | ||
524 | cr->db_id = ++dbe->call_return_last_db_id; | 522 | if (!cr->db_id) |
523 | cr->db_id = ++dbe->call_return_last_db_id; | ||
524 | |||
525 | if (parent_db_id) { | ||
526 | if (!*parent_db_id) | ||
527 | *parent_db_id = ++dbe->call_return_last_db_id; | ||
528 | cr->parent_db_id = *parent_db_id; | ||
529 | } | ||
525 | 530 | ||
526 | if (dbe->export_call_return) | 531 | if (dbe->export_call_return) |
527 | return dbe->export_call_return(dbe, cr); | 532 | return dbe->export_call_return(dbe, cr); |
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h index 67bc6b8ad2d6..4e2424c89df9 100644 --- a/tools/perf/util/db-export.h +++ b/tools/perf/util/db-export.h | |||
@@ -104,6 +104,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, | |||
104 | int db_export__branch_types(struct db_export *dbe); | 104 | int db_export__branch_types(struct db_export *dbe); |
105 | 105 | ||
106 | int db_export__call_path(struct db_export *dbe, struct call_path *cp); | 106 | int db_export__call_path(struct db_export *dbe, struct call_path *cp); |
107 | int db_export__call_return(struct db_export *dbe, struct call_return *cr); | 107 | int db_export__call_return(struct db_export *dbe, struct call_return *cr, |
108 | u64 *parent_db_id); | ||
108 | 109 | ||
109 | #endif | 110 | #endif |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 0e17db41b49b..09604c6508f0 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -1173,7 +1173,7 @@ static int python_export_call_return(struct db_export *dbe, | |||
1173 | u64 comm_db_id = cr->comm ? cr->comm->db_id : 0; | 1173 | u64 comm_db_id = cr->comm ? cr->comm->db_id : 0; |
1174 | PyObject *t; | 1174 | PyObject *t; |
1175 | 1175 | ||
1176 | t = tuple_new(11); | 1176 | t = tuple_new(12); |
1177 | 1177 | ||
1178 | tuple_set_u64(t, 0, cr->db_id); | 1178 | tuple_set_u64(t, 0, cr->db_id); |
1179 | tuple_set_u64(t, 1, cr->thread->db_id); | 1179 | tuple_set_u64(t, 1, cr->thread->db_id); |
@@ -1186,6 +1186,7 @@ static int python_export_call_return(struct db_export *dbe, | |||
1186 | tuple_set_u64(t, 8, cr->return_ref); | 1186 | tuple_set_u64(t, 8, cr->return_ref); |
1187 | tuple_set_u64(t, 9, cr->cp->parent->db_id); | 1187 | tuple_set_u64(t, 9, cr->cp->parent->db_id); |
1188 | tuple_set_s32(t, 10, cr->flags); | 1188 | tuple_set_s32(t, 10, cr->flags); |
1189 | tuple_set_u64(t, 11, cr->parent_db_id); | ||
1189 | 1190 | ||
1190 | call_object(tables->call_return_handler, t, "call_return_table"); | 1191 | call_object(tables->call_return_handler, t, "call_return_table"); |
1191 | 1192 | ||
@@ -1194,11 +1195,12 @@ static int python_export_call_return(struct db_export *dbe, | |||
1194 | return 0; | 1195 | return 0; |
1195 | } | 1196 | } |
1196 | 1197 | ||
1197 | static int python_process_call_return(struct call_return *cr, void *data) | 1198 | static int python_process_call_return(struct call_return *cr, u64 *parent_db_id, |
1199 | void *data) | ||
1198 | { | 1200 | { |
1199 | struct db_export *dbe = data; | 1201 | struct db_export *dbe = data; |
1200 | 1202 | ||
1201 | return db_export__call_return(dbe, cr); | 1203 | return db_export__call_return(dbe, cr, parent_db_id); |
1202 | } | 1204 | } |
1203 | 1205 | ||
1204 | static void python_process_general_event(struct perf_sample *sample, | 1206 | static void python_process_general_event(struct perf_sample *sample, |
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index a8b45168513c..41942c2aaa18 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
@@ -49,6 +49,7 @@ enum retpoline_state_t { | |||
49 | * @timestamp: timestamp (if known) | 49 | * @timestamp: timestamp (if known) |
50 | * @ref: external reference (e.g. db_id of sample) | 50 | * @ref: external reference (e.g. db_id of sample) |
51 | * @branch_count: the branch count when the entry was created | 51 | * @branch_count: the branch count when the entry was created |
52 | * @db_id: id used for db-export | ||
52 | * @cp: call path | 53 | * @cp: call path |
53 | * @no_call: a 'call' was not seen | 54 | * @no_call: a 'call' was not seen |
54 | * @trace_end: a 'call' but trace ended | 55 | * @trace_end: a 'call' but trace ended |
@@ -59,6 +60,7 @@ struct thread_stack_entry { | |||
59 | u64 timestamp; | 60 | u64 timestamp; |
60 | u64 ref; | 61 | u64 ref; |
61 | u64 branch_count; | 62 | u64 branch_count; |
63 | u64 db_id; | ||
62 | struct call_path *cp; | 64 | struct call_path *cp; |
63 | bool no_call; | 65 | bool no_call; |
64 | bool trace_end; | 66 | bool trace_end; |
@@ -280,12 +282,14 @@ static int thread_stack__call_return(struct thread *thread, | |||
280 | .comm = ts->comm, | 282 | .comm = ts->comm, |
281 | .db_id = 0, | 283 | .db_id = 0, |
282 | }; | 284 | }; |
285 | u64 *parent_db_id; | ||
283 | 286 | ||
284 | tse = &ts->stack[idx]; | 287 | tse = &ts->stack[idx]; |
285 | cr.cp = tse->cp; | 288 | cr.cp = tse->cp; |
286 | cr.call_time = tse->timestamp; | 289 | cr.call_time = tse->timestamp; |
287 | cr.return_time = timestamp; | 290 | cr.return_time = timestamp; |
288 | cr.branch_count = ts->branch_count - tse->branch_count; | 291 | cr.branch_count = ts->branch_count - tse->branch_count; |
292 | cr.db_id = tse->db_id; | ||
289 | cr.call_ref = tse->ref; | 293 | cr.call_ref = tse->ref; |
290 | cr.return_ref = ref; | 294 | cr.return_ref = ref; |
291 | if (tse->no_call) | 295 | if (tse->no_call) |
@@ -295,7 +299,14 @@ static int thread_stack__call_return(struct thread *thread, | |||
295 | if (tse->non_call) | 299 | if (tse->non_call) |
296 | cr.flags |= CALL_RETURN_NON_CALL; | 300 | cr.flags |= CALL_RETURN_NON_CALL; |
297 | 301 | ||
298 | return crp->process(&cr, crp->data); | 302 | /* |
303 | * The parent db_id must be assigned before exporting the child. Note | ||
304 | * it is not possible to export the parent first because its information | ||
305 | * is not yet complete because its 'return' has not yet been processed. | ||
306 | */ | ||
307 | parent_db_id = idx ? &(tse - 1)->db_id : NULL; | ||
308 | |||
309 | return crp->process(&cr, parent_db_id, crp->data); | ||
299 | } | 310 | } |
300 | 311 | ||
301 | static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts) | 312 | static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts) |
@@ -484,7 +495,7 @@ void thread_stack__sample(struct thread *thread, int cpu, | |||
484 | } | 495 | } |
485 | 496 | ||
486 | struct call_return_processor * | 497 | struct call_return_processor * |
487 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), | 498 | call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data), |
488 | void *data) | 499 | void *data) |
489 | { | 500 | { |
490 | struct call_return_processor *crp; | 501 | struct call_return_processor *crp; |
@@ -537,6 +548,7 @@ static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr, | |||
537 | tse->no_call = no_call; | 548 | tse->no_call = no_call; |
538 | tse->trace_end = trace_end; | 549 | tse->trace_end = trace_end; |
539 | tse->non_call = false; | 550 | tse->non_call = false; |
551 | tse->db_id = 0; | ||
540 | 552 | ||
541 | return 0; | 553 | return 0; |
542 | } | 554 | } |
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index b7c04e19ad41..9c45f947f5a9 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h | |||
@@ -55,6 +55,7 @@ enum { | |||
55 | * @call_ref: external reference to 'call' sample (e.g. db_id) | 55 | * @call_ref: external reference to 'call' sample (e.g. db_id) |
56 | * @return_ref: external reference to 'return' sample (e.g. db_id) | 56 | * @return_ref: external reference to 'return' sample (e.g. db_id) |
57 | * @db_id: id used for db-export | 57 | * @db_id: id used for db-export |
58 | * @parent_db_id: id of parent call used for db-export | ||
58 | * @flags: Call/Return flags | 59 | * @flags: Call/Return flags |
59 | */ | 60 | */ |
60 | struct call_return { | 61 | struct call_return { |
@@ -67,6 +68,7 @@ struct call_return { | |||
67 | u64 call_ref; | 68 | u64 call_ref; |
68 | u64 return_ref; | 69 | u64 return_ref; |
69 | u64 db_id; | 70 | u64 db_id; |
71 | u64 parent_db_id; | ||
70 | u32 flags; | 72 | u32 flags; |
71 | }; | 73 | }; |
72 | 74 | ||
@@ -79,7 +81,7 @@ struct call_return { | |||
79 | */ | 81 | */ |
80 | struct call_return_processor { | 82 | struct call_return_processor { |
81 | struct call_path_root *cpr; | 83 | struct call_path_root *cpr; |
82 | int (*process)(struct call_return *cr, void *data); | 84 | int (*process)(struct call_return *cr, u64 *parent_db_id, void *data); |
83 | void *data; | 85 | void *data; |
84 | }; | 86 | }; |
85 | 87 | ||
@@ -93,7 +95,7 @@ void thread_stack__free(struct thread *thread); | |||
93 | size_t thread_stack__depth(struct thread *thread, int cpu); | 95 | size_t thread_stack__depth(struct thread *thread, int cpu); |
94 | 96 | ||
95 | struct call_return_processor * | 97 | struct call_return_processor * |
96 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), | 98 | call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data), |
97 | void *data); | 99 | void *data); |
98 | void call_return_processor__free(struct call_return_processor *crp); | 100 | void call_return_processor__free(struct call_return_processor *crp); |
99 | int thread_stack__process(struct thread *thread, struct comm *comm, | 101 | int thread_stack__process(struct thread *thread, struct comm *comm, |