00001
00002
00003
00004
00005
00006 #include "GaudiKernel/Auditor.h"
00007 #include "GaudiKernel/IToolSvc.h"
00008 #include "GaudiKernel/IIncidentListener.h"
00009 #include "GaudiKernel/IIncidentSvc.h"
00010 #include "GaudiKernel/IToolSvc.h"
00011 #include "GaudiKernel/VectorMap.h"
00012 #include "GaudiKernel/HashMap.h"
00013 #include "GaudiKernel/AudFactory.h"
00014 #include "GaudiKernel/MsgStream.h"
00015
00016
00017 #include <iostream>
00018 #include <string>
00019 #include <cstring>
00020 #include <fstream>
00021 #include <perfmon/pfmlib.h>
00022 #include <perfmon/pfmlib_core.h>
00023 #include <perfmon/pfmlib_intel_nhm.h>
00024 #include <vector>
00025 #include <map>
00026 #include <utility>
00027 #include <sstream>
00028
00029 #include <perfmon/perfmon.h>
00030 #include <perfmon/perfmon_dfl_smpl.h>
00031
00033
00035
00036
00037
00038 #include <sys/types.h>
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <stdarg.h>
00042 #include <errno.h>
00043 #include <unistd.h>
00044 #include <string.h>
00045 #include <signal.h>
00046 #include <stdarg.h>
00047 #include <stdint.h>
00048 #include <getopt.h>
00049 #include <time.h>
00050 #include <sys/ptrace.h>
00051 #include <sys/wait.h>
00052 #include <sys/mman.h>
00053 #include <sys/time.h>
00054 #include <sys/resource.h>
00055 #include <unistd.h>
00056 #include <fcntl.h>
00057 #include <zlib.h>
00058
00059 #include <algorithm>
00060 #include <list>
00061 #include <stack>
00062 #include <cmath>
00063 #include <sys/stat.h>
00064 #include "IgHook_IgHookTrace.h"
00065
00066
00067 #include <dlfcn.h>
00068
00069
00070 #define MAX_EVT_NAME_LEN 256
00071 #define NUM_PMCS PFMLIB_MAX_PMCS
00072 #define NUM_PMDS PFMLIB_MAX_PMDS
00073 #define FMT_NAME PFM_DFL_SMPL_NAME
00074 #define BPL (sizeof(uint64_t)<<3)
00075 #define LBPL 6
00076
00077 #define SYM_NAME_MAX_LENGTH 10000
00078 #define MAX_OUTPUT_FILENAME_LENGTH 1024
00079 #define MAX_EVENT_NAME_LENGTH 500
00080 #define MAX_PREFIX_NAME_LENGTH 1024
00081 #define FILENAME_MAX_LENGTH 1024
00082
00083 #define MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS 4
00084
00085 #define cpuid(func,ax,bx,cx,dx) __asm__ __volatile__ ("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
00086
00087
00088 static pfarg_pmd_t pd_smpl[NUM_PMDS];
00089 static uint64_t collected_samples, collected_partial;
00090 static int ctx_fd;
00091 static pfm_dfl_smpl_hdr_t *hdr;
00092 static uint64_t ovfl_count;
00093 static size_t entry_size;
00094 static unsigned int num_smpl_pmds;
00095 static std::vector<std::map<std::string, std::map<unsigned long, unsigned int> > > samples(MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS);
00096 static std::vector<std::map<std::string, std::vector<unsigned long int> > > results(MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS);
00097 static uint64_t last_overflow;
00098 static uint64_t last_count;
00099 static std::string current_module;
00100 static int sp[MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS];
00101
00102 static std::stack<std::pair<INamedInterface *, std::vector<unsigned long int> > > alg_stack;
00103
00104
00105
00106
00107 namespace {
00108 class PFMon {
00109 public:
00110 bool loaded;
00111 typedef void (*pfm_stop_t)(int);
00112 pfm_stop_t pfm_stop;
00113 typedef void (*pfm_self_stop_t)(int);
00114 pfm_self_stop_t pfm_self_stop;
00115 typedef os_err_t (*pfm_restart_t)(int);
00116 pfm_restart_t pfm_restart;
00117 typedef int (*pfm_read_pmds_t)(int, pfarg_pmd_t*, int);
00118 pfm_read_pmds_t pfm_read_pmds;
00119 typedef pfm_err_t (*pfm_initialize_t)();
00120 pfm_initialize_t pfm_initialize;
00121 typedef pfm_err_t (*pfm_find_full_event_t)(const char *, pfmlib_event_t *);
00122 pfm_find_full_event_t pfm_find_full_event;
00123 typedef pfm_err_t (*pfm_dispatch_events_t)(pfmlib_input_param_t *, void *, pfmlib_output_param_t *, void *);
00124 pfm_dispatch_events_t pfm_dispatch_events;
00125 typedef os_err_t (*pfm_create_context_t)(pfarg_ctx_t *, char *, void *, size_t);
00126 pfm_create_context_t pfm_create_context;
00127 typedef os_err_t (*pfm_write_pmcs_t)(int, pfarg_pmc_t *, int);
00128 pfm_write_pmcs_t pfm_write_pmcs;
00129 typedef os_err_t (*pfm_write_pmds_t)(int, pfarg_pmd_t *, int);
00130 pfm_write_pmds_t pfm_write_pmds;
00131 typedef os_err_t (*pfm_load_context_t)(int, pfarg_load_t *);
00132 pfm_load_context_t pfm_load_context;
00133 typedef os_err_t (*pfm_start_t)(int fd, pfarg_start_t *);
00134 pfm_start_t pfm_start;
00135 typedef char* (*pfm_strerror_t)(int);
00136 pfm_strerror_t pfm_strerror;
00137 typedef pfm_err_t (*pfm_set_options_t)(pfmlib_options_t *);
00138 pfm_set_options_t pfm_set_options;
00139 typedef pfm_err_t (*pfm_get_num_counters_t)(unsigned int *);
00140 pfm_get_num_counters_t pfm_get_num_counters;
00141 static PFMon &instance() {
00142 return s_instance;
00143 }
00144 private:
00145
00146
00147 void* handle;
00148
00149 PFMon() {
00150 handle = dlopen("libpfm.so", RTLD_NOW);
00151 if (handle) { loaded = true; } else { loaded = false; }
00152 if (loaded) {
00153 pfm_start = (pfm_start_t) dlsym(handle, "pfm_start");
00154 pfm_stop = (pfm_stop_t) dlsym(handle, "pfm_stop");
00155 pfm_self_stop = (pfm_self_stop_t) dlsym(handle, "pfm_stop");
00156 pfm_restart = (pfm_restart_t) dlsym(handle, "pfm_restart");
00157 pfm_read_pmds = (pfm_read_pmds_t) dlsym(handle, "pfm_read_pmds");
00158 pfm_initialize = (pfm_initialize_t) dlsym(handle, "pfm_initialize");
00159 pfm_find_full_event = (pfm_find_full_event_t) dlsym(handle, "pfm_find_full_event");
00160 pfm_dispatch_events = (pfm_dispatch_events_t) dlsym(handle, "pfm_dispatch_events");
00161 pfm_create_context = (pfm_create_context_t) dlsym(handle, "pfm_create_context");
00162 pfm_write_pmcs = (pfm_write_pmcs_t) dlsym(handle, "pfm_write_pmcs");
00163 pfm_write_pmds = (pfm_write_pmds_t) dlsym(handle, "pfm_write_pmds");
00164 pfm_load_context = (pfm_load_context_t) dlsym(handle, "pfm_load_context");
00165 pfm_strerror = (pfm_strerror_t) dlsym(handle, "pfm_strerror");
00166 pfm_set_options = (pfm_set_options_t) dlsym(handle, "pfm_set_options");
00167 pfm_get_num_counters = (pfm_get_num_counters_t) dlsym(handle, "pfm_get_num_counters");
00168 } else {
00169
00170 }
00171 }
00172 ~PFMon() {
00173 if (handle) dlclose(handle);
00174 }
00175
00176 static PFMon s_instance;
00177 };
00178
00179 PFMon PFMon::s_instance;
00180 }
00181
00182
00183
00184
00185
00186
00187
00197 class PerfMonAuditor: virtual public Auditor
00198 {
00199 public:
00200 virtual void before(StandardEventType evt, INamedInterface* alg);
00201 virtual void after(StandardEventType evt, INamedInterface* alg, const StatusCode &sc);
00202 using Auditor::before;
00203 using Auditor::after;
00204
00205 private:
00206 void i_beforeInitialize(INamedInterface* alg);
00207 void i_afterInitialize(INamedInterface* alg);
00208 void i_beforeExecute(INamedInterface* alg);
00209 void i_afterExecute(INamedInterface* alg);
00210
00211 public:
00212 virtual StatusCode initialize();
00213 virtual StatusCode finalize();
00214 int is_nehalem() {
00215 #ifdef __ICC
00216
00217 #pragma warning(push)
00218 #pragma warning(disable:593)
00219 #endif
00220 int a,b,c,d;
00221 cpuid(1,a,b,c,d);
00222 int sse4_2_mask = 1 << 20;
00223 if(c & sse4_2_mask) return 1; else return 0;
00224 #ifdef __ICC
00225 #pragma warning(pop)
00226 #endif
00227 }
00228
00229 private:
00230 PFMon &m_pfm;
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 public:
00269 PerfMonAuditor(const std::string& name, ISvcLocator* pSvc):
00270 Auditor(name, pSvc),
00271 m_pfm(PFMon::instance()),
00272 m_map(),
00273 m_indent(0),
00274 m_inEvent(false)
00275 {
00276 is_nehalem_ret = is_nehalem();
00277 declareProperty("EVENT0", event_str[0]);
00278 declareProperty("EVENT1", event_str[1]);
00279 declareProperty("EVENT2", event_str[2]);
00280 declareProperty("EVENT3", event_str[3]);
00281 declareProperty("FAMILY", family);
00282 declareProperty("PREFIX", prefix);
00283 declareProperty("INV0", inv[0]);
00284 declareProperty("INV1", inv[1]);
00285 declareProperty("INV2", inv[2]);
00286 declareProperty("INV3", inv[3]);
00287 declareProperty("CMASK0", cmask[0]);
00288 declareProperty("CMASK1", cmask[1]);
00289 declareProperty("CMASK2", cmask[2]);
00290 declareProperty("CMASK3", cmask[3]);
00291 declareProperty("SP0", sp[0]);
00292 declareProperty("SP1", sp[1]);
00293 declareProperty("SP2", sp[2]);
00294 declareProperty("SP3", sp[3]);
00295 declareProperty("SAMPLE", sampling);
00296 declareProperty("START_AT_EVENT", start_at_event);
00297 declareProperty("IS_NEHALEM", is_nehalem_ret);
00298
00299
00300
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00340
00341 }
00342
00343 virtual ~PerfMonAuditor() {}
00344
00345 private:
00346 PerfMonAuditor();
00347 PerfMonAuditor(const PerfMonAuditor&);
00348 PerfMonAuditor& operator=(const PerfMonAuditor&);
00349
00350 private:
00351 typedef GaudiUtils::VectorMap<const INamedInterface*,int> Map;
00352 Map m_map;
00353 int m_indent;
00354 bool m_inEvent;
00355
00356 private:
00357 int is_nehalem_ret;
00358
00359 pfmlib_input_param_t inp;
00360 pfmlib_output_param_t outp;
00361 pfarg_ctx_t ctx;
00362 pfarg_pmd_t pd[NUM_PMDS];
00363 pfarg_pmc_t pc[NUM_PMCS];
00364 pfarg_load_t load_arg;
00365 int fd;
00366 unsigned int i;
00367 int ret;
00368 void startpm();
00369 void pausepm();
00370 void stoppm();
00371 void finalizepm();
00372 std::string event_str[MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS];
00373 std::string prefix;
00374 std::string family;
00375 char event_cstr[MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS][MAX_EVENT_NAME_LENGTH];
00376 char prefix_cstr[MAX_PREFIX_NAME_LENGTH];
00377 unsigned int ph_ev_count;
00378 bool inv[MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS];
00379 unsigned int cmask[MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS];
00380 unsigned int start_at_event;
00381 pfmlib_core_input_param_t params;
00382 pfmlib_nhm_input_param_t nhm_params;
00383 int used_counters_number;
00384 bool nehalem;
00385 bool westmere;
00386 bool core;
00387
00388 bool sampling;
00389 int detect_unavail_pmu_regs(int fd, pfmlib_regmask_t *r_pmcs, pfmlib_regmask_t *r_pmds);
00390 int detect_unavail_pmcs(int fd, pfmlib_regmask_t *r_pmcs){return detect_unavail_pmu_regs(fd, r_pmcs, NULL);}
00391 void pfm_bv_set(uint64_t *bv, uint16_t rnum){bv[rnum>>LBPL] |= 1UL << (rnum&(BPL-1));}
00392 int pfm_bv_isset(uint64_t *bv, uint16_t rnum){return bv[rnum>>LBPL] & (1UL <<(rnum&(BPL-1))) ? 1 : 0;}
00393 void pfm_bv_copy(uint64_t *d, uint64_t *j, uint16_t n){if(n<=BPL) *d = *j; else {memcpy(d, j, (n>>LBPL)*sizeof(uint64_t));}}
00394 static void process_smpl_buf(pfm_dfl_smpl_hdr_t *hdr, size_t entry_size);
00395 static void sigio_handler(int, struct siginfo *, struct sigcontext *);
00396
00397 void start_smpl();
00398 void stop_smpl();
00399 void finalize_smpl();
00400 pfm_dfl_smpl_arg_t buf_arg;
00401 pfarg_load_t load_args;
00402 void *buf_addr;
00403 unsigned num_counters;
00404 unsigned int max_pmd;
00405 pfmlib_options_t pfmlib_options;
00406
00407
00408 int level;
00409
00410 bool first_alg;
00411 std::string first_alg_name;
00412 bool event_count_reached;
00413
00414
00415 };
00416
00417 void PerfMonAuditor::startpm()
00418 {
00419 MsgStream log(msgSvc(), name());
00420 memset(&ctx,0, sizeof(ctx));
00421 memset(&inp,0, sizeof(inp));
00422 memset(&outp,0, sizeof(outp));
00423 memset(pd, 0, sizeof(pd));
00424 memset(pc, 0, sizeof(pc));
00425 memset(&load_arg, 0, sizeof(load_arg));
00426 memset(¶ms, 0, sizeof(params));
00427 memset(&nhm_params, 0, sizeof(nhm_params));
00428
00429 for(int i=0; i<used_counters_number; i++)
00430 {
00431 ret = m_pfm.pfm_find_full_event(event_cstr[i], &inp.pfp_events[i]);
00432 if(ret != PFMLIB_SUCCESS)
00433 {
00434 log << MSG::ERROR << "ERROR: cannot find event: " << event_cstr[i] << ". Aborting..." << endmsg;
00435 }
00436 }
00437 inp.pfp_dfl_plm = PFM_PLM3;
00438 inp.pfp_event_count = 4;
00439 for(int i=0; i<used_counters_number; i++)
00440 {
00441 if(inv[i])
00442 {
00443 (params.pfp_core_counters[i]).flags |= PFM_CORE_SEL_INV;
00444 (nhm_params.pfp_nhm_counters[i]).flags |= PFM_NHM_SEL_INV;
00445 }
00446 if(cmask[i]>0)
00447 {
00448 (params.pfp_core_counters[i]).cnt_mask = cmask[i];
00449 (nhm_params.pfp_nhm_counters[i]).cnt_mask = cmask[i];
00450 }
00451 }
00452 if(nehalem || westmere)
00453 {
00454 ret = m_pfm.pfm_dispatch_events(&inp, &nhm_params, &outp, NULL);
00455 }
00456 else
00457 {
00458 ret = m_pfm.pfm_dispatch_events(&inp, ¶ms, &outp, NULL);
00459 }
00460 if(ret != PFMLIB_SUCCESS)
00461 {
00462 log << MSG::ERROR << "ERROR: cannot dispatch events: " << m_pfm.pfm_strerror(ret) << ". Aborting..." << endmsg;
00463 }
00464 for(unsigned int i=0; i<outp.pfp_pmc_count; i++)
00465 {
00466 pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
00467 pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
00468 }
00469 for(unsigned int i=0; i<outp.pfp_pmd_count; i++)
00470 {
00471 pd[i].reg_num = outp.pfp_pmds[i].reg_num;
00472 pd[i].reg_value = 0;
00473 }
00474 fd = m_pfm.pfm_create_context(&ctx, NULL, 0, 0);
00475 if(fd == -1)
00476 {
00477 log << MSG::ERROR << "ERROR: Context not created. Aborting..." << endmsg;
00478 }
00479 if(m_pfm.pfm_write_pmcs(fd, pc, outp.pfp_pmc_count) == -1)
00480 {
00481 log << MSG::ERROR << "ERROR: Could not write pmcs. Aborting..." << endmsg;
00482 }
00483 if(m_pfm.pfm_write_pmds(fd, pd, outp.pfp_pmd_count) == -1)
00484 {
00485 log << MSG::ERROR << "ERROR: Could not write pmds. Aborting..." << endmsg;
00486 }
00487 load_arg.load_pid = getpid();
00488 if(m_pfm.pfm_load_context(fd, &load_arg) == -1)
00489 {
00490 log << MSG::ERROR << "ERROR: Could not load context. Aborting..." << endmsg;
00491
00492
00493 }
00494
00495 m_pfm.pfm_start(fd, NULL);
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505 void PerfMonAuditor::stoppm()
00506 {
00507 MsgStream log(msgSvc(), name());
00508 m_pfm.pfm_stop(fd);
00509 if(m_pfm.pfm_read_pmds(fd, pd, inp.pfp_event_count) == -1)
00510 {
00511 log << MSG::ERROR << "Could not read pmds" << endmsg;
00512 }
00513 for(int i=0; i<used_counters_number; i++)
00514 {
00515 results[i][(alg_stack.top().first)->name()].push_back(alg_stack.top().second[i] + pd[i].reg_value);
00516 }
00517
00518 close(fd);
00519 }
00520
00521
00522 void PerfMonAuditor::pausepm()
00523 {
00524 MsgStream log(msgSvc(), name());
00525 m_pfm.pfm_stop(fd);
00526 if(m_pfm.pfm_read_pmds(fd, pd, inp.pfp_event_count) == -1)
00527 {
00528 log << MSG::ERROR << "Could not read pmds" << endmsg;
00529 }
00530
00531 for(int i=0; i<used_counters_number; i++)
00532 {
00533 alg_stack.top().second[i] += pd[i].reg_value;
00534 }
00535
00536 close(fd);
00537 }
00538
00539
00540
00541
00542
00543 void PerfMonAuditor::finalizepm()
00544 {
00545 MsgStream log(msgSvc(), name());
00546 log << MSG::INFO << "start of finalizepm ucn:" << used_counters_number << endmsg;
00547 char filename[MAX_OUTPUT_FILENAME_LENGTH];
00548 char to_cat[50];
00549 FILE *outfile;
00550 for(int i=0; i<used_counters_number; i++)
00551 {
00552 bzero(filename, MAX_OUTPUT_FILENAME_LENGTH);
00553 sprintf(filename, "%s_%s", prefix_cstr, event_cstr[i]);
00554 for(int j=0; j<(int)strlen(filename); j++)
00555 {
00556 if(filename[j]==':')
00557 {
00558 filename[j]='-';
00559 }
00560 }
00561 bzero(to_cat, 50);
00562 if(inv[i])
00563 {
00564 strcpy(to_cat, "_INV_1");
00565 }
00566 if(cmask[i]>0)
00567 {
00568 sprintf(to_cat, "%s_CMASK_%d", to_cat, cmask[i]);
00569 }
00570 sprintf(filename, "%s%s.txt", filename, to_cat);
00571 log << MSG::INFO << "Filename:" << filename << endmsg;
00572 outfile = fopen(filename, "w");
00573 if(nehalem)
00574 {
00575 fprintf(outfile, "NHM ");
00576 }
00577 else if(westmere)
00578 {
00579 fprintf(outfile, "WSM ");
00580 }
00581 else if(core)
00582 {
00583 fprintf(outfile, "CORE ");
00584 }
00585 fprintf(outfile, "%s %d %d %d\n", event_cstr[i], cmask[i], inv[i], sp[i]);
00586 for(std::map<std::string, std::vector<unsigned long int> >::iterator it=(results[i]).begin(); it!=(results[i]).end(); it++)
00587 {
00588 fprintf(outfile, "%s\n", (it->first).c_str());
00589 for(std::vector<unsigned long int>::iterator j=(it->second).begin(); j!=(it->second).end(); j++)
00590 {
00591 fprintf(outfile, "%lu\n", *j);
00592 }
00593 }
00594 fclose(outfile);
00595 }
00596 }
00597
00598 StatusCode PerfMonAuditor::initialize()
00599 {
00600 MsgStream log(msgSvc(), name());
00601
00602 if (!m_pfm.loaded) {
00603 log << MSG::ERROR << "pfm library could not be loaded" << endmsg;
00604 return false;
00605 }
00606
00607 log << MSG::INFO << "Initializing..." << endmsg;
00608 StatusCode sc = Auditor::initialize() ;
00609 if(sc.isFailure())
00610 {
00611 return sc;
00612 }
00613 used_counters_number = 0;
00614 for(int i=0; i<MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS; i++)
00615 {
00616 if(event_str[i].length()>0) used_counters_number++;
00617 }
00618 for(int i=0; i<MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS; i++)
00619 {
00620 strcpy(event_cstr[i], event_str[i].c_str());
00621 }
00622 strcpy(prefix_cstr, prefix.c_str());
00623
00624 if(m_pfm.pfm_initialize() != PFMLIB_SUCCESS)
00625 {
00626 log << MSG::ERROR << "Cannot initialize perfmon!!" << endmsg;
00627 }
00628 ph_ev_count = 0;
00629 first_alg = true;
00630 event_count_reached = false;
00631 nehalem = false;
00632 core = false;
00633 westmere = false;
00634 if(family.compare("CORE")==0) core = true;
00635 else if(family.compare("NEHALEM")==0) nehalem = true;
00636 else if(family.compare("WESTMERE")==0) westmere = true;
00637 else
00638 {
00639 log << MSG::ERROR << "ERROR: Unsupported processor family " << family << ". aborting..." << endmsg;
00640 }
00641
00642 log << MSG::INFO << "Initialized!" << endmsg;
00643 return StatusCode::SUCCESS ;
00644 }
00645
00646
00647
00648
00649
00650 void PerfMonAuditor::process_smpl_buf(pfm_dfl_smpl_hdr_t *hdr, size_t entry_size)
00651 {
00653 pfm_dfl_smpl_entry_t *ent;
00654 size_t pos, count;
00655 uint64_t entry;
00656 if(hdr->hdr_overflows == last_overflow && hdr->hdr_count == last_count)
00657 {
00658 printf("skipping identical set of samples...\n");
00659 return;
00660 }
00661 count = hdr->hdr_count;
00662 ent = (pfm_dfl_smpl_entry_t *)(hdr+1);
00663 pos = (unsigned long)ent;
00664 entry = collected_samples;
00665 while(count--)
00666 {
00667
00668 if(ent->ovfl_pmd<=3)
00669 {
00670 ((samples[ent->ovfl_pmd])[(alg_stack.top().first)->name()])[(unsigned long)(ent->ip)]++;
00671 }
00672 pos += entry_size;
00673 ent = (pfm_dfl_smpl_entry_t *)pos;
00674 entry++;
00675 }
00676 collected_samples = entry;
00677 last_overflow = hdr->hdr_overflows;
00678 if (last_count != hdr->hdr_count && (last_count || last_overflow == 0))
00679 {
00680 collected_partial += hdr->hdr_count;
00681 }
00682 last_count = hdr->hdr_count;
00683 return;
00684 }
00685
00686
00687
00688
00689
00690
00691 void PerfMonAuditor::sigio_handler(int , struct siginfo *, struct sigcontext *)
00692 {
00693
00694 PFMon& pfm = PFMon::instance();
00695 pfarg_msg_t msg;
00696 int fd = ctx_fd;
00697 int r;
00698 if(fd != ctx_fd)
00699 {
00700
00701 }
00702 if(pfm.pfm_read_pmds(fd, pd_smpl+1, 1) == -1)
00703 {
00704
00705 }
00706 while(true)
00707 {
00708 r = read(fd, &msg, sizeof(msg));
00709 if(r!=sizeof(msg))
00710 {
00711 if(r==-1 && errno==EINTR)
00712 {
00713 printf("read interrupted, retrying\n");
00714 continue;
00715 }
00716
00717 }
00718 break;
00719 }
00720 switch(msg.type)
00721 {
00722 case PFM_MSG_OVFL:
00723 process_smpl_buf(hdr, entry_size);
00724 ovfl_count++;
00725 if(pfm.pfm_restart(fd))
00726 {
00727 if(errno!=EBUSY)
00728 {
00729
00730 }
00731 else
00732 {
00733 printf("pfm_restart: task probably terminated \n");
00734 }
00735 }
00736 break;
00737 default:
00738
00739 break;
00740 }
00741
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 void PerfMonAuditor::start_smpl()
00754 {
00755 MsgStream log(msgSvc(), name());
00756 ovfl_count = 0;
00757 num_smpl_pmds = 0;
00758 last_overflow = ~0;
00759 max_pmd = 0;
00760 memset(&pfmlib_options, 0, sizeof(pfmlib_options));
00761 pfmlib_options.pfm_debug = 0;
00762 pfmlib_options.pfm_verbose = 0;
00763 m_pfm.pfm_set_options(&pfmlib_options);
00764 ret = m_pfm.pfm_initialize();
00765 if(ret != PFMLIB_SUCCESS)
00766 {
00767 log << MSG::ERROR << "ERROR: Cannot initialize library: " << m_pfm.pfm_strerror(ret) << ". Aborting..." << endmsg;
00768 }
00769 struct sigaction act;
00770 memset(&act, 0, sizeof(act));
00771 act.sa_handler = (sig_t)sigio_handler;
00772
00773 sigaction(SIGIO, &act, 0);
00774 memset(&ctx, 0, sizeof(ctx));
00775 memset(&buf_arg, 0, sizeof(buf_arg));
00776 memset(&inp,0, sizeof(inp));
00777 memset(&outp,0, sizeof(outp));
00778 memset(pd_smpl, 0, sizeof(pd_smpl));
00779 memset(pc, 0, sizeof(pc));
00780 memset(&load_args, 0, sizeof(load_args));
00781 m_pfm.pfm_get_num_counters(&num_counters);
00782 memset(¶ms, 0, sizeof(params));
00783 memset(&nhm_params, 0, sizeof(nhm_params));
00784
00785 for(int i=0; i<used_counters_number; i++)
00786 {
00787 ret = m_pfm.pfm_find_full_event(event_cstr[i], &inp.pfp_events[i]);
00788 if(ret != PFMLIB_SUCCESS)
00789 {
00790 log << MSG::ERROR << "ERROR: cannot find event: " << event_cstr[i] << ". Aborting..." << endmsg;
00791 }
00792 }
00793 inp.pfp_dfl_plm = PFM_PLM3;
00794 inp.pfp_event_count = 4;
00795 for(int i=0; i<used_counters_number; i++)
00796 {
00797 if(inv[i])
00798 {
00799 (params.pfp_core_counters[i]).flags |= PFM_CORE_SEL_INV;
00800 (nhm_params.pfp_nhm_counters[i]).flags |= PFM_NHM_SEL_INV;
00801 }
00802 if(cmask[i]>0)
00803 {
00804 (params.pfp_core_counters[i]).cnt_mask = cmask[i];
00805 (nhm_params.pfp_nhm_counters[i]).cnt_mask = cmask[i];
00806 }
00807 }
00808 if(nehalem || westmere)
00809 {
00810 ret = m_pfm.pfm_dispatch_events(&inp, &nhm_params, &outp, NULL);
00811 }
00812 else
00813 {
00814 ret = m_pfm.pfm_dispatch_events(&inp, ¶ms, &outp, NULL);
00815 }
00816 if(ret != PFMLIB_SUCCESS)
00817 {
00818 log << MSG::ERROR << "ERROR: cannot configure events: " << m_pfm.pfm_strerror(ret) << ". Aborting..." << endmsg;
00819 }
00820 for(unsigned int i=0; i<outp.pfp_pmc_count; i++)
00821 {
00822 pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
00823 pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
00824 }
00825 for(unsigned int i=0; i<outp.pfp_pmd_count; i++)
00826 {
00827 pd_smpl[i].reg_num = outp.pfp_pmds[i].reg_num;
00828 if(i)
00829 {
00830 pfm_bv_set(pd_smpl[0].reg_smpl_pmds, pd_smpl[i].reg_num);
00831 if(pd_smpl[i].reg_num>max_pmd)
00832 {
00833 max_pmd = pd_smpl[i].reg_num;
00834 }
00835 num_smpl_pmds++;
00836 }
00837 }
00838 for(int i=0; i<used_counters_number; i++)
00839 {
00840 pd_smpl[i].reg_flags |= PFM_REGFL_OVFL_NOTIFY | PFM_REGFL_RANDOM;
00841 pfm_bv_copy(pd_smpl[i].reg_reset_pmds, pd_smpl[i].reg_smpl_pmds, max_pmd);
00842 pd_smpl[i].reg_value = (uint64_t)(sp[i] * -1);
00843 pd_smpl[i].reg_short_reset = (uint64_t)(sp[i] * -1);
00844 pd_smpl[i].reg_long_reset = (uint64_t)(sp[i] * -1);
00845 pd_smpl[i].reg_random_seed = 5;
00846 pd_smpl[i].reg_random_mask = 0xff;
00847 }
00848 entry_size = sizeof(pfm_dfl_smpl_entry_t)+(num_smpl_pmds<<3);
00849 ctx.ctx_flags = 0;
00850 buf_arg.buf_size = 3*getpagesize()+512;
00851 ctx_fd = m_pfm.pfm_create_context(&ctx, (char *)FMT_NAME, &buf_arg, sizeof(buf_arg));
00852 if(ctx_fd==-1)
00853 {
00854 if(errno==ENOSYS)
00855 {
00856 log << MSG::ERROR << "ERROR: Your kernel does not have performance monitoring support! Aborting..." << endmsg;
00857 }
00858 log << MSG::ERROR << "ERROR: Can't create PFM context " << strerror(errno) << ". Aborting..." << endmsg;
00859 }
00860 buf_addr = mmap(NULL, (size_t)buf_arg.buf_size, PROT_READ, MAP_PRIVATE, ctx_fd, 0);
00861 if(buf_addr==MAP_FAILED)
00862 {
00863 log << MSG::ERROR << "ERROR: cannot mmap sampling buffer: " << strerror(errno) << ". Aborting..." << endmsg;
00864 }
00865 hdr = (pfm_dfl_smpl_hdr_t *)buf_addr;
00866 if(PFM_VERSION_MAJOR(hdr->hdr_version)<1)
00867 {
00868 log << MSG::ERROR << "ERROR: invalid buffer format version. Aborting..." << endmsg;
00869 }
00870 if(m_pfm.pfm_write_pmcs(ctx_fd, pc, outp.pfp_pmc_count))
00871 {
00872 log << MSG::ERROR << "ERROR: pfm_write_pmcs error errno " << strerror(errno) << ". Aborting..." << endmsg;
00873 }
00874 if(m_pfm.pfm_write_pmds(ctx_fd, pd_smpl, outp.pfp_pmd_count))
00875 {
00876 log << MSG::ERROR << "ERROR: pfm_write_pmds error errno " << strerror(errno) << ". Aborting..." << endmsg;
00877 }
00878 load_args.load_pid = getpid();
00879 if(m_pfm.pfm_load_context(ctx_fd, &load_args))
00880 {
00881 log << MSG::ERROR << "ERROR: pfm_load_context error errno " << strerror(errno) << ". Aborting..." << endmsg;
00882 }
00883 ret = fcntl(ctx_fd, F_SETFL, fcntl(ctx_fd, F_GETFL, 0) | O_ASYNC);
00884 if(ret == -1)
00885 {
00886 log << MSG::ERROR << "ERROR: cannot set ASYNC: " << strerror(errno) << ". Aborting..." << endmsg;
00887 }
00888 ret = fcntl(ctx_fd, F_SETOWN, getpid());
00889 if(ret == -1)
00890 {
00891 log << MSG::ERROR << "ERROR: cannot setown: " << strerror(errno) << ". Aborting..." << endmsg;
00892 }
00893
00894 m_pfm.pfm_start(ctx_fd, NULL);
00895 }
00896
00897
00898
00899
00900
00901 void PerfMonAuditor::stop_smpl()
00902 {
00903 MsgStream log(msgSvc(), name());
00904 m_pfm.pfm_self_stop(ctx_fd);
00905 process_smpl_buf(hdr, entry_size);
00906 close(ctx_fd);
00907 ret = munmap(hdr, (size_t)buf_arg.buf_size);
00908 if(ret)
00909 {
00910 log << MSG::ERROR << "Cannot unmap buffer: %s" << strerror(errno) << endmsg;
00911 }
00912 return;
00913 }
00914
00915
00916
00917
00918
00919
00920 void PerfMonAuditor::finalize_smpl()
00921 {
00922 MsgStream log(msgSvc(), name());
00923 char filename[MAX_OUTPUT_FILENAME_LENGTH];
00924 bzero(filename, MAX_OUTPUT_FILENAME_LENGTH);
00925 char to_cat[50];
00926 gzFile outfile;
00927 int err;
00928 for(int i=0; i<used_counters_number; i++)
00929 {
00930 sprintf(filename, "%s_%s", prefix_cstr, event_cstr[i]);
00931 for(int j=0; j<(int)strlen(filename); j++)
00932 {
00933 if(filename[j]==':')
00934 {
00935 filename[j]='-';
00936 }
00937 }
00938 bzero(to_cat, 50);
00939 if(inv[i])
00940 {
00941 strcpy(to_cat, "_INV_1");
00942 }
00943 if(cmask[i]>0)
00944 {
00945 sprintf(to_cat, "%s_CMASK_%d", to_cat, cmask[i]);
00946 }
00947 sprintf(filename, "%s%s.txt.gz", filename, to_cat);
00948 outfile = gzopen(filename, "wb");
00949 if(outfile!=NULL)
00950 {
00951 if(nehalem)
00952 {
00953 gzprintf(outfile, "NHM ");
00954 }
00955 else if(westmere)
00956 {
00957 gzprintf(outfile, "WSM ");
00958 }
00959 else if(core)
00960 {
00961 gzprintf(outfile, "CORE ");
00962 }
00963 if(gzprintf(outfile, "%s %d %d %d\n", event_cstr[i], cmask[i], inv[i], sp[i]) < (int)strlen(event_cstr[i]))
00964 {
00965 log << MSG::ERROR << "ERROR: gzputs err: " << gzerror(outfile, &err) << ". Aborting..." << endmsg;
00966 }
00967 for(std::map<std::string, std::map<unsigned long, unsigned int> >::iterator it=samples[i].begin(); it!=samples[i].end(); it++)
00968 {
00969 unsigned long long sum = 0;
00970 for(std::map<unsigned long, unsigned int>::iterator jt=(it->second).begin(); jt!=(it->second).end(); jt++)
00971 {
00972 sum += jt->second;
00973 }
00974 if(gzprintf(outfile, "%s%%%llu\n", (it->first).c_str(), sum) < (int)((it->first).length()))
00975 {
00976 log << MSG::ERROR << "ERROR: gzputs err: " << gzerror(outfile, &err) << ". Aborting..." << endmsg;
00977 }
00978 for(std::map<unsigned long, unsigned int>::iterator jt=(it->second).begin(); jt!=(it->second).end(); jt++)
00979 {
00980 char sym_name[SYM_NAME_MAX_LENGTH];
00981 bzero(sym_name, SYM_NAME_MAX_LENGTH);
00982 const char *libName;
00983 const char *symbolName;
00984 int libOffset = 0;
00985 int offset = 0;
00986 void *sym_addr = IgHookTrace::tosymbol((void *)(jt->first));
00987 if(sym_addr != NULL)
00988 {
00989 bool success = IgHookTrace::symbol(sym_addr, symbolName, libName, offset, libOffset);
00990 if(success)
00991 {
00992 if(symbolName!=NULL && strlen(symbolName)>0)
00993 {
00994 strcpy(sym_name, symbolName);
00995 strcat(sym_name, " ");
00996 }
00997 else
00998 {
00999 strcpy(sym_name, "??? ");
01000 }
01001 if(libName!=NULL && strlen(libName)>0)
01002 {
01003 strcat(sym_name, libName);
01004 strcat(sym_name, " ");
01005 }
01006 else
01007 {
01008 strcat(sym_name, "??? ");
01009 }
01010 sprintf(sym_name, "%s%d ", sym_name, libOffset);
01011 if(strlen(sym_name)<=0)
01012 {
01013 log << MSG::ERROR << "ERROR: Symbol name length is zero. Aborting..." << endmsg;
01014 }
01015 }
01016 else
01017 {
01018 strcpy(sym_name,"??? ??? 0 ");
01019 }
01020 }
01021 else
01022 {
01023 strcpy(sym_name,"??? ??? 0 ");
01024 }
01025 if(gzprintf(outfile, "%s %d\n", sym_name, jt->second) < (int)strlen(sym_name))
01026 {
01027 log << MSG::ERROR << "ERROR: gzputs err: " << gzerror(outfile, &err) << endmsg;
01028 }
01029 }
01030 }
01031 }
01032 else
01033 {
01034 log << MSG::ERROR << "ERROR: Could not open file: " << filename << ". Aborting..." << endmsg;
01035 }
01036 gzclose(outfile);
01037 }
01038 }
01039
01040
01041
01042 StatusCode PerfMonAuditor::finalize()
01043 {
01044 if(sampling == 0) finalizepm();
01045 else finalize_smpl();
01046 return Auditor::finalize();
01047 }
01048
01049
01050 void PerfMonAuditor::before(StandardEventType evt, INamedInterface *alg)
01051 {
01052 switch(evt)
01053 {
01054 case IAuditor::Initialize:
01055 i_beforeInitialize(alg);
01056 break;
01057 case IAuditor::Execute:
01058 i_beforeExecute(alg);
01059 break;
01060 default:
01061 break;
01062 }
01063 return;
01064 }
01065
01066 void PerfMonAuditor::after(StandardEventType evt, INamedInterface *alg, const StatusCode &)
01067 {
01068 switch(evt)
01069 {
01070 case IAuditor::Initialize:
01071 i_afterInitialize(alg);
01072 break;
01073 case IAuditor::Execute:
01074 i_afterExecute(alg);
01075 break;
01076 default:
01077 break;
01078 }
01079 return;
01080 }
01081
01082 void PerfMonAuditor::i_beforeInitialize(INamedInterface* alg)
01083 {
01084 if(alg == 0)
01085 {
01086 return;
01087 }
01088 return;
01089 }
01090
01091 void PerfMonAuditor::i_afterInitialize(INamedInterface* alg)
01092 {
01093 if(alg == 0)
01094 {
01095 return;
01096 }
01097 return;
01098 }
01099
01100 void PerfMonAuditor::i_beforeExecute(INamedInterface* alg)
01101 {
01102 MsgStream log(msgSvc(), name());
01103 if(alg == 0)
01104 {
01105 return;
01106 }
01107
01108 if(first_alg)
01109 {
01110 first_alg = false;
01111 first_alg_name = alg->name();
01112
01113 }
01114 if(!event_count_reached)
01115 {
01116 if(!first_alg_name.compare(alg->name()))
01117 {
01118 ph_ev_count++;
01119
01120 if(ph_ev_count==start_at_event)
01121 {
01122 event_count_reached = true;
01123
01124 }
01125 }
01126 }
01127 if(event_count_reached)
01128 {
01129
01130
01131 if(!alg_stack.empty())
01132 {
01133 if(sampling == 0) pausepm();
01134 else stop_smpl();
01135 }
01136 ++m_indent;
01137 std::vector <unsigned long int> zeroes(4,0);
01138 alg_stack.push(std::make_pair(alg, zeroes));
01139 if(sampling == 0) startpm();
01140 else start_smpl();
01141 }
01142 return;
01143 }
01144
01145 void PerfMonAuditor::i_afterExecute(INamedInterface* alg)
01146 {
01147 MsgStream log(msgSvc(), name());
01148 if(alg == 0)
01149 {
01150 return;
01151 }
01152
01153 if(event_count_reached)
01154 {
01155
01156
01157 if(sampling == 0) stoppm();
01158 else stop_smpl();
01159 alg_stack.pop();
01160 --m_indent;
01161 if(!alg_stack.empty())
01162 {
01163 if(sampling == 0) startpm();
01164 else start_smpl();
01165 }
01166 }
01167 return;
01168 }
01169
01170 DECLARE_AUDITOR_FACTORY(PerfMonAuditor)