Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp616134ybc; Tue, 19 Nov 2019 06:39:00 -0800 (PST) X-Google-Smtp-Source: APXvYqzksWl4gEzFCcBc663rR2M8ckSaI9OIDcJi66wvQR9ina9n0Ay2arIMDFCIgneSuOOyiOd7 X-Received: by 2002:a1c:a78b:: with SMTP id q133mr6036694wme.115.1574174340853; Tue, 19 Nov 2019 06:39:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1574174340; cv=none; d=google.com; s=arc-20160816; b=qZVgkvncEO4tYDmWXc6kaOiqyD9OgvuIa2FPBW/8uBudPicw9c1U3mDJi9aqendmNS +Daxb1xs2S+QFDXfTrEKUQehuMEKtG1CnJzHMOCiOe3Ext+3suXCfiiKTEaT6xk32iLJ KmGQLPMRFMgNDCYT7YwPJXthVuS3Z6ySatYvVL9tlNHbH0/ZEcMpbkYF4PZdE7fGWdU+ FvEN/QFHK4hFpbjYIjaa57uWCQiJahvypDr/hEOYprQBFquhum1lxUlMF9jdAI5+P98U jZxtxOEX7welTbSLYiOD0VkfdjA/wsTujjAPBEiJv+RS6c2r5cM97zQNDzl7aKGJUqXH qpGw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=XCGyZKyFcUe8g1tUIOAbIkl8B3k1M+m0k7AOgsgyzOw=; b=nZlyQNSJqK+PfRuAmjGLM4y6eqBQQal0gpjvnqoWeQuj3jRlc1Zmhahti041fBgPOG 7OVDoAjYFb94O4UrbTQ/plbBUN9+Ij6de24Patony4SWsbEKKkH5NSaLVWaIJk23BXnn T1aShFBsc79U3WqkUGs0/WhdmHi0bdKMb15O39STUGwVjUHVTta5LzQXqFZXsdkpSZ1/ EdGNuTGfdKVWJC3bBnOoms9MP4pdwoP2YkTvNoDFmVGLc/1lZaCA4gnwApEmeeegKwxl +a04mCeRIcR2k/cZbj+GMs9vSa3sq+tjUSzi5r99NkX2XOmK89pp/Dce+v1BlpGCeULZ +M/g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l10si15777093edk.212.2019.11.19.06.38.36; Tue, 19 Nov 2019 06:39:00 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728278AbfKSOfO (ORCPT + 99 others); Tue, 19 Nov 2019 09:35:14 -0500 Received: from mga04.intel.com ([192.55.52.120]:64767 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728270AbfKSOfN (ORCPT ); Tue, 19 Nov 2019 09:35:13 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Nov 2019 06:35:12 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.68,324,1569308400"; d="scan'208";a="215552400" Received: from labuser-ice-lake-client-platform.jf.intel.com ([10.54.55.50]) by fmsmga001.fm.intel.com with ESMTP; 19 Nov 2019 06:35:12 -0800 From: kan.liang@linux.intel.com To: peterz@infradead.org, acme@redhat.com, mingo@kernel.org, linux-kernel@vger.kernel.org Cc: jolsa@kernel.org, namhyung@kernel.org, vitaly.slobodskoy@intel.com, pavel.gerasimov@intel.com, ak@linux.intel.com, eranian@google.com, mpe@ellerman.id.au, Kan Liang Subject: [PATCH V4 07/13] perf machine: Refine the function for LBR call stack reconstruction Date: Tue, 19 Nov 2019 06:34:05 -0800 Message-Id: <20191119143411.3482-8-kan.liang@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191119143411.3482-1-kan.liang@linux.intel.com> References: <20191119143411.3482-1-kan.liang@linux.intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Kan Liang LBR only collect the user call stack. To reconstruct a call stack, both kernel call stack and user call stack are required. The function resolve_lbr_callchain_sample() mix the kernel call stack and user call stack. Now, with the help of TOS, perf tool can reconstruct a more complete call stack by adding some user call stack from previous sample. However, current implementation is hard to be extended to support it. Abstract two new functions to resolve user call stack and kernel call stack respectively. No functional changes. Reviewed-by: Andi Kleen Signed-off-by: Kan Liang --- tools/perf/util/machine.c | 186 ++++++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 67 deletions(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 6a0f5c25ce3e..1a2c3e26c01f 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2194,6 +2194,96 @@ static int remove_loops(struct branch_entry *l, int nr, return nr; } + +static int lbr_callchain_add_kernel_ip(struct thread *thread, + struct callchain_cursor *cursor, + struct perf_sample *sample, + struct symbol **parent, + struct addr_location *root_al, + bool callee, int end) +{ + struct ip_callchain *chain = sample->callchain; + u8 cpumode = PERF_RECORD_MISC_USER; + int err, i; + + if (callee) { + for (i = 0; i < end + 1; i++) { + err = add_callchain_ip(thread, cursor, parent, + root_al, &cpumode, chain->ips[i], + false, NULL, NULL, 0); + if (err) + return err; + } + } else { + for (i = end; i >= 0; i--) { + err = add_callchain_ip(thread, cursor, parent, + root_al, &cpumode, chain->ips[i], + false, NULL, NULL, 0); + if (err) + return err; + } + } + + return 0; +} + +static int lbr_callchain_add_lbr_ip(struct thread *thread, + struct callchain_cursor *cursor, + struct perf_sample *sample, + struct symbol **parent, + struct addr_location *root_al, + bool callee) +{ + struct branch_stack *lbr_stack = sample->branch_stack; + u8 cpumode = PERF_RECORD_MISC_USER; + int lbr_nr = lbr_stack->nr; + struct branch_flags *flags; + u64 ip, branch_from = 0; + int err, i; + + if (callee) { + ip = lbr_stack->entries[0].to; + flags = &lbr_stack->entries[0].flags; + branch_from = lbr_stack->entries[0].from; + err = add_callchain_ip(thread, cursor, parent, + root_al, &cpumode, ip, + true, flags, NULL, branch_from); + if (err) + return err; + + for (i = 0; i < lbr_nr; i++) { + ip = lbr_stack->entries[i].from; + flags = &lbr_stack->entries[i].flags; + err = add_callchain_ip(thread, cursor, parent, + root_al, &cpumode, ip, + true, flags, NULL, branch_from); + if (err) + return err; + } + } else { + for (i = lbr_nr - 1; i >= 0; i--) { + ip = lbr_stack->entries[i].from; + flags = &lbr_stack->entries[i].flags; + err = add_callchain_ip(thread, cursor, parent, + root_al, &cpumode, ip, + true, flags, NULL, branch_from); + if (err) + return err; + } + + ip = lbr_stack->entries[0].to; + flags = &lbr_stack->entries[0].flags; + branch_from = lbr_stack->entries[0].from; + err = add_callchain_ip(thread, cursor, parent, + root_al, &cpumode, ip, + true, flags, NULL, branch_from); + if (err) + return err; + } + + return 0; +} + /* * Recolve LBR callstack chain sample * Return: @@ -2209,82 +2299,44 @@ static int resolve_lbr_callchain_sample(struct thread *thread, int max_stack) { struct ip_callchain *chain = sample->callchain; - int chain_nr = min(max_stack, (int)chain->nr), i; - u8 cpumode = PERF_RECORD_MISC_USER; - u64 ip, branch_from = 0; + int chain_nr = min(max_stack, (int)chain->nr); + int i, err; for (i = 0; i < chain_nr; i++) { if (chain->ips[i] == PERF_CONTEXT_USER) break; } - /* LBR only affects the user callchain */ - if (i != chain_nr) { - struct branch_stack *lbr_stack = sample->branch_stack; - int lbr_nr = lbr_stack->nr, j, k; - bool branch; - struct branch_flags *flags; - /* - * LBR callstack can only get user call chain. - * The mix_chain_nr is kernel call chain - * number plus LBR user call chain number. - * i is kernel call chain number, - * 1 is PERF_CONTEXT_USER, - * lbr_nr + 1 is the user call chain number. - * For details, please refer to the comments - * in callchain__printf - */ - int mix_chain_nr = i + 1 + lbr_nr + 1; - - for (j = 0; j < mix_chain_nr; j++) { - int err; - branch = false; - flags = NULL; - - if (callchain_param.order == ORDER_CALLEE) { - if (j < i + 1) - ip = chain->ips[j]; - else if (j > i + 1) { - k = j - i - 2; - ip = lbr_stack->entries[k].from; - branch = true; - flags = &lbr_stack->entries[k].flags; - } else { - ip = lbr_stack->entries[0].to; - branch = true; - flags = &lbr_stack->entries[0].flags; - branch_from = - lbr_stack->entries[0].from; - } - } else { - if (j < lbr_nr) { - k = lbr_nr - j - 1; - ip = lbr_stack->entries[k].from; - branch = true; - flags = &lbr_stack->entries[k].flags; - } - else if (j > lbr_nr) - ip = chain->ips[i + 1 - (j - lbr_nr)]; - else { - ip = lbr_stack->entries[0].to; - branch = true; - flags = &lbr_stack->entries[0].flags; - branch_from = - lbr_stack->entries[0].from; - } - } + /* + * LBR only affects the user callchain. + * Fall back if there is no user callchain. + */ + if (i == chain_nr) + return 0; - err = add_callchain_ip(thread, cursor, parent, - root_al, &cpumode, ip, - branch, flags, NULL, - branch_from); - if (err) - return (err < 0) ? err : 0; - } - return 1; + if (callchain_param.order == ORDER_CALLEE) { + err = lbr_callchain_add_kernel_ip(thread, cursor, sample, + parent, root_al, true, i); + if (err) + goto error; + err = lbr_callchain_add_lbr_ip(thread, cursor, sample, + parent, root_al, true); + if (err) + goto error; + } else { + err = lbr_callchain_add_lbr_ip(thread, cursor, sample, + parent, root_al, false); + if (err) + goto error; + err = lbr_callchain_add_kernel_ip(thread, cursor, sample, + parent, root_al, false, i); + if (err) + goto error; } - return 0; + return 1; +error: + return (err < 0) ? err : 0; } static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, -- 2.17.1