49 #include <sys/ptrace.h>
50 #include <sys/resource.h>
52 #include <sys/types.h>
68 #define MAX_EVT_NAME_LEN 256
69 #define NUM_PMCS PFMLIB_MAX_PMCS
70 #define NUM_PMDS PFMLIB_MAX_PMDS
71 #define FMT_NAME PFM_DFL_SMPL_NAME
72 #define BPL ( sizeof( uint64_t ) << 3 )
75 #define SYM_NAME_MAX_LENGTH 10000
76 #define MAX_OUTPUT_FILENAME_LENGTH 1024
77 #define MAX_EVENT_NAME_LENGTH 500
78 #define MAX_PREFIX_NAME_LENGTH 1024
79 #define FILENAME_MAX_LENGTH 1024
81 #define MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS 4
83 #define cpuid( func, ax, bx, cx, dx ) \
84 __asm__ __volatile__( "cpuid" : "=a"( ax ), "=b"( bx ), "=c"( cx ), "=d"( dx ) : "a"( func ) );
87 static uint64_t collected_samples, collected_partial;
90 static uint64_t ovfl_count;
91 static size_t entry_size;
92 static unsigned int num_smpl_pmds;
98 static uint64_t last_overflow;
99 static uint64_t last_count;
107 template <
typename T>
108 inline T function_cast(
void* p ) {
114 return caster.function;
119 typedef void ( *pfm_stop_t )( int );
121 typedef void ( *pfm_self_stop_t )( int );
122 pfm_self_stop_t pfm_self_stop{
nullptr };
123 typedef os_err_t ( *pfm_restart_t )( int );
125 typedef int ( *pfm_read_pmds_t )( int,
pfarg_pmd_t*, int );
127 typedef pfm_err_t ( *pfm_initialize_t )();
143 typedef char* ( *pfm_strerror_t )( int );
147 typedef pfm_err_t ( *pfm_get_num_counters_t )(
unsigned int* );
149 static PFMon& instance() {
return s_instance; }
157 handle = dlopen(
"libpfm.so", RTLD_NOW );
164 pfm_start = function_cast<pfm_start_t>( dlsym( handle,
"pfm_start" ) );
165 pfm_stop = function_cast<pfm_stop_t>( dlsym( handle,
"pfm_stop" ) );
166 pfm_self_stop = function_cast<pfm_self_stop_t>( dlsym( handle,
"pfm_stop" ) );
167 pfm_restart = function_cast<pfm_restart_t>( dlsym( handle,
"pfm_restart" ) );
168 pfm_read_pmds = function_cast<pfm_read_pmds_t>( dlsym( handle,
"pfm_read_pmds" ) );
169 pfm_initialize = function_cast<pfm_initialize_t>( dlsym( handle,
"pfm_initialize" ) );
170 pfm_find_full_event = function_cast<pfm_find_full_event_t>( dlsym( handle,
"pfm_find_full_event" ) );
171 pfm_dispatch_events = function_cast<pfm_dispatch_events_t>( dlsym( handle,
"pfm_dispatch_events" ) );
172 pfm_create_context = function_cast<pfm_create_context_t>( dlsym( handle,
"pfm_create_context" ) );
173 pfm_write_pmcs = function_cast<pfm_write_pmcs_t>( dlsym( handle,
"pfm_write_pmcs" ) );
174 pfm_write_pmds = function_cast<pfm_write_pmds_t>( dlsym( handle,
"pfm_write_pmds" ) );
175 pfm_load_context = function_cast<pfm_load_context_t>( dlsym( handle,
"pfm_load_context" ) );
176 pfm_strerror = function_cast<pfm_strerror_t>( dlsym( handle,
"pfm_strerror" ) );
177 pfm_set_options = function_cast<pfm_set_options_t>( dlsym( handle,
"pfm_set_options" ) );
178 pfm_get_num_counters = function_cast<pfm_get_num_counters_t>( dlsym( handle,
"pfm_get_num_counters" ) );
186 if ( handle ) dlclose( handle );
189 static PFMon s_instance;
192 PFMon PFMon::s_instance;
224 # pragma warning( push )
225 # pragma warning( disable : 593 )
229 int sse4_2_mask = 1 << 20;
230 if (
c & sse4_2_mask )
235 # pragma warning( pop )
281 ,
m_pfm( PFMon::instance() )
397 void pfm_bv_set( uint64_t* bv, uint16_t rnum ) { bv[rnum >>
LBPL] |= 1UL << ( rnum & (
BPL - 1 ) ); }
399 return bv[rnum >>
LBPL] & ( 1UL << ( rnum & (
BPL - 1 ) ) ) ? 1 : 0;
404 else { memcpy( d,
j, (
n >>
LBPL ) *
sizeof( uint64_t ) ); }
427 memset( &
ctx, 0,
sizeof(
ctx ) );
428 memset( &
inp, 0,
sizeof(
inp ) );
430 memset(
pd, 0,
sizeof(
pd ) );
431 memset(
pc, 0,
sizeof(
pc ) );
439 error() <<
"ERROR: cannot find event: " <<
event_cstr[
i] <<
". Aborting..." <<
endmsg;
460 error() <<
"ERROR: cannot dispatch events: " <<
m_pfm.pfm_strerror(
ret ) <<
". Aborting..." <<
endmsg;
470 fd =
m_pfm.pfm_create_context( &
ctx, NULL, 0, 0 );
471 if (
fd == -1 ) { error() <<
"ERROR: Context not created. Aborting..." <<
endmsg; }
473 error() <<
"ERROR: Could not write pmcs. Aborting..." <<
endmsg;
476 error() <<
"ERROR: Could not write pmds. Aborting..." <<
endmsg;
480 error() <<
"ERROR: Could not load context. Aborting..." <<
endmsg;
495 results[
i][( alg_stack.top().first )->
name()].push_back( alg_stack.top().second[
i] +
pd[
i].
reg_value );
521 if (
c ==
':' )
c =
'-';
528 FILE* outfile = fopen(
filename.c_str(),
"w" );
530 fprintf( outfile,
"NHM " );
532 fprintf( outfile,
"WSM " );
534 fprintf( outfile,
"CORE " );
538 it != ( results[
i] ).
end(); it++ ) {
539 fprintf( outfile,
"%s\n", ( it->first ).c_str() );
541 fprintf( outfile,
"%lu\n", *
j );
549 if ( !
m_pfm.loaded ) {
550 error() <<
"pfm library could not be loaded" <<
endmsg;
554 info() <<
"Initializing..." <<
endmsg;
577 else { error() <<
"ERROR: Unsupported processor family " <<
family <<
". aborting..." <<
endmsg; }
579 info() <<
"Initialized!" <<
endmsg;
593 printf(
"skipping identical set of samples...\n" );
598 pos = (
unsigned long)ent;
599 entry = collected_samples;
603 ( ( samples[ent->
ovfl_pmd] )[( alg_stack.top().first )->
name()] )[(
unsigned long)( ent->
ip )]++;
609 collected_samples = entry;
611 if ( last_count != hdr->
hdr_count && ( last_count || last_overflow == 0 ) ) { collected_partial += hdr->
hdr_count; }
621 PFMon& pfm = PFMon::instance();
625 if (
fd != ctx_fd ) {
628 if ( pfm.pfm_read_pmds(
fd, pd_smpl + 1, 1 ) == -1 ) {
633 if ( r !=
sizeof(
msg ) ) {
634 if ( r == -1 && errno == EINTR ) {
635 printf(
"read interrupted, retrying\n" );
642 switch (
msg.type ) {
646 if ( pfm.pfm_restart(
fd ) ) {
647 if ( errno != EBUSY ) {
650 printf(
"pfm_restart: task probably terminated \n" );
675 error() <<
"ERROR: Cannot initialize library: " <<
m_pfm.pfm_strerror(
ret ) <<
". Aborting..." <<
endmsg;
677 struct sigaction act;
678 memset( &act, 0,
sizeof( act ) );
681 sigaction( SIGIO, &act, 0 );
682 memset( &
ctx, 0,
sizeof(
ctx ) );
684 memset( &
inp, 0,
sizeof(
inp ) );
686 memset( pd_smpl, 0,
sizeof( pd_smpl ) );
687 memset(
pc, 0,
sizeof(
pc ) );
696 error() <<
"ERROR: cannot find event: " <<
event_cstr[
i] <<
". Aborting..." <<
endmsg;
717 error() <<
"ERROR: cannot configure events: " <<
m_pfm.pfm_strerror(
ret ) <<
". Aborting..." <<
endmsg;
726 pfm_bv_set( pd_smpl[0].reg_smpl_pmds, pd_smpl[
i].reg_num );
744 if ( ctx_fd == -1 ) {
745 if ( errno == ENOSYS ) {
746 error() <<
"ERROR: Your kernel does not have performance monitoring support! Aborting..." <<
endmsg;
748 error() <<
"ERROR: Can't create PFM context " << strerror( errno ) <<
". Aborting..." <<
endmsg;
752 error() <<
"ERROR: cannot mmap sampling buffer: " << strerror( errno ) <<
". Aborting..." <<
endmsg;
756 error() <<
"ERROR: invalid buffer format version. Aborting..." <<
endmsg;
759 error() <<
"ERROR: pfm_write_pmcs error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
762 error() <<
"ERROR: pfm_write_pmds error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
766 error() <<
"ERROR: pfm_load_context error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
768 ret = fcntl( ctx_fd, F_SETFL, fcntl( ctx_fd, F_GETFL, 0 ) | O_ASYNC );
769 if (
ret == -1 ) { error() <<
"ERROR: cannot set ASYNC: " << strerror( errno ) <<
". Aborting..." <<
endmsg; }
770 ret = fcntl( ctx_fd, F_SETOWN, getpid() );
771 if (
ret == -1 ) { error() <<
"ERROR: cannot setown: " << strerror( errno ) <<
". Aborting..." <<
endmsg; }
773 m_pfm.pfm_start( ctx_fd, NULL );
781 m_pfm.pfm_self_stop( ctx_fd );
785 if (
ret ) { error() <<
"Cannot unmap buffer: %s" << strerror( errno ) <<
endmsg; }
801 if (
c ==
':' )
c =
'-';
807 gzFile outfile = gzopen(
filename.c_str(),
"wb" );
808 if ( outfile != NULL ) {
810 gzprintf( outfile,
"NHM " );
812 gzprintf( outfile,
"WSM " );
814 gzprintf( outfile,
"CORE " );
818 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
". Aborting..." <<
endmsg;
821 it != samples[
i].end(); it++ ) {
822 unsigned long long sum = 0;
827 if ( gzprintf( outfile,
"%s%%%llu\n", ( it->first ).c_str(), sum ) < (
int)( ( it->first ).length() ) ) {
828 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
". Aborting..." <<
endmsg;
835 const char* symbolName;
839 if ( sym_addr != NULL ) {
842 if ( symbolName != NULL && strlen( symbolName ) > 0 ) {
843 strcpy( sym_name, symbolName );
844 strcat( sym_name,
" " );
846 strcpy( sym_name,
"??? " );
848 if ( libName != NULL && strlen( libName ) > 0 ) {
849 strcat( sym_name, libName );
850 strcat( sym_name,
" " );
852 strcat( sym_name,
"??? " );
854 sprintf( sym_name + strlen( sym_name ),
"%d ", libOffset );
855 if ( strlen( sym_name ) <= 0 ) { error() <<
"ERROR: Symbol name length is zero. Aborting..." <<
endmsg; }
857 strcpy( sym_name,
"??? ??? 0 " );
860 strcpy( sym_name,
"??? ??? 0 " );
862 if ( gzprintf( outfile,
"%s %d\n", sym_name, jt->second ) < (
int)strlen( sym_name ) ) {
863 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
endmsg;
868 error() <<
"ERROR: Could not open file: " <<
filename <<
". Aborting..." <<
endmsg;
935 if ( !alg_stack.empty() ) {
952 if ( !
alg ) {
return; }
963 if ( !alg_stack.empty() ) {