2017-04-17 21:23:08 +03:00
# include <inttypes.h>
2016-04-15 01:45:01 +03:00
# include <stdio.h>
# include <stdbool.h>
# include <traceevent/event-parse.h>
# include "evsel.h"
# include "callchain.h"
# include "map.h"
2017-04-18 16:57:25 +03:00
# include "strlist.h"
2016-04-15 01:45:01 +03:00
# include "symbol.h"
perf script: Add --inline option for debugging
The --inline option is to show inlined functions in callchains.
For example:
$ perf script
a.out 5644 11611.467597: 309961 cycles:u:
790 main (/home/namhyung/tmp/perf/a.out)
20511 __libc_start_main (/usr/lib/libc-2.25.so)
8ba _start (/home/namhyung/tmp/perf/a.out)
...
$ perf script --inline
a.out 5644 11611.467597: 309961 cycles:u:
790 main (/home/namhyung/tmp/perf/a.out)
std::__detail::_Adaptor<std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul>, double>::operator()
std::uniform_real_distribution<double>::operator()<std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul> >
std::uniform_real_distribution<double>::operator()<std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul> >
main
20511 __libc_start_main (/usr/lib/libc-2.25.so)
8ba _start (/home/namhyung/tmp/perf/a.out)
...
Reviewed-and-tested-by: Milian Wolff <milian.wolff@kdab.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Milian Wolff <milian.wolff@kdab.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kernel-team@lge.com
Link: http://lkml.kernel.org/r/20170524062129.32529-5-namhyung@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-05-24 09:21:26 +03:00
# include "srcline.h"
2016-04-15 01:45:01 +03:00
static int comma_fprintf ( FILE * fp , bool * first , const char * fmt , . . . )
{
va_list args ;
int ret = 0 ;
if ( ! * first ) {
ret + = fprintf ( fp , " , " ) ;
} else {
ret + = fprintf ( fp , " : " ) ;
* first = false ;
}
va_start ( args , fmt ) ;
ret + = vfprintf ( fp , fmt , args ) ;
va_end ( args ) ;
return ret ;
}
static int __print_attr__fprintf ( FILE * fp , const char * name , const char * val , void * priv )
{
return comma_fprintf ( fp , ( bool * ) priv , " %s: %s " , name , val ) ;
}
int perf_evsel__fprintf ( struct perf_evsel * evsel ,
struct perf_attr_details * details , FILE * fp )
{
bool first = true ;
int printed = 0 ;
if ( details - > event_group ) {
struct perf_evsel * pos ;
if ( ! perf_evsel__is_group_leader ( evsel ) )
return 0 ;
if ( evsel - > nr_members > 1 )
printed + = fprintf ( fp , " %s{ " , evsel - > group_name ? : " " ) ;
printed + = fprintf ( fp , " %s " , perf_evsel__name ( evsel ) ) ;
for_each_group_member ( pos , evsel )
printed + = fprintf ( fp , " ,%s " , perf_evsel__name ( pos ) ) ;
if ( evsel - > nr_members > 1 )
printed + = fprintf ( fp , " } " ) ;
goto out ;
}
printed + = fprintf ( fp , " %s " , perf_evsel__name ( evsel ) ) ;
if ( details - > verbose ) {
printed + = perf_event_attr__fprintf ( fp , & evsel - > attr ,
__print_attr__fprintf , & first ) ;
} else if ( details - > freq ) {
const char * term = " sample_freq " ;
if ( ! evsel - > attr . freq )
term = " sample_period " ;
printed + = comma_fprintf ( fp , & first , " %s=% " PRIu64 ,
term , ( u64 ) evsel - > attr . sample_freq ) ;
}
if ( details - > trace_fields ) {
struct format_field * field ;
if ( evsel - > attr . type ! = PERF_TYPE_TRACEPOINT ) {
printed + = comma_fprintf ( fp , & first , " (not a tracepoint) " ) ;
goto out ;
}
field = evsel - > tp_format - > format . fields ;
if ( field = = NULL ) {
printed + = comma_fprintf ( fp , & first , " (no trace field) " ) ;
goto out ;
}
printed + = comma_fprintf ( fp , & first , " trace_fields: %s " , field - > name ) ;
field = field - > next ;
while ( field ) {
printed + = comma_fprintf ( fp , & first , " %s " , field - > name ) ;
field = field - > next ;
}
}
out :
fputc ( ' \n ' , fp ) ;
return + + printed ;
}
int sample__fprintf_callchain ( struct perf_sample * sample , int left_alignment ,
unsigned int print_opts , struct callchain_cursor * cursor ,
FILE * fp )
{
int printed = 0 ;
struct callchain_cursor_node * node ;
int print_ip = print_opts & EVSEL__PRINT_IP ;
int print_sym = print_opts & EVSEL__PRINT_SYM ;
int print_dso = print_opts & EVSEL__PRINT_DSO ;
int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET ;
int print_oneline = print_opts & EVSEL__PRINT_ONELINE ;
int print_srcline = print_opts & EVSEL__PRINT_SRCLINE ;
int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR ;
2016-11-16 09:06:28 +03:00
int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW ;
2016-11-24 04:11:13 +03:00
int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED ;
2016-04-15 01:45:01 +03:00
char s = print_oneline ? ' ' : ' \t ' ;
2016-11-16 09:06:28 +03:00
bool first = true ;
2016-04-15 01:45:01 +03:00
if ( sample - > callchain ) {
struct addr_location node_al ;
callchain_cursor_commit ( cursor ) ;
while ( 1 ) {
u64 addr = 0 ;
node = callchain_cursor_current ( cursor ) ;
if ( ! node )
break ;
2016-11-24 04:11:13 +03:00
if ( node - > sym & & node - > sym - > ignore & & print_skip_ignored )
goto next ;
2016-04-15 01:45:01 +03:00
printed + = fprintf ( fp , " %-*.*s " , left_alignment , left_alignment , " " ) ;
2016-11-16 09:06:28 +03:00
if ( print_arrow & & ! first )
printed + = fprintf ( fp , " <- " ) ;
2016-04-15 01:45:01 +03:00
if ( print_ip )
printed + = fprintf ( fp , " %c%16 " PRIx64 , s , node - > ip ) ;
if ( node - > map )
addr = node - > map - > map_ip ( node - > map , node - > ip ) ;
if ( print_sym ) {
printed + = fprintf ( fp , " " ) ;
node_al . addr = addr ;
node_al . map = node - > map ;
if ( print_symoffset ) {
printed + = __symbol__fprintf_symname_offs ( node - > sym , & node_al ,
2016-11-16 09:06:27 +03:00
print_unknown_as_addr ,
true , fp ) ;
2016-04-15 01:45:01 +03:00
} else {
printed + = __symbol__fprintf_symname ( node - > sym , & node_al ,
print_unknown_as_addr , fp ) ;
}
}
if ( print_dso ) {
printed + = fprintf ( fp , " ( " ) ;
printed + = map__fprintf_dsoname ( node - > map , fp ) ;
printed + = fprintf ( fp , " ) " ) ;
}
if ( print_srcline )
printed + = map__fprintf_srcline ( node - > map , addr , " \n " , fp ) ;
if ( ! print_oneline )
printed + = fprintf ( fp , " \n " ) ;
2016-09-23 17:38:35 +03:00
perf script: Add --inline option for debugging
The --inline option is to show inlined functions in callchains.
For example:
$ perf script
a.out 5644 11611.467597: 309961 cycles:u:
790 main (/home/namhyung/tmp/perf/a.out)
20511 __libc_start_main (/usr/lib/libc-2.25.so)
8ba _start (/home/namhyung/tmp/perf/a.out)
...
$ perf script --inline
a.out 5644 11611.467597: 309961 cycles:u:
790 main (/home/namhyung/tmp/perf/a.out)
std::__detail::_Adaptor<std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul>, double>::operator()
std::uniform_real_distribution<double>::operator()<std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul> >
std::uniform_real_distribution<double>::operator()<std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul> >
main
20511 __libc_start_main (/usr/lib/libc-2.25.so)
8ba _start (/home/namhyung/tmp/perf/a.out)
...
Reviewed-and-tested-by: Milian Wolff <milian.wolff@kdab.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Milian Wolff <milian.wolff@kdab.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kernel-team@lge.com
Link: http://lkml.kernel.org/r/20170524062129.32529-5-namhyung@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-05-24 09:21:26 +03:00
if ( symbol_conf . inline_name & & node - > map ) {
struct inline_node * inode ;
addr = map__rip_2objdump ( node - > map , node - > ip ) ,
inode = dso__parse_addr_inlines ( node - > map - > dso , addr ) ;
if ( inode ) {
struct inline_list * ilist ;
list_for_each_entry ( ilist , & inode - > val , list ) {
if ( print_arrow )
printed + = fprintf ( fp , " <- " ) ;
/* IP is same, just skip it */
if ( print_ip )
printed + = fprintf ( fp , " %c%16s " ,
s , " " ) ;
if ( print_sym )
printed + = fprintf ( fp , " %s " ,
ilist - > funcname ) ;
if ( print_srcline )
printed + = fprintf ( fp , " \n %s:%d " ,
ilist - > filename ,
ilist - > line_nr ) ;
if ( ! print_oneline )
printed + = fprintf ( fp , " \n " ) ;
}
inline_node__delete ( inode ) ;
}
}
2016-11-25 23:00:21 +03:00
if ( symbol_conf . bt_stop_list & &
node - > sym & &
strlist__has_entry ( symbol_conf . bt_stop_list ,
node - > sym - > name ) ) {
break ;
}
2016-11-16 09:06:28 +03:00
first = false ;
2016-11-24 04:11:13 +03:00
next :
callchain_cursor_advance ( cursor ) ;
2016-04-15 01:45:01 +03:00
}
}
return printed ;
}
int sample__fprintf_sym ( struct perf_sample * sample , struct addr_location * al ,
int left_alignment , unsigned int print_opts ,
struct callchain_cursor * cursor , FILE * fp )
{
int printed = 0 ;
int print_ip = print_opts & EVSEL__PRINT_IP ;
int print_sym = print_opts & EVSEL__PRINT_SYM ;
int print_dso = print_opts & EVSEL__PRINT_DSO ;
int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET ;
int print_srcline = print_opts & EVSEL__PRINT_SRCLINE ;
int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR ;
if ( cursor ! = NULL ) {
printed + = sample__fprintf_callchain ( sample , left_alignment ,
print_opts , cursor , fp ) ;
2016-09-23 17:38:35 +03:00
} else {
2016-04-15 01:45:01 +03:00
printed + = fprintf ( fp , " %-*.*s " , left_alignment , left_alignment , " " ) ;
if ( print_ip )
printed + = fprintf ( fp , " %16 " PRIx64 , sample - > ip ) ;
if ( print_sym ) {
printed + = fprintf ( fp , " " ) ;
if ( print_symoffset ) {
printed + = __symbol__fprintf_symname_offs ( al - > sym , al ,
2016-11-16 09:06:27 +03:00
print_unknown_as_addr ,
true , fp ) ;
2016-04-15 01:45:01 +03:00
} else {
printed + = __symbol__fprintf_symname ( al - > sym , al ,
print_unknown_as_addr , fp ) ;
}
}
if ( print_dso ) {
printed + = fprintf ( fp , " ( " ) ;
printed + = map__fprintf_dsoname ( al - > map , fp ) ;
printed + = fprintf ( fp , " ) " ) ;
}
if ( print_srcline )
printed + = map__fprintf_srcline ( al - > map , al - > addr , " \n " , fp ) ;
}
return printed ;
}