Thread (6 messages) 6 messages, 2 authors, 2017-05-18

Re: [PATCH v2] perf report: fix off-by-one for non-activation frames

From: Namhyung Kim <namhyung@kernel.org>
Date: 2017-05-17 05:12:39
Also in: lkml

On Tue, May 16, 2017 at 06:26:47PM +0200, Milian Wolff wrote:
On Dienstag, 16. Mai 2017 18:17:26 CEST Milian Wolff wrote:
quoted
On Dienstag, 16. Mai 2017 16:38:29 CEST Namhyung Kim wrote:
quoted
On Tue, May 16, 2017 at 10:59:51AM +0200, Milian Wolff wrote:
quoted
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 <thread>
  #include <chrono>
  
  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;
  
  }

~~~~~~~~~~~~~~~
It'd be nice if the test program has a signal frame for verification.
I have pretty much zero experience about signals. Would it be enough to add
a signal handler for, say, SIGUSR1 to my test application and then trigger
a sleep when that signal is delivered? If that should be enough, I'll write
and test it out.
~~~~~~~~~~~~~~~
#include <thread>
#include <chrono>
#include <signal.h>

using namespace std;

volatile bool run_loop = true;

void my_handler(int signum)
{
    this_thread::sleep_for(chrono::milliseconds(1000));
    this_thread::sleep_for(chrono::milliseconds(100));
    this_thread::sleep_for(chrono::milliseconds(10));
    run_loop = false;
}

int main()
{
    signal(SIGUSR1, my_handler);

    while (run_loop) {}

    return 0;
}
~~~~~~~~~~~~~~~

This does not properly unwind neither before nor after this patch. I only ever 
get:

   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<long, std::ratio<1l, 1000l> > 
thread:323

So... should this work? Please tell me how to test this properly.
How did you send the SIGUSR1 to the process?

Anyway it does nothing to do with inlining, right?  I just wrote a
test code below to burn a cpu with or without a signal frame.

  $ nl -ba frame-addr.c
     1	#include <stdio.h>
     2	#include <stdlib.h>
     3	#include <signal.h>
     4	
     5	#define __noinline  __attribute__((noinline))
     6	
     7	__noinline void bar(void)
     8	{
     9	  volatile long cnt = 0;
    10	
    11	  for (cnt = 0; cnt < 100000000; cnt++);
    12	}
    13	
    14	__noinline void foo(void)
    15	{
    16	  bar();
    17	}
    18	
    19	void sig_handler(int sig)
    20	{
    21	  foo();
    22	}
    23	
    24	int main(void)
    25	{
    26	  signal(SIGUSR1, sig_handler);
    27	  raise(SIGUSR1);
    28	
    29	  foo();
    30	  return 0;
    31	}

  $ gcc -O2 -g -fno-optimize-sibling-calls -o frame-addr frame-addr.c

  $ perf record --call-graph dwarf ./frame-addr

  $ perf report -q -g srcline | head -15
      99.88%  frame-addr  frame-addr        [.] bar
              |
              ---bar frame-addr.c:11
                 foo frame-addr.c:16
                 |          
                 |--51.12%--main frame-addr.c:29
                 |          __libc_start_main
                 |          _start
                 |          
                  --48.76%--sig_handler frame-addr.c:21
                            0x33a8f
                            raise .:0
                            main frame-addr.c:29       <--- bad
                            __libc_start_main
                            _start

Note that 'raise' was called at line 27.  It seems that simply
checking current frame fixes it.

Thanks,
Namhyung
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help