Gaudi Framework, version v24r2

Home   Generated: Wed Dec 4 2013
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
PerfMonAuditor.cpp
Go to the documentation of this file.
1 // $Id: PerfMonAuditor.cpp,v 0.1 2009/10/28 Daniele Francesco Kruse $
2 // ============================================================================
3 // CVS tag $Name: $, version $Revision: 0.1 $
4 // ============================================================================
5 
6 #include "GaudiKernel/Auditor.h"
7 #include "GaudiKernel/IToolSvc.h"
10 #include "GaudiKernel/IToolSvc.h"
11 #include "GaudiKernel/VectorMap.h"
12 #include "GaudiKernel/HashMap.h"
13 #include "GaudiKernel/AudFactory.h"
14 #include "GaudiKernel/MsgStream.h"
15 
16 /*BEGIN: perfmon*/
17 #include <iostream>
18 #include <string>
19 #include <cstring>
20 #include <fstream>
21 #include <perfmon/pfmlib.h>
22 #include <perfmon/pfmlib_core.h>
24 #include <vector>
25 #include <map>
26 #include <utility>
27 #include <sstream>
28 
29 #include <perfmon/perfmon.h>
31 
33 
35 
36 
37 
38 #include <sys/types.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <errno.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <signal.h>
46 #include <stdarg.h>
47 #include <stdint.h>
48 #include <getopt.h>
49 #include <time.h>
50 #include <sys/ptrace.h>
51 #include <sys/wait.h>
52 #include <sys/mman.h>
53 #include <sys/time.h>
54 #include <sys/resource.h>
55 #include <unistd.h>
56 #include <fcntl.h>
57 #include <zlib.h>
58 
59 #include <algorithm>
60 #include <list>
61 #include <stack>
62 #include <cmath>
63 #include <sys/stat.h>
64 #include "IgHook_IgHookTrace.h"
65 
66 // dlopen (link with -ldl)
67 #include <dlfcn.h>
68 
69 
70 #define MAX_EVT_NAME_LEN 256
71 #define NUM_PMCS PFMLIB_MAX_PMCS
72 #define NUM_PMDS PFMLIB_MAX_PMDS
73 #define FMT_NAME PFM_DFL_SMPL_NAME
74 #define BPL (sizeof(uint64_t)<<3)
75 #define LBPL 6
76 
77 #define SYM_NAME_MAX_LENGTH 10000
78 #define MAX_OUTPUT_FILENAME_LENGTH 1024
79 #define MAX_EVENT_NAME_LENGTH 500
80 #define MAX_PREFIX_NAME_LENGTH 1024
81 #define FILENAME_MAX_LENGTH 1024
82 
83 #define MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS 4
84 
85 #define cpuid(func,ax,bx,cx,dx) __asm__ __volatile__ ("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
86 
87 
90 static int ctx_fd;
92 static uint64_t ovfl_count;
93 static size_t entry_size;
94 static unsigned int num_smpl_pmds;
95 static std::vector<std::map<std::string, std::map<unsigned long, unsigned int> > > samples(MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS); //a map of modules each containing numbers of samples of their addresses
96 static std::vector<std::map<std::string, std::vector<unsigned long int> > > results(MAX_NUMBER_OF_PROGRAMMABLE_COUNTERS); //a map of modules and their result values across multiple events
97 static uint64_t last_overflow;
98 static uint64_t last_count;
100 
102 /*END: perfmon*/
103 
104 
105 
106 namespace {
108  template <typename T>
109  inline T function_cast(void *p) {
110  union {
111  void* object;
112  T function;
113  } caster;
114  caster.object = p;
115  return caster.function;
116  }
117  class PFMon {
118  public:
119  bool loaded;
120  typedef void (*pfm_stop_t)(int);
121  pfm_stop_t pfm_stop;
122  typedef void (*pfm_self_stop_t)(int);
123  pfm_self_stop_t pfm_self_stop;
124  typedef os_err_t (*pfm_restart_t)(int);
125  pfm_restart_t pfm_restart;
126  typedef int (*pfm_read_pmds_t)(int, pfarg_pmd_t*, int);
127  pfm_read_pmds_t pfm_read_pmds;
128  typedef pfm_err_t (*pfm_initialize_t)();
129  pfm_initialize_t pfm_initialize;
130  typedef pfm_err_t (*pfm_find_full_event_t)(const char *, pfmlib_event_t *);
131  pfm_find_full_event_t pfm_find_full_event;
132  typedef pfm_err_t (*pfm_dispatch_events_t)(pfmlib_input_param_t *, void *, pfmlib_output_param_t *, void *);
133  pfm_dispatch_events_t pfm_dispatch_events;
134  typedef os_err_t (*pfm_create_context_t)(pfarg_ctx_t *, char *, void *, size_t);
135  pfm_create_context_t pfm_create_context;
136  typedef os_err_t (*pfm_write_pmcs_t)(int, pfarg_pmc_t *, int);
137  pfm_write_pmcs_t pfm_write_pmcs;
138  typedef os_err_t (*pfm_write_pmds_t)(int, pfarg_pmd_t *, int);
139  pfm_write_pmds_t pfm_write_pmds;
140  typedef os_err_t (*pfm_load_context_t)(int, pfarg_load_t *);
141  pfm_load_context_t pfm_load_context;
142  typedef os_err_t (*pfm_start_t)(int fd, pfarg_start_t *);
143  pfm_start_t pfm_start;
144  typedef char* (*pfm_strerror_t)(int);
145  pfm_strerror_t pfm_strerror;
146  typedef pfm_err_t (*pfm_set_options_t)(pfmlib_options_t *);
147  pfm_set_options_t pfm_set_options;
148  typedef pfm_err_t (*pfm_get_num_counters_t)(unsigned int *);
149  pfm_get_num_counters_t pfm_get_num_counters;
150  static PFMon &instance() {
151  return s_instance;
152  }
153  private:
154  // static void failure() { throw 1; }
155 
156  void* handle;
157 
158  PFMon() {
159  handle = dlopen("libpfm.so", RTLD_NOW);
160  if (handle) { loaded = true; } else { loaded = false; }
161  if (loaded) {
162  pfm_start = function_cast<pfm_start_t>(dlsym(handle, "pfm_start"));
163  pfm_stop = function_cast<pfm_stop_t>(dlsym(handle, "pfm_stop"));
164  pfm_self_stop = function_cast<pfm_self_stop_t>(dlsym(handle, "pfm_stop")); //it's the same
165  pfm_restart = function_cast<pfm_restart_t>(dlsym(handle, "pfm_restart"));
166  pfm_read_pmds = function_cast<pfm_read_pmds_t>(dlsym(handle, "pfm_read_pmds"));
167  pfm_initialize = function_cast<pfm_initialize_t>(dlsym(handle, "pfm_initialize"));
168  pfm_find_full_event = function_cast<pfm_find_full_event_t>(dlsym(handle, "pfm_find_full_event"));
169  pfm_dispatch_events = function_cast<pfm_dispatch_events_t>(dlsym(handle, "pfm_dispatch_events"));
170  pfm_create_context = function_cast<pfm_create_context_t>(dlsym(handle, "pfm_create_context"));
171  pfm_write_pmcs = function_cast<pfm_write_pmcs_t>(dlsym(handle, "pfm_write_pmcs"));
172  pfm_write_pmds = function_cast<pfm_write_pmds_t>(dlsym(handle, "pfm_write_pmds"));
173  pfm_load_context = function_cast<pfm_load_context_t>(dlsym(handle, "pfm_load_context"));
174  pfm_strerror = function_cast<pfm_strerror_t>(dlsym(handle, "pfm_strerror"));
175  pfm_set_options = function_cast<pfm_set_options_t>(dlsym(handle, "pfm_set_options"));
176  pfm_get_num_counters = function_cast<pfm_get_num_counters_t>(dlsym(handle, "pfm_get_num_counters"));
177  } else {
178  // pfm_start = pfm_stop = pfm_self_stop = pfm_restart = pfm_read_pmds = pfm_initialize = pfm_find_full_event = pfm_dispatch_events = pfm_create_context = pfm_write_pmcs = pfm_write_pmds = pfm_load_context = pfm_strerror = pfm_set_options = pfm_get_num_counters = failure;
179  }
180  }
181  ~PFMon() {
182  if (handle) dlclose(handle);
183  }
184 
185  static PFMon s_instance;
186  };
187 
188  PFMon PFMon::s_instance;
189 }
190 
191 
192 
193 // ============================================================================
194 // GaudiAlg
195 // ============================================================================
196 // ============================================================================
206 class PerfMonAuditor: virtual public Auditor
207 {
208  public:
209  virtual void before(StandardEventType evt, INamedInterface* alg);
210  virtual void after(StandardEventType evt, INamedInterface* alg, const StatusCode &sc);
211  using Auditor::before;
212  using Auditor::after;
213 
214  private:
217  void i_beforeExecute(INamedInterface* alg);
218  void i_afterExecute(INamedInterface* alg);
219 
220  public:
221  virtual StatusCode initialize();
222  virtual StatusCode finalize();
223  int is_nehalem() {
224 #ifdef __ICC
225 // Disable ICC remark #593: variable "x" was set but never used
226 #pragma warning(push)
227 #pragma warning(disable:593)
228 #endif
229  int a,b,c,d;
230  cpuid(1,a,b,c,d);
231  int sse4_2_mask = 1 << 20;
232  if(c & sse4_2_mask) return 1; else return 0;
233 #ifdef __ICC
234 #pragma warning(pop)
235 #endif
236  }
237 
238  private:
239  PFMon &m_pfm;
240 /*
241  typedef void (*pfm_stop_t)(int);
242  pfm_stop_t pfm_stop;
243  typedef void (*pfm_self_stop_t)(int);
244  pfm_self_stop_t pfm_self_stop;
245 
246  typedef os_err_t (*pfm_restart_t)(int);
247  pfm_restart_t pfm_restart;
248 
249  //typedef int (*pfm_read_pmds_t)(int, pfarg_pmd_t*, int);
250  //pfm_read_pmds_t pfm_read_pmds;
251 
252  typedef pfm_err_t (*pfm_initialize_t)();
253  pfm_initialize_t pfm_initialize;
254  typedef pfm_err_t (*pfm_find_full_event_t)(const char *, pfmlib_event_t *);
255  pfm_find_full_event_t pfm_find_full_event;
256  typedef pfm_err_t (*pfm_dispatch_events_t)(pfmlib_input_param_t *, void *, pfmlib_output_param_t *, void *);
257  pfm_dispatch_events_t pfm_dispatch_events;
258  typedef os_err_t (*pfm_create_context_t)(pfarg_ctx_t *, char *, void *, size_t);
259  pfm_create_context_t pfm_create_context;
260  typedef os_err_t (*pfm_write_pmcs_t)(int, pfarg_pmc_t *, int);
261  pfm_write_pmcs_t pfm_write_pmcs;
262  typedef os_err_t (*pfm_write_pmds_t)(int, pfarg_pmd_t *, int);
263  pfm_write_pmds_t pfm_write_pmds;
264  typedef os_err_t (*pfm_load_context_t)(int, pfarg_load_t *);
265  pfm_load_context_t pfm_load_context;
266  typedef os_err_t (*pfm_start_t)(int fd, pfarg_start_t *);
267  pfm_start_t pfm_start;
268  typedef char* (*pfm_strerror_t)(int);
269  pfm_strerror_t pfm_strerror;
270  typedef pfm_err_t (*pfm_set_options_t)(pfmlib_options_t *);
271  pfm_set_options_t pfm_set_options;
272  typedef pfm_err_t (*pfm_get_num_counters_t)(unsigned int *);
273  pfm_get_num_counters_t pfm_get_num_counters;
274 */
275 
276 
277  public:
278  PerfMonAuditor(const std::string& name, ISvcLocator* pSvc): // standard constructor
279  Auditor(name, pSvc),
280  m_pfm(PFMon::instance()),
281  m_map(),
282  m_indent(0),
283  m_inEvent(false)
284  {
286 declareProperty("EVENT0", event_str[0]);
287 declareProperty("EVENT1", event_str[1]);
288 declareProperty("EVENT2", event_str[2]);
289 declareProperty("EVENT3", event_str[3]);
290 declareProperty("FAMILY", family);
291 declareProperty("PREFIX", prefix);
292 declareProperty("INV0", inv[0]);
293 declareProperty("INV1", inv[1]);
294 declareProperty("INV2", inv[2]);
295 declareProperty("INV3", inv[3]);
296 declareProperty("CMASK0", cmask[0]);
297 declareProperty("CMASK1", cmask[1]);
298 declareProperty("CMASK2", cmask[2]);
299 declareProperty("CMASK3", cmask[3]);
300 declareProperty("SP0", sp[0]);
301 declareProperty("SP1", sp[1]);
302 declareProperty("SP2", sp[2]);
303 declareProperty("SP3", sp[3]);
304 declareProperty("SAMPLE", sampling);
305 declareProperty("START_AT_EVENT", start_at_event);
306 declareProperty("IS_NEHALEM", is_nehalem_ret);
307 
308 // MsgStream log(msgSvc(), name());
309 
311 /*
312 // loading functions from PFM library
313  void* handle = dlopen("libpfm.so", RTLD_NOW);
314  if (!handle) {
315 // log << MSG::ERROR << "Cannot open library: " << dlerror() << endmsg;
316  }
317  typedef void (*hello_t)();
318  hello_t hello = (hello_t) dlsym(handle, "hello");
319  if (!hello) {
320 // log << MSG::ERROR << "Cannot load symbol 'hello': " << dlerror() << endmsg;
321  dlclose(handle);
322  }
323 
324  pfm_start = (pfm_start_t) dlsym(handle, "pfm_start");
325  pfm_stop = (pfm_stop_t) dlsym(handle, "pfm_stop");
326  pfm_self_stop = (pfm_self_stop_t) dlsym(handle, "pfm_stop"); //it's the same
327  pfm_restart = (pfm_restart_t) dlsym(handle, "pfm_restart");
328  //pfm_read_pmds = (pfm_read_pmds_t) dlsym(handle, "pfm_read_pmds");
329  pfm_initialize = (pfm_initialize_t) dlsym(handle, "pfm_initialize");
330  pfm_find_full_event = (pfm_find_full_event_t) dlsym(handle, "pfm_find_full_event");
331  pfm_dispatch_events = (pfm_dispatch_events_t) dlsym(handle, "pfm_dispatch_events");
332  pfm_create_context = (pfm_create_context_t) dlsym(handle, "pfm_create_context");
333  pfm_write_pmcs = (pfm_write_pmcs_t) dlsym(handle, "pfm_write_pmcs");
334  pfm_write_pmds = (pfm_write_pmds_t) dlsym(handle, "pfm_write_pmds");
335  pfm_load_context = (pfm_load_context_t) dlsym(handle, "pfm_load_context");
336  pfm_strerror = (pfm_strerror_t) dlsym(handle, "pfm_strerror");
337  pfm_set_options = (pfm_set_options_t) dlsym(handle, "pfm_set_options");
338  pfm_get_num_counters = (pfm_get_num_counters_t) dlsym(handle, "pfm_get_num_counters");
339  // use it to do the calculation
340 // log << MSG::INFO << "Calling hello..." << endmsg;
341 // hello();
342 
343  // close the library
344 // log << MSG::INFO << "Closing library..." << endmsg;
345  dlclose(handle);
346 */
347 
349 
350  }
351 
352  virtual ~PerfMonAuditor() {} // virtual destructor
353 
354  private:
355  PerfMonAuditor(); // the default constructor is disabled
356  PerfMonAuditor(const PerfMonAuditor&); // copy constructor is disabled
357  PerfMonAuditor& operator=(const PerfMonAuditor&); // assignement operator is disabled
358 
359  private:
362  int m_indent; // indentation level
363  bool m_inEvent; // "In event" flag
364 
365  private:
367 
374  int fd;
375  unsigned int i;
376  int ret;
377  void startpm();
378  void pausepm();
379  void stoppm();
380  void finalizepm();
386  unsigned int ph_ev_count;
389  unsigned int start_at_event;
393  bool nehalem;
394  bool westmere;
395  bool core;
396 
397  bool sampling;
398  int detect_unavail_pmu_regs(int fd, pfmlib_regmask_t *r_pmcs, pfmlib_regmask_t *r_pmds);
399  int detect_unavail_pmcs(int fd, pfmlib_regmask_t *r_pmcs){return detect_unavail_pmu_regs(fd, r_pmcs, NULL);}
400  void pfm_bv_set(uint64_t *bv, uint16_t rnum){bv[rnum>>LBPL] |= 1UL << (rnum&(BPL-1));}
401  int pfm_bv_isset(uint64_t *bv, uint16_t rnum){return bv[rnum>>LBPL] & (1UL <<(rnum&(BPL-1))) ? 1 : 0;}
402  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));}}
403  static void process_smpl_buf(pfm_dfl_smpl_hdr_t *hdr, size_t entry_size);
404  static void sigio_handler(int, struct siginfo *, struct sigcontext *); // dlopen ==>
405  //void sigio_handler(int, struct siginfo *, struct sigcontext *);
406  void start_smpl();
407  void stop_smpl();
408  void finalize_smpl();
411  void *buf_addr;
412  unsigned num_counters;
413  unsigned int max_pmd;
415 
416 
417  int level;
418 
419  bool first_alg;
422 
423 
424 };
425 
427 {
428  MsgStream log(msgSvc(), name());
429  memset(&ctx,0, sizeof(ctx));
430  memset(&inp,0, sizeof(inp));
431  memset(&outp,0, sizeof(outp));
432  memset(pd, 0, sizeof(pd));
433  memset(pc, 0, sizeof(pc));
434  memset(&load_arg, 0, sizeof(load_arg));
435  memset(&params, 0, sizeof(params));
436  memset(&nhm_params, 0, sizeof(nhm_params));
437 
438  for(int i=0; i<used_counters_number; i++)
439  {
440  ret = m_pfm.pfm_find_full_event(event_cstr[i], &inp.pfp_events[i]);
441  if(ret != PFMLIB_SUCCESS)
442  {
443  log << MSG::ERROR << "ERROR: cannot find event: " << event_cstr[i] << ". Aborting..." << endmsg;
444  }
445  }
447  inp.pfp_event_count = 4;
448  for(int i=0; i<used_counters_number; i++)
449  {
450  if(inv[i])
451  {
454  }
455  if(cmask[i]>0)
456  {
457  (params.pfp_core_counters[i]).cnt_mask = cmask[i];
458  (nhm_params.pfp_nhm_counters[i]).cnt_mask = cmask[i];
459  }
460  }
461  if(nehalem || westmere)
462  {
463  ret = m_pfm.pfm_dispatch_events(&inp, &nhm_params, &outp, NULL);
464  }
465  else
466  {
467  ret = m_pfm.pfm_dispatch_events(&inp, &params, &outp, NULL);
468  }
469  if(ret != PFMLIB_SUCCESS)
470  {
471  log << MSG::ERROR << "ERROR: cannot dispatch events: " << m_pfm.pfm_strerror(ret) << ". Aborting..." << endmsg;
472  }
473  for(unsigned int i=0; i<outp.pfp_pmc_count; i++)
474  {
477  }
478  for(unsigned int i=0; i<outp.pfp_pmd_count; i++)
479  {
481  pd[i].reg_value = 0;
482  }
483  fd = m_pfm.pfm_create_context(&ctx, NULL, 0, 0);
484  if(fd == -1)
485  {
486  log << MSG::ERROR << "ERROR: Context not created. Aborting..." << endmsg;
487  }
488  if(m_pfm.pfm_write_pmcs(fd, pc, outp.pfp_pmc_count) == -1)
489  {
490  log << MSG::ERROR << "ERROR: Could not write pmcs. Aborting..." << endmsg;
491  }
492  if(m_pfm.pfm_write_pmds(fd, pd, outp.pfp_pmd_count) == -1)
493  {
494  log << MSG::ERROR << "ERROR: Could not write pmds. Aborting..." << endmsg;
495  }
496  load_arg.load_pid = getpid();
497  if(m_pfm.pfm_load_context(fd, &load_arg) == -1)
498  {
499  log << MSG::ERROR << "ERROR: Could not load context. Aborting..." << endmsg;
500 // MsgStream log(msgSvc(), name());
501 // log << MSG::ERROR << "Could not read pmds" << endmsg;
502  }
503 
504  m_pfm.pfm_start(fd, NULL);
505 }
506 
507 
508 
509 
510 
511  // stoppm()
512  // const ModuleDescription& desc : description of the module that just finished its execution (we are only interested in its name)
513  // stops the counting calling pfm_stop() and stores the counting results into the "results" map
515 {
516  MsgStream log(msgSvc(), name());
517  m_pfm.pfm_stop(fd);
518  if(m_pfm.pfm_read_pmds(fd, pd, inp.pfp_event_count) == -1)
519  {
520  log << MSG::ERROR << "Could not read pmds" << endmsg;
521  }
522  for(int i=0; i<used_counters_number; i++)
523  {
524  results[i][(alg_stack.top().first)->name()].push_back(alg_stack.top().second[i] + pd[i].reg_value);
525  }
526 
527  close(fd);
528 }
529 
530 
532 {
533  MsgStream log(msgSvc(), name());
534  m_pfm.pfm_stop(fd);
535  if(m_pfm.pfm_read_pmds(fd, pd, inp.pfp_event_count) == -1)
536  {
537  log << MSG::ERROR << "Could not read pmds" << endmsg;
538  }
539 
540  for(int i=0; i<used_counters_number; i++)
541  {
542  alg_stack.top().second[i] += pd[i].reg_value;
543  }
544 
545  close(fd);
546 }
547 
548 
549  // finalizepm()
550  // called when all the countings of the current event are finished, it dumps the results
551  // into the output file corresponding to the event being counted
553 {
554  MsgStream log(msgSvc(), name());
555  log << MSG::INFO << "start of finalizepm ucn:" << used_counters_number << endmsg;
556  char filename[MAX_OUTPUT_FILENAME_LENGTH];
557  char to_cat[50];
558  FILE *outfile;
559  for(int i=0; i<used_counters_number; i++)
560  {
561  bzero(filename, MAX_OUTPUT_FILENAME_LENGTH);
562  sprintf(filename, "%s_%s", prefix_cstr, event_cstr[i]);
563  for(int j=0; j<(int)strlen(filename); j++)
564  {
565  if(filename[j]==':')
566  {
567  filename[j]='-';
568  }
569  }
570  bzero(to_cat, 50);
571  if(inv[i])
572  {
573  strcpy(to_cat, "_INV_1");
574  }
575  if(cmask[i]>0)
576  {
577  sprintf(to_cat, "%s_CMASK_%d", to_cat, cmask[i]);
578  }
579  sprintf(filename, "%s%s.txt", filename, to_cat);
580  log << MSG::INFO << "Filename:" << filename << endmsg;
581  outfile = fopen(filename, "w");
582  if(nehalem)
583  {
584  fprintf(outfile, "NHM ");
585  }
586  else if(westmere)
587  {
588  fprintf(outfile, "WSM ");
589  }
590  else if(core)
591  {
592  fprintf(outfile, "CORE ");
593  }
594  fprintf(outfile, "%s %d %d %d\n", event_cstr[i], cmask[i], inv[i], sp[i]);
595  for(std::map<std::string, std::vector<unsigned long int> >::iterator it=(results[i]).begin(); it!=(results[i]).end(); it++)
596  {
597  fprintf(outfile, "%s\n", (it->first).c_str());
598  for(std::vector<unsigned long int>::iterator j=(it->second).begin(); j!=(it->second).end(); j++)
599  {
600  fprintf(outfile, "%lu\n", *j);
601  }
602  }
603  fclose(outfile);
604  }
605 }
606 
608 {
609  MsgStream log(msgSvc(), name());
610 
611  if (!m_pfm.loaded) {
612  log << MSG::ERROR << "pfm library could not be loaded" << endmsg;
613  return false;
614  }
615 
616  log << MSG::INFO << "Initializing..." << endmsg;
618  if(sc.isFailure())
619  {
620  return sc;
621  }
624  {
625  if(event_str[i].length()>0) used_counters_number++;
626  }
628  {
629  strcpy(event_cstr[i], event_str[i].c_str());
630  }
631  strcpy(prefix_cstr, prefix.c_str());
632 
633  if(m_pfm.pfm_initialize() != PFMLIB_SUCCESS)
634  {
635  log << MSG::ERROR << "Cannot initialize perfmon!!" << endmsg;
636  }
637  ph_ev_count = 0;
638  first_alg = true;
639  event_count_reached = false;
640  nehalem = false;
641  core = false;
642  westmere = false;
643  if(family.compare("CORE")==0) core = true;
644  else if(family.compare("NEHALEM")==0) nehalem = true;
645  else if(family.compare("WESTMERE")==0) westmere = true;
646  else
647  {
648  log << MSG::ERROR << "ERROR: Unsupported processor family " << family << ". aborting..." << endmsg;
649  }
650 
651  log << MSG::INFO << "Initialized!" << endmsg;
652  return StatusCode::SUCCESS ;
653 }
654 
655  // process_smpl_buf()
656  // pfm_dfl_smpl_hdr_t *hdr : pointer to header of the buffer containing addresses sampled during the sampling process
657  // size_t entry_size : size of each entry, used to navigate through the various entries
658  // called when the sampling buffer is full, saves the samples into memory ("samples" map)
660 {
663  size_t pos, count;
664  uint64_t entry;
665  if(hdr->hdr_overflows == last_overflow && hdr->hdr_count == last_count)
666  {
667  printf("skipping identical set of samples...\n");
668  return;
669  }
670  count = hdr->hdr_count;
671  ent = (pfm_dfl_smpl_entry_t *)(hdr+1);
672  pos = (unsigned long)ent;
673  entry = collected_samples;
674  while(count--)
675  {
676  //if(ent->ovfl_pmd>=0 && ent->ovfl_pmd<=3)
677  if(ent->ovfl_pmd<=3)
678  {
679  ((samples[ent->ovfl_pmd])[(alg_stack.top().first)->name()])[(unsigned long)(ent->ip)]++;
680  }
681  pos += entry_size;
682  ent = (pfm_dfl_smpl_entry_t *)pos;
683  entry++;
684  }
685  collected_samples = entry;
687  if (last_count != hdr->hdr_count && (last_count || last_overflow == 0))
688  {
690  }
691  last_count = hdr->hdr_count;
692  return;
693 }
694 
695  // sigio_handler()
696  // int n : signal number of the signal being delivered
697  // struct siginfo *info : pointer to a siginfo_t structure containing info about the signal
698  // struct sigcontext *sc : context of the signal, NULL in our case
699  // signal handler used to catch sampling buffer overflows. When they occur it calls the process_smpl_buf() function
700 void PerfMonAuditor::sigio_handler(int /*n*/, struct siginfo */*info*/, struct sigcontext */*sc*/)
701 {
702  //MsgStream log(msgSvc(), name());
703  PFMon& pfm = PFMon::instance();
705  int fd = ctx_fd;
706  int r;
707  if(fd != ctx_fd)
708  {
709  //log << MSG::ERROR << "ERROR: handler does not get valid file descriptor. Aborting..." << endmsg;
710  }
711  if(pfm.pfm_read_pmds(fd, pd_smpl+1, 1) == -1)
712  {
713  //log << MSG::ERROR << "ERROR: pfm_read_pmds: " << strerror(errno) << ". Aborting..." << endmsg;
714  }
715  while(true)
716  {
717  r = read(fd, &msg, sizeof(msg));
718  if(r!=sizeof(msg))
719  {
720  if(r==-1 && errno==EINTR)
721  {
722  printf("read interrupted, retrying\n");
723  continue;
724  }
725  //log << MSG::ERROR << "ERROR: cannot read overflow message: " << strerror(errno) << ". Aborting..." << endmsg;
726  }
727  break;
728  }
729  switch(msg.type)
730  {
731  case PFM_MSG_OVFL: // the sampling buffer is full
733  ovfl_count++;
734  if(pfm.pfm_restart(fd))
735  {
736  if(errno!=EBUSY)
737  {
738  //log << MSG::ERROR << "ERROR: pfm_restart error errno " << errno << ". Aborting..." << endmsg;
739  }
740  else
741  {
742  printf("pfm_restart: task probably terminated \n");
743  }
744  }
745  break;
746  default:
747  //log << MSG::ERROR << "ERROR: unknown message type " << msg.type << ". Aborting..." << endmsg;
748  break;
749  }
750 
751 }
752 
753 
754 
755 
756 
757 
758 
759  // start_smpl()
760  // const ModuleDescription& desc : description of the module that is just starting its execution (we are only interested in its name)
761  // initializes all the necessary structures to start the sampling, calling pfm_self_start()
763 {
764  MsgStream log(msgSvc(), name());
765  ovfl_count = 0;
766  num_smpl_pmds = 0;
767  last_overflow = ~0;
768  max_pmd = 0;
769  memset(&pfmlib_options, 0, sizeof(pfmlib_options));
772  m_pfm.pfm_set_options(&pfmlib_options);
773  ret = m_pfm.pfm_initialize();
774  if(ret != PFMLIB_SUCCESS)
775  {
776  log << MSG::ERROR << "ERROR: Cannot initialize library: " << m_pfm.pfm_strerror(ret) << ". Aborting..." << endmsg;
777  }
778  struct sigaction act;
779  memset(&act, 0, sizeof(act));
780  act.sa_handler = (sig_t)sigio_handler; // dlopen() ==>
781  //act.sa_handler = (sig_t)&sigio_handler;
782  sigaction(SIGIO, &act, 0);
783  memset(&ctx, 0, sizeof(ctx));
784  memset(&buf_arg, 0, sizeof(buf_arg));
785  memset(&inp,0, sizeof(inp));
786  memset(&outp,0, sizeof(outp));
787  memset(pd_smpl, 0, sizeof(pd_smpl));
788  memset(pc, 0, sizeof(pc));
789  memset(&load_args, 0, sizeof(load_args));
790  m_pfm.pfm_get_num_counters(&num_counters);
791  memset(&params, 0, sizeof(params));
792  memset(&nhm_params, 0, sizeof(nhm_params));
793 
794  for(int i=0; i<used_counters_number; i++)
795  {
796  ret = m_pfm.pfm_find_full_event(event_cstr[i], &inp.pfp_events[i]);
797  if(ret != PFMLIB_SUCCESS)
798  {
799  log << MSG::ERROR << "ERROR: cannot find event: " << event_cstr[i] << ". Aborting..." << endmsg;
800  }
801  }
803  inp.pfp_event_count = 4;
804  for(int i=0; i<used_counters_number; i++)
805  {
806  if(inv[i])
807  {
810  }
811  if(cmask[i]>0)
812  {
813  (params.pfp_core_counters[i]).cnt_mask = cmask[i];
814  (nhm_params.pfp_nhm_counters[i]).cnt_mask = cmask[i];
815  }
816  }
817  if(nehalem || westmere)
818  {
819  ret = m_pfm.pfm_dispatch_events(&inp, &nhm_params, &outp, NULL);
820  }
821  else
822  {
823  ret = m_pfm.pfm_dispatch_events(&inp, &params, &outp, NULL);
824  }
825  if(ret != PFMLIB_SUCCESS)
826  {
827  log << MSG::ERROR << "ERROR: cannot configure events: " << m_pfm.pfm_strerror(ret) << ". Aborting..." << endmsg;
828  }
829  for(unsigned int i=0; i<outp.pfp_pmc_count; i++)
830  {
833  }
834  for(unsigned int i=0; i<outp.pfp_pmd_count; i++)
835  {
836  pd_smpl[i].reg_num = outp.pfp_pmds[i].reg_num;
837  if(i)
838  {
839  pfm_bv_set(pd_smpl[0].reg_smpl_pmds, pd_smpl[i].reg_num);
840  if(pd_smpl[i].reg_num>max_pmd)
841  {
842  max_pmd = pd_smpl[i].reg_num;
843  }
844  num_smpl_pmds++;
845  }
846  }
847  for(int i=0; i<used_counters_number; i++)
848  {
850  pfm_bv_copy(pd_smpl[i].reg_reset_pmds, pd_smpl[i].reg_smpl_pmds, max_pmd);
851  pd_smpl[i].reg_value = (uint64_t)(sp[i] * -1);
852  pd_smpl[i].reg_short_reset = (uint64_t)(sp[i] * -1);
853  pd_smpl[i].reg_long_reset = (uint64_t)(sp[i] * -1);
854  pd_smpl[i].reg_random_seed = 5; //tocheck
855  pd_smpl[i].reg_random_mask = 0xff; //tocheck
856  }
858  ctx.ctx_flags = 0;
859  buf_arg.buf_size = 3*getpagesize()+512;
860  ctx_fd = m_pfm.pfm_create_context(&ctx, (char *)FMT_NAME, &buf_arg, sizeof(buf_arg));
861  if(ctx_fd==-1)
862  {
863  if(errno==ENOSYS)
864  {
865  log << MSG::ERROR << "ERROR: Your kernel does not have performance monitoring support! Aborting..." << endmsg;
866  }
867  log << MSG::ERROR << "ERROR: Can't create PFM context " << strerror(errno) << ". Aborting..." << endmsg;
868  }
869  buf_addr = mmap(NULL, (size_t)buf_arg.buf_size, PROT_READ, MAP_PRIVATE, ctx_fd, 0);
870  if(buf_addr==MAP_FAILED)
871  {
872  log << MSG::ERROR << "ERROR: cannot mmap sampling buffer: " << strerror(errno) << ". Aborting..." << endmsg;
873  }
874  hdr = (pfm_dfl_smpl_hdr_t *)buf_addr;
875  if(PFM_VERSION_MAJOR(hdr->hdr_version)<1)
876  {
877  log << MSG::ERROR << "ERROR: invalid buffer format version. Aborting..." << endmsg;
878  }
879  if(m_pfm.pfm_write_pmcs(ctx_fd, pc, outp.pfp_pmc_count))
880  {
881  log << MSG::ERROR << "ERROR: pfm_write_pmcs error errno " << strerror(errno) << ". Aborting..." << endmsg;
882  }
883  if(m_pfm.pfm_write_pmds(ctx_fd, pd_smpl, outp.pfp_pmd_count))
884  {
885  log << MSG::ERROR << "ERROR: pfm_write_pmds error errno " << strerror(errno) << ". Aborting..." << endmsg;
886  }
887  load_args.load_pid = getpid();
888  if(m_pfm.pfm_load_context(ctx_fd, &load_args))
889  {
890  log << MSG::ERROR << "ERROR: pfm_load_context error errno " << strerror(errno) << ". Aborting..." << endmsg;
891  }
892  ret = fcntl(ctx_fd, F_SETFL, fcntl(ctx_fd, F_GETFL, 0) | O_ASYNC);
893  if(ret == -1)
894  {
895  log << MSG::ERROR << "ERROR: cannot set ASYNC: " << strerror(errno) << ". Aborting..." << endmsg;
896  }
897  ret = fcntl(ctx_fd, F_SETOWN, getpid());
898  if(ret == -1)
899  {
900  log << MSG::ERROR << "ERROR: cannot setown: " << strerror(errno) << ". Aborting..." << endmsg;
901  }
902  //pfm_self_start(ctx_fd); ==>
903  m_pfm.pfm_start(ctx_fd, NULL);
904  }
905 
906 
907  // stop_smpl()
908  // const ModuleDescription& desc : description of the module that just finished its execution (we are only interested in its name)
909  // stops the sampling and calls process_smpl_buf() one last time to process all the remaining samples
911  {
912  MsgStream log(msgSvc(), name());
913  m_pfm.pfm_self_stop(ctx_fd);
915  close(ctx_fd);
916  ret = munmap(hdr, (size_t)buf_arg.buf_size);
917  if(ret)
918  {
919  log << MSG::ERROR << "Cannot unmap buffer: %s" << strerror(errno) << endmsg;
920  }
921  return;
922  }
923 
924 
925 
926  // finalize_smpl()
927  // processes the sampling results in order to find library and offset of each sampled address, using the symbol() and tosymbol() functions,
928  // and then dumps the new found information into gzipped output files, to be processed later
930 {
931  MsgStream log(msgSvc(), name());
932  char filename[MAX_OUTPUT_FILENAME_LENGTH];
933  bzero(filename, MAX_OUTPUT_FILENAME_LENGTH);
934  char to_cat[50];
935  gzFile outfile;
936  int err;
937  for(int i=0; i<used_counters_number; i++)
938  {
939  sprintf(filename, "%s_%s", prefix_cstr, event_cstr[i]);
940  for(int j=0; j<(int)strlen(filename); j++)
941  {
942  if(filename[j]==':')
943  {
944  filename[j]='-';
945  }
946  }
947  bzero(to_cat, 50);
948  if(inv[i])
949  {
950  strcpy(to_cat, "_INV_1");
951  }
952  if(cmask[i]>0)
953  {
954  sprintf(to_cat, "%s_CMASK_%d", to_cat, cmask[i]);
955  }
956  sprintf(filename, "%s%s.txt.gz", filename, to_cat);
957  outfile = gzopen(filename, "wb");
958  if(outfile!=NULL)
959  {
960  if(nehalem)
961  {
962  gzprintf(outfile, "NHM ");
963  }
964  else if(westmere)
965  {
966  gzprintf(outfile, "WSM ");
967  }
968  else if(core)
969  {
970  gzprintf(outfile, "CORE ");
971  }
972  if(gzprintf(outfile, "%s %d %d %d\n", event_cstr[i], cmask[i], inv[i], sp[i]) < (int)strlen(event_cstr[i]))
973  {
974  log << MSG::ERROR << "ERROR: gzputs err: " << gzerror(outfile, &err) << ". Aborting..." << endmsg;
975  }
976  for(std::map<std::string, std::map<unsigned long, unsigned int> >::iterator it=samples[i].begin(); it!=samples[i].end(); it++)
977  {
978  unsigned long long sum = 0;
979  for(std::map<unsigned long, unsigned int>::iterator jt=(it->second).begin(); jt!=(it->second).end(); jt++)
980  {
981  sum += jt->second;
982  }
983  if(gzprintf(outfile, "%s%%%llu\n", (it->first).c_str(), sum) < (int)((it->first).length()))
984  {
985  log << MSG::ERROR << "ERROR: gzputs err: " << gzerror(outfile, &err) << ". Aborting..." << endmsg;
986  }
987  for(std::map<unsigned long, unsigned int>::iterator jt=(it->second).begin(); jt!=(it->second).end(); jt++)
988  {
989  char sym_name[SYM_NAME_MAX_LENGTH];
990  bzero(sym_name, SYM_NAME_MAX_LENGTH);
991  const char *libName;
992  const char *symbolName;
993  int libOffset = 0;
994  int offset = 0;
995  void *sym_addr = IgHookTrace::tosymbol((void *)(jt->first));
996  if(sym_addr != NULL)
997  {
998  bool success = IgHookTrace::symbol(sym_addr, symbolName, libName, offset, libOffset);
999  if(success)
1000  {
1001  if(symbolName!=NULL && strlen(symbolName)>0)
1002  {
1003  strcpy(sym_name, symbolName);
1004  strcat(sym_name, " ");
1005  }
1006  else
1007  {
1008  strcpy(sym_name, "??? ");
1009  }
1010  if(libName!=NULL && strlen(libName)>0)
1011  {
1012  strcat(sym_name, libName);
1013  strcat(sym_name, " ");
1014  }
1015  else
1016  {
1017  strcat(sym_name, "??? ");
1018  }
1019  sprintf(sym_name, "%s%d ", sym_name, libOffset);
1020  if(strlen(sym_name)<=0)
1021  {
1022  log << MSG::ERROR << "ERROR: Symbol name length is zero. Aborting..." << endmsg;
1023  }
1024  }
1025  else
1026  {
1027  strcpy(sym_name,"??? ??? 0 ");
1028  }
1029  }
1030  else
1031  {
1032  strcpy(sym_name,"??? ??? 0 ");
1033  }
1034  if(gzprintf(outfile, "%s %d\n", sym_name, jt->second) < (int)strlen(sym_name))
1035  {
1036  log << MSG::ERROR << "ERROR: gzputs err: " << gzerror(outfile, &err) << endmsg;
1037  }
1038  }
1039  }
1040  }
1041  else
1042  {
1043  log << MSG::ERROR << "ERROR: Could not open file: " << filename << ". Aborting..." << endmsg;
1044  }
1045  gzclose(outfile);
1046  }
1047  }
1048 
1049 
1050 
1052 {
1053  if(sampling == 0) finalizepm();
1054  else finalize_smpl();
1055  return Auditor::finalize();
1056 }
1057 
1058 
1059 void PerfMonAuditor::before(StandardEventType evt, INamedInterface *alg)
1060 {
1061  switch(evt)
1062  {
1063  case IAuditor::Initialize:
1064  i_beforeInitialize(alg);
1065  break;
1066  case IAuditor::Execute:
1067  i_beforeExecute(alg);
1068  break;
1069  default:
1070  break;
1071  }
1072  return;
1073 }
1074 
1075 void PerfMonAuditor::after(StandardEventType evt, INamedInterface *alg, const StatusCode &)
1076 {
1077  switch(evt)
1078  {
1079  case IAuditor::Initialize:
1080  i_afterInitialize(alg);
1081  break;
1082  case IAuditor::Execute:
1083  i_afterExecute(alg);
1084  break;
1085  default:
1086  break;
1087  }
1088  return;
1089 }
1090 
1092 {
1093  if(alg == 0)
1094  {
1095  return;
1096  }
1097  return;
1098 }
1099 
1101 {
1102  if(alg == 0)
1103  {
1104  return;
1105  }
1106  return;
1107 }
1108 
1110 {
1111  MsgStream log(msgSvc(), name());
1112  if(alg == 0)
1113  {
1114  return;
1115  }
1116  //log << MSG::INFO << "before:inside! " << alg->name() << endmsg;
1117  if(first_alg)
1118  {
1119  first_alg = false;
1120  first_alg_name = alg->name();
1121  //log << MSG::INFO << "first_alg_name= " << alg->name() << endmsg;
1122  }
1123  if(!event_count_reached)
1124  {
1125  if(!first_alg_name.compare(alg->name()))
1126  {
1127  ph_ev_count++;
1128  //log << MSG::INFO << "EVENT COUNT: " << ph_ev_count << endmsg;
1130  {
1131  event_count_reached = true;
1132  //log << MSG::INFO << "!!! EVENT COUNT REACHED: " << ph_ev_count << endmsg;
1133  }
1134  }
1135  }
1137  {
1138  //log << MSG::INFO << "before:inside! " << alg->name() << endmsg;
1139 
1140  if(!alg_stack.empty())
1141  {
1142  if(sampling == 0) pausepm(); //pausing father algorithm counting
1143  else stop_smpl();
1144  }
1145  ++m_indent;
1146  std::vector <unsigned long int> zeroes(4,0);
1147  alg_stack.push(std::make_pair(alg, zeroes));
1148  if(sampling == 0) startpm();
1149  else start_smpl();
1150  }
1151  return;
1152 }
1153 
1155 {
1156  MsgStream log(msgSvc(), name());
1157  if(alg == 0)
1158  {
1159  return;
1160  }// log << MSG::INFO << "after:inside! " << alg->name() << endmsg;
1161 
1163  {
1164  //log << MSG::INFO << "after:inside! " << alg->name() << endmsg;
1165 
1166  if(sampling == 0) stoppm();
1167  else stop_smpl();
1168  alg_stack.pop();
1169  --m_indent;
1170  if(!alg_stack.empty())
1171  {
1172  if(sampling == 0) startpm();
1173  else start_smpl(); //resuming father algorithm counting
1174  }
1175  }
1176  return;
1177 }
1178 

Generated at Wed Dec 4 2013 14:33:10 for Gaudi Framework, version v24r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004