2009-12-15 01:09:31 +03:00
/*
* builtin - diff . c
*
* Builtin diff command : Analyze two perf . data input files , look up and read
* DSOs and symbol information , sort them and produce a diff .
*/
# include "builtin.h"
# include "util/debug.h"
# include "util/event.h"
# include "util/hist.h"
2011-11-28 13:56:39 +04:00
# include "util/evsel.h"
2012-09-06 19:46:55 +04:00
# include "util/evlist.h"
2009-12-15 01:09:31 +03:00
# include "util/session.h"
2011-11-28 14:30:20 +04:00
# include "util/tool.h"
2009-12-15 01:09:31 +03:00
# include "util/sort.h"
# include "util/symbol.h"
# include "util/util.h"
# include <stdlib.h>
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-12-16 18:49:27 +03:00
static char const * input_old = " perf.data.old " ,
* input_new = " perf.data " ;
2009-12-16 19:09:53 +03:00
static char diff__default_sort_order [ ] = " dso,symbol " ;
2010-04-13 12:37:33 +04:00
static bool force ;
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-12-16 18:49:27 +03:00
static bool show_displacement ;
2012-10-05 18:44:40 +04:00
static bool show_baseline_only ;
2009-12-15 01:09:31 +03:00
2012-10-05 18:44:41 +04:00
enum {
COMPUTE_DELTA ,
COMPUTE_RATIO ,
COMPUTE_MAX ,
} ;
const char * compute_names [ COMPUTE_MAX ] = {
[ COMPUTE_DELTA ] = " delta " ,
[ COMPUTE_RATIO ] = " ratio " ,
} ;
static int compute ;
static int setup_compute ( const struct option * opt , const char * str ,
int unset __maybe_unused )
{
int * cp = ( int * ) opt - > value ;
unsigned i ;
if ( ! str ) {
* cp = COMPUTE_DELTA ;
return 0 ;
}
for ( i = 0 ; i < COMPUTE_MAX ; i + + )
if ( ! strcmp ( str , compute_names [ i ] ) ) {
* cp = i ;
return 0 ;
}
pr_err ( " Failed: '%s' is not computation method "
" (use 'delta' or 'ratio'). \n " , str ) ;
return - EINVAL ;
}
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
static int hists__add_entry ( struct hists * self ,
2010-05-14 21:19:35 +04:00
struct addr_location * al , u64 period )
2009-12-15 01:09:31 +03:00
{
2010-05-14 21:19:35 +04:00
if ( __hists__add_entry ( self , al , NULL , period ) ! = NULL )
2010-05-09 20:02:23 +04:00
return 0 ;
return - ENOMEM ;
2009-12-15 01:09:31 +03:00
}
2012-09-11 02:15:03 +04:00
static int diff__process_sample_event ( struct perf_tool * tool __maybe_unused ,
2011-11-25 14:19:45 +04:00
union perf_event * event ,
2011-01-29 18:02:00 +03:00
struct perf_sample * sample ,
2012-09-06 19:46:55 +04:00
struct perf_evsel * evsel ,
2011-11-28 13:56:39 +04:00
struct machine * machine )
2009-12-15 01:09:31 +03:00
{
struct addr_location al ;
2011-11-28 13:56:39 +04:00
if ( perf_event__preprocess_sample ( event , machine , & al , sample , NULL ) < 0 ) {
2009-12-15 01:09:31 +03:00
pr_warning ( " problem processing %d event, skipping it. \n " ,
event - > header . type ) ;
return - 1 ;
}
2009-12-29 03:48:35 +03:00
if ( al . filtered | | al . sym = = NULL )
2009-12-16 01:04:41 +03:00
return 0 ;
2012-09-06 19:46:55 +04:00
if ( hists__add_entry ( & evsel - > hists , & al , sample - > period ) ) {
2010-05-14 21:19:35 +04:00
pr_warning ( " problem incrementing symbol period, skipping event \n " ) ;
2009-12-15 01:09:31 +03:00
return - 1 ;
}
2012-09-06 19:46:55 +04:00
evsel - > hists . stats . total_period + = sample - > period ;
2009-12-15 01:09:31 +03:00
return 0 ;
}
2012-09-06 19:46:55 +04:00
static struct perf_tool tool = {
. sample = diff__process_sample_event ,
. mmap = perf_event__process_mmap ,
. comm = perf_event__process_comm ,
. exit = perf_event__process_task ,
. fork = perf_event__process_task ,
. lost = perf_event__process_lost ,
. ordered_samples = true ,
. ordering_requires_timestamps = true ,
2009-12-15 01:09:31 +03:00
} ;
2012-10-04 16:49:36 +04:00
static void insert_hist_entry_by_name ( struct rb_root * root ,
struct hist_entry * he )
2009-12-15 01:09:31 +03:00
{
struct rb_node * * p = & root - > rb_node ;
struct rb_node * parent = NULL ;
struct hist_entry * iter ;
while ( * p ! = NULL ) {
parent = * p ;
iter = rb_entry ( parent , struct hist_entry , rb_node ) ;
2009-12-29 03:48:36 +03:00
if ( hist_entry__cmp ( he , iter ) < 0 )
2009-12-15 01:09:31 +03:00
p = & ( * p ) - > rb_left ;
2009-12-29 03:48:36 +03:00
else
2009-12-15 01:09:31 +03:00
p = & ( * p ) - > rb_right ;
}
rb_link_node ( & he - > rb_node , parent , p ) ;
rb_insert_color ( & he - > rb_node , root ) ;
}
2012-10-04 16:49:36 +04:00
static void hists__name_resort ( struct hists * self , bool sort )
2009-12-15 01:09:31 +03:00
{
unsigned long position = 1 ;
struct rb_root tmp = RB_ROOT ;
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
struct rb_node * next = rb_first ( & self - > entries ) ;
2009-12-15 01:09:31 +03:00
while ( next ! = NULL ) {
struct hist_entry * n = rb_entry ( next , struct hist_entry , rb_node ) ;
next = rb_next ( & n - > rb_node ) ;
n - > position = position + + ;
2012-10-04 16:49:36 +04:00
if ( sort ) {
rb_erase ( & n - > rb_node , & self - > entries ) ;
insert_hist_entry_by_name ( & tmp , n ) ;
}
2009-12-15 01:09:31 +03:00
}
2012-10-04 16:49:36 +04:00
if ( sort )
self - > entries = tmp ;
2009-12-15 01:09:31 +03:00
}
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
static struct hist_entry * hists__find_entry ( struct hists * self ,
struct hist_entry * he )
2009-12-15 01:09:31 +03:00
{
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
struct rb_node * n = self - > entries . rb_node ;
2009-12-15 01:09:31 +03:00
while ( n ) {
struct hist_entry * iter = rb_entry ( n , struct hist_entry , rb_node ) ;
2009-12-29 03:48:36 +03:00
int64_t cmp = hist_entry__cmp ( he , iter ) ;
2009-12-15 01:09:31 +03:00
2009-12-29 03:48:36 +03:00
if ( cmp < 0 )
2009-12-15 01:09:31 +03:00
n = n - > rb_left ;
2009-12-29 03:48:36 +03:00
else if ( cmp > 0 )
2009-12-15 01:09:31 +03:00
n = n - > rb_right ;
2012-10-04 16:49:36 +04:00
else
2009-12-29 03:48:36 +03:00
return iter ;
2009-12-15 01:09:31 +03:00
}
return NULL ;
}
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
static void hists__match ( struct hists * older , struct hists * newer )
2009-12-15 01:09:31 +03:00
{
struct rb_node * nd ;
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
for ( nd = rb_first ( & newer - > entries ) ; nd ; nd = rb_next ( nd ) ) {
2009-12-15 01:09:31 +03:00
struct hist_entry * pos = rb_entry ( nd , struct hist_entry , rb_node ) ;
perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a
new "event_stat_id" struct and then made several perf_session methods
receive a point to it instead of a pointer to perf_session, and kept the
event_stats and hists rb_tree in perf_session.
While working on the new newt based browser, I realised that it would be
better to introduce a new class, "hists" (short for "histograms"),
renaming the "event_stat_id" struct and the perf_session methods that
were really "hists" methods, as they manipulate only struct hists
members, not touching anything in the other perf_session members.
Other optimizations, such as calculating the maximum lenght of a symbol
name present in an hists instance will be possible as we add them,
avoiding a re-traversal just for finding that information.
The rationale for the name "hists" to replace "event_stat_id" is that we
may have multiple sets of hists for the same event_stat id, as, for
instance, the 'perf diff' tool has, so event stat id is not what
characterizes what this struct and the functions that manipulate it do.
Cc: Eric B Munson <ebmunson@us.ibm.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-10 20:04:11 +04:00
pos - > pair = hists__find_entry ( older , pos ) ;
2009-12-15 01:09:31 +03:00
}
}
2012-09-06 19:46:55 +04:00
static struct perf_evsel * evsel_match ( struct perf_evsel * evsel ,
struct perf_evlist * evlist )
{
struct perf_evsel * e ;
list_for_each_entry ( e , & evlist - > entries , node )
if ( perf_evsel__match2 ( evsel , e ) )
return e ;
return NULL ;
}
2012-10-04 16:49:36 +04:00
static void perf_evlist__resort_hists ( struct perf_evlist * evlist , bool name )
{
struct perf_evsel * evsel ;
list_for_each_entry ( evsel , & evlist - > entries , node ) {
struct hists * hists = & evsel - > hists ;
hists__output_resort ( hists ) ;
/*
* The hists__name_resort only sets possition
* if name is false .
*/
if ( name | | ( ( ! name ) & & show_displacement ) )
hists__name_resort ( hists , name ) ;
}
}
2012-10-05 18:44:40 +04:00
static void hists__baseline_only ( struct hists * hists )
{
struct rb_node * next = rb_first ( & hists - > entries ) ;
while ( next ! = NULL ) {
struct hist_entry * he = rb_entry ( next , struct hist_entry , rb_node ) ;
next = rb_next ( & he - > rb_node ) ;
if ( ! he - > pair ) {
rb_erase ( & he - > rb_node , & hists - > entries ) ;
hist_entry__free ( he ) ;
}
}
}
static void hists__process ( struct hists * old , struct hists * new )
{
hists__match ( old , new ) ;
if ( show_baseline_only )
hists__baseline_only ( new ) ;
hists__fprintf ( new , true , 0 , 0 , stdout ) ;
}
2009-12-15 01:09:31 +03:00
static int __cmd_diff ( void )
{
int ret , i ;
2012-03-22 17:37:26 +04:00
# define older (session[0])
# define newer (session[1])
2009-12-15 01:09:31 +03:00
struct perf_session * session [ 2 ] ;
2012-09-06 19:46:55 +04:00
struct perf_evlist * evlist_new , * evlist_old ;
struct perf_evsel * evsel ;
bool first = true ;
2009-12-15 01:09:31 +03:00
2012-03-22 17:37:26 +04:00
older = perf_session__new ( input_old , O_RDONLY , force , false ,
2012-09-06 19:46:55 +04:00
& tool ) ;
2012-03-22 17:37:26 +04:00
newer = perf_session__new ( input_new , O_RDONLY , force , false ,
2012-09-06 19:46:55 +04:00
& tool ) ;
2009-12-15 01:09:31 +03:00
if ( session [ 0 ] = = NULL | | session [ 1 ] = = NULL )
return - ENOMEM ;
for ( i = 0 ; i < 2 ; + + i ) {
2012-09-06 19:46:55 +04:00
ret = perf_session__process_events ( session [ i ] , & tool ) ;
2009-12-15 01:09:31 +03:00
if ( ret )
goto out_delete ;
}
2012-09-06 19:46:55 +04:00
evlist_old = older - > evlist ;
evlist_new = newer - > evlist ;
2012-10-04 16:49:36 +04:00
perf_evlist__resort_hists ( evlist_old , true ) ;
perf_evlist__resort_hists ( evlist_new , false ) ;
2012-09-06 19:46:55 +04:00
list_for_each_entry ( evsel , & evlist_new - > entries , node ) {
struct perf_evsel * evsel_old ;
evsel_old = evsel_match ( evsel , evlist_old ) ;
if ( ! evsel_old )
continue ;
fprintf ( stdout , " %s# Event '%s' \n # \n " , first ? " " : " \n " ,
perf_evsel__name ( evsel ) ) ;
first = false ;
2012-10-05 18:44:40 +04:00
hists__process ( & evsel_old - > hists , & evsel - > hists ) ;
2012-09-06 19:46:55 +04:00
}
2009-12-29 03:48:36 +03:00
2009-12-15 01:09:31 +03:00
out_delete :
for ( i = 0 ; i < 2 ; + + i )
perf_session__delete ( session [ i ] ) ;
return ret ;
2012-03-22 17:37:26 +04:00
# undef older
# undef newer
2009-12-15 01:09:31 +03:00
}
2009-12-18 21:35:58 +03:00
static const char * const diff_usage [ ] = {
2009-12-15 01:09:31 +03:00
" perf diff [<options>] [old_file] [new_file] " ,
2009-12-18 21:35:58 +03:00
NULL ,
2009-12-15 01:09:31 +03:00
} ;
static const struct option options [ ] = {
2010-04-13 12:37:33 +04:00
OPT_INCR ( ' v ' , " verbose " , & verbose ,
2009-12-15 01:09:31 +03:00
" be more verbose (show symbol address, etc) " ) ,
2010-12-01 04:57:11 +03:00
OPT_BOOLEAN ( ' M ' , " displacement " , & show_displacement ,
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-12-16 18:49:27 +03:00
" Show position displacement relative to baseline " ) ,
2012-10-05 18:44:40 +04:00
OPT_BOOLEAN ( ' b ' , " baseline-only " , & show_baseline_only ,
" Show only items with match in baseline " ) ,
2012-10-05 18:44:41 +04:00
OPT_CALLBACK ( ' c ' , " compute " , & compute , " delta,ratio (default delta) " ,
" Entries differential computation selection " ,
setup_compute ) ,
2009-12-15 01:09:31 +03:00
OPT_BOOLEAN ( ' D ' , " dump-raw-trace " , & dump_trace ,
" dump raw trace in ASCII " ) ,
OPT_BOOLEAN ( ' f ' , " force " , & force , " don't complain, do it " ) ,
OPT_BOOLEAN ( ' m ' , " modules " , & symbol_conf . use_modules ,
" load module symbols - WARNING: use only with -k and LIVE kernel " ) ,
2009-12-16 01:04:41 +03:00
OPT_STRING ( ' d ' , " dsos " , & symbol_conf . dso_list_str , " dso[,dso...] " ,
" only consider symbols in these dsos " ) ,
OPT_STRING ( ' C ' , " comms " , & symbol_conf . comm_list_str , " comm[,comm...] " ,
" only consider symbols in these comms " ) ,
OPT_STRING ( ' S ' , " symbols " , & symbol_conf . sym_list_str , " symbol[,symbol...] " ,
" only consider these symbols " ) ,
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-12-16 18:49:27 +03:00
OPT_STRING ( ' s ' , " sort " , & sort_order , " key[,key2...] " ,
" sort by key(s): pid, comm, dso, symbol, parent " ) ,
OPT_STRING ( ' t ' , " field-separator " , & symbol_conf . field_sep , " separator " ,
" separator for columns, no spaces will be added between "
" columns '.' is reserved. " ) ,
2010-12-09 23:27:07 +03:00
OPT_STRING ( 0 , " symfs " , & symbol_conf . symfs , " directory " ,
" Look for files with symbols relative to this directory " ) ,
2009-12-15 01:09:31 +03:00
OPT_END ( )
} ;
2012-10-04 16:49:39 +04:00
static void ui_init ( void )
{
perf_hpp__init ( ) ;
/* No overhead column. */
perf_hpp__column_enable ( PERF_HPP__OVERHEAD , false ) ;
2012-10-05 18:44:41 +04:00
/* Display baseline/delta/ratio/displacement columns. */
2012-10-04 16:49:39 +04:00
perf_hpp__column_enable ( PERF_HPP__BASELINE , true ) ;
2012-10-05 18:44:41 +04:00
switch ( compute ) {
case COMPUTE_DELTA :
perf_hpp__column_enable ( PERF_HPP__DELTA , true ) ;
break ;
case COMPUTE_RATIO :
perf_hpp__column_enable ( PERF_HPP__RATIO , true ) ;
break ;
default :
BUG_ON ( 1 ) ;
} ;
2012-10-04 16:49:39 +04:00
if ( show_displacement )
perf_hpp__column_enable ( PERF_HPP__DISPL , true ) ;
}
2012-09-11 02:15:03 +04:00
int cmd_diff ( int argc , const char * * argv , const char * prefix __maybe_unused )
2009-12-15 01:09:31 +03:00
{
2009-12-16 19:09:53 +03:00
sort_order = diff__default_sort_order ;
2009-12-15 01:09:31 +03:00
argc = parse_options ( argc , argv , options , diff_usage , 0 ) ;
if ( argc ) {
if ( argc > 2 )
usage_with_options ( diff_usage , options ) ;
if ( argc = = 2 ) {
input_old = argv [ 0 ] ;
input_new = argv [ 1 ] ;
} else
input_new = argv [ 0 ] ;
2010-04-19 09:32:50 +04:00
} else if ( symbol_conf . default_guest_vmlinux_name | |
symbol_conf . default_guest_kallsyms ) {
input_old = " perf.data.host " ;
input_new = " perf.data.guest " ;
2009-12-15 01:09:31 +03:00
}
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-12-16 18:49:27 +03:00
symbol_conf . exclude_other = false ;
2009-12-16 01:04:40 +03:00
if ( symbol__init ( ) < 0 )
return - 1 ;
2012-10-04 16:49:39 +04:00
ui_init ( ) ;
2009-12-16 01:04:40 +03:00
setup_sorting ( diff_usage , options ) ;
2009-12-15 01:09:31 +03:00
setup_pager ( ) ;
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-12-16 18:49:27 +03:00
sort_entry__setup_elide ( & sort_dso , symbol_conf . dso_list , " dso " , NULL ) ;
sort_entry__setup_elide ( & sort_comm , symbol_conf . comm_list , " comm " , NULL ) ;
sort_entry__setup_elide ( & sort_sym , symbol_conf . sym_list , " symbol " , NULL ) ;
2009-12-15 01:09:31 +03:00
return __cmd_diff ( ) ;
}