2009-05-26 11:17:18 +04:00
# include "util/util.h"
# include <libelf.h>
2009-05-18 21:28:47 +04:00
# include <gelf.h>
# include <elf.h>
2009-05-26 11:17:18 +04:00
2009-05-18 23:24:49 +04:00
# include "util/list.h"
# include "util/rbtree.h"
2009-05-18 19:45:42 +04:00
2009-05-26 11:17:18 +04:00
# include "perf.h"
# include "util/parse-options.h"
# include "util/parse-events.h"
2009-05-18 19:45:42 +04:00
# define SHOW_KERNEL 1
# define SHOW_USER 2
# define SHOW_HV 4
2009-05-26 11:17:18 +04:00
static char const * input_name = " output.perf " ;
2009-05-18 19:45:42 +04:00
static int input ;
static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV ;
2009-05-26 20:48:58 +04:00
static int dump_trace = 0 ;
2009-05-18 19:45:42 +04:00
static unsigned long page_size ;
static unsigned long mmap_window = 32 ;
2009-05-26 11:17:18 +04:00
const char * perf_event_names [ ] = {
2009-05-18 19:45:42 +04:00
[ PERF_EVENT_MMAP ] = " PERF_EVENT_MMAP " ,
[ PERF_EVENT_MUNMAP ] = " PERF_EVENT_MUNMAP " ,
[ PERF_EVENT_COMM ] = " PERF_EVENT_COMM " ,
} ;
struct ip_event {
struct perf_event_header header ;
__u64 ip ;
__u32 pid , tid ;
} ;
struct mmap_event {
struct perf_event_header header ;
__u32 pid , tid ;
__u64 start ;
__u64 len ;
__u64 pgoff ;
char filename [ PATH_MAX ] ;
} ;
struct comm_event {
struct perf_event_header header ;
__u32 pid , tid ;
char comm [ 16 ] ;
} ;
typedef union event_union {
struct perf_event_header header ;
struct ip_event ip ;
struct mmap_event mmap ;
struct comm_event comm ;
} event_t ;
struct symbol {
2009-05-18 23:24:49 +04:00
struct rb_node rb_node ;
uint64_t start ;
uint64_t end ;
char name [ 0 ] ;
2009-05-18 19:45:42 +04:00
} ;
static struct symbol * symbol__new ( uint64_t start , uint64_t len , const char * name )
{
struct symbol * self = malloc ( sizeof ( * self ) + strlen ( name ) + 1 ) ;
if ( self ! = NULL ) {
self - > start = start ;
self - > end = start + len ;
strcpy ( self - > name , name ) ;
}
return self ;
}
static void symbol__delete ( struct symbol * self )
{
free ( self ) ;
}
static size_t symbol__fprintf ( struct symbol * self , FILE * fp )
{
return fprintf ( fp , " %lx-%lx %s \n " ,
self - > start , self - > end , self - > name ) ;
}
struct dso {
struct list_head node ;
2009-05-18 23:24:49 +04:00
struct rb_root syms ;
2009-05-18 19:45:42 +04:00
char name [ 0 ] ;
} ;
static struct dso * dso__new ( const char * name )
{
struct dso * self = malloc ( sizeof ( * self ) + strlen ( name ) + 1 ) ;
if ( self ! = NULL ) {
strcpy ( self - > name , name ) ;
2009-05-18 23:24:49 +04:00
self - > syms = RB_ROOT ;
2009-05-18 19:45:42 +04:00
}
return self ;
}
static void dso__delete_symbols ( struct dso * self )
{
2009-05-18 23:24:49 +04:00
struct symbol * pos ;
struct rb_node * next = rb_first ( & self - > syms ) ;
2009-05-18 19:45:42 +04:00
2009-05-18 23:24:49 +04:00
while ( next ) {
pos = rb_entry ( next , struct symbol , rb_node ) ;
next = rb_next ( & pos - > rb_node ) ;
2009-05-18 19:45:42 +04:00
symbol__delete ( pos ) ;
2009-05-18 23:24:49 +04:00
}
2009-05-18 19:45:42 +04:00
}
static void dso__delete ( struct dso * self )
{
dso__delete_symbols ( self ) ;
free ( self ) ;
}
static void dso__insert_symbol ( struct dso * self , struct symbol * sym )
{
2009-05-18 23:24:49 +04:00
struct rb_node * * p = & self - > syms . rb_node ;
struct rb_node * parent = NULL ;
const uint64_t ip = sym - > start ;
struct symbol * s ;
while ( * p ! = NULL ) {
parent = * p ;
s = rb_entry ( parent , struct symbol , rb_node ) ;
if ( ip < s - > start )
p = & ( * p ) - > rb_left ;
else
p = & ( * p ) - > rb_right ;
}
rb_link_node ( & sym - > rb_node , parent , p ) ;
rb_insert_color ( & sym - > rb_node , & self - > syms ) ;
2009-05-18 19:45:42 +04:00
}
static struct symbol * dso__find_symbol ( struct dso * self , uint64_t ip )
{
if ( self = = NULL )
return NULL ;
2009-05-18 23:24:49 +04:00
struct rb_node * n = self - > syms . rb_node ;
2009-05-18 19:45:42 +04:00
2009-05-18 23:24:49 +04:00
while ( n ) {
struct symbol * s = rb_entry ( n , struct symbol , rb_node ) ;
if ( ip < s - > start )
n = n - > rb_left ;
else if ( ip > s - > end )
n = n - > rb_right ;
else
return s ;
}
2009-05-18 19:45:42 +04:00
return NULL ;
}
2009-05-18 21:28:47 +04:00
/**
* elf_symtab__for_each_symbol - iterate thru all the symbols
*
* @ self : struct elf_symtab instance to iterate
* @ index : uint32_t index
* @ sym : GElf_Sym iterator
*/
# define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
for ( index = 0 , gelf_getsym ( syms , index , & sym ) ; \
index < nr_syms ; \
index + + , gelf_getsym ( syms , index , & sym ) )
static inline uint8_t elf_sym__type ( const GElf_Sym * sym )
{
return GELF_ST_TYPE ( sym - > st_info ) ;
}
2009-05-26 11:17:18 +04:00
static inline int elf_sym__is_function ( const GElf_Sym * sym )
2009-05-18 21:28:47 +04:00
{
return elf_sym__type ( sym ) = = STT_FUNC & &
sym - > st_name ! = 0 & &
sym - > st_shndx ! = SHN_UNDEF ;
}
static inline const char * elf_sym__name ( const GElf_Sym * sym ,
const Elf_Data * symstrs )
{
return symstrs - > d_buf + sym - > st_name ;
}
static Elf_Scn * elf_section_by_name ( Elf * elf , GElf_Ehdr * ep ,
GElf_Shdr * shp , const char * name ,
size_t * index )
{
Elf_Scn * sec = NULL ;
size_t cnt = 1 ;
while ( ( sec = elf_nextscn ( elf , sec ) ) ! = NULL ) {
char * str ;
gelf_getshdr ( sec , shp ) ;
str = elf_strptr ( elf , ep - > e_shstrndx , shp - > sh_name ) ;
if ( ! strcmp ( name , str ) ) {
if ( index )
* index = cnt ;
break ;
}
+ + cnt ;
}
return sec ;
}
2009-05-18 19:45:42 +04:00
static int dso__load ( struct dso * self )
{
2009-05-18 21:28:47 +04:00
int fd = open ( self - > name , O_RDONLY ) , err = - 1 ;
if ( fd = = - 1 )
return - 1 ;
Elf * elf = elf_begin ( fd , ELF_C_READ_MMAP , NULL ) ;
if ( elf = = NULL ) {
fprintf ( stderr , " %s: cannot read %s ELF file. \n " ,
__func__ , self - > name ) ;
goto out_close ;
}
GElf_Ehdr ehdr ;
if ( gelf_getehdr ( elf , & ehdr ) = = NULL ) {
fprintf ( stderr , " %s: cannot get elf header. \n " , __func__ ) ;
goto out_elf_end ;
}
GElf_Shdr shdr ;
Elf_Scn * sec = elf_section_by_name ( elf , & ehdr , & shdr , " .symtab " , NULL ) ;
if ( sec = = NULL )
sec = elf_section_by_name ( elf , & ehdr , & shdr , " .dynsym " , NULL ) ;
if ( sec = = NULL )
goto out_elf_end ;
Elf_Data * syms = elf_getdata ( sec , NULL ) ;
if ( syms = = NULL )
goto out_elf_end ;
sec = elf_getscn ( elf , shdr . sh_link ) ;
if ( sec = = NULL )
goto out_elf_end ;
Elf_Data * symstrs = elf_getdata ( sec , NULL ) ;
if ( symstrs = = NULL )
goto out_elf_end ;
const uint32_t nr_syms = shdr . sh_size / shdr . sh_entsize ;
GElf_Sym sym ;
uint32_t index ;
elf_symtab__for_each_symbol ( syms , nr_syms , index , sym ) {
2009-05-26 17:30:22 +04:00
struct symbol * f ;
2009-05-18 21:28:47 +04:00
if ( ! elf_sym__is_function ( & sym ) )
continue ;
2009-05-26 17:30:22 +04:00
sec = elf_getscn ( elf , sym . st_shndx ) ;
if ( ! sec )
goto out_elf_end ;
gelf_getshdr ( sec , & shdr ) ;
sym . st_value - = shdr . sh_addr - shdr . sh_offset ;
f = symbol__new ( sym . st_value , sym . st_size ,
elf_sym__name ( & sym , symstrs ) ) ;
if ( ! f )
2009-05-18 21:28:47 +04:00
goto out_elf_end ;
dso__insert_symbol ( self , f ) ;
}
err = 0 ;
out_elf_end :
elf_end ( elf ) ;
out_close :
close ( fd ) ;
return err ;
2009-05-18 19:45:42 +04:00
}
static size_t dso__fprintf ( struct dso * self , FILE * fp )
{
size_t ret = fprintf ( fp , " dso: %s \n " , self - > name ) ;
2009-05-18 23:24:49 +04:00
struct rb_node * nd ;
for ( nd = rb_first ( & self - > syms ) ; nd ; nd = rb_next ( nd ) ) {
struct symbol * pos = rb_entry ( nd , struct symbol , rb_node ) ;
2009-05-18 19:45:42 +04:00
ret + = symbol__fprintf ( pos , fp ) ;
2009-05-18 23:24:49 +04:00
}
2009-05-18 19:45:42 +04:00
return ret ;
}
static LIST_HEAD ( dsos ) ;
static struct dso * kernel_dso ;
static void dsos__add ( struct dso * dso )
{
list_add_tail ( & dso - > node , & dsos ) ;
}
static struct dso * dsos__find ( const char * name )
{
struct dso * pos ;
list_for_each_entry ( pos , & dsos , node )
if ( strcmp ( pos - > name , name ) = = 0 )
return pos ;
return NULL ;
}
static struct dso * dsos__findnew ( const char * name )
{
struct dso * dso = dsos__find ( name ) ;
if ( dso = = NULL ) {
dso = dso__new ( name ) ;
if ( dso ! = NULL & & dso__load ( dso ) < 0 )
goto out_delete_dso ;
dsos__add ( dso ) ;
}
return dso ;
out_delete_dso :
dso__delete ( dso ) ;
return NULL ;
}
2009-05-26 11:17:18 +04:00
void dsos__fprintf ( FILE * fp )
2009-05-18 19:45:42 +04:00
{
struct dso * pos ;
list_for_each_entry ( pos , & dsos , node )
dso__fprintf ( pos , fp ) ;
}
static int load_kallsyms ( void )
{
kernel_dso = dso__new ( " [kernel] " ) ;
if ( kernel_dso = = NULL )
return - 1 ;
FILE * file = fopen ( " /proc/kallsyms " , " r " ) ;
if ( file = = NULL )
goto out_delete_dso ;
char * line = NULL ;
size_t n ;
while ( ! feof ( file ) ) {
unsigned long long start ;
2009-05-26 19:21:34 +04:00
char c , symbf [ 4096 ] ;
2009-05-18 19:45:42 +04:00
if ( getline ( & line , & n , file ) < 0 )
break ;
if ( ! line )
goto out_delete_dso ;
if ( sscanf ( line , " %llx %c %s " , & start , & c , symbf ) = = 3 ) {
2009-05-26 19:21:34 +04:00
/*
* Well fix up the end later , when we have all sorted .
*/
struct symbol * sym = symbol__new ( start , 0xdead , symbf ) ;
if ( sym = = NULL )
goto out_delete_dso ;
dso__insert_symbol ( kernel_dso , sym ) ;
2009-05-18 19:45:42 +04:00
}
}
2009-05-26 19:21:34 +04:00
/*
* Now that we have all sorted out , just set the - > end of all
* symbols
*/
struct rb_node * nd , * prevnd = rb_first ( & kernel_dso - > syms ) ;
if ( prevnd = = NULL )
goto out_delete_line ;
for ( nd = rb_next ( prevnd ) ; nd ; nd = rb_next ( nd ) ) {
struct symbol * prev = rb_entry ( prevnd , struct symbol , rb_node ) ,
* curr = rb_entry ( nd , struct symbol , rb_node ) ;
prev - > end = curr - > start - 1 ;
prevnd = nd ;
}
2009-05-18 19:45:42 +04:00
dsos__add ( kernel_dso ) ;
free ( line ) ;
fclose ( file ) ;
return 0 ;
2009-05-26 18:14:27 +04:00
out_delete_line :
free ( line ) ;
2009-05-18 19:45:42 +04:00
out_delete_dso :
dso__delete ( kernel_dso ) ;
return - 1 ;
}
struct map {
struct list_head node ;
uint64_t start ;
uint64_t end ;
uint64_t pgoff ;
struct dso * dso ;
} ;
static struct map * map__new ( struct mmap_event * event )
{
struct map * self = malloc ( sizeof ( * self ) ) ;
if ( self ! = NULL ) {
self - > start = event - > start ;
self - > end = event - > start + event - > len ;
self - > pgoff = event - > pgoff ;
self - > dso = dsos__findnew ( event - > filename ) ;
if ( self - > dso = = NULL )
goto out_delete ;
}
return self ;
out_delete :
free ( self ) ;
return NULL ;
}
static size_t map__fprintf ( struct map * self , FILE * fp )
{
return fprintf ( fp , " %lx-%lx %lx %s \n " ,
self - > start , self - > end , self - > pgoff , self - > dso - > name ) ;
}
struct symhist {
2009-05-19 16:30:23 +04:00
struct rb_node rb_node ;
2009-05-18 19:45:42 +04:00
struct dso * dso ;
struct symbol * sym ;
2009-05-19 16:30:23 +04:00
uint64_t ip ;
2009-05-18 19:45:42 +04:00
uint32_t count ;
char level ;
} ;
2009-05-19 16:30:23 +04:00
static struct symhist * symhist__new ( struct symbol * sym , uint64_t ip ,
struct dso * dso , char level )
2009-05-18 19:45:42 +04:00
{
struct symhist * self = malloc ( sizeof ( * self ) ) ;
if ( self ! = NULL ) {
self - > sym = sym ;
2009-05-19 16:30:23 +04:00
self - > ip = ip ;
2009-05-18 19:45:42 +04:00
self - > dso = dso ;
self - > level = level ;
2009-05-19 16:30:23 +04:00
self - > count = 1 ;
2009-05-18 19:45:42 +04:00
}
return self ;
}
2009-05-26 11:17:18 +04:00
void symhist__delete ( struct symhist * self )
2009-05-18 19:45:42 +04:00
{
free ( self ) ;
}
static void symhist__inc ( struct symhist * self )
{
+ + self - > count ;
}
static size_t symhist__fprintf ( struct symhist * self , FILE * fp )
{
2009-05-19 16:30:23 +04:00
size_t ret = fprintf ( fp , " %#llx [%c] " , ( unsigned long long ) self - > ip , self - > level ) ;
2009-05-18 19:45:42 +04:00
if ( self - > level ! = ' . ' )
2009-05-22 17:34:54 +04:00
ret + = fprintf ( fp , " %s " , self - > sym ? self - > sym - > name : " <unknown> " ) ;
2009-05-18 19:45:42 +04:00
else
ret + = fprintf ( fp , " %s: %s " ,
2009-05-26 17:30:22 +04:00
self - > dso ? self - > dso - > name : " <unknown> " ,
2009-05-18 19:45:42 +04:00
self - > sym ? self - > sym - > name : " <unknown> " ) ;
return ret + fprintf ( fp , " : %u \n " , self - > count ) ;
}
struct thread {
2009-05-19 16:30:23 +04:00
struct rb_node rb_node ;
2009-05-18 19:45:42 +04:00
struct list_head maps ;
2009-05-19 16:30:23 +04:00
struct rb_root symhists ;
2009-05-18 19:45:42 +04:00
pid_t pid ;
char * comm ;
} ;
static struct thread * thread__new ( pid_t pid )
{
struct thread * self = malloc ( sizeof ( * self ) ) ;
if ( self ! = NULL ) {
self - > pid = pid ;
self - > comm = NULL ;
INIT_LIST_HEAD ( & self - > maps ) ;
2009-05-19 16:30:23 +04:00
self - > symhists = RB_ROOT ;
2009-05-18 19:45:42 +04:00
}
return self ;
}
2009-05-19 16:30:23 +04:00
static int thread__symbol_incnew ( struct thread * self , struct symbol * sym ,
uint64_t ip , struct dso * dso , char level )
2009-05-18 19:45:42 +04:00
{
2009-05-19 16:30:23 +04:00
struct rb_node * * p = & self - > symhists . rb_node ;
struct rb_node * parent = NULL ;
struct symhist * sh ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
while ( * p ! = NULL ) {
parent = * p ;
sh = rb_entry ( parent , struct symhist , rb_node ) ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
if ( sh - > sym = = sym | | ip = = sh - > ip ) {
symhist__inc ( sh ) ;
return 0 ;
}
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
/* Handle unresolved symbols too */
const uint64_t start = ! sh - > sym ? sh - > ip : sh - > sym - > start ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
if ( ip < start )
p = & ( * p ) - > rb_left ;
else
p = & ( * p ) - > rb_right ;
2009-05-18 19:45:42 +04:00
}
2009-05-19 16:30:23 +04:00
sh = symhist__new ( sym , ip , dso , level ) ;
if ( sh = = NULL )
return - ENOMEM ;
rb_link_node ( & sh - > rb_node , parent , p ) ;
rb_insert_color ( & sh - > rb_node , & self - > symhists ) ;
2009-05-18 19:45:42 +04:00
return 0 ;
}
static int thread__set_comm ( struct thread * self , const char * comm )
{
self - > comm = strdup ( comm ) ;
return self - > comm ? 0 : - ENOMEM ;
}
2009-05-26 11:17:18 +04:00
size_t thread__maps_fprintf ( struct thread * self , FILE * fp )
2009-05-18 19:45:42 +04:00
{
struct map * pos ;
size_t ret = 0 ;
list_for_each_entry ( pos , & self - > maps , node )
ret + = map__fprintf ( pos , fp ) ;
return ret ;
}
static size_t thread__fprintf ( struct thread * self , FILE * fp )
{
int ret = fprintf ( fp , " thread: %d %s \n " , self - > pid , self - > comm ) ;
2009-05-19 16:30:23 +04:00
struct rb_node * nd ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
for ( nd = rb_first ( & self - > symhists ) ; nd ; nd = rb_next ( nd ) ) {
struct symhist * pos = rb_entry ( nd , struct symhist , rb_node ) ;
2009-05-18 19:45:42 +04:00
ret + = symhist__fprintf ( pos , fp ) ;
2009-05-19 16:30:23 +04:00
}
2009-05-18 19:45:42 +04:00
return ret ;
}
2009-05-19 16:30:23 +04:00
static struct rb_root threads = RB_ROOT ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
static struct thread * threads__findnew ( pid_t pid )
2009-05-18 19:45:42 +04:00
{
2009-05-19 16:30:23 +04:00
struct rb_node * * p = & threads . rb_node ;
struct rb_node * parent = NULL ;
struct thread * th ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
while ( * p ! = NULL ) {
parent = * p ;
th = rb_entry ( parent , struct thread , rb_node ) ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
if ( th - > pid = = pid )
return th ;
2009-05-18 19:45:42 +04:00
2009-05-19 16:30:23 +04:00
if ( pid < th - > pid )
p = & ( * p ) - > rb_left ;
else
p = & ( * p ) - > rb_right ;
2009-05-18 19:45:42 +04:00
}
2009-05-19 16:30:23 +04:00
th = thread__new ( pid ) ;
if ( th ! = NULL ) {
rb_link_node ( & th - > rb_node , parent , p ) ;
rb_insert_color ( & th - > rb_node , & threads ) ;
}
return th ;
2009-05-18 19:45:42 +04:00
}
static void thread__insert_map ( struct thread * self , struct map * map )
{
list_add_tail ( & map - > node , & self - > maps ) ;
}
static struct map * thread__find_map ( struct thread * self , uint64_t ip )
{
if ( self = = NULL )
return NULL ;
struct map * pos ;
list_for_each_entry ( pos , & self - > maps , node )
if ( ip > = pos - > start & & ip < = pos - > end )
return pos ;
return NULL ;
}
static void threads__fprintf ( FILE * fp )
{
2009-05-19 16:30:23 +04:00
struct rb_node * nd ;
for ( nd = rb_first ( & threads ) ; nd ; nd = rb_next ( nd ) ) {
struct thread * pos = rb_entry ( nd , struct thread , rb_node ) ;
2009-05-18 19:45:42 +04:00
thread__fprintf ( pos , fp ) ;
2009-05-19 16:30:23 +04:00
}
2009-05-18 19:45:42 +04:00
}
2009-05-26 11:17:18 +04:00
static int __cmd_report ( void )
2009-05-18 19:45:42 +04:00
{
unsigned long offset = 0 ;
unsigned long head = 0 ;
struct stat stat ;
char * buf ;
event_t * event ;
int ret , rc = EXIT_FAILURE ;
2009-05-26 22:51:47 +04:00
uint32_t size ;
2009-05-26 21:03:36 +04:00
unsigned long total = 0 , total_mmap = 0 , total_comm = 0 , total_unknown = 0 ;
2009-05-18 19:45:42 +04:00
input = open ( input_name , O_RDONLY ) ;
if ( input < 0 ) {
perror ( " failed to open file " ) ;
exit ( - 1 ) ;
}
ret = fstat ( input , & stat ) ;
if ( ret < 0 ) {
perror ( " failed to stat file " ) ;
exit ( - 1 ) ;
}
if ( ! stat . st_size ) {
fprintf ( stderr , " zero-sized file, nothing to do! \n " ) ;
exit ( 0 ) ;
}
if ( load_kallsyms ( ) < 0 ) {
perror ( " failed to open kallsyms " ) ;
return EXIT_FAILURE ;
}
remap :
buf = ( char * ) mmap ( NULL , page_size * mmap_window , PROT_READ ,
MAP_SHARED , input , offset ) ;
if ( buf = = MAP_FAILED ) {
perror ( " failed to mmap file " ) ;
exit ( - 1 ) ;
}
more :
event = ( event_t * ) ( buf + head ) ;
2009-05-26 22:51:47 +04:00
size = event - > header . size ;
if ( ! size )
size = 8 ;
2009-05-18 19:45:42 +04:00
if ( head + event - > header . size > = page_size * mmap_window ) {
unsigned long shift = page_size * ( head / page_size ) ;
int ret ;
ret = munmap ( buf , page_size * mmap_window ) ;
assert ( ret = = 0 ) ;
offset + = shift ;
head - = shift ;
goto remap ;
}
2009-05-26 22:51:47 +04:00
size = event - > header . size ;
if ( ! size )
goto broken_event ;
2009-05-18 19:45:42 +04:00
if ( event - > header . misc & PERF_EVENT_MISC_OVERFLOW ) {
char level ;
int show = 0 ;
struct dso * dso = NULL ;
struct thread * thread = threads__findnew ( event - > ip . pid ) ;
2009-05-26 17:30:22 +04:00
uint64_t ip = event - > ip . ip ;
2009-05-18 19:45:42 +04:00
2009-05-26 20:48:58 +04:00
if ( dump_trace ) {
2009-05-26 21:03:36 +04:00
fprintf ( stderr , " %p [%p]: PERF_EVENT (IP, %d): %d: %p \n " ,
( void * ) ( offset + head ) ,
( void * ) ( long ) ( event - > header . size ) ,
2009-05-26 20:48:58 +04:00
event - > header . misc ,
event - > ip . pid ,
( void * ) event - > ip . ip ) ;
}
2009-05-19 16:30:23 +04:00
if ( thread = = NULL ) {
fprintf ( stderr , " problem processing %d event, bailing out \n " ,
event - > header . type ) ;
2009-05-18 19:45:42 +04:00
goto done ;
2009-05-19 16:30:23 +04:00
}
2009-05-18 19:45:42 +04:00
if ( event - > header . misc & PERF_EVENT_MISC_KERNEL ) {
show = SHOW_KERNEL ;
level = ' k ' ;
dso = kernel_dso ;
} else if ( event - > header . misc & PERF_EVENT_MISC_USER ) {
show = SHOW_USER ;
level = ' . ' ;
2009-05-26 17:30:22 +04:00
struct map * map = thread__find_map ( thread , ip ) ;
if ( map ! = NULL ) {
2009-05-18 19:45:42 +04:00
dso = map - > dso ;
2009-05-26 17:30:22 +04:00
ip - = map - > start + map - > pgoff ;
}
2009-05-18 19:45:42 +04:00
} else {
show = SHOW_HV ;
level = ' H ' ;
}
if ( show & show_mask ) {
2009-05-26 17:30:22 +04:00
struct symbol * sym = dso__find_symbol ( dso , ip ) ;
2009-05-18 19:45:42 +04:00
2009-05-26 17:30:22 +04:00
if ( thread__symbol_incnew ( thread , sym , ip , dso , level ) ) {
2009-05-19 16:30:23 +04:00
fprintf ( stderr , " problem incrementing symbol count, bailing out \n " ) ;
2009-05-18 19:45:42 +04:00
goto done ;
2009-05-19 16:30:23 +04:00
}
2009-05-18 19:45:42 +04:00
}
total + + ;
} else switch ( event - > header . type ) {
case PERF_EVENT_MMAP : {
struct thread * thread = threads__findnew ( event - > mmap . pid ) ;
struct map * map = map__new ( & event - > mmap ) ;
2009-05-26 20:48:58 +04:00
if ( dump_trace ) {
2009-05-26 21:03:36 +04:00
fprintf ( stderr , " %p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s \n " ,
( void * ) ( offset + head ) ,
( void * ) ( long ) ( event - > header . size ) ,
2009-05-26 20:48:58 +04:00
( void * ) event - > mmap . start ,
( void * ) event - > mmap . len ,
( void * ) event - > mmap . pgoff ,
event - > mmap . filename ) ;
}
2009-05-19 16:30:23 +04:00
if ( thread = = NULL | | map = = NULL ) {
fprintf ( stderr , " problem processing PERF_EVENT_MMAP, bailing out \n " ) ;
2009-05-18 19:45:42 +04:00
goto done ;
2009-05-19 16:30:23 +04:00
}
2009-05-18 19:45:42 +04:00
thread__insert_map ( thread , map ) ;
2009-05-26 20:48:58 +04:00
total_mmap + + ;
2009-05-18 19:45:42 +04:00
break ;
}
case PERF_EVENT_COMM : {
struct thread * thread = threads__findnew ( event - > comm . pid ) ;
2009-05-26 20:48:58 +04:00
if ( dump_trace ) {
2009-05-26 21:03:36 +04:00
fprintf ( stderr , " %p [%p]: PERF_EVENT_COMM: %s:%d \n " ,
( void * ) ( offset + head ) ,
( void * ) ( long ) ( event - > header . size ) ,
2009-05-26 20:48:58 +04:00
event - > comm . comm , event - > comm . pid ) ;
}
2009-05-18 19:45:42 +04:00
if ( thread = = NULL | |
2009-05-19 16:30:23 +04:00
thread__set_comm ( thread , event - > comm . comm ) ) {
fprintf ( stderr , " problem processing PERF_EVENT_COMM, bailing out \n " ) ;
2009-05-18 19:45:42 +04:00
goto done ;
2009-05-19 16:30:23 +04:00
}
2009-05-26 20:48:58 +04:00
total_comm + + ;
2009-05-18 19:45:42 +04:00
break ;
}
2009-05-26 20:48:58 +04:00
default : {
2009-05-26 22:51:47 +04:00
broken_event :
2009-05-26 21:03:36 +04:00
fprintf ( stderr , " %p [%p]: skipping unknown header type: %d \n " ,
( void * ) ( offset + head ) ,
( void * ) ( long ) ( event - > header . size ) ,
2009-05-26 20:48:58 +04:00
event - > header . type ) ;
2009-05-26 20:53:17 +04:00
total_unknown + + ;
2009-05-26 22:51:47 +04:00
/*
* assume we lost track of the stream , check alignment , and
* increment a single u64 in the hope to catch on again ' soon ' .
*/
if ( unlikely ( head & 7 ) )
head & = ~ 7ULL ;
size = 8 ;
2009-05-26 20:48:58 +04:00
}
2009-05-18 19:45:42 +04:00
}
2009-05-26 22:51:47 +04:00
head + = size ;
2009-05-26 21:03:36 +04:00
2009-05-18 19:45:42 +04:00
if ( offset + head < stat . st_size )
goto more ;
rc = EXIT_SUCCESS ;
done :
close ( input ) ;
2009-05-26 20:48:58 +04:00
if ( dump_trace ) {
2009-05-26 20:53:17 +04:00
fprintf ( stderr , " IP events: %10ld \n " , total ) ;
fprintf ( stderr , " mmap events: %10ld \n " , total_mmap ) ;
fprintf ( stderr , " comm events: %10ld \n " , total_comm ) ;
fprintf ( stderr , " unknown events: %10ld \n " , total_unknown ) ;
2009-05-26 20:48:58 +04:00
return 0 ;
}
2009-05-18 19:45:42 +04:00
//dsos__fprintf(stdout);
threads__fprintf ( stdout ) ;
#if 0
std : : map < std : : string , int > : : iterator hi = hist . begin ( ) ;
while ( hi ! = hist . end ( ) ) {
rev_hist . insert ( std : : pair < int , std : : string > ( hi - > second , hi - > first ) ) ;
hist . erase ( hi + + ) ;
}
std : : multimap < int , std : : string > : : const_iterator ri = rev_hist . begin ( ) ;
while ( ri ! = rev_hist . end ( ) ) {
printf ( " %5.2f %s \n " , ( 100.0 * ri - > first ) / total , ri - > second . c_str ( ) ) ;
ri + + ;
}
# endif
return rc ;
}
2009-05-26 11:17:18 +04:00
static const char * const report_usage [ ] = {
" perf report [<options>] <command> " ,
NULL
} ;
static const struct option options [ ] = {
OPT_STRING ( ' i ' , " input " , & input_name , " file " ,
" input file name " ) ,
2009-05-26 20:48:58 +04:00
OPT_BOOLEAN ( ' D ' , " dump-raw-trace " , & dump_trace ,
" dump raw trace in ASCII " ) ,
2009-05-26 11:17:18 +04:00
OPT_END ( )
} ;
int cmd_report ( int argc , const char * * argv , const char * prefix )
{
elf_version ( EV_CURRENT ) ;
page_size = getpagesize ( ) ;
parse_options ( argc , argv , options , report_usage , 0 ) ;
return __cmd_report ( ) ;
}