39 #include <sys/ptrace.h> 40 #include <sys/resource.h> 42 #include <sys/types.h> 58 #define MAX_EVT_NAME_LEN 256 59 #define NUM_PMCS PFMLIB_MAX_PMCS 60 #define NUM_PMDS PFMLIB_MAX_PMDS 61 #define FMT_NAME PFM_DFL_SMPL_NAME 62 #define BPL ( sizeof( uint64_t ) << 3 ) 65 #define SYM_NAME_MAX_LENGTH 10000 66 #define MAX_OUTPUT_FILENAME_LENGTH 1024 67 #define MAX_EVENT_NAME_LENGTH 500 68 #define MAX_PREFIX_NAME_LENGTH 1024 69 #define FILENAME_MAX_LENGTH 1024 71 #define MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS 4 73 #define cpuid( func, ax, bx, cx, dx ) \ 74 __asm__ __volatile__( "cpuid" : "=a"( ax ), "=b"( bx ), "=c"( cx ), "=d"( dx ) : "a"( func ) ); 77 static uint64_t collected_samples, collected_partial;
81 static size_t entry_size;
82 static unsigned int num_smpl_pmds;
98 inline T function_cast(
void* p )
105 return caster.function;
111 typedef void ( *pfm_stop_t )( int );
113 typedef void ( *pfm_self_stop_t )( int );
114 pfm_self_stop_t pfm_self_stop;
115 typedef os_err_t ( *pfm_restart_t )( int );
117 typedef int ( *pfm_read_pmds_t )( int,
pfarg_pmd_t*, int );
119 typedef pfm_err_t ( *pfm_initialize_t )();
129 typedef os_err_t ( *pfm_write_pmds_t )( int, pfarg_pmd_t*, int );
135 typedef char* ( *pfm_strerror_t )( int );
139 typedef pfm_err_t ( *pfm_get_num_counters_t )(
unsigned int* );
141 static PFMon& instance() {
return s_instance; }
150 handle = dlopen(
"libpfm.so", RTLD_NOW );
157 pfm_start = function_cast<pfm_start_t>( dlsym( handle,
"pfm_start" ) );
158 pfm_stop = function_cast<pfm_stop_t>( dlsym( handle,
"pfm_stop" ) );
159 pfm_self_stop = function_cast<pfm_self_stop_t>( dlsym( handle,
"pfm_stop" ) );
160 pfm_restart = function_cast<pfm_restart_t>( dlsym( handle,
"pfm_restart" ) );
161 pfm_read_pmds = function_cast<pfm_read_pmds_t>( dlsym( handle,
"pfm_read_pmds" ) );
162 pfm_initialize = function_cast<pfm_initialize_t>( dlsym( handle,
"pfm_initialize" ) );
163 pfm_find_full_event = function_cast<pfm_find_full_event_t>( dlsym( handle,
"pfm_find_full_event" ) );
164 pfm_dispatch_events = function_cast<pfm_dispatch_events_t>( dlsym( handle,
"pfm_dispatch_events" ) );
165 pfm_create_context = function_cast<pfm_create_context_t>( dlsym( handle,
"pfm_create_context" ) );
166 pfm_write_pmcs = function_cast<pfm_write_pmcs_t>( dlsym( handle,
"pfm_write_pmcs" ) );
167 pfm_write_pmds = function_cast<pfm_write_pmds_t>( dlsym( handle,
"pfm_write_pmds" ) );
168 pfm_load_context = function_cast<pfm_load_context_t>( dlsym( handle,
"pfm_load_context" ) );
169 pfm_strerror = function_cast<pfm_strerror_t>( dlsym( handle,
"pfm_strerror" ) );
170 pfm_set_options = function_cast<pfm_set_options_t>( dlsym( handle,
"pfm_set_options" ) );
171 pfm_get_num_counters = function_cast<pfm_get_num_counters_t>( dlsym( handle,
"pfm_get_num_counters" ) );
180 if ( handle ) dlclose( handle );
183 static PFMon s_instance;
186 PFMon PFMon::s_instance;
223 #pragma warning( push ) 224 #pragma warning( disable : 593 ) 227 cpuid( 1, a, b, c, d );
228 int sse4_2_mask = 1 << 20;
229 if ( c & sse4_2_mask )
234 #pragma warning( pop ) 280 , m_pfm( PFMon::instance() )
400 return bv[rnum >>
LBPL] & ( 1UL << ( rnum & (
BPL - 1 ) ) ) ? 1 : 0;
411 static void sigio_handler(
int,
struct siginfo*,
struct sigcontext* );
415 void finalize_smpl();
432 memset( &ctx, 0,
sizeof( ctx ) );
433 memset( &inp, 0,
sizeof( inp ) );
434 memset( &outp, 0,
sizeof( outp ) );
435 memset( pd, 0,
sizeof( pd ) );
436 memset(
pc, 0,
sizeof(
pc ) );
437 memset( &load_arg, 0,
sizeof( load_arg ) );
438 memset( ¶ms, 0,
sizeof( params ) );
439 memset( &nhm_params, 0,
sizeof( nhm_params ) );
441 for (
int i = 0; i < used_counters_number; i++ ) {
442 ret = m_pfm.pfm_find_full_event( event_cstr[i], &inp.pfp_events[i] );
444 error() <<
"ERROR: cannot find event: " << event_cstr[i] <<
". Aborting..." <<
endmsg;
448 inp.pfp_event_count = 4;
449 for (
int i = 0; i < used_counters_number; i++ ) {
454 if ( cmask[i] > 0 ) {
455 ( params.pfp_core_counters[i] ).cnt_mask = cmask[i];
456 ( nhm_params.pfp_nhm_counters[i] ).cnt_mask = cmask[i];
459 if ( nehalem || westmere ) {
460 ret = m_pfm.pfm_dispatch_events( &inp, &nhm_params, &outp, NULL );
462 ret = m_pfm.pfm_dispatch_events( &inp, ¶ms, &outp, NULL );
465 error() <<
"ERROR: cannot dispatch events: " << m_pfm.pfm_strerror( ret ) <<
". Aborting..." <<
endmsg;
467 for (
unsigned int i = 0; i < outp.pfp_pmc_count; i++ ) {
468 pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
469 pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
471 for (
unsigned int i = 0; i < outp.pfp_pmd_count; i++ ) {
472 pd[i].reg_num = outp.pfp_pmds[i].reg_num;
475 fd = m_pfm.pfm_create_context( &ctx, NULL, 0, 0 );
477 error() <<
"ERROR: Context not created. Aborting..." <<
endmsg;
479 if ( m_pfm.pfm_write_pmcs( fd,
pc, outp.pfp_pmc_count ) == -1 ) {
480 error() <<
"ERROR: Could not write pmcs. Aborting..." <<
endmsg;
482 if ( m_pfm.pfm_write_pmds( fd, pd, outp.pfp_pmd_count ) == -1 ) {
483 error() <<
"ERROR: Could not write pmds. Aborting..." <<
endmsg;
485 load_arg.load_pid = getpid();
486 if ( m_pfm.pfm_load_context( fd, &load_arg ) == -1 ) {
487 error() <<
"ERROR: Could not load context. Aborting..." <<
endmsg;
491 m_pfm.pfm_start( fd, NULL );
500 m_pfm.pfm_stop( fd );
501 if ( m_pfm.pfm_read_pmds( fd, pd, inp.pfp_event_count ) == -1 ) {
502 error() <<
"Could not read pmds" <<
endmsg;
504 for (
int i = 0; i < used_counters_number; i++ ) {
505 results[i][( alg_stack.
top().first )->
name()].push_back( alg_stack.
top().second[i] + pd[i].reg_value );
513 m_pfm.pfm_stop( fd );
514 if ( m_pfm.pfm_read_pmds( fd, pd, inp.pfp_event_count ) == -1 ) {
515 error() <<
"Could not read pmds" <<
endmsg;
518 for (
int i = 0; i < used_counters_number; i++ ) {
519 alg_stack.
top().second[i] += pd[i].reg_value;
530 info() <<
"start of finalizepm ucn:" << used_counters_number <<
endmsg;
531 for (
int i = 0; i < used_counters_number; i++ ) {
534 filename += event_cstr[i];
536 for (
auto&
c : filename )
537 if (
c ==
':' )
c =
'-';
539 if ( inv[i] ) filename +=
"_INV_1";
540 if ( cmask[i] > 0 ) filename +=
"_CMASK_" +
std::to_string( cmask[i] );
543 info() <<
"Filename:" << filename <<
endmsg;
544 FILE* outfile = fopen( filename.c_str(),
"w" );
546 fprintf( outfile,
"NHM " );
547 }
else if ( westmere ) {
548 fprintf( outfile,
"WSM " );
550 fprintf( outfile,
"CORE " );
552 fprintf( outfile,
"%s %d %d %d\n", event_cstr[i], cmask[i], inv[i],
sp[i] );
554 it != ( results[i] ).
end(); it++ ) {
555 fprintf( outfile,
"%s\n", ( it->first ).c_str() );
557 fprintf( outfile,
"%lu\n", *j );
566 if ( !m_pfm.loaded ) {
567 error() <<
"pfm library could not be loaded" <<
endmsg;
571 info() <<
"Initializing..." <<
endmsg;
576 used_counters_number = 0;
578 if ( event_str[i].length() > 0 ) used_counters_number++;
581 strcpy( event_cstr[i], event_str[i].c_str() );
583 strcpy( prefix_cstr,
prefix.c_str() );
586 error() <<
"Cannot initialize perfmon!!" <<
endmsg;
590 event_count_reached =
false;
594 if ( family.compare(
"CORE" ) == 0 )
596 else if ( family.compare(
"NEHALEM" ) == 0 )
598 else if ( family.compare(
"WESTMERE" ) == 0 )
601 error() <<
"ERROR: Unsupported processor family " << family <<
". aborting..." <<
endmsg;
604 info() <<
"Initialized!" <<
endmsg;
619 printf(
"skipping identical set of samples...\n" );
624 pos = (
unsigned long)ent;
625 entry = collected_samples;
629 ( ( samples[ent->
ovfl_pmd] )[( alg_stack.
top().first )->
name()] )[(
unsigned long)( ent->
ip )]++;
635 collected_samples = entry;
637 if ( last_count != hdr->
hdr_count && ( last_count || last_overflow == 0 ) ) {
651 PFMon& pfm = PFMon::instance();
655 if ( fd != ctx_fd ) {
658 if ( pfm.pfm_read_pmds( fd, pd_smpl + 1, 1 ) == -1 ) {
662 r =
read( fd, &msg,
sizeof( msg ) );
663 if ( r !=
sizeof( msg ) ) {
664 if ( r == -1 && errno == EINTR ) {
665 printf(
"read interrupted, retrying\n" );
672 switch ( msg.
type ) {
674 process_smpl_buf( hdr, entry_size );
676 if ( pfm.pfm_restart( fd ) ) {
677 if ( errno != EBUSY ) {
680 printf(
"pfm_restart: task probably terminated \n" );
700 memset( &pfmlib_options, 0,
sizeof( pfmlib_options ) );
701 pfmlib_options.pfm_debug = 0;
702 pfmlib_options.pfm_verbose = 0;
703 m_pfm.pfm_set_options( &pfmlib_options );
704 ret = m_pfm.pfm_initialize();
706 error() <<
"ERROR: Cannot initialize library: " << m_pfm.pfm_strerror( ret ) <<
". Aborting..." <<
endmsg;
708 struct sigaction act;
709 memset( &act, 0,
sizeof( act ) );
710 act.sa_handler = (sig_t)sigio_handler;
712 sigaction( SIGIO, &act, 0 );
713 memset( &ctx, 0,
sizeof( ctx ) );
714 memset( &buf_arg, 0,
sizeof( buf_arg ) );
715 memset( &inp, 0,
sizeof( inp ) );
716 memset( &outp, 0,
sizeof( outp ) );
717 memset( pd_smpl, 0,
sizeof( pd_smpl ) );
718 memset(
pc, 0,
sizeof(
pc ) );
719 memset( &load_args, 0,
sizeof( load_args ) );
720 m_pfm.pfm_get_num_counters( &num_counters );
721 memset( ¶ms, 0,
sizeof( params ) );
722 memset( &nhm_params, 0,
sizeof( nhm_params ) );
724 for (
int i = 0; i < used_counters_number; i++ ) {
725 ret = m_pfm.pfm_find_full_event( event_cstr[i], &inp.pfp_events[i] );
727 error() <<
"ERROR: cannot find event: " << event_cstr[i] <<
". Aborting..." <<
endmsg;
731 inp.pfp_event_count = 4;
732 for (
int i = 0; i < used_counters_number; i++ ) {
737 if ( cmask[i] > 0 ) {
738 ( params.pfp_core_counters[i] ).cnt_mask = cmask[i];
739 ( nhm_params.pfp_nhm_counters[i] ).cnt_mask = cmask[i];
742 if ( nehalem || westmere ) {
743 ret = m_pfm.pfm_dispatch_events( &inp, &nhm_params, &outp, NULL );
745 ret = m_pfm.pfm_dispatch_events( &inp, ¶ms, &outp, NULL );
748 error() <<
"ERROR: cannot configure events: " << m_pfm.pfm_strerror( ret ) <<
". Aborting..." <<
endmsg;
750 for (
unsigned int i = 0; i < outp.pfp_pmc_count; i++ ) {
751 pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
752 pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
754 for (
unsigned int i = 0; i < outp.pfp_pmd_count; i++ ) {
755 pd_smpl[i].
reg_num = outp.pfp_pmds[i].reg_num;
757 pfm_bv_set( pd_smpl[0].reg_smpl_pmds, pd_smpl[i].reg_num );
758 if ( pd_smpl[i].reg_num > max_pmd ) {
764 for (
int i = 0; i < used_counters_number; i++ ) {
766 pfm_bv_copy( pd_smpl[i].reg_reset_pmds, pd_smpl[i].reg_smpl_pmds, max_pmd );
775 buf_arg.buf_size = 3 * getpagesize() + 512;
776 ctx_fd = m_pfm.pfm_create_context( &ctx, (
char*)
FMT_NAME, &buf_arg,
sizeof( buf_arg ) );
777 if ( ctx_fd == -1 ) {
778 if ( errno == ENOSYS ) {
779 error() <<
"ERROR: Your kernel does not have performance monitoring support! Aborting..." <<
endmsg;
781 error() <<
"ERROR: Can't create PFM context " << strerror( errno ) <<
". Aborting..." <<
endmsg;
783 buf_addr = mmap( NULL, (
size_t)buf_arg.buf_size, PROT_READ, MAP_PRIVATE, ctx_fd, 0 );
784 if ( buf_addr == MAP_FAILED ) {
785 error() <<
"ERROR: cannot mmap sampling buffer: " << strerror( errno ) <<
". Aborting..." <<
endmsg;
789 error() <<
"ERROR: invalid buffer format version. Aborting..." <<
endmsg;
791 if ( m_pfm.pfm_write_pmcs( ctx_fd,
pc, outp.pfp_pmc_count ) ) {
792 error() <<
"ERROR: pfm_write_pmcs error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
794 if ( m_pfm.pfm_write_pmds( ctx_fd, pd_smpl, outp.pfp_pmd_count ) ) {
795 error() <<
"ERROR: pfm_write_pmds error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
797 load_args.load_pid = getpid();
798 if ( m_pfm.pfm_load_context( ctx_fd, &load_args ) ) {
799 error() <<
"ERROR: pfm_load_context error errno " << strerror( errno ) <<
". Aborting..." <<
endmsg;
801 ret = fcntl( ctx_fd, F_SETFL, fcntl( ctx_fd, F_GETFL, 0 ) | O_ASYNC );
803 error() <<
"ERROR: cannot set ASYNC: " << strerror( errno ) <<
". Aborting..." <<
endmsg;
805 ret = fcntl( ctx_fd, F_SETOWN, getpid() );
807 error() <<
"ERROR: cannot setown: " << strerror( errno ) <<
". Aborting..." <<
endmsg;
810 m_pfm.pfm_start( ctx_fd, NULL );
819 m_pfm.pfm_self_stop( ctx_fd );
820 process_smpl_buf( hdr, entry_size );
822 ret = munmap( hdr, (
size_t)buf_arg.buf_size );
824 error() <<
"Cannot unmap buffer: %s" << strerror( errno ) <<
endmsg;
836 for (
int i = 0; i < used_counters_number; i++ ) {
839 filename += event_cstr[i];
841 for (
auto&
c : filename )
842 if (
c ==
':' )
c =
'-';
844 if ( inv[i] ) filename +=
"_INV_1";
845 if ( cmask[i] > 0 ) filename +=
"_CMASK_" +
std::to_string( cmask[i] );
846 filename +=
".txt.gz";
848 gzFile outfile = gzopen( filename.c_str(),
"wb" );
849 if ( outfile != NULL ) {
851 gzprintf( outfile,
"NHM " );
852 }
else if ( westmere ) {
853 gzprintf( outfile,
"WSM " );
855 gzprintf( outfile,
"CORE " );
857 if ( gzprintf( outfile,
"%s %d %d %d\n", event_cstr[i], cmask[i], inv[i],
sp[i] ) <
858 (
int)strlen( event_cstr[i] ) ) {
859 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
". Aborting..." <<
endmsg;
862 it != samples[i].end(); it++ ) {
863 unsigned long long sum = 0;
868 if ( gzprintf( outfile,
"%s%%%llu\n", ( it->first ).c_str(),
sum ) < (
int)( ( it->first ).length() ) ) {
869 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
". Aborting..." <<
endmsg;
876 const char* symbolName;
880 if ( sym_addr != NULL ) {
883 if ( symbolName != NULL && strlen( symbolName ) > 0 ) {
884 strcpy( sym_name, symbolName );
885 strcat( sym_name,
" " );
887 strcpy( sym_name,
"??? " );
889 if ( libName != NULL && strlen( libName ) > 0 ) {
890 strcat( sym_name, libName );
891 strcat( sym_name,
" " );
893 strcat( sym_name,
"??? " );
895 sprintf( sym_name,
"%s%d ", sym_name, libOffset );
896 if ( strlen( sym_name ) <= 0 ) {
897 error() <<
"ERROR: Symbol name length is zero. Aborting..." <<
endmsg;
900 strcpy( sym_name,
"??? ??? 0 " );
903 strcpy( sym_name,
"??? ??? 0 " );
905 if ( gzprintf( outfile,
"%s %d\n", sym_name, jt->second ) < (
int)strlen( sym_name ) ) {
906 error() <<
"ERROR: gzputs err: " << gzerror( outfile, &err ) <<
endmsg;
911 error() <<
"ERROR: Could not open file: " << filename <<
". Aborting..." <<
endmsg;
930 i_beforeInitialize( alg );
933 i_beforeExecute( alg );
945 i_afterInitialize( alg );
948 i_afterExecute( alg );
974 first_alg_name = alg->
name();
977 if ( !event_count_reached ) {
978 if ( !first_alg_name.compare( alg->
name() ) ) {
981 if ( ph_ev_count == start_at_event ) {
982 event_count_reached =
true;
987 if ( event_count_reached ) {
990 if ( !alg_stack.
empty() ) {
1012 if ( event_count_reached ) {
1015 if ( sampling == 0 )
1021 if ( !alg_stack.
empty() ) {
1022 if ( sampling == 0 )
pfmlib_core_input_param_t params
os_err_t pfm_write_pmds(int fd, pfarg_pmd_t *pmds, int count)
#define cpuid(func, ax, bx, cx, dx)
virtual StatusCode finalize()
#define PFM_REGFL_OVFL_NOTIFY
#define MAX_PREFIX_NAME_LENGTH
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
os_err_t pfm_create_context(pfarg_ctx_t *ctx, char *smpl_name, void *smpl_arg, size_t smpl_size)
PerfMonAuditor(const std::string &name, ISvcLocator *pSvc)
char * pfm_strerror(int code)
static void * tosymbol(void *address)
double sum(double x, double y, double z)
pfm_err_t pfm_get_num_counters(unsigned int *num)
#define SYM_NAME_MAX_LENGTH
class MergingTransformer< Out(const vector_of_const_< In > void
def read(f, regex='.*', skipevents=0)
unsigned long long uint64_t
void i_afterExecute(INamedInterface *alg)
unsigned short int uint16_t
os_err_t pfm_write_pmcs(int fd, pfarg_pmc_t *pmcs, int count)
Performance Monitoring Auditor that uses Perfmon2 library to monitor algorithms.
pfm_err_t pfm_dispatch_events(pfmlib_input_param_t *p, void *model_in, pfmlib_output_param_t *q, void *model_out)
pfmlib_options_t pfmlib_options
static void sigio_handler(int, struct siginfo *, struct sigcontext *)
bool isFailure() const
Test for a status code of FAILURE.
std::string first_alg_name
pfm_err_t pfm_find_full_event(const char *str, pfmlib_event_t *e)
StatusCode finalize() override
#define MAX_EVENT_NAME_LENGTH
pfmlib_nhm_input_param_t nhm_params
#define DECLARE_COMPONENT(type)
auto begin(reverse_wrapper< T > &w)
PropertyMgr & operator=(const PropertyMgr &)=delete
#define PFM_VERSION_MAJOR(x)
void pfm_bv_copy(uint64_t *d, uint64_t *j, uint16_t n)
GaudiUtils::VectorMap< const INamedInterface *, int > Map
int detect_unavail_pmcs(int fd, pfmlib_regmask_t *r_pmcs)
void pfm_bv_set(uint64_t *bv, uint16_t rnum)
os_err_t pfm_restart(int fd)
This class is used for returning status codes from appropriate routines.
Gaudi::Details::PropertyBase * declareProperty(const std::string &name, TYPE &value, const std::string &doc="none")
Declare a property (templated)
pfmlib_output_param_t outp
void after(StandardEventType, INamedInterface *, const StatusCode &) override
static bool symbol(void *address, const char *&sym, const char *&lib, int &offset, int &liboffset)
auto end(reverse_wrapper< T > &w)
void after(StandardEventType evt, INamedInterface *alg, const StatusCode &sc) override
os_err_t pfm_start(int fd, pfarg_start_t *start)
pfm_err_t pfm_initialize(void)
IInterface compliant class extending IInterface with the name() method.
int pfm_bv_isset(uint64_t *bv, uint16_t rnum)
unsigned int start_at_event
static void process_smpl_buf(pfm_dfl_smpl_hdr_t *hdr, size_t entry_size)
os_err_t pfm_load_context(int fd, pfarg_load_t *load)
pfm_dfl_smpl_arg_t buf_arg
os_err_t pfm_read_pmds(int fd, pfarg_pmd_t *pmds, int count)
StatusCode initialize() override
void i_beforeExecute(INamedInterface *alg)
virtual StatusCode initialize()
#define MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS
void i_afterInitialize(INamedInterface *alg)
void i_beforeInitialize(INamedInterface *alg)
os_err_t pfm_stop(int fd)
virtual ~PerfMonAuditor()
void before(StandardEventType, INamedInterface *) override
The following methods are meant to be implemented by the child class...
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
virtual const std::string & name() const =0
Retrieve the name of the instance.
void before(StandardEventType evt, INamedInterface *alg) override
pfm_err_t pfm_set_options(pfmlib_options_t *opt)
Base class from which all concrete auditor classes should be derived.