HPCToolkit
papi-c.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL: https://outreach.scidac.gov/svn/hpctoolkit/trunk/src/tool/hpcrun/sample-sources/papi.c $
6 // $Id: papi.c 4027 2012-11-28 20:03:03Z krentel $
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //
48 // PAPI-C (Component PAPI) sample source simple oo interface
49 //
50 
51 
52 /******************************************************************************
53  * system includes
54  *****************************************************************************/
55 #include <alloca.h>
56 #include <assert.h>
57 #include <ctype.h>
58 #include <papi.h>
59 #include <setjmp.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <ucontext.h>
64 #include <stdbool.h>
65 #include <stdint.h>
66 #include <pthread.h>
67 
68 /******************************************************************************
69  * libmonitor
70  *****************************************************************************/
71 #include <monitor.h>
72 
73 /******************************************************************************
74  * local includes
75  *****************************************************************************/
76 
77 #include "simple_oo.h"
78 #include "sample_source_obj.h"
79 #include "common.h"
80 #include "papi-c-extended-info.h"
81 
82 #include <hpcrun/hpcrun_options.h>
83 #include <hpcrun/hpcrun_stats.h>
84 #include <hpcrun/metrics.h>
85 #include <hpcrun/safe-sampling.h>
87 #include <hpcrun/sample_event.h>
88 #include <hpcrun/thread_data.h>
89 #include <hpcrun/threadmgr.h>
90 
92 #include <utilities/tokenize.h>
93 #include <messages/messages.h>
94 #include <lush/lush-backtrace.h>
96 
97 
98 
99 /******************************************************************************
100  * macros
101  *****************************************************************************/
102 
103 #define OVERFLOW_MODE 0
104 #define WEIGHT_METRIC 0
105 #define DEFAULT_THRESHOLD 2000000L
106 
107 #include "papi-c.h"
108 
109 /******************************************************************************
110  * forward declarations
111  *****************************************************************************/
112 static void papi_event_handler(int event_set, void *pc, long long ovec, void *context);
113 static int event_is_derived(int ev_code);
114 static void event_fatal_error(int ev_code, int papi_ret);
115 
116 /******************************************************************************
117  * local variables
118  *****************************************************************************/
119 
120 
121 // Special case to make PAPI_library_init() a soft failure.
122 // Make sure that we call no other PAPI functions.
123 //
124 static int papi_unavail = 0;
125 
126 //
127 // To accomodate GPU blame shifting, we must disable the cuda component
128 // Flag below controls this disabling
129 //
130 static bool disable_papi_cuda = false;
131 
132 /******************************************************************************
133  * private operations
134  *****************************************************************************/
135 
136 static int
137 get_event_index(sample_source_t *self, int event_code)
138 {
139  int i;
140  int nevents = self->evl.nevents;
141  for (i = 0; i < nevents; i++) {
142  int evcode = self->evl.events[i].event;
143  if (event_code == evcode) return i;
144  }
145  assert(0);
146 }
147 
148 //
149 // fetch a given component's event set. Create one if need be
150 //
151 int
153 {
154  if (cidx < 0 || cidx >= psi->num_components) {
155  hpcrun_abort("PAPI component index out of range [0,%d]: %d", psi->num_components, cidx);
156  }
157 
158  papi_component_info_t* ci = &(psi->component_info[cidx]);
159 
160  if (!ci->inUse) {
161  ci->get_event_set(&(ci->eventSet));
162  ci->inUse = true;
163  }
164  return ci->eventSet;
165 }
166 
167 //
168 // add an event to a component's event set
169 //
170 int
171 component_add_event(papi_source_info_t* psi, int cidx, int evcode)
172 {
173  int event_set = get_component_event_set(psi, cidx);
174  papi_component_info_t* ci = &(psi->component_info[cidx]);
175  return ci->add_event(event_set, evcode);
176 }
177 
178 static bool
180 {
181  const PAPI_component_info_t *pci = PAPI_get_component_info(cidx);
182  if (strcmp(pci->name, "bgpm/L2Unit") == 0) return true;
183  return 0;
184 }
185 
186 //-----------------------------------------------------------
187 // function print_desc
188 // wrap lines for native event descriptions to contain
189 // four white space followed by BUFLEN characters
190 //-----------------------------------------------------------
191 static void
192 print_desc(char *s)
193 {
194 #define BUFLEN 68
195  char buffer[BUFLEN];
196  char *s_end = s + strlen(s);
197  while (s < s_end) {
198  int i;
199  char *cur = s;
200 
201  //-------------------------------------------------
202  // peel off at most the next BUFLEN characters from
203  // the string. break the text at last white
204  // space if a word will extend beyond the boundary.
205  //-------------------------------------------------
206  int last_blank = BUFLEN-1;
207  for(i=0;i<BUFLEN; i++) {
208  buffer[i] = *cur;
209  if (*cur == ' ') {
210  // remember last white space
211  last_blank = i;
212  }
213  if (*cur == '\n'|| *cur == 0) {
214  // break at newline or end of string
215  last_blank = i;
216  break;
217  }
218  cur++;
219  }
220  buffer[last_blank] = 0;
221  s += last_blank + 1;
222 
223  printf(" %s\n", buffer);
224  }
225 }
226 
227 /******************************************************************************
228  * sample source registration
229  *****************************************************************************/
230 
231 // Support for derived events (proxy sampling).
232 static int derived[MAX_EVENTS];
233 static int some_overflow;
234 
235 
236 /******************************************************************************
237  * external thread-local variables
238  *****************************************************************************/
239 extern __thread bool hpcrun_thread_suppress_sample;
240 
241 /******************************************************************************
242  * method functions
243  *****************************************************************************/
244 
245 // strip the prefix "papi::" from an event name, if exists.
246 // this allows forcing a papi event over a perf event.
247 // allow case-insensitive and any number of ':'
248 static const char *
249 strip_papi_prefix(const char *str)
250 {
251  if (strncasecmp(str, "papi:", 5) == 0) {
252  str = &str[5];
253 
254  while (str[0] == ':') {
255  str = &str[1];
256  }
257  }
258 
259  return str;
260 }
261 
262 static void
264 {
265  // PAPI_set_debug(0x3ff);
266 
267  // **NOTE: some papi components may start threads, so
268  // hpcrun must ignore these threads to ensure that PAPI_library_init
269  // succeeds
270  //
271  monitor_disable_new_threads();
272  if (disable_papi_cuda) {
273  TMSG(PAPI_C, "Will disable PAPI cuda component (if component is active)");
274  int cidx = PAPI_get_component_index("cuda");
275  if (cidx) {
276  int res = PAPI_disable_component(cidx);
277  if (res == PAPI_OK) {
278  TMSG(PAPI, "PAPI cuda component disabled");
279  }
280  else {
281  EMSG("*** PAPI cuda component could not be disabled!!!");
282  }
283  }
284  }
285  int ret = PAPI_library_init(PAPI_VER_CURRENT);
286  monitor_enable_new_threads();
287 
288  TMSG(PAPI_C,"PAPI_library_init = %d", ret);
289  TMSG(PAPI_C,"PAPI_VER_CURRENT = %d", PAPI_VER_CURRENT);
290 
291  // Delay reporting PAPI_library_init() errors. This allows running
292  // with other events if PAPI is not available.
293  if (ret < 0) {
295  papi_unavail = 1;
296  } else if (ret != PAPI_VER_CURRENT) {
298  papi_unavail = 1;
299  }
300 
301  // Tell PAPI to count events in all contexts (user, kernel, etc).
302  // FIXME: PAPI_DOM_ALL causes some syscalls to fail which then
303  // breaks some applications. For example, this breaks some Gemini
304  // (GNI) functions called from inside gasnet_init() or MPI_Init() on
305  // the Cray XE (hopper).
306  //
307  if (ENABLED(SYSCALL_RISKY)) {
308  ret = PAPI_set_domain(PAPI_DOM_ALL);
309  if (ret != PAPI_OK) {
310  EMSG("warning: PAPI_set_domain(PAPI_DOM_ALL) failed: %d", ret);
311  }
312  }
313 
314  self->state = INIT;
315 }
316 
317 static void
318 METHOD_FN(thread_init)
319 {
320  TMSG(PAPI, "thread init");
321  if (papi_unavail) { return; }
322 
323  int retval = PAPI_thread_init(pthread_self);
324  if (retval != PAPI_OK) {
325  EEMSG("PAPI_thread_init NOT ok, retval = %d", retval);
327  }
328  TMSG(PAPI, "thread init OK");
329 }
330 
331 static void
332 METHOD_FN(thread_init_action)
333 {
334  TMSG(PAPI, "register thread");
335  if (papi_unavail) { return; }
336 
337  int retval = PAPI_register_thread();
338  if (retval != PAPI_OK) {
339  EEMSG("PAPI_register_thread NOT ok, retval = %d", retval);
341  }
342  TMSG(PAPI, "register thread ok");
343 }
344 
345 static void
346 METHOD_FN(start)
347 {
348  int cidx;
349  TMSG(PAPI, "start");
350 
351  if (papi_unavail) {
352  return;
353  }
354 
356  source_state_t my_state = TD_GET(ss_state)[self->sel_idx];
357 
358  // make PAPI start idempotent. the application can turn on sampling
359  // anywhere via the start-stop interface, so we can't control what
360  // state PAPI is in.
361 
362  if (my_state == START) {
363  TMSG(PAPI,"*NOTE* PAPI start called when already in state START");
364  return;
365  }
366 
367  // for each active component, start its event set
368  papi_source_info_t* psi = td->ss_info[self->sel_idx].ptr;
369  for (cidx=0; cidx < psi->num_components; cidx++) {
370  papi_component_info_t* ci = &(psi->component_info[cidx]);
371  if (ci->inUse) {
372  if (component_uses_sync_samples(cidx)) {
373  TMSG(PAPI, "component %d is synchronous, use synchronous start", cidx);
374  ci->sync_start();
375  }
376  else {
377  TMSG(PAPI,"starting PAPI event set %d for component %d", ci->eventSet, cidx);
378  int ret = PAPI_start(ci->eventSet);
379  if (ret == PAPI_EISRUN) {
380  // this case should not happen, but maybe it's not fatal
381  EMSG("PAPI returned EISRUN for event set %d component %d", ci->eventSet, cidx);
382  }
383  else if (ret != PAPI_OK) {
384  EMSG("PAPI_start failed with %s (%d) for event set %d component %d ",
385  PAPI_strerror(ret), ret, ci->eventSet, cidx);
386  hpcrun_ssfail_start("PAPI");
387  }
388 
389  if (ci->some_derived) {
390  ret = PAPI_read(ci->eventSet, ci->prev_values);
391  if (ret != PAPI_OK) {
392  EMSG("PAPI_read of event set %d for component %d failed with %s (%d)",
393  ci->eventSet, cidx, PAPI_strerror(ret), ret);
394  }
395  }
396  }
397  }
398  }
399  td->ss_state[self->sel_idx] = START;
400 }
401 
402 static void
403 METHOD_FN(thread_fini_action)
404 {
405  TMSG(PAPI, "unregister thread");
406  if (papi_unavail) { return; }
407 
408  int retval = PAPI_unregister_thread();
409  char msg[] = "!!NOT PAPI_OK!! (code = -9999999)\n";
410  snprintf(msg, sizeof(msg)-1, "!!NOT PAPI_OK!! (code = %d)", retval);
411  TMSG(PAPI, "unregister thread returns %s", retval == PAPI_OK? "PAPI_OK" : msg);
412 }
413 
414 static void
416 {
417  int cidx;
418 
419  TMSG(PAPI, "stop");
420  if (papi_unavail) { return; }
421 
423  int nevents = self->evl.nevents;
424  source_state_t my_state = TD_GET(ss_state)[self->sel_idx];
425 
426  if (my_state == STOP) {
427  TMSG(PAPI,"*NOTE* PAPI stop called when already in state STOP");
428  return;
429  }
430 
431  if (my_state != START) {
432  TMSG(PAPI,"*WARNING* PAPI stop called when not in state START");
433  return;
434  }
435 
436  papi_source_info_t *psi = td->ss_info[self->sel_idx].ptr;
437  for (cidx=0; cidx < psi->num_components; cidx++) {
438  papi_component_info_t *ci = &(psi->component_info[cidx]);
439  if (ci->inUse) {
440  if (component_uses_sync_samples(cidx)) {
441  TMSG(PAPI, "component %d is synchronous, stop is trivial", cidx);
442  }
443  else {
444  TMSG(PAPI,"stop w event set = %d", ci->eventSet);
445  long_long values[nevents+2];
446  // long_long *values = (long_long *) alloca(sizeof(long_long) * (nevents+2));
447  int ret = PAPI_stop(ci->eventSet, values);
448  if (ret != PAPI_OK){
449  EMSG("Failed to stop PAPI for eventset %d. Return code = %d ==> %s",
450  ci->eventSet, ret, PAPI_strerror(ret));
451  }
452  }
453  }
454  }
455 
456  TD_GET(ss_state)[self->sel_idx] = STOP;
457 }
458 
459 static void
460 METHOD_FN(shutdown)
461 {
462  TMSG(PAPI, "shutdown");
463  if (papi_unavail) { return; }
464 
465  METHOD_CALL(self, stop); // make sure stop has been called
466  // FIXME: add component shutdown code here
467  PAPI_shutdown();
468 
469  self->state = UNINIT;
470 }
471 
472 // Return true if PAPI recognizes the name, whether supported or not.
473 // We'll handle unsupported events later.
474 static bool
475 METHOD_FN(supports_event, const char *ev_str)
476 {
477  ev_str = strip_papi_prefix(ev_str);
478 
479  TMSG(PAPI, "supports event");
480  if (papi_unavail) { return false; }
481 
482  if (self->state == UNINIT){
483  METHOD_CALL(self, init);
484  }
485 
486  char evtmp[1024];
487  int ec;
488  long th;
489 
490  hpcrun_extract_ev_thresh(ev_str, sizeof(evtmp), evtmp, &th, DEFAULT_THRESHOLD);
491  return PAPI_event_name_to_code(evtmp, &ec) == PAPI_OK;
492 }
493 
494 static void
495 METHOD_FN(process_event_list, int lush_metrics)
496 {
497  TMSG(PAPI, "process event list");
498  if (papi_unavail) { return; }
499 
500  char *event;
501  int i, ret;
502  int num_lush_metrics = 0;
503 
504  char* evlist = METHOD_CALL(self, get_event_str);
505  for (event = start_tok(evlist); more_tok(); event = next_tok()) {
506  char name[1024];
507  int evcode;
508  long thresh;
509 
510  event = (char *) strip_papi_prefix(event);
511 
512  TMSG(PAPI,"checking event spec = %s",event);
513  // FIXME: restore checking will require deciding if the event is synchronous or not
514 #ifdef USE_PAPI_CHECKING
515  if (! hpcrun_extract_ev_thresh(event, sizeof(name), name, &thresh, DEFAULT_THRESHOLD)) {
516  AMSG("WARNING: %s using default threshold %ld, "
517  "better to use an explicit threshold.", name, DEFAULT_THRESHOLD);
518  }
519 #else
520  hpcrun_extract_ev_thresh(event, sizeof(name), name, &thresh, DEFAULT_THRESHOLD);
521 #endif // USE_PAPI_CHECKING
522  ret = PAPI_event_name_to_code(name, &evcode);
523  if (ret != PAPI_OK) {
524  EMSG("unexpected failure in PAPI process_event_list(): "
525  "PAPI_event_name_to_code() returned %s (%d)",
526  PAPI_strerror(ret), ret);
527  hpcrun_ssfail_unsupported("PAPI", name);
528  }
529  if (PAPI_query_event(evcode) != PAPI_OK) {
530  hpcrun_ssfail_unsupported("PAPI", name);
531  }
532 
533  // FIXME:LUSH: need a more flexible metric interface
534  if (lush_metrics == 1 && strncmp(event, "PAPI_TOT_CYC", 12) == 0) {
535  num_lush_metrics++;
536  }
537 
538  TMSG(PAPI,"event %s -> event code = %x, thresh = %ld", event, evcode, thresh);
539  METHOD_CALL(self, store_event, evcode, thresh);
540  }
541  int nevents = (self->evl).nevents;
542  TMSG(PAPI,"nevents = %d", nevents);
543 
544  hpcrun_pre_allocate_metrics(nevents + num_lush_metrics);
545 
546  some_overflow = 0;
547  for (i = 0; i < nevents; i++) {
548  char buffer[PAPI_MAX_STR_LEN + 10];
549  int metric_id = hpcrun_new_metric(); /* weight */
551  METHOD_CALL(self, store_metric_id, i, metric_id);
552  PAPI_event_code_to_name(self->evl.events[i].event, buffer);
553  TMSG(PAPI, "metric for event %d = %s", i, buffer);
554 
555  // blame shifting needs to know if there is a cycles metric
556  if (strcmp(buffer, "PAPI_TOT_CYC") == 0) {
557  prop = metric_property_cycles;
559  }
560 
561  // allow derived events (proxy sampling), as long as some event
562  // supports hardware overflow. use threshold = 0 to force proxy
563  // sampling (for testing).
564  if (event_is_derived(self->evl.events[i].event)
565  || self->evl.events[i].thresh == 0) {
566  TMSG(PAPI, "using proxy sampling for event %s", buffer);
567  strcat(buffer, " (proxy)");
568  self->evl.events[i].thresh = 1;
569  derived[i] = 1;
570  }
571  else {
572  derived[i] = 0;
573  some_overflow = 1;
574  }
575 
576  int cidx = PAPI_get_event_component(self->evl.events[i].event);
577  int threshold;
579  threshold = 1;
580  }
581  else {
582  threshold = self->evl.events[i].thresh;
583  }
584 
585  if (component_uses_sync_samples(cidx))
586  TMSG(PAPI, "Event %s from synchronous component", buffer);
587  hpcrun_set_metric_info_and_period(metric_id, strdup(buffer),
589  threshold, prop);
590 
591  // FIXME:LUSH: need a more flexible metric interface
592  if (num_lush_metrics > 0 && strcmp(buffer, "PAPI_TOT_CYC") == 0) {
593  // there should be one lush metric; its source is the last event
594  assert(num_lush_metrics == 1 && (i == (nevents - 1)));
595  int mid_idleness = hpcrun_new_metric();
596  lush_agents->metric_time = metric_id;
597  lush_agents->metric_idleness = mid_idleness;
598 
599  hpcrun_set_metric_info_and_period(mid_idleness, "idleness",
601  self->evl.events[i].thresh, prop);
602  }
603  }
604 
605  if (! some_overflow) {
607  }
608 }
609 
610 static void
611 METHOD_FN(gen_event_set, int lush_metrics)
612 {
614  int i;
615  int ret;
616 
617  TMSG(PAPI, "generating all event sets for all components");
618  if (papi_unavail) { return; }
619 
620  int num_components = PAPI_num_components();
621  int ss_info_size = sizeof(papi_source_info_t) +
622  num_components * sizeof(papi_component_info_t);
623 
624  TMSG(PAPI, "Num components = %d", num_components);
625  papi_source_info_t* psi = hpcrun_malloc(ss_info_size);
626  if (psi == NULL) {
627  hpcrun_abort("Failure to allocate vector for PAPI components");
628  }
629 
630  // initialize state for each component
631  psi->num_components = num_components;
632  for (i = 0; i < num_components; i++) {
633  papi_component_info_t *ci = &(psi->component_info[i]);
634  ci->inUse = false;
635  ci->eventSet = PAPI_NULL;
636  ci->state = INIT;
637  ci->some_derived = 0;
647  memset(ci->prev_values, 0, sizeof(ci->prev_values));
648  }
649 
650  // record the component state in thread state
651  td->ss_info[self->sel_idx].ptr = psi;
652 
653  int nevents = (self->evl).nevents;
654  for (i = 0; i < nevents; i++) {
655  int evcode = self->evl.events[i].event;
656  int cidx = PAPI_get_event_component(evcode);
657 
658  ret = component_add_event(psi, cidx, evcode);
659  psi->component_info[cidx].some_derived |= event_is_derived(evcode);
660  TMSG(PAPI, "Added event code %x to component %d", evcode, cidx);
661  {
662  char buffer[PAPI_MAX_STR_LEN];
663  PAPI_event_code_to_name(evcode, buffer);
664  TMSG(PAPI,
665  "PAPI_add_event(eventSet=%%d, event_code=%x (event name %s)) component=%d",
666  /* eventSet, */ evcode, buffer, cidx);
667  }
668  if (ret != PAPI_OK) {
669  EMSG("failure in PAPI gen_event_set(): PAPI_add_event() returned: %s (%d)",
670  PAPI_strerror(ret), ret);
671  event_fatal_error(evcode, ret);
672  }
673  }
674 
675  // finalize component event sets
676  for (i = 0; i < num_components; i++) {
677  papi_component_info_t *ci = &(psi->component_info[i]);
678  ci->finalize_event_set();
679  }
680 
681  // set up overflow handling for asynchronous event sets for active components
682  // set up synchronous handling for synchronous event sets for active compoents
683  for (i = 0; i < nevents; i++) {
684  int evcode = self->evl.events[i].event;
685  long thresh = self->evl.events[i].thresh;
686  int cidx = PAPI_get_event_component(evcode);
687  int eventSet = get_component_event_set(psi, cidx);
688 
689  // **** No overflow for synchronous events ****
690  // **** Use component-specific setup for synchronous events ****
691  if (component_uses_sync_samples(cidx)) {
692  TMSG(PAPI, "event code %d (component %d) is synchronous, so do NOT set overflow", evcode, cidx);
693  TMSG(PAPI, "Set up sync handler instead");
694  TMSG(PAPI, "synchronous sample component index = %d", cidx);
695  sync_setup_for_component(cidx)();
696  continue;
697  }
698  // ***** Only set overflow if NOT derived event *****
699  if (! derived[i]) {
700  ret = PAPI_overflow(eventSet, evcode, thresh, OVERFLOW_MODE,
702  TMSG(PAPI, "PAPI_overflow(eventSet=%d, evcode=%x, thresh=%d) = %d",
703  eventSet, evcode, thresh, ret);
704  if (ret != PAPI_OK) {
705  EMSG("failure in PAPI gen_event_set(): PAPI_overflow() returned: %s (%d)",
706  PAPI_strerror(ret), ret);
707  event_fatal_error(evcode, ret);
708  }
709  }
710  }
711 }
712 
713 static void
714 METHOD_FN(display_events)
715 {
716  PAPI_event_info_t info;
717  int ev, ret, num_total, num_prof;
718  int num_components, cidx;
719 
720  if (papi_unavail) {
721  printf("PAPI is not available. Probably, the kernel doesn't support PAPI,\n"
722  "or else maybe HPCToolkit is out of sync with PAPI.\n\n");
723  return;
724  }
725 
726  cidx = 0; // CPU component
727  {
728  const PAPI_component_info_t *component = PAPI_get_component_info(cidx);
729  printf("===========================================================================\n");
730  printf("Available PAPI preset events in component %s\n", component->name);
731  printf("\n");
732  printf("Name\t Profilable\tDescription\n");
733  printf("===========================================================================\n");
734 
735  num_total = 0;
736  num_prof = 0;
737  ev = 0| PAPI_PRESET_MASK;
738  ret = PAPI_enum_cmp_event(&ev, PAPI_ENUM_FIRST, cidx);
739  while (ret == PAPI_OK) {
740  char *prof;
741  memset(&info, 0, sizeof(info));
742  if (PAPI_get_event_info(ev, &info) == PAPI_OK && info.count != 0) {
743  if (event_is_derived(ev)) {
744  prof = "No";
745  } else {
746  prof = "Yes";
747  num_prof++;
748  }
749  num_total++;
750  printf("%-10s\t%s\t%s\n", info.symbol, prof, info.long_descr);
751  }
752  ret = PAPI_enum_cmp_event(&ev, PAPI_ENUM_EVENTS, cidx);
753  }
754  printf("---------------------------------------------------------------------------\n");
755  printf("Total PAPI events: %d, able to profile: %d\n", num_total, num_prof);
756  printf("\n\n");
757  }
758 
759  num_components = PAPI_num_components();
760  for(cidx = 0; cidx < num_components; cidx++) {
761  const PAPI_component_info_t* component = PAPI_get_component_info(cidx);
762  int cmp_event_count = 0;
763 
764  if (component->disabled) continue;
765 
766  printf("===========================================================================\n");
767  printf("Native events in component %s\n", component->name);
768  printf("\n");
769  printf("Name Description\n");
770  printf("===========================================================================\n");
771 
772  ev = 0 | PAPI_NATIVE_MASK;
773  ret = PAPI_enum_cmp_event(&ev, PAPI_ENUM_FIRST, cidx);
774  while (ret == PAPI_OK) {
775  memset(&info, 0, sizeof(info));
776  if (PAPI_get_event_info(ev, &info) == PAPI_OK) {
777  cmp_event_count++;
778  printf("%-48s\n", info.symbol);
779  print_desc(info.long_descr);
780  printf("---------------------------------------------------------------------------\n");
781  }
782  ret = PAPI_enum_cmp_event(&ev, PAPI_ENUM_EVENTS, cidx);
783  }
784  printf("Total native events for component %s: %d\n", component->name, cmp_event_count);
785  printf("\n\n");
786  num_total += cmp_event_count;
787  }
788 
789  printf( "Total events reported: %d\n", num_total);
790  printf("\n\n");
791 }
792 
793 
794 /***************************************************************************
795  * object
796  ***************************************************************************/
797 
798 #define ss_name papi
799 #define ss_cls SS_HARDWARE
800 #define ss_sort_order 70
801 
802 #include "ss_obj.h"
803 
804 // **************************************************************************
805 // * public operations
806 // **************************************************************************
807 void
809 {
810  disable_papi_cuda = true;
811 }
812 
813 /******************************************************************************
814  * private operations
815  *****************************************************************************/
816 
817 // Returns: 1 if the event code is a derived event.
818 // The papi_avail(1) utility shows how to do this.
819 static int
820 event_is_derived(int ev_code)
821 {
822  PAPI_event_info_t info;
823 
824  // "Is derived" is kind of a bad thing, so if any unexpected failure
825  // occurs, we'll return the "bad" answer.
826  if (PAPI_get_event_info(ev_code, &info) != PAPI_OK
827  || info.derived == NULL) {
828  return 1;
829  }
830  if (info.count == 1
831  || strlen(info.derived) == 0
832  || strcmp(info.derived, "NOT_DERIVED") == 0
833  || strcmp(info.derived, "DERIVED_CMPD") == 0) {
834  return 0;
835  }
836  return 1;
837 }
838 
839 static void
840 event_fatal_error(int ev_code, int papi_ret)
841 {
842  char name[1024];
843 
844  PAPI_event_code_to_name(ev_code, name);
845  if (PAPI_query_event(ev_code) != PAPI_OK) {
846  hpcrun_ssfail_unsupported("PAPI", name);
847  }
848  if (event_is_derived(ev_code)) {
849  hpcrun_ssfail_derived("PAPI", name);
850  }
851  if (papi_ret == PAPI_ECNFLCT) {
852  hpcrun_ssfail_conflict("PAPI", name);
853  }
854  hpcrun_ssfail_unsupported("PAPI", name);
855 }
856 
857 static void
858 papi_event_handler(int event_set, void *pc, long long ovec,
859  void *context)
860 {
861  sample_source_t *self = &obj_name();
862  long long values[MAX_EVENTS];
863  int my_events[MAX_EVENTS];
864  int my_event_count = MAX_EVENTS;
865  int nevents = self->evl.nevents;
866  int i, ret;
867 
868  int my_event_codes[MAX_EVENTS];
869  int my_event_codes_count = MAX_EVENTS;
870 
871  // if sampling disabled explicitly for this thread, skip all processing
872  if (hpcrun_thread_suppress_sample) return;
873 
874  if (!ovec) {
875  TMSG(PAPI_SAMPLE, "papi overflow event: event set %d ovec = %ld",
876  event_set, ovec);
877  return;
878  }
879 
880  // If the interrupt came from inside our code, then drop the sample
881  // and return and avoid any MSG.
882  if (! hpcrun_safe_enter_async(pc)) {
884  return;
885  }
886 
887  int cidx = PAPI_get_eventset_component(event_set);
889  papi_source_info_t *psi = td->ss_info[self->sel_idx].ptr;
890  papi_component_info_t *ci = &(psi->component_info[cidx]);
891 
892  if (ci->some_derived) {
893  ret = PAPI_read(event_set, values);
894  if (ret != PAPI_OK) {
895  EMSG("PAPI_read failed with %s (%d)", PAPI_strerror(ret), ret);
896  }
897  }
898 
899  ret = PAPI_get_overflow_event_index(event_set, ovec, my_events,
900  &my_event_count);
901  if (ret != PAPI_OK) {
902  TMSG(PAPI_SAMPLE, "papi_event_handler: event set %d ovec %ld "
903  "get_overflow_event_index return code = %d ==> %s",
904  event_set, ovec, ret, PAPI_strerror(ret));
905 #ifdef DEBUG_PAPI_OVERFLOW
906  ret = PAPI_list_events(event_set, my_event_codes, &my_event_codes_count);
907  if (ret != PAPI_OK) {
908  TMSG(PAPI_SAMPLE, "PAPI_list_events failed inside papi_event_handler."
909  "Return code = %d ==> %s", ret, PAPI_strerror(ret));
910  } else {
911  for (i = 0; i < my_event_codes_count; i++) {
912  TMSG(PAPI_SAMPLE, "event set %d event code %d = %x\n",
913  event_set, i, my_event_codes[i]);
914  }
915  }
916  TMSG(PAPI_SAMPLE, "get_overflow_event_index failure in papi_event_handler");
917 #endif
918  }
919 
920  ret = PAPI_list_events(event_set, my_event_codes, &my_event_codes_count);
921  if (ret != PAPI_OK) {
922  hpcrun_abort("PAPI_list_events failed inside papi_event_handler."
923  "Return code = %d ==> %s", ret, PAPI_strerror(ret));
924  }
925 
926  for (i = 0; i < my_event_count; i++) {
927  // FIXME: SUBTLE ERROR: metric_id may not be same from hpcrun_new_metric()!
928  // This means lush's 'time' metric should be *last*
929 
930  TMSG(PAPI_SAMPLE,"handling papi overflow event: "
931  "event set %d event index = %d event code = 0x%x",
932  event_set, my_events[i], my_event_codes[my_events[i]]);
933 
934  int event_index = get_event_index(self, my_event_codes[my_events[i]]);
935 
936  int metric_id = hpcrun_event2metric(self, event_index);
937 
938  TMSG(PAPI_SAMPLE,"sampling call path for metric_id = %d", metric_id);
939 
940  uint64_t metricIncrement;
941  if (ci->scale_by_thread_count) {
942  float liveThreads = (float) hpcrun_threadmgr_thread_count();
943  float myShare = 1.0 / liveThreads;
944  metricIncrement = self->evl.events[i].thresh * myShare;
945  } else {
946  metricIncrement = 1;
947  }
948 
949  sample_val_t sv = hpcrun_sample_callpath(context, metric_id,
950  (hpcrun_metricVal_t) {.i=metricIncrement},
951  0/*skipInner*/, 0/*isSync*/, NULL);
952 
953  blame_shift_apply(metric_id, sv.sample_node, 1 /*metricIncr*/);
954  }
955 
956  // Add metric values for derived events by the difference in counter
957  // values. Some samples can take a long time (e.g., analyzing a new
958  // load module), so read the counters both on entry and exit to
959  // avoid counting our work.
960 
961  if (ci->some_derived) {
962  for (i = 0; i < nevents; i++) {
963  if (derived[i]) {
965  (hpcrun_metricVal_t) {.i=values[i] - ci->prev_values[i]},
966  0, 0, NULL);
967  }
968  }
969 
970  ret = PAPI_read(event_set, ci->prev_values);
971  if (ret != PAPI_OK) {
972  EMSG("PAPI_read failed with %s (%d)", PAPI_strerror(ret), ret);
973  }
974  }
975 
977 }
stop_proc_t sync_stop_for_component(int cidx)
#define obj_name()
Definition: ss_obj.h:71
source_state_t
get_event_set_proc_t component_get_event_set(int cidx)
static int derived[MAX_EVENTS]
Definition: papi-c.c:232
add_event_proc_t component_add_event_proc(int cidx)
static void papi_event_handler(int event_set, void *pc, long long ovec, void *context)
Definition: papi-c.c:858
static void hpcrun_safe_exit(void)
static int event_is_derived(int ev_code)
Definition: papi-c.c:820
sample_val_t hpcrun_sample_callpath(void *context, int metricId, hpcrun_metricVal_t metricIncr, int skipInner, int isSync, sampling_info_t *data)
Definition: sample_event.c:160
void hpcrun_ssfail_derived(char *source, char *event)
Definition: common.c:238
int hpcrun_threadmgr_thread_count()
Definition: threadmgr.c:232
finalize_event_set_proc_t component_finalize_event_set(int cidx)
void blame_shift_source_register(bs_type bst)
Definition: blame-shift.c:25
void hpcrun_save_papi_error(int error)
Definition: common.c:184
void hpcrun_ssfail_all_derived(char *source)
Definition: common.c:246
static const char * strip_papi_prefix(const char *str)
Definition: papi-c.c:249
void hpcrun_disable_papi_cuda(void)
Definition: papi-c.c:808
setup_proc_t sync_setup
Definition: papi-c.h:76
teardown_proc_t sync_teardown_for_component(int cidx)
#define hpcrun_abort(...)
Definition: messages.h:102
cct_node_t * sample_node
Definition: sample_event.h:96
bool component_uses_sync_samples(int cidx)
static int papi_unavail
Definition: papi-c.c:124
static bool disable_papi_cuda
Definition: papi-c.c:130
void blame_shift_apply(int metric_id, cct_node_t *node, int metric_incr)
Definition: blame-shift.c:15
void hpcrun_stats_num_samples_blocked_async_inc(void)
Definition: hpcrun_stats.c:148
start_proc_t sync_start
Definition: papi-c.h:74
char * next_tok(void)
Definition: tokenize.c:87
metric_desc_t * hpcrun_set_metric_info_and_period(int metric_id, const char *name, MetricFlags_ValFmt_t valFmt, size_t period, metric_desc_properties_t prop)
Definition: metrics.c:411
get_event_set_proc_t get_event_set
Definition: papi-c.h:71
#define EMSG
Definition: messages.h:70
static int get_event_index(sample_source_t *self, int event_code)
Definition: papi-c.c:137
void hpcrun_ssfail_unsupported(char *source, char *event)
Definition: common.c:230
source_state_t * ss_state
Definition: thread_data.h:150
int component_add_event(papi_source_info_t *psi, int cidx, int evcode)
Definition: papi-c.c:171
#define metric_property_cycles
Definition: hpcrun-fmt.h:201
finalize_event_set_proc_t finalize_event_set
Definition: papi-c.h:73
long long prev_values[MAX_EVENTS]
Definition: papi-c.h:68
add_event_proc_t add_event
Definition: papi-c.h:72
char * start_tok(char *lst)
Definition: tokenize.c:70
papi_component_info_t component_info[0]
Definition: papi-c.h:83
int lush_metrics
Definition: main.c:188
bool scale_by_thread_count
Definition: papi-c.h:67
#define DEFAULT_THRESHOLD
Definition: papi-c.c:105
static void METHOD_FN(init)
Definition: papi-c.c:263
__thread bool hpcrun_thread_suppress_sample
Definition: main.c:193
void hpcrun_ssfail_start(char *source)
Definition: common.c:265
void * hpcrun_malloc(size_t size)
Definition: mem.c:275
#define TD_GET(field)
Definition: thread_data.h:256
static int some_overflow
Definition: papi-c.c:233
int metric_idleness
Definition: lush.h:96
#define TMSG(f,...)
Definition: messages.h:93
int hpcrun_extract_ev_thresh(const char *in, int evlen, char *ev, long *th, long def)
Definition: tokenize.c:157
teardown_proc_t sync_teardown
Definition: papi-c.h:77
static int hpcrun_safe_enter_async(void *pc)
int hpcrun_event2metric(sample_source_t *ss, int event_idx)
Definition: common.c:143
#define AMSG
Definition: messages.h:71
#define METHOD_CALL(obj, meth,...)
Definition: simple_oo.h:87
int get_component_event_set(papi_source_info_t *psi, int cidx)
Definition: papi-c.c:152
#define EEMSG(...)
Definition: messages.h:90
#define NULL
Definition: ElfHelper.cpp:85
int num_components
Definition: papi-c.h:82
#define BUFLEN
static int const threshold
int hpcrun_new_metric(void)
Definition: metrics.c:333
#define HPCRUN_PAPI_ERROR_VERSION
Definition: common.h:53
source_state_t state
Definition: papi-c.h:65
#define OVERFLOW_MODE
Definition: papi-c.c:103
#define MAX_EVENTS
Definition: evlist.h:51
void monitor_real_abort(void)
void hpcrun_pre_allocate_metrics(size_t num)
Definition: metrics.c:190
setup_proc_t sync_setup_for_component(int cidx)
source_info_t * ss_info
Definition: thread_data.h:151
static void print_desc(char *s)
Definition: papi-c.c:192
static bool thread_count_scaling_for_component(int cidx)
Definition: papi-c.c:179
start_proc_t sync_start_for_component(int cidx)
lush_agent_pool_t * lush_agents
static void event_fatal_error(int ev_code, int papi_ret)
Definition: papi-c.c:840
int more_tok(void)
Definition: tokenize.c:78
#define ENABLED(f)
Definition: debug-flag.h:76
#define HPCRUN_PAPI_ERROR_UNAVAIL
Definition: common.h:52
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
#define metric_property_none
Definition: hpcrun-fmt.h:202
stop_proc_t sync_stop
Definition: papi-c.h:75
int metric_time
Definition: lush.h:95
void hpcrun_ssfail_conflict(char *source, char *event)
Definition: common.c:255