mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 20:24:12 +08:00
perf callchain: Use pthread keys for tls callchain_cursor
Pthread keys are more portable than __thread and allow the association of a destructor with the key. Use the destructor to clean up TLS callchain cursors to aid understanding memory leaks. Committer notes: Had to fixup a series of unconverted places and also check for the return of get_tls_callchain_cursor() as it may fail and return NULL. In that unlikely case we now either print something to a file, if the caller was expecting to print a callchain, or return an error code to state that resolving the callchain isn't possible. In some cases this was made easier because thread__resolve_callchain() already can fail for other reasons, so this new one (cursor == NULL) can be added and the callers don't have to explicitely check for this new condition. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ali Saidi <alisaidi@amazon.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Brian Robbins <brianrob@linux.microsoft.com> Cc: Changbin Du <changbin.du@huawei.com> Cc: Dmitrii Dolgov <9erthalion6@gmail.com> Cc: Fangrui Song <maskray@google.com> Cc: German Gomez <german.gomez@arm.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Ivan Babrou <ivan@cloudflare.com> Cc: James Clark <james.clark@arm.com> Cc: Jing Zhang <renyu.zj@linux.alibaba.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.g.garry@oracle.com> Cc: K Prateek Nayak <kprateek.nayak@amd.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Miguel Ojeda <ojeda@kernel.org> Cc: Mike Leach <mike.leach@linaro.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Steinar H. Gunderson <sesse@google.com> Cc: Suzuki Poulouse <suzuki.poulose@arm.com> Cc: Wenyu Liu <liuwenyu7@huawei.com> Cc: Will Deacon <will@kernel.org> Cc: Yang Jihong <yangjihong1@huawei.com> Cc: Ye Xingchen <ye.xingchen@zte.com.cn> Cc: Yuan Can <yuancan@huawei.com> Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230608232823.4027869-25-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
d7ba60a4e5
commit
8ab12a2038
@ -284,6 +284,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
struct hist_entry *he;
|
||||
struct addr_location al;
|
||||
struct mem_info *mi, *mi_dup;
|
||||
struct callchain_cursor *cursor;
|
||||
int ret;
|
||||
|
||||
addr_location__init(&al);
|
||||
@ -297,7 +298,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
if (c2c.stitch_lbr)
|
||||
thread__set_lbr_stitch_enable(al.thread, true);
|
||||
|
||||
ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
|
||||
cursor = get_tls_callchain_cursor();
|
||||
ret = sample__resolve_callchain(sample, cursor, NULL,
|
||||
evsel, &al, sysctl_perf_event_max_stack);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -399,6 +399,7 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
|
||||
struct addr_location al;
|
||||
struct machine *machine = &kmem_session->machines.host;
|
||||
struct callchain_cursor_node *node;
|
||||
struct callchain_cursor *cursor;
|
||||
u64 result = sample->ip;
|
||||
|
||||
addr_location__init(&al);
|
||||
@ -408,14 +409,19 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
|
||||
}
|
||||
|
||||
al.thread = machine__findnew_thread(machine, sample->pid, sample->tid);
|
||||
sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16);
|
||||
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
cursor = get_tls_callchain_cursor();
|
||||
if (cursor == NULL)
|
||||
goto out;
|
||||
|
||||
sample__resolve_callchain(sample, cursor, NULL, evsel, &al, 16);
|
||||
|
||||
callchain_cursor_commit(cursor);
|
||||
while (true) {
|
||||
struct alloc_func key, *caller;
|
||||
u64 addr;
|
||||
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
node = callchain_cursor_current(cursor);
|
||||
if (node == NULL)
|
||||
break;
|
||||
|
||||
@ -434,7 +440,7 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
|
||||
} else
|
||||
pr_debug3("skipping alloc function: %s\n", caller->name);
|
||||
|
||||
callchain_cursor_advance(&callchain_cursor);
|
||||
callchain_cursor_advance(cursor);
|
||||
}
|
||||
|
||||
pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
|
||||
|
@ -589,7 +589,7 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
|
||||
struct symbol *sym;
|
||||
struct thread *thread;
|
||||
struct callchain_cursor_node *node;
|
||||
struct callchain_cursor *cursor = &callchain_cursor;
|
||||
struct callchain_cursor *cursor;
|
||||
|
||||
if (!kwork->show_callchain || sample->callchain == NULL)
|
||||
return;
|
||||
@ -601,6 +601,8 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
|
||||
return;
|
||||
}
|
||||
|
||||
cursor = get_tls_callchain_cursor();
|
||||
|
||||
if (thread__resolve_callchain(thread, cursor, evsel, sample,
|
||||
NULL, NULL, kwork->max_stack + 2) != 0) {
|
||||
pr_debug("Failed to resolve callchain, skipping\n");
|
||||
@ -686,12 +688,18 @@ static void timehist_print_event(struct perf_kwork *kwork,
|
||||
* callchain
|
||||
*/
|
||||
if (kwork->show_callchain) {
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
if (cursor == NULL)
|
||||
return;
|
||||
|
||||
printf(" ");
|
||||
|
||||
sample__fprintf_sym(sample, al, 0,
|
||||
EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
|
||||
EVSEL__PRINT_CALLCHAIN_ARROW |
|
||||
EVSEL__PRINT_SKIP_IGNORED,
|
||||
&callchain_cursor, symbol_conf.bt_stop_list,
|
||||
cursor, symbol_conf.bt_stop_list,
|
||||
stdout);
|
||||
}
|
||||
|
||||
|
@ -911,7 +911,7 @@ static int lock_contention_caller(struct evsel *evsel, struct perf_sample *sampl
|
||||
char *buf, int size)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct callchain_cursor *cursor = &callchain_cursor;
|
||||
struct callchain_cursor *cursor;
|
||||
struct machine *machine = &session->machines.host;
|
||||
struct symbol *sym;
|
||||
int skip = 0;
|
||||
@ -925,6 +925,8 @@ static int lock_contention_caller(struct evsel *evsel, struct perf_sample *sampl
|
||||
if (thread == NULL)
|
||||
return -1;
|
||||
|
||||
cursor = get_tls_callchain_cursor();
|
||||
|
||||
/* use caller function name from the callchain */
|
||||
ret = thread__resolve_callchain(thread, cursor, evsel, sample,
|
||||
NULL, NULL, max_stack_depth);
|
||||
@ -962,7 +964,7 @@ next:
|
||||
|
||||
static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample)
|
||||
{
|
||||
struct callchain_cursor *cursor = &callchain_cursor;
|
||||
struct callchain_cursor *cursor;
|
||||
struct machine *machine = &session->machines.host;
|
||||
struct thread *thread;
|
||||
u64 hash = 0;
|
||||
@ -973,6 +975,7 @@ static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample)
|
||||
if (thread == NULL)
|
||||
return -1;
|
||||
|
||||
cursor = get_tls_callchain_cursor();
|
||||
/* use caller function name from the callchain */
|
||||
ret = thread__resolve_callchain(thread, cursor, evsel, sample,
|
||||
NULL, NULL, max_stack_depth);
|
||||
|
@ -2111,7 +2111,7 @@ static void timehist_print_sample(struct perf_sched *sched,
|
||||
EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
|
||||
EVSEL__PRINT_CALLCHAIN_ARROW |
|
||||
EVSEL__PRINT_SKIP_IGNORED,
|
||||
&callchain_cursor, symbol_conf.bt_stop_list, stdout);
|
||||
get_tls_callchain_cursor(), symbol_conf.bt_stop_list, stdout);
|
||||
|
||||
out:
|
||||
printf("\n");
|
||||
@ -2196,7 +2196,7 @@ static void save_task_callchain(struct perf_sched *sched,
|
||||
struct evsel *evsel,
|
||||
struct machine *machine)
|
||||
{
|
||||
struct callchain_cursor *cursor = &callchain_cursor;
|
||||
struct callchain_cursor *cursor;
|
||||
struct thread *thread;
|
||||
|
||||
/* want main thread for process - has maps */
|
||||
@ -2209,6 +2209,8 @@ static void save_task_callchain(struct perf_sched *sched,
|
||||
if (!sched->show_callchain || sample->callchain == NULL)
|
||||
return;
|
||||
|
||||
cursor = get_tls_callchain_cursor();
|
||||
|
||||
if (thread__resolve_callchain(thread, cursor, evsel, sample,
|
||||
NULL, NULL, sched->max_stack + 2) != 0) {
|
||||
if (verbose > 0)
|
||||
@ -2338,10 +2340,16 @@ static void save_idle_callchain(struct perf_sched *sched,
|
||||
struct idle_thread_runtime *itr,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
struct callchain_cursor *cursor;
|
||||
|
||||
if (!sched->show_callchain || sample->callchain == NULL)
|
||||
return;
|
||||
|
||||
callchain_cursor__copy(&itr->cursor, &callchain_cursor);
|
||||
cursor = get_tls_callchain_cursor();
|
||||
if (cursor == NULL)
|
||||
return;
|
||||
|
||||
callchain_cursor__copy(&itr->cursor, cursor);
|
||||
}
|
||||
|
||||
static struct thread *timehist_get_thread(struct perf_sched *sched,
|
||||
|
@ -1557,11 +1557,13 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample,
|
||||
unsigned int print_opts = output[type].print_ip_opts;
|
||||
struct callchain_cursor *cursor = NULL;
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain &&
|
||||
thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
|
||||
sample, NULL, NULL, scripting_max_stack) == 0)
|
||||
cursor = &callchain_cursor;
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain) {
|
||||
cursor = get_tls_callchain_cursor();
|
||||
if (thread__resolve_callchain(al->thread, cursor, evsel,
|
||||
sample, NULL, NULL,
|
||||
scripting_max_stack))
|
||||
cursor = NULL;
|
||||
}
|
||||
if (cursor == NULL) {
|
||||
printed += fprintf(fp, " ");
|
||||
if (print_opts & EVSEL__PRINT_SRCLINE) {
|
||||
@ -2203,11 +2205,13 @@ static void process_event(struct perf_script *script,
|
||||
if (script->stitch_lbr)
|
||||
thread__set_lbr_stitch_enable(al->thread, true);
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain &&
|
||||
thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
|
||||
sample, NULL, NULL, scripting_max_stack) == 0)
|
||||
cursor = &callchain_cursor;
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain) {
|
||||
cursor = get_tls_callchain_cursor();
|
||||
if (thread__resolve_callchain(al->thread, cursor, evsel,
|
||||
sample, NULL, NULL,
|
||||
scripting_max_stack))
|
||||
cursor = NULL;
|
||||
}
|
||||
fputc(cursor ? '\n' : ' ', fp);
|
||||
sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor,
|
||||
symbol_conf.bt_stop_list, fp);
|
||||
|
@ -2437,7 +2437,7 @@ static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sam
|
||||
EVSEL__PRINT_DSO |
|
||||
EVSEL__PRINT_UNKNOWN_AS_ADDR;
|
||||
|
||||
return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, symbol_conf.bt_stop_list, trace->output);
|
||||
return sample__fprintf_callchain(sample, 38, print_opts, get_tls_callchain_cursor(), symbol_conf.bt_stop_list, trace->output);
|
||||
}
|
||||
|
||||
static const char *errno_to_name(struct evsel *evsel, int err)
|
||||
@ -2491,9 +2491,11 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
|
||||
goto out;
|
||||
|
||||
if (sample->callchain) {
|
||||
callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
callchain_ret = trace__resolve_callchain(trace, evsel, sample, cursor);
|
||||
if (callchain_ret == 0) {
|
||||
if (callchain_cursor.nr < trace->min_stack)
|
||||
if (cursor->nr < trace->min_stack)
|
||||
goto out;
|
||||
callchain_ret = 1;
|
||||
}
|
||||
@ -2795,9 +2797,11 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel,
|
||||
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
||||
|
||||
if (sample->callchain) {
|
||||
callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
callchain_ret = trace__resolve_callchain(trace, evsel, sample, cursor);
|
||||
if (callchain_ret == 0) {
|
||||
if (callchain_cursor.nr < trace->min_stack)
|
||||
if (cursor->nr < trace->min_stack)
|
||||
goto out;
|
||||
callchain_ret = 1;
|
||||
}
|
||||
@ -2899,9 +2903,11 @@ static int trace__pgfault(struct trace *trace,
|
||||
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
||||
|
||||
if (sample->callchain) {
|
||||
callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
callchain_ret = trace__resolve_callchain(trace, evsel, sample, cursor);
|
||||
if (callchain_ret == 0) {
|
||||
if (callchain_cursor.nr < trace->min_stack)
|
||||
if (cursor->nr < trace->min_stack)
|
||||
goto out_put;
|
||||
callchain_ret = 1;
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ struct callchain_param callchain_param_default = {
|
||||
CALLCHAIN_PARAM_DEFAULT
|
||||
};
|
||||
|
||||
__thread struct callchain_cursor callchain_cursor;
|
||||
/* Used for thread-local struct callchain_cursor. */
|
||||
static pthread_key_t callchain_cursor;
|
||||
|
||||
int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
|
||||
{
|
||||
@ -986,6 +987,9 @@ int callchain_append(struct callchain_root *root,
|
||||
struct callchain_cursor *cursor,
|
||||
u64 period)
|
||||
{
|
||||
if (cursor == NULL)
|
||||
return -1;
|
||||
|
||||
if (!cursor->nr)
|
||||
return 0;
|
||||
|
||||
@ -1116,7 +1120,7 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
|
||||
if ((!symbol_conf.use_callchain || sample->callchain == NULL) &&
|
||||
!symbol_conf.show_branchflag_count)
|
||||
return 0;
|
||||
return callchain_append(he->callchain, &callchain_cursor, sample->period);
|
||||
return callchain_append(he->callchain, get_tls_callchain_cursor(), sample->period);
|
||||
}
|
||||
|
||||
int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
|
||||
@ -1570,6 +1574,43 @@ out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void callchain_cursor__delete(void *vcursor)
|
||||
{
|
||||
struct callchain_cursor *cursor = vcursor;
|
||||
struct callchain_cursor_node *node, *next;
|
||||
|
||||
callchain_cursor_reset(cursor);
|
||||
for (node = cursor->first; node != NULL; node = next) {
|
||||
next = node->next;
|
||||
free(node);
|
||||
}
|
||||
free(cursor);
|
||||
}
|
||||
|
||||
static void init_callchain_cursor_key(void)
|
||||
{
|
||||
if (pthread_key_create(&callchain_cursor, callchain_cursor__delete)) {
|
||||
pr_err("callchain cursor creation failed");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
struct callchain_cursor *get_tls_callchain_cursor(void)
|
||||
{
|
||||
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
||||
struct callchain_cursor *cursor;
|
||||
|
||||
pthread_once(&once_control, init_callchain_cursor_key);
|
||||
cursor = pthread_getspecific(callchain_cursor);
|
||||
if (!cursor) {
|
||||
cursor = zalloc(sizeof(*cursor));
|
||||
if (!cursor)
|
||||
pr_debug3("%s: not enough memory\n", __func__);
|
||||
pthread_setspecific(callchain_cursor, cursor);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
int callchain_cursor__copy(struct callchain_cursor *dst,
|
||||
struct callchain_cursor *src)
|
||||
{
|
||||
|
@ -168,8 +168,6 @@ struct callchain_cursor {
|
||||
struct callchain_cursor_node *curr;
|
||||
};
|
||||
|
||||
extern __thread struct callchain_cursor callchain_cursor;
|
||||
|
||||
static inline void callchain_init(struct callchain_root *root)
|
||||
{
|
||||
INIT_LIST_HEAD(&root->node.val);
|
||||
@ -211,6 +209,8 @@ int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
|
||||
/* Close a cursor writing session. Initialize for the reader */
|
||||
static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
|
||||
{
|
||||
if (cursor == NULL)
|
||||
return;
|
||||
cursor->curr = cursor->first;
|
||||
cursor->pos = 0;
|
||||
}
|
||||
@ -219,7 +219,7 @@ static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
|
||||
static inline struct callchain_cursor_node *
|
||||
callchain_cursor_current(struct callchain_cursor *cursor)
|
||||
{
|
||||
if (cursor->pos == cursor->nr)
|
||||
if (cursor == NULL || cursor->pos == cursor->nr)
|
||||
return NULL;
|
||||
|
||||
return cursor->curr;
|
||||
@ -231,6 +231,8 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
|
||||
cursor->pos++;
|
||||
}
|
||||
|
||||
struct callchain_cursor *get_tls_callchain_cursor(void);
|
||||
|
||||
int callchain_cursor__copy(struct callchain_cursor *dst,
|
||||
struct callchain_cursor *src);
|
||||
|
||||
|
@ -215,6 +215,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
||||
u64 kernel_start = machine__kernel_start(machine);
|
||||
struct call_path *current = &dbe->cpr->call_path;
|
||||
enum chain_order saved_order = callchain_param.order;
|
||||
struct callchain_cursor *cursor;
|
||||
int err;
|
||||
|
||||
if (!symbol_conf.use_callchain || !sample->callchain)
|
||||
@ -226,13 +227,14 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
||||
* the callchain starting with the root node and ending with the leaf.
|
||||
*/
|
||||
callchain_param.order = ORDER_CALLER;
|
||||
err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
|
||||
cursor = get_tls_callchain_cursor();
|
||||
err = thread__resolve_callchain(thread, cursor, evsel,
|
||||
sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
|
||||
if (err) {
|
||||
callchain_param.order = saved_order;
|
||||
return NULL;
|
||||
}
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
callchain_cursor_commit(cursor);
|
||||
|
||||
while (1) {
|
||||
struct callchain_cursor_node *node;
|
||||
@ -240,7 +242,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
||||
u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
|
||||
|
||||
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
node = callchain_cursor_current(cursor);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
@ -265,7 +267,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
||||
al.sym, node->ip,
|
||||
kernel_start);
|
||||
|
||||
callchain_cursor_advance(&callchain_cursor);
|
||||
callchain_cursor_advance(cursor);
|
||||
addr_location__exit(&al);
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,9 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
|
||||
char s = print_oneline ? ' ' : '\t';
|
||||
bool first = true;
|
||||
|
||||
if (cursor == NULL)
|
||||
return fprintf(fp, "<not enough memory for the callchain cursor>%s", print_oneline ? "" : "\n");
|
||||
|
||||
if (sample->callchain) {
|
||||
callchain_cursor_commit(cursor);
|
||||
|
||||
|
@ -1029,15 +1029,19 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter,
|
||||
struct addr_location *al __maybe_unused)
|
||||
{
|
||||
struct hist_entry **he_cache;
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
if (cursor == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
callchain_cursor_commit(cursor);
|
||||
|
||||
/*
|
||||
* This is for detecting cycles or recursions so that they're
|
||||
* cumulated only one time to prevent entries more than 100%
|
||||
* overhead.
|
||||
*/
|
||||
he_cache = malloc(sizeof(*he_cache) * (callchain_cursor.nr + 1));
|
||||
he_cache = malloc(sizeof(*he_cache) * (cursor->nr + 1));
|
||||
if (he_cache == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1072,7 +1076,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
|
||||
* We need to re-initialize the cursor since callchain_append()
|
||||
* advanced the cursor to the end.
|
||||
*/
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
callchain_cursor_commit(get_tls_callchain_cursor());
|
||||
|
||||
hists__inc_nr_samples(hists, he->filtered);
|
||||
|
||||
@ -1085,7 +1089,7 @@ iter_next_cumulative_entry(struct hist_entry_iter *iter,
|
||||
{
|
||||
struct callchain_cursor_node *node;
|
||||
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
node = callchain_cursor_current(get_tls_callchain_cursor());
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
|
||||
@ -1131,12 +1135,15 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
|
||||
.raw_size = sample->raw_size,
|
||||
};
|
||||
int i;
|
||||
struct callchain_cursor cursor;
|
||||
struct callchain_cursor cursor, *tls_cursor = get_tls_callchain_cursor();
|
||||
bool fast = hists__has(he_tmp.hists, sym);
|
||||
|
||||
callchain_cursor_snapshot(&cursor, &callchain_cursor);
|
||||
if (tls_cursor == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
callchain_cursor_advance(&callchain_cursor);
|
||||
callchain_cursor_snapshot(&cursor, tls_cursor);
|
||||
|
||||
callchain_cursor_advance(tls_cursor);
|
||||
|
||||
/*
|
||||
* Check if there's duplicate entries in the callchain.
|
||||
@ -1222,7 +1229,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
|
||||
if (al)
|
||||
alm = map__get(al->map);
|
||||
|
||||
err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent,
|
||||
err = sample__resolve_callchain(iter->sample, get_tls_callchain_cursor(), &iter->parent,
|
||||
iter->evsel, al, max_stack_depth);
|
||||
if (err) {
|
||||
map__put(alm);
|
||||
@ -1568,8 +1575,13 @@ static int hists__hierarchy_insert_entry(struct hists *hists,
|
||||
|
||||
if (hist_entry__has_callchains(new_he) &&
|
||||
symbol_conf.use_callchain) {
|
||||
callchain_cursor_reset(&callchain_cursor);
|
||||
if (callchain_merge(&callchain_cursor,
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
if (cursor == NULL)
|
||||
return -1;
|
||||
|
||||
callchain_cursor_reset(cursor);
|
||||
if (callchain_merge(cursor,
|
||||
new_he->callchain,
|
||||
he->callchain) < 0)
|
||||
ret = -1;
|
||||
@ -1610,11 +1622,15 @@ static int hists__collapse_insert_entry(struct hists *hists,
|
||||
he_stat__add_stat(iter->stat_acc, he->stat_acc);
|
||||
|
||||
if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
|
||||
callchain_cursor_reset(&callchain_cursor);
|
||||
if (callchain_merge(&callchain_cursor,
|
||||
iter->callchain,
|
||||
he->callchain) < 0)
|
||||
ret = -1;
|
||||
struct callchain_cursor *cursor = get_tls_callchain_cursor();
|
||||
|
||||
if (cursor != NULL) {
|
||||
callchain_cursor_reset(cursor);
|
||||
if (callchain_merge(cursor, iter->callchain, he->callchain) < 0)
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
hist_entry__delete(he);
|
||||
return ret;
|
||||
|
@ -3180,6 +3180,9 @@ int thread__resolve_callchain(struct thread *thread,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (cursor == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
callchain_cursor_reset(cursor);
|
||||
|
||||
if (callchain_param.order == ORDER_CALLEE) {
|
||||
|
@ -260,6 +260,7 @@ static SV *perl_process_callchain(struct perf_sample *sample,
|
||||
struct evsel *evsel,
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct callchain_cursor *cursor;
|
||||
AV *list;
|
||||
|
||||
list = newAV();
|
||||
@ -269,18 +270,20 @@ static SV *perl_process_callchain(struct perf_sample *sample,
|
||||
if (!symbol_conf.use_callchain || !sample->callchain)
|
||||
goto exit;
|
||||
|
||||
if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
|
||||
cursor = get_tls_callchain_cursor();
|
||||
|
||||
if (thread__resolve_callchain(al->thread, cursor, evsel,
|
||||
sample, NULL, NULL, scripting_max_stack) != 0) {
|
||||
pr_err("Failed to resolve callchain. Skipping\n");
|
||||
goto exit;
|
||||
}
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
callchain_cursor_commit(cursor);
|
||||
|
||||
|
||||
while (1) {
|
||||
HV *elem;
|
||||
struct callchain_cursor_node *node;
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
node = callchain_cursor_current(cursor);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
@ -328,7 +331,7 @@ static SV *perl_process_callchain(struct perf_sample *sample,
|
||||
}
|
||||
}
|
||||
|
||||
callchain_cursor_advance(&callchain_cursor);
|
||||
callchain_cursor_advance(cursor);
|
||||
av_push(list, newRV_noinc((SV*)elem));
|
||||
}
|
||||
|
||||
|
@ -417,6 +417,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
|
||||
struct addr_location *al)
|
||||
{
|
||||
PyObject *pylist;
|
||||
struct callchain_cursor *cursor;
|
||||
|
||||
pylist = PyList_New(0);
|
||||
if (!pylist)
|
||||
@ -425,19 +426,20 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
|
||||
if (!symbol_conf.use_callchain || !sample->callchain)
|
||||
goto exit;
|
||||
|
||||
if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
|
||||
cursor = get_tls_callchain_cursor();
|
||||
if (thread__resolve_callchain(al->thread, cursor, evsel,
|
||||
sample, NULL, NULL,
|
||||
scripting_max_stack) != 0) {
|
||||
pr_err("Failed to resolve callchain. Skipping\n");
|
||||
goto exit;
|
||||
}
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
callchain_cursor_commit(cursor);
|
||||
|
||||
|
||||
while (1) {
|
||||
PyObject *pyelem;
|
||||
struct callchain_cursor_node *node;
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
node = callchain_cursor_current(cursor);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
@ -493,7 +495,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
|
||||
_PyUnicode_FromString(dsoname));
|
||||
}
|
||||
|
||||
callchain_cursor_advance(&callchain_cursor);
|
||||
callchain_cursor_advance(cursor);
|
||||
PyList_Append(pylist, pyelem);
|
||||
Py_DECREF(pyelem);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user