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 PFMon(
const PFMon& ) =
delete;
190 PFMon& operator=(
const PFMon& ) =
delete;
192 static PFMon s_instance;
195 PFMon PFMon::s_instance;
227 # pragma warning( push )
228 # pragma warning( disable : 593 )
232 int sse4_2_mask = 1 << 20;
233 if (
c & sse4_2_mask )
238 # pragma warning( pop )
284 ,
m_pfm( PFMon::instance() )
400 void pfm_bv_set( uint64_t* bv, uint16_t rnum ) { bv[rnum >>
LBPL] |= 1UL << ( rnum & (
BPL - 1 ) ); }
402 return bv[rnum >>
LBPL] & ( 1UL << ( rnum & (
BPL - 1 ) ) ) ? 1 : 0;
407 else { memcpy( d,
j, (
n >>
LBPL ) *
sizeof( uint64_t ) ); }
430 memset( &
ctx, 0,
sizeof(
ctx ) );
431 memset( &
inp, 0,
sizeof(
inp ) );
433 memset(
pd, 0,
sizeof(
pd ) );
434 memset(
pc, 0,
sizeof(
pc ) );
442 error() <<
"ERROR: cannot find event: " <<
event_cstr[
i] <<
". Aborting..." <<
endmsg;
463 error() <<
"ERROR: cannot dispatch events: " <<
m_pfm.pfm_strerror(
ret ) <<
". Aborting..." <<
endmsg;
473 fd =
m_pfm.pfm_create_context( &
ctx, NULL, 0, 0 );
474 if (
fd == -1 ) { error() <<
"ERROR: Context not created. Aborting..." <<
endmsg; }
476 error() <<
"ERROR: Could not write pmcs. Aborting..." <<
endmsg;
479 error() <<
"ERROR: Could not write pmds. Aborting..." <<
endmsg;
483 error() <<
"ERROR: Could not load context. Aborting..." <<
endmsg;
498 results[
i][( alg_stack.top().first )->
name()].push_back( alg_stack.top().second[
i] +
pd[
i].
reg_value );
524 if (
c ==
':' )
c =
'-';
531 FILE* outfile = fopen(
filename.c_str(),
"w" );
533 fprintf( outfile,
"NHM " );
535 fprintf( outfile,
"WSM " );
537 fprintf( outfile,
"CORE " );
541 for (
const auto& r : results[
i] ) {
542 fprintf( outfile,
"%s\n", r.first.c_str() );
543 for (
unsigned long int j : r.second ) { fprintf( outfile,
"%lu\n",
j ); }
550 if ( !
m_pfm.loaded ) {
551 error() <<
"pfm library could not be loaded" <<
endmsg;
555 info() <<
"Initializing..." <<
endmsg;
578 else { error() <<
"ERROR: Unsupported processor family " <<
family <<
". aborting..." <<
endmsg; }
580 info() <<
"Initialized!" <<
endmsg;
594 printf(
"skipping identical set of samples...\n" );
599 pos = (
unsigned long)ent;
600 entry = collected_samples;
604 ( ( samples[ent->
ovfl_pmd] )[( alg_stack.top().first )->
name()] )[(
unsigned long)( ent->
ip )]++;
610 collected_samples = entry;
612 if ( last_count != hdr->
hdr_count && ( last_count || last_overflow == 0 ) ) { collected_partial += hdr->
hdr_count; }
622 PFMon& pfm = PFMon::instance();
626 if (
fd != ctx_fd ) {
629 if ( pfm.pfm_read_pmds(
fd, pd_smpl + 1, 1 ) == -1 ) {
634 if ( r !=
sizeof(
msg ) ) {
635 if ( r == -1 && errno == EINTR ) {
636 printf(
"read interrupted, retrying\n" );
643 switch (
msg.type ) {
647 if ( pfm.pfm_restart(
fd ) ) {
648 if ( errno != EBUSY ) {
651 printf(
"pfm_restart: task probably terminated \n" );
676 error() <<
"ERROR: Cannot initialize library: " <<
m_pfm.pfm_strerror(
ret ) <<
". Aborting..." <<
endmsg;
678 struct sigaction act;
679 memset( &act, 0,
sizeof( act ) );
682 sigaction( SIGIO, &act, 0 );
683 memset( &
ctx, 0,
sizeof(
ctx ) );
685 memset( &
inp, 0,
sizeof(
inp ) );
687 memset( pd_smpl, 0,
sizeof( pd_smpl ) );
688 memset(
pc, 0,
sizeof(
pc ) );
697 error() <<
"ERROR: cannot find event: " <<
event_cstr[
i] <<
". Aborting..." <<
endmsg;
718 error() <<
"ERROR: cannot configure events: " <<
m_pfm.pfm_strerror(
ret ) <<
". Aborting..." <<
endmsg;
727 pfm_bv_set( pd_smpl[0].reg_smpl_pmds, pd_smpl[
i].reg_num );
745 if ( ctx_fd == -1 ) {
746 if ( errno == ENOSYS ) {
747 error() <<
"ERROR: Your kernel does not have performance monitoring support! Aborting..." <<
endmsg;
749 error() <<
"ERROR: Can't create PFM context " << strerror( errno ) <<
". Aborting..." <<
endmsg;
753 error() <<
"ERROR: cannot mmap sampling buffer: " << strerror( errno ) <<
". Aborting..." <<
endmsg;
757 error() <<
"ERROR: invalid buffer format version. Aborting..." <<
endmsg;
760 error() <<
"ERROR: pfm_write_pmcs error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
763 error() <<
"ERROR: pfm_write_pmds error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
767 error() <<
"ERROR: pfm_load_context error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
769 ret = fcntl( ctx_fd, F_SETFL, fcntl( ctx_fd, F_GETFL, 0 ) | O_ASYNC );
770 if (
ret == -1 ) { error() <<
"ERROR: cannot set ASYNC: " << strerror( errno ) <<
". Aborting..." <<
endmsg; }
771 ret = fcntl( ctx_fd, F_SETOWN, getpid() );
772 if (
ret == -1 ) { error() <<
"ERROR: cannot setown: " << strerror( errno ) <<
". Aborting..." <<
endmsg; }
774 m_pfm.pfm_start( ctx_fd, NULL );
782 m_pfm.pfm_self_stop( ctx_fd );
786 if (
ret ) { error() <<
"Cannot unmap buffer: %s" << strerror( errno ) <<
endmsg; }
802 if (
c ==
':' )
c =
'-';
808 gzFile outfile = gzopen(
filename.c_str(),
"wb" );
809 if ( outfile != NULL ) {
811 gzprintf( outfile,
"NHM " );
813 gzprintf( outfile,
"WSM " );
815 gzprintf( outfile,
"CORE " );
819 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
". Aborting..." <<
endmsg;
821 for (
const auto& it : samples[
i] ) {
822 unsigned long long sum = 0;
823 for (
const auto& jt : it.second ) { sum += jt.second; }
824 if ( gzprintf( outfile,
"%s%%%llu\n", it.first.c_str(), sum ) < (
int)( it.first.length() ) ) {
825 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
". Aborting..." <<
endmsg;
827 for (
const auto& jt : it.second ) {
831 const char* symbolName;
835 if ( sym_addr != NULL ) {
838 if ( symbolName != NULL && strlen( symbolName ) > 0 ) {
839 strcpy( sym_name, symbolName );
840 strcat( sym_name,
" " );
842 strcpy( sym_name,
"??? " );
844 if ( libName != NULL && strlen( libName ) > 0 ) {
845 strcat( sym_name, libName );
846 strcat( sym_name,
" " );
848 strcat( sym_name,
"??? " );
850 sprintf( sym_name + strlen( sym_name ),
"%d ", libOffset );
851 if ( strlen( sym_name ) <= 0 ) { error() <<
"ERROR: Symbol name length is zero. Aborting..." <<
endmsg; }
853 strcpy( sym_name,
"??? ??? 0 " );
856 strcpy( sym_name,
"??? ??? 0 " );
858 if ( gzprintf( outfile,
"%s %d\n", sym_name, jt.second ) < (
int)strlen( sym_name ) ) {
859 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
endmsg;
864 error() <<
"ERROR: Could not open file: " <<
filename <<
". Aborting..." <<
endmsg;
931 if ( !alg_stack.empty() ) {
948 if ( !
alg ) {
return; }
959 if ( !alg_stack.empty() ) {