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