Skip to content

Commit 7f1d393

Browse files
Kan Liangacmel
authored andcommitted
perf callchain: Save previous cursor nodes for LBR stitching approach
The cursor nodes which generates from sample are eventually added into callchain. To avoid generating cursor nodes from previous samples again, the previous cursor nodes are also saved for LBR stitching approach. Some option, e.g. hide-unresolved, may hide some LBRs. Add a variable 'valid' in struct callchain_cursor_node to indicate this case. The LBR stitching approach will only append the valid cursor nodes from previous samples later. Signed-off-by: Kan Liang <[email protected]> Reviewed-by: Andi Kleen <[email protected]> Acked-by: Jiri Olsa <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexey Budankov <[email protected]> Cc: Mathieu Poirier <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Pavel Gerasimov <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ravi Bangoria <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Vitaly Slobodskoy <[email protected]> Link: http://lore.kernel.org/lkml/[email protected] [ Use zfree() instead of open coded equivalent, and use it when freeing members of structs ] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 9c6c3f4 commit 7f1d393

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed

tools/perf/util/callchain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ struct callchain_cursor_node {
143143
u64 ip;
144144
struct map_symbol ms;
145145
const char *srcline;
146+
/* Indicate valid cursor node for LBR stitch */
147+
bool valid;
148+
146149
bool branch;
147150
struct branch_flags branch_flags;
148151
u64 branch_from;

tools/perf/util/machine.c

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,6 +2224,31 @@ static int lbr_callchain_add_kernel_ip(struct thread *thread,
22242224
return 0;
22252225
}
22262226

2227+
static void save_lbr_cursor_node(struct thread *thread,
2228+
struct callchain_cursor *cursor,
2229+
int idx)
2230+
{
2231+
struct lbr_stitch *lbr_stitch = thread->lbr_stitch;
2232+
2233+
if (!lbr_stitch)
2234+
return;
2235+
2236+
if (cursor->pos == cursor->nr) {
2237+
lbr_stitch->prev_lbr_cursor[idx].valid = false;
2238+
return;
2239+
}
2240+
2241+
if (!cursor->curr)
2242+
cursor->curr = cursor->first;
2243+
else
2244+
cursor->curr = cursor->curr->next;
2245+
memcpy(&lbr_stitch->prev_lbr_cursor[idx], cursor->curr,
2246+
sizeof(struct callchain_cursor_node));
2247+
2248+
lbr_stitch->prev_lbr_cursor[idx].valid = true;
2249+
cursor->pos++;
2250+
}
2251+
22272252
static int lbr_callchain_add_lbr_ip(struct thread *thread,
22282253
struct callchain_cursor *cursor,
22292254
struct perf_sample *sample,
@@ -2240,6 +2265,21 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
22402265
int err, i;
22412266
u64 ip;
22422267

2268+
/*
2269+
* The curr and pos are not used in writing session. They are cleared
2270+
* in callchain_cursor_commit() when the writing session is closed.
2271+
* Using curr and pos to track the current cursor node.
2272+
*/
2273+
if (thread->lbr_stitch) {
2274+
cursor->curr = NULL;
2275+
cursor->pos = cursor->nr;
2276+
if (cursor->nr) {
2277+
cursor->curr = cursor->first;
2278+
for (i = 0; i < (int)(cursor->nr - 1); i++)
2279+
cursor->curr = cursor->curr->next;
2280+
}
2281+
}
2282+
22432283
if (callee) {
22442284
/* Add LBR ip from first entries.to */
22452285
ip = entries[0].to;
@@ -2252,6 +2292,20 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
22522292
if (err)
22532293
return err;
22542294

2295+
/*
2296+
* The number of cursor node increases.
2297+
* Move the current cursor node.
2298+
* But does not need to save current cursor node for entry 0.
2299+
* It's impossible to stitch the whole LBRs of previous sample.
2300+
*/
2301+
if (thread->lbr_stitch && (cursor->pos != cursor->nr)) {
2302+
if (!cursor->curr)
2303+
cursor->curr = cursor->first;
2304+
else
2305+
cursor->curr = cursor->curr->next;
2306+
cursor->pos++;
2307+
}
2308+
22552309
/* Add LBR ip from entries.from one by one. */
22562310
for (i = 0; i < lbr_nr; i++) {
22572311
ip = entries[i].from;
@@ -2262,6 +2316,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
22622316
*branch_from);
22632317
if (err)
22642318
return err;
2319+
save_lbr_cursor_node(thread, cursor, i);
22652320
}
22662321
return 0;
22672322
}
@@ -2276,6 +2331,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
22762331
*branch_from);
22772332
if (err)
22782333
return err;
2334+
save_lbr_cursor_node(thread, cursor, i);
22792335
}
22802336

22812337
/* Add LBR ip from first entries.to */
@@ -2292,7 +2348,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
22922348
return 0;
22932349
}
22942350

2295-
static bool alloc_lbr_stitch(struct thread *thread)
2351+
static bool alloc_lbr_stitch(struct thread *thread, unsigned int max_lbr)
22962352
{
22972353
if (thread->lbr_stitch)
22982354
return true;
@@ -2301,6 +2357,14 @@ static bool alloc_lbr_stitch(struct thread *thread)
23012357
if (!thread->lbr_stitch)
23022358
goto err;
23032359

2360+
thread->lbr_stitch->prev_lbr_cursor = calloc(max_lbr + 1, sizeof(struct callchain_cursor_node));
2361+
if (!thread->lbr_stitch->prev_lbr_cursor)
2362+
goto free_lbr_stitch;
2363+
2364+
return true;
2365+
2366+
free_lbr_stitch:
2367+
zfree(&thread->lbr_stitch);
23042368
err:
23052369
pr_warning("Failed to allocate space for stitched LBRs. Disable LBR stitch\n");
23062370
thread->lbr_stitch_enable = false;
@@ -2319,7 +2383,8 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
23192383
struct perf_sample *sample,
23202384
struct symbol **parent,
23212385
struct addr_location *root_al,
2322-
int max_stack)
2386+
int max_stack,
2387+
unsigned int max_lbr)
23232388
{
23242389
struct ip_callchain *chain = sample->callchain;
23252390
int chain_nr = min(max_stack, (int)chain->nr), i;
@@ -2337,7 +2402,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
23372402
return 0;
23382403

23392404
if (thread->lbr_stitch_enable && !sample->no_hw_idx &&
2340-
alloc_lbr_stitch(thread)) {
2405+
(max_lbr > 0) && alloc_lbr_stitch(thread, max_lbr)) {
23412406
lbr_stitch = thread->lbr_stitch;
23422407

23432408
memcpy(&lbr_stitch->prev_sample, sample, sizeof(*sample));
@@ -2417,8 +2482,11 @@ static int thread__resolve_callchain_sample(struct thread *thread,
24172482
chain_nr = chain->nr;
24182483

24192484
if (perf_evsel__has_branch_callstack(evsel)) {
2485+
struct perf_env *env = perf_evsel__env(evsel);
2486+
24202487
err = resolve_lbr_callchain_sample(thread, cursor, sample, parent,
2421-
root_al, max_stack);
2488+
root_al, max_stack,
2489+
!env ? 0 : env->max_branches);
24222490
if (err)
24232491
return (err < 0) ? err : 0;
24242492
}

tools/perf/util/thread.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <intlist.h>
1616
#include "rwsem.h"
1717
#include "event.h"
18+
#include "callchain.h"
1819

1920
struct addr_location;
2021
struct map;
@@ -24,6 +25,7 @@ struct unwind_libunwind_ops;
2425

2526
struct lbr_stitch {
2627
struct perf_sample prev_sample;
28+
struct callchain_cursor_node *prev_lbr_cursor;
2729
};
2830

2931
struct thread {
@@ -154,6 +156,12 @@ static inline bool thread__is_filtered(struct thread *thread)
154156

155157
static inline void thread__free_stitch_list(struct thread *thread)
156158
{
159+
struct lbr_stitch *lbr_stitch = thread->lbr_stitch;
160+
161+
if (!lbr_stitch)
162+
return;
163+
164+
zfree(&lbr_stitch->prev_lbr_cursor);
157165
zfree(&thread->lbr_stitch);
158166
}
159167

0 commit comments

Comments
 (0)