Received: by 10.192.165.156 with SMTP id m28csp1122393imm; Wed, 11 Apr 2018 12:52:15 -0700 (PDT) X-Google-Smtp-Source: AIpwx49xxHo71u85v9mUnbggalmz3Bsqslz0/LmfPjMoaD0sfA5aXGKBxc8g2TUlWXYfzNDfTkP9 X-Received: by 10.99.122.70 with SMTP id j6mr4404269pgn.269.1523476335377; Wed, 11 Apr 2018 12:52:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523476335; cv=none; d=google.com; s=arc-20160816; b=sB/yuiVyROWfhMFkhEYV3/8B357hSdlWR5O7lmZtF+liKyRdkTo24JMGhO4lnn6n/D HzbXLX0OikqTlzqotSZsxibSQpX/lSeKaMvUbku1y9UJXFe25GoD94MbgIdQphkxp3dH OjfmvvsxjyyoApo23Qu/KUg79H/D6dMmKmRrZkfHDLCgl5tnOK34U//DhZ2iqEkDNKuz sd/4zdBKbV44aEe+8irZk/D5shEmdbrrSDGb6/3pCLxAgPOmaQQ/mKCDpreEYxKSnkqe xX4njXDUAMFbdJYDcLlBmt7U550rKqpwTt5o1vAOG//RCI1kXzVO1W2onBc0qwkFskbt RJCA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=97wsgHlIBlTmRd+HmzCCm7Elw0KTBWvDjm5fyFzl9Zw=; b=f2hcKaFEA8QGusLXwZrgxlfF4pk/92zyWPuALSInrrcXooEylMYLiy/v5go9VZF28Q FXHw9VP0odZFFxevUYhd3f0+ly3OHREdLBnIB+HtyC/FXOqOVdHz5UC5ZR9QOF1DoytD bEaBu+KKuoIJ40cyC50t/OI0SRUS+7PiGqzR53BkBdPZP/adAlbLsyoYvmjWeenhZ/fE IlyxFt3GTwVzW1f0iyMyxW17ushK8RWpY5MAJG7lbTFJKp0HQHxkiyRIbWpbp461HNy+ ded5Ev4kn0qDCMTPPiyK+Fyyq8yT8cQ45Dl07BR3HK6ao4jL/GeOof2SL3S5qn4DFmrW IjxQ== 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b10-v6si1635932plz.464.2018.04.11.12.51.38; Wed, 11 Apr 2018 12:52:15 -0700 (PDT) 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932285AbeDKTsf (ORCPT + 99 others); Wed, 11 Apr 2018 15:48:35 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:36956 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934048AbeDKS7I (ORCPT ); Wed, 11 Apr 2018 14:59:08 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 03F17E1E; Wed, 11 Apr 2018 18:59:08 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Milian Wolff , Namhyung Kim , Arnaldo Carvalho de Melo , Arnaldo Carvalho de Melo , David Ahern , Jiri Olsa , Jiri Olsa , Linus Torvalds , Peter Zijlstra , Peter Zijlstra , Thomas Gleixner , Yao Jin , kernel-team@lge.com, Ingo Molnar , Sasha Levin Subject: [PATCH 4.9 101/310] perf report: Fix off-by-one for non-activation frames Date: Wed, 11 Apr 2018 20:34:00 +0200 Message-Id: <20180411183626.574856488@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180411183622.305902791@linuxfoundation.org> References: <20180411183622.305902791@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Milian Wolff [ Upstream commit 1982ad48fc82c284a5cc55697a012d3357e84d01 ] As the documentation for dwfl_frame_pc says, frames that are no activation frames need to have their program counter decremented by one to properly find the function of the caller. This fixes many cases where perf report currently attributes the cost to the next line. I.e. I have code like this: ~~~~~~~~~~~~~~~ #include #include using namespace std; int main() { this_thread::sleep_for(chrono::milliseconds(1000)); this_thread::sleep_for(chrono::milliseconds(100)); this_thread::sleep_for(chrono::milliseconds(10)); return 0; } ~~~~~~~~~~~~~~~ Now compile and record it: ~~~~~~~~~~~~~~~ g++ -std=c++11 -g -O2 test.cpp echo 1 | sudo tee /proc/sys/kernel/sched_schedstats perf record \ --event sched:sched_stat_sleep \ --event sched:sched_process_exit \ --event sched:sched_switch --call-graph=dwarf \ --output perf.data.raw \ ./a.out echo 0 | sudo tee /proc/sys/kernel/sched_schedstats perf inject --sched-stat --input perf.data.raw --output perf.data ~~~~~~~~~~~~~~~ Before this patch, the report clearly shows the off-by-one issue. Most notably, the last sleep invocation is incorrectly attributed to the "return 0;" line: ~~~~~~~~~~~~~~~ Overhead Source:Line ........ ........... 100.00% core.c:0 | ---__schedule core.c:0 schedule do_nanosleep hrtimer.c:0 hrtimer_nanosleep sys_nanosleep entry_SYSCALL_64_fastpath .tmp_entry_64.o:0 __nanosleep_nocancel .:0 std::this_thread::sleep_for > thread:323 | |--90.08%--main test.cpp:9 | __libc_start_main | _start | |--9.01%--main test.cpp:10 | __libc_start_main | _start | --0.91%--main test.cpp:13 __libc_start_main _start ~~~~~~~~~~~~~~~ With this patch here applied, the issue is fixed. The report becomes much more usable: ~~~~~~~~~~~~~~~ Overhead Source:Line ........ ........... 100.00% core.c:0 | ---__schedule core.c:0 schedule do_nanosleep hrtimer.c:0 hrtimer_nanosleep sys_nanosleep entry_SYSCALL_64_fastpath .tmp_entry_64.o:0 __nanosleep_nocancel .:0 std::this_thread::sleep_for > thread:323 | |--90.08%--main test.cpp:8 | __libc_start_main | _start | |--9.01%--main test.cpp:9 | __libc_start_main | _start | --0.91%--main test.cpp:10 __libc_start_main _start ~~~~~~~~~~~~~~~ Similarly it works for signal frames: ~~~~~~~~~~~~~~~ __noinline void bar(void) { volatile long cnt = 0; for (cnt = 0; cnt < 100000000; cnt++); } __noinline void foo(void) { bar(); } void sig_handler(int sig) { foo(); } int main(void) { signal(SIGUSR1, sig_handler); raise(SIGUSR1); foo(); return 0; } ~~~~~~~~~~~~~~~~ Before, the report wrongly points to `signal.c:29` after raise(): ~~~~~~~~~~~~~~~~ $ perf report --stdio --no-children -g srcline -s srcline ... 100.00% signal.c:11 | ---bar signal.c:11 | |--50.49%--main signal.c:29 | __libc_start_main | _start | --49.51%--0x33a8f raise .:0 main signal.c:29 __libc_start_main _start ~~~~~~~~~~~~~~~~ With this patch in, the issue is fixed and we instead get: ~~~~~~~~~~~~~~~~ 100.00% signal signal [.] bar | ---bar signal.c:11 | |--50.49%--main signal.c:29 | __libc_start_main | _start | --49.51%--0x33a8f raise .:0 main signal.c:27 __libc_start_main _start ~~~~~~~~~~~~~~~~ Note how this patch fixes this issue for both unwinding methods, i.e. both dwfl and libunwind. The former case is straight-forward thanks to dwfl_frame_pc(). For libunwind, we replace the functionality via unw_is_signal_frame() for any but the very first frame. Signed-off-by: Milian Wolff Signed-off-by: Namhyung Kim Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yao Jin Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170524062129.32529-4-namhyung@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/unwind-libdw.c | 6 +++++- tools/perf/util/unwind-libunwind-local.c | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -167,12 +167,16 @@ frame_callback(Dwfl_Frame *state, void * { struct unwind_info *ui = arg; Dwarf_Addr pc; + bool isactivation; - if (!dwfl_frame_pc(state, &pc, NULL)) { + if (!dwfl_frame_pc(state, &pc, &isactivation)) { pr_err("%s", dwfl_errmsg(-1)); return DWARF_CB_ABORT; } + if (!isactivation) + --pc; + return entry(pc, ui) || !(--ui->max_stack) ? DWARF_CB_ABORT : DWARF_CB_OK; } --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -646,6 +646,17 @@ static int get_entries(struct unwind_inf while (!ret && (unw_step(&c) > 0) && i < max_stack) { unw_get_reg(&c, UNW_REG_IP, &ips[i]); + + /* + * Decrement the IP for any non-activation frames. + * this is required to properly find the srcline + * for caller frames. + * See also the documentation for dwfl_frame_pc(), + * which this code tries to replicate. + */ + if (unw_is_signal_frame(&c) <= 0) + --ips[i]; + ++i; }