PAPI  5.4.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
peu_libpfm4_events.c
Go to the documentation of this file.
1 /*
2 * File: peu_libpfm4_events.c
3 * Author: Vince Weaver vincent.weaver @ maine.edu
4 * Mods: Gary Mohr
5 * gary.mohr@bull.com
6 * Modified the perf_event_uncore component to use PFM_OS_PERF_EVENT_EXT mode in libpfm4.
7 * This adds several new event masks, including cpu=, u=, and k= which give the user
8 * the ability to set cpu number to use or control the domain (user, kernel, or both)
9 * in which the counter should be incremented. These are event masks so it is now
10 * possible to have multiple events in the same event set that count activity from
11 * differennt cpu's or count activity in different domains.
12 *
13 * Handle the libpfm4 event interface for the perf_event_uncore component
14 */
15 
16 #include <string.h>
17 
18 #include "papi.h"
19 #include "papi_internal.h"
20 #include "papi_vector.h"
21 
22 #include "papi_libpfm4_events.h"
23 #include "peu_libpfm4_events.h"
25 
26 #include "perfmon/pfmlib.h"
27 #include "perfmon/pfmlib_perf_event.h"
28 #include "libpfm4/lib/pfmlib_priv.h"
29 
30 #define NATIVE_EVENT_CHUNK 1024
31 
32 // used to step through the attributes when enumerating events
33 static int attr_idx;
34 
47 static int find_existing_event(char *name,
48  struct native_event_table_t *event_table) {
49  SUBDBG("Entry: name: %s, event_table: %p, num_native_events: %d\n", name, event_table, event_table->num_native_events);
50 
51  int i,event=PAPI_ENOEVNT;
52 
54 
55  for(i=0;i<event_table->num_native_events;i++) {
56  // Most names passed in will contain the pmu name, so first we compare to the allocated name (it has pmu name on front)
57  if (!strcmp(name,event_table->native_events[i].allocated_name)) {
58  SUBDBG("Found allocated_name: %s, libpfm4_idx: %#x, papi_event_code: %#x\n",
59  event_table->native_events[i].allocated_name, event_table->native_events[i].libpfm4_idx, event_table->native_events[i].papi_event_code);
60  event=i;
61  break;
62  }
63  // some callers have an event name without the pmu name on the front, so we also compare to the base name (just the event name part)
64  if (!strcmp(name,event_table->native_events[i].base_name)) {
65  SUBDBG("Found base_name: %s, libpfm4_idx: %#x, papi_event_code: %#x\n",
66  event_table->native_events[i].base_name, event_table->native_events[i].libpfm4_idx, event_table->native_events[i].papi_event_code);
67  event=i;
68  break;
69  }
70  }
72 
73  SUBDBG("EXIT: returned: %#x\n", event);
74  return event;
75 }
76 
77 
78 static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type) {
79 // SUBDBG("ENTER: pinfo: %p, pinfo->is_present: %d, pinfo->type: %#x, type: %#x\n", pinfo, pinfo->is_present, pinfo->type, type);
80  if (!pinfo->is_present) {
81 // SUBDBG("EXIT: not present\n");
82  return 0;
83  }
84 
85  if ((pinfo->type==PFM_PMU_TYPE_UNCORE) && (type&PMU_TYPE_UNCORE)) {
86 // SUBDBG("EXIT: found PFM_PMU_TYPE_UNCORE\n");
87  return 1;
88  }
89  if ((pinfo->type==PFM_PMU_TYPE_CORE) && (type&PMU_TYPE_CORE)) {
90 // SUBDBG("EXIT: found PFM_PMU_TYPE_CORE\n");
91  return 1;
92  }
93  if ((pinfo->type==PFM_PMU_TYPE_OS_GENERIC) && (type&PMU_TYPE_OS)) {
94 // SUBDBG("EXIT: found PFM_PMU_TYPE_OS_GENERIC\n");
95  return 1;
96  }
97 
98 // SUBDBG("EXIT: not right type\n");
99  return 0;
100 }
101 
102 
117 static struct native_event_t *allocate_native_event(char *name, int libpfm4_index,
118  struct native_event_table_t *event_table) {
119 
120  SUBDBG("ENTER: name: %s, libpfm4_index: %#x, event_table: %p, event_table->pmu_type: %d\n", name, libpfm4_index, event_table, event_table->pmu_type);
121 
122  int nevt_idx;
123  int event_num;
124  int encode_failed=0;
125 
126  pfm_err_t ret;
127  char *event_string=NULL;
128  char *pmu_name;
129  char *event;
130  char *masks;
131  char fullname[BUFSIZ];
132  struct native_event_t *ntv_evt;
133 
134  pfm_perf_encode_arg_t perf_arg;
135  pfm_event_info_t einfo;
136  pfm_event_attr_info_t ainfo;
137  pfm_pmu_info_t pinfo;
138 
139  // if no place to put native events, report that allocate failed
140  if (event_table->native_events==NULL) {
141  SUBDBG("EXIT: no place to put native events\n");
142  return NULL;
143  }
144 
145  // find out if this event is already known
146  event_num=find_existing_event(name, event_table);
147 
148  /* add the event to our event table */
150 
151  // if we already know this event name, it was created as part of setting up the preset tables
152  // we need to use the event table which is already created
153  if (event_num >= 0) {
154  nevt_idx = event_num;
155  ntv_evt = &(event_table->native_events[event_num]);
156  } else {
157  // set to use a new event table (count of used events not bumped until we are sure setting it up does not get an errro)
158  nevt_idx = event_table->num_native_events;
159  ntv_evt = &(event_table->native_events[nevt_idx]);
160  }
161 
162  SUBDBG("event_num: %d, nevt_idx: %d, ntv_evt: %p\n", event_num, nevt_idx, ntv_evt);
163 
164  /* clear the argument and attribute structures */
165  memset(&perf_arg,0,sizeof(pfm_perf_encode_arg_t));
166  memset(&(ntv_evt->attr),0,sizeof(struct perf_event_attr));
167 
168  // set argument structure fields so the encode function can give us what we need
169  perf_arg.attr=&ntv_evt->attr;
170  perf_arg.fstr=&event_string;
171 
172  /* use user provided name of the event to get the perf_event encoding and a fully qualified event string */
173  ret = pfm_get_os_event_encoding(name,
174  PFM_PLM0 | PFM_PLM3,
175  PFM_OS_PERF_EVENT_EXT,
176  &perf_arg);
177 
178  // If the encode function failed, skip processing of the event_string
179  if ((ret != PFM_SUCCESS) || (event_string == NULL)) {
180  SUBDBG("encode failed for event: %s, returned: %d\n", name, ret);
181 
182  // we need to remember that this event encoding failed but still create the native event table
183  // the event table is used by the list so we put what we can get into it
184  // but the failure doing the encode causes us to return null to our caller
185  encode_failed = 1;
186 
187  // Noting the encode_failed error in the attr.config allows
188  // any later validate attempts to return an error value
189  ntv_evt->attr.config = 0xFFFFFF;
190 
191  // we also want to make it look like a cpu number was not provided as an event mask
192  perf_arg.cpu = -1;
193  }
194 
195  // get a copy of the event name and break it up into its parts
196  event_string = strdup(name);
197 
198  SUBDBG("event_string: %s\n", event_string);
199 
200  // get the pmu name, event name and mask list pointers from the event string
201  event = strstr (event_string, "::");
202  if (event != NULL) {
203  *event = 0; // null terminate pmu name
204  event += 2; // event name follows '::'
205  pmu_name = strdup(event_string);
206  } else {
207  // no pmu name in event string
208  pmu_name = malloc(2);
209  pmu_name[0] = 0;
210  event = event_string;
211  }
212  masks = strstr (event, ":");
213  if (masks != NULL) {
214  *masks = 0; // null terminate event name
215  masks += 1; // masks follow :
216  } else {
217  masks = "";
218  }
219 
220  // build event name to find, put a pmu name on it if we have one
221  if(strlen(pmu_name) == 0) {
222  sprintf(fullname,"%s", event);
223  } else {
224  sprintf(fullname,"%s::%s", pmu_name, event);
225  }
226  SUBDBG("pmu_name: %s, event: %s, masks: %s, fullname: %s\n", pmu_name, event, masks, fullname);
227 
228  // if the libpfm4 index was not provided, try to get one based on the event name passed in.
229  if (libpfm4_index == -1) {
230  libpfm4_index = pfm_find_event(fullname);
231  if (libpfm4_index < 0) {
232  free(event_string);
233  free(pmu_name);
235  SUBDBG("EXIT: error from libpfm4 find event\n");
236  return NULL;
237  }
238  SUBDBG("libpfm4_index: %#x\n", libpfm4_index);
239  }
240 
241  // get this events information from libpfm4, if unavailable return event not found (structure be zeroed)
242  memset( &einfo, 0, sizeof( pfm_event_info_t ));
243  einfo.size = sizeof(pfm_event_info_t);
244  if ((ret = pfm_get_event_info(libpfm4_index, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
245  free(event_string);
246  free(pmu_name);
248  SUBDBG("EXIT: pfm_get_event_info failed with %d\n", ret);
249  return NULL;
250  }
251 
252  // if pmu type is not one supported by this component, return event not found (structure be zeroed)
253  memset(&pinfo,0,sizeof(pfm_pmu_info_t));
254  pinfo.size = sizeof(pfm_pmu_info_t);
255  pfm_get_pmu_info(einfo.pmu, &pinfo);
256  if (pmu_is_present_and_right_type(&pinfo, event_table->pmu_type) == 0) {
257  free(event_string);
258  free(pmu_name);
260  SUBDBG("EXIT: PMU not supported by this component: einfo.pmu: %d, PFM_PMU_TYPE_UNCORE: %d\n", einfo.pmu, PFM_PMU_TYPE_UNCORE);
261  return NULL;
262  }
263 
264  ntv_evt->allocated_name=strdup(name);
265  ntv_evt->mask_string=strdup(masks);
266  ntv_evt->component=_peu_libpfm4_get_cidx();
267  ntv_evt->pmu=pmu_name;
268  ntv_evt->base_name=strdup(event);
269  ntv_evt->pmu_plus_name=strdup(fullname);
270  ntv_evt->libpfm4_idx=libpfm4_index;
271  ntv_evt->event_description=strdup(einfo.desc);
272  ntv_evt->users=0; /* is this needed? */
273  ntv_evt->cpu=perf_arg.cpu;
274 
275  SUBDBG("ntv_evt->mask_string: %p (%s)\n", ntv_evt->mask_string, ntv_evt->mask_string);
276  char *msk_ptr = strdup(masks); // get a work copy of the mask string before we free the space it was in
277  free(event_string);
278 
279  // if there is any mask data, collect their descriptions
280  if ((msk_ptr != NULL) && (strlen(msk_ptr) > 0)) {
281  // go get the descriptions for each of the masks provided with this event
282  char mask_desc[PAPI_HUGE_STR_LEN] = "";
283  char *ptr = msk_ptr;
284  SUBDBG("ptr: %p (%s)\n", ptr, ptr);
285  while (ptr != NULL) {
286  char *ptrm = strstr(ptr, ":");
287  if (ptrm != NULL) {
288  *ptrm = '\0';
289  ptrm++;
290  }
291 
292  // get the length of the mask name
293  char *wrk = strchr(ptr, '=');
294  unsigned int msk_name_len;
295  if (wrk != NULL) {
296  msk_name_len = wrk - ptr;
297  } else {
298  msk_name_len = strlen (ptr);
299  }
300 
301  int i;
302  for (i=0 ; i<einfo.nattrs ; i++) {
303  // get this events attribute information from libpfm4, if unavailable return event not found (table must be cleared)
304  memset (&ainfo, 0, sizeof(pfm_event_attr_info_t));
305  ainfo.size = sizeof(pfm_event_attr_info_t);
306  ret = pfm_get_event_attr_info(libpfm4_index, i, PFM_OS_PERF_EVENT_EXT, &ainfo);
307  if (ret != PFM_SUCCESS) {
308  free (msk_ptr);
309  SUBDBG("EXIT: Attribute info not found, libpfm4_index: %#x, ret: %d\n", libpfm4_index, _papi_libpfm4_error(ret));
310  return NULL;
311  }
312 
313  // if this is the one we want, append its description
314  if ((msk_name_len == strlen(ainfo.name)) && (strncmp(ptr, ainfo.name, msk_name_len) == 0)) {
315  SUBDBG("Found mask: %s, i: %d\n", ainfo.name, i);
316  // find out how much space is left in the mask description work buffer we are building
317  unsigned int mskleft = sizeof(mask_desc) - strlen(mask_desc);
318  // if no space left, just discard this mask description
319  if (mskleft <= 1) {
320  SUBDBG("EXIT: Attribute description discarded: %s\n", ainfo.desc);
321  break;
322  }
323  // if description buffer is not empty, put in mask description separator
324  if (strlen(mask_desc) > 0) {
325  strcat (mask_desc, ":");
326  mskleft--;
327  }
328  // if new description will not all fit in buffer, report truncation
329  if (mskleft < (strlen(ainfo.desc) + 1)) {
330  SUBDBG("EXIT: Attribute description truncated: %s\n", ainfo.desc);
331  }
332  // move as much of this description as will fit
333  strncat (mask_desc, ainfo.desc, mskleft-1);
334  mask_desc[mskleft-1] = '\0';
335  break;
336  }
337  }
338 
339  // if we have filled the work buffer, we can quit now
340  if ( (sizeof(mask_desc) - strlen(mask_desc)) <= 1) {
341  break;
342  }
343  ptr = ptrm;
344  }
345  ntv_evt->mask_description=strdup(mask_desc);
346  SUBDBG("ntv_evt->mask_description: %p (%s)\n", ntv_evt->mask_description, ntv_evt->mask_description);
347  }
348 
349  // give back space if we got any
350  if (msk_ptr != NULL) {
351  free (msk_ptr);
352  }
353 
354  // create a papi table for this native event, put the index into the event sets array of native events into the papi table
355  int new_event_code = _papi_hwi_native_to_eventcode(_peu_libpfm4_get_cidx(), libpfm4_index, nevt_idx, ntv_evt->allocated_name);
356  _papi_hwi_set_papi_event_string((const char *)ntv_evt->allocated_name);
357  _papi_hwi_set_papi_event_code(new_event_code, 1);
358 
359  ntv_evt->papi_event_code=new_event_code;
360 
361  SUBDBG("Using %#x as index for %s\n", ntv_evt->libpfm4_idx, fullname);
362  SUBDBG("num_native_events: %d, allocated_native_events: %d\n", event_table->num_native_events, event_table->allocated_native_events);
363  SUBDBG("Native Event: papi_event_code: %#x, libpfm4_idx: %#x, pmu: %s, base_name: %s, mask_string: %s, allocated_name: %s\n",
364  ntv_evt->papi_event_code, ntv_evt->libpfm4_idx, ntv_evt->pmu, ntv_evt->base_name, ntv_evt->mask_string, ntv_evt->allocated_name);
365  SUBDBG("event_table->native_events[%d]: %p, cpu: %d, attr.config: 0x%"PRIx64", attr.config1: 0x%"PRIx64", attr.config2: 0x%"PRIx64", attr.type: 0x%"PRIx32", attr.exclude_user: %d, attr.exclude_kernel: %d, attr.exclude_guest: %d\n",
366  nevt_idx, &(event_table->native_events[nevt_idx]), ntv_evt->cpu, ntv_evt->attr.config,
367  ntv_evt->attr.config1, ntv_evt->attr.config2, ntv_evt->attr.type,
368  ntv_evt->attr.exclude_user, ntv_evt->attr.exclude_kernel, ntv_evt->attr.exclude_guest);
369 
370  /* If we've used all of the allocated native events, then allocate more room */
371  if (event_table->num_native_events >=
372  event_table->allocated_native_events-1) {
373 
374  SUBDBG("Allocating more room for native events (%d %ld)\n",
376  (long)sizeof(struct native_event_t) *
378 
379  event_table->native_events=realloc(event_table->native_events,
380  sizeof(struct native_event_t) *
383 
384  // we got new space so we need to reset the pointer to the correct native event in the new space
385  ntv_evt = &(event_table->native_events[nevt_idx]);
386  }
387 
389 
390  // if getting more space for native events failed, report that allocate failed
391  if (event_table->native_events==NULL) {
392  SUBDBG("EXIT: attempt to get more space for native events failed\n");
393  return NULL;
394  }
395 
396  // if we created a new event, bump the number used
397  if (event_num < 0) {
398  event_table->num_native_events++;
399  }
400 
401  if (encode_failed != 0) {
402  SUBDBG("EXIT: encoding event failed\n");
403  return NULL;
404  }
405 
406  SUBDBG("EXIT: new_event: %p\n", ntv_evt);
407  return ntv_evt;
408 }
409 
410 
419 static int
420 get_first_event_next_pmu(int pmu_idx, int pmu_type)
421 {
422  SUBDBG("ENTER: pmu_idx: %d, pmu_type: %d\n", pmu_idx, pmu_type);
423  int pidx, ret;
424 
425  pfm_pmu_info_t pinfo;
426 
427  // start looking at the next pmu in the list
428  pmu_idx++;
429 
430  while(pmu_idx<PFM_PMU_MAX) {
431 
432  /* clear the PMU structure (required by libpfm4) */
433  memset(&pinfo,0,sizeof(pfm_pmu_info_t));
434  pinfo.size = sizeof(pfm_pmu_info_t);
435  ret=pfm_get_pmu_info(pmu_idx, &pinfo);
436 
437  if ((ret==PFM_SUCCESS) && pmu_is_present_and_right_type(&pinfo,pmu_type)) {
438 
439  pidx=pinfo.first_event;
440  SUBDBG("First event in pmu: %s is %#x\n", pinfo.name, pidx);
441 
442  if (pidx<0) {
443  /* For some reason no events available */
444  /* despite the PMU being active. */
445  /* This can happen, for example with ix86arch */
446  /* inside of VMware */
447  }
448  else {
449  SUBDBG("EXIT: pidx: %#x\n", pidx);
450  return pidx;
451  }
452  }
453 
454  pmu_idx++;
455 
456  }
457 
458  SUBDBG("EXIT: PAPI_ENOEVNT\n");
459  return PAPI_ENOEVNT;
460 
461 }
462 
463 
464 /***********************************************************/
465 /* Exported functions */
466 /***********************************************************/
467 
482 int
483 _peu_libpfm4_ntv_name_to_code( char *name, unsigned int *event_code,
484  struct native_event_table_t *event_table)
485 {
486  SUBDBG( "ENTER: name: %s, event_code: %p, *event_code: %#x, event_table: %p\n", name, event_code, *event_code, event_table);
487 
488  struct native_event_t *our_event;
489  int event_num;
490 
491  // if we already know this event name, just return its native code
492  event_num=find_existing_event(name, event_table);
493  if (event_num >= 0) {
494  *event_code=event_table->native_events[event_num].libpfm4_idx;
495  // the following call needs to happen to prevent the internal layer from creating a new papi native event table
496  _papi_hwi_set_papi_event_code(event_table->native_events[event_num].papi_event_code, 1);
497  SUBDBG("EXIT: Found papi_event_code: %#x, libpfm4_idx: %#x\n", event_table->native_events[event_num].papi_event_code, event_table->native_events[event_num].libpfm4_idx);
498  return PAPI_OK;
499  }
500 
501  // Try to allocate this event to see if it is known by libpfm4, if allocate fails tell the caller it is not valid
502  our_event=allocate_native_event(name, -1, event_table);
503  if (our_event==NULL) {
504  SUBDBG("EXIT: Allocating event: '%s' failed\n", name);
505  return PAPI_ENOEVNT;
506  }
507 
508  *event_code = our_event->libpfm4_idx;
509  SUBDBG("EXIT: Found code: %#x\n",*event_code);
510  return PAPI_OK;
511 }
512 
513 
531 int
532 _peu_libpfm4_ntv_code_to_name(unsigned int EventCode,
533  char *ntv_name, int len,
534  struct native_event_table_t *event_table)
535 {
536  SUBDBG("ENTER: EventCode: %#x, ntv_name: %p, len: %d, event_table: %p\n", EventCode, ntv_name, len, event_table);
537 
538  int eidx;
539  int papi_event_code;
540 
541  // get the attribute index for this papi event
542  papi_event_code = _papi_hwi_get_papi_event_code();
543 
544  // a papi event code less than 0 is invalid, return error
545  if (papi_event_code <= 0) {
546  SUBDBG("EXIT: PAPI_ENOEVNT\n");
547  return PAPI_ENOEVNT;
548  }
549 
550  // find our native event table for this papi event code (search list backwards because it improves chances of finding it quickly)
551  for (eidx=event_table->num_native_events-1 ; eidx>=0 ; eidx--) {
552  if ((papi_event_code == event_table->native_events[eidx].papi_event_code) && (EventCode == ((unsigned)event_table->native_events[eidx].libpfm4_idx))) {
553  SUBDBG("Found native_event[%d]: papi_event_code: %#x, libpfm4_idx: %#x\n", eidx, event_table->native_events[eidx].papi_event_code, event_table->native_events[eidx].libpfm4_idx);
554  break;
555  }
556  }
557 
558  // if we did not find a match, return an error
559  if (eidx < 0) {
560  // If we did not find a match in our native event table, then the code passed in has not been
561  // allocated yet It should not be possible to get to this code. The user has to call the papi
562  // code_to_name api with a papi event code for a native event. But the only way to get one of
563  // those is to call either name_to_code or enum_cmp_events first. When one of these calls is
564  // done we allocate the event so it should always be there.
565 
566  SUBDBG("EXIT: PAPI_ENOEVNT\n");
567  return PAPI_ENOEVNT;
568  }
569 
570  // always use pmu name and event name for uncore events
571  char *ename = event_table->native_events[eidx].pmu_plus_name;
572 
573  // if it will not fit, return error
574  if (strlen (ename) >= (unsigned)len) {
575  SUBDBG("EXIT: event name %s will not fit in buffer provided\n", ename);
576  return PAPI_EBUF;
577  }
578  strcpy (ntv_name, ename);
579 
580  // if this event had masks, also add their names
581  char *mname = event_table->native_events[eidx].mask_string;
582  if ((mname != NULL) && (strlen(mname) > 0)) {
583  if ((strlen(ename) + 8 + strlen(mname)) >= (unsigned)len) {
584  SUBDBG("EXIT: Not enough room for event and mask descriptions: need: %u, have: %u", (unsigned)(strlen(ename) + 8 + strlen(mname)), (unsigned)len);
585  return PAPI_EBUF;
586  }
587  strcat (ntv_name, ":");
588  strcat (ntv_name, mname);
589  }
590 
591  SUBDBG("EXIT: event name: %s\n", ntv_name);
592  return PAPI_OK;
593 }
594 
595 
618 int
619 _peu_libpfm4_ntv_code_to_descr( unsigned int EventCode,
620  char *ntv_descr, int len,
621  struct native_event_table_t *event_table)
622 {
623  SUBDBG("ENTER: EventCode: %#x, ntv_descr: %p, len: %d: event_table: %p\n", EventCode, ntv_descr, len, event_table);
624 
625  int eidx;
626  int papi_event_code;
627 
628  // get the attribute index for this papi event
629  papi_event_code = _papi_hwi_get_papi_event_code();
630 
631  // a papi event code less than 0 is invalid, return error
632  if (papi_event_code <= 0) {
633  SUBDBG("EXIT: PAPI_ENOEVNT\n");
634  return PAPI_ENOEVNT;
635  }
636 
637  // find our native event table for this papi event code (search list backwards because it improves chances of finding it quickly)
638  for (eidx=event_table->num_native_events-1 ; eidx>=0 ; eidx--) {
639  SUBDBG("native_event[%d]: papi_event_code: %#x, libpfm4_idx: %#x\n", eidx, event_table->native_events[eidx].papi_event_code, event_table->native_events[eidx].libpfm4_idx);
640  if ((papi_event_code == event_table->native_events[eidx].papi_event_code) && (EventCode == ((unsigned)event_table->native_events[eidx].libpfm4_idx))) {
641  break;
642  }
643  }
644 
645  // if we did not find a match, return an error
646  if (eidx < 0) {
647  // If we did not find a match in our native event table, then the code passed in has not been
648  // allocated yet It should not be possible to get to this code. The user has to call the papi
649  // code_to_name api with a papi event code for a native event. But the only way to get one of
650  // those is to call either name_to_code or enum_cmp_events first. When one of these calls is
651  // done we allocate the event so it should always be there.
652 
653  SUBDBG("EXIT: PAPI_ENOEVNT\n");
654  return PAPI_ENOEVNT;
655  }
656 
657  char *edesc = event_table->native_events[eidx].event_description;
658 
659  // if it will not fit, return error
660  if (strlen (edesc) >= (unsigned)len) {
661  SUBDBG("EXIT: event name %s will not fit in buffer provided\n", edesc);
662  return PAPI_EBUF;
663  }
664  strcpy (ntv_descr, edesc);
665 
666  // if this event had masks, also add their descriptions
667  char *mdesc = event_table->native_events[eidx].mask_description;
668  if ((mdesc != NULL) && (strlen(mdesc) > 0)) {
669  if ((strlen(edesc) + 8 + strlen(mdesc)) >= (unsigned)len) {
670  SUBDBG("EXIT: Not enough room for event and mask descriptions: need: %u, have: %u", (unsigned)(strlen(edesc) + 8 + strlen(mdesc)), (unsigned)len);
671  return PAPI_EBUF;
672  }
673  strcat (ntv_descr, ", masks:");
674  strcat (ntv_descr, mdesc);
675  }
676 
677  SUBDBG("EXIT: event description: %s\n", ntv_descr);
678  return PAPI_OK;
679 }
680 
681 
682 int
683 _peu_libpfm4_ntv_code_to_info(unsigned int EventCode,
684  PAPI_event_info_t *info,
685  struct native_event_table_t *event_table)
686 {
687  SUBDBG("ENTER: EventCode: %#x, info: %p, event_table: %p\n", EventCode, info, event_table);
688 
689  int ret;
690 
691  // get the event name first
692  if ((ret = _peu_libpfm4_ntv_code_to_name(EventCode, info->symbol, sizeof(info->symbol), event_table)) != PAPI_OK) {
693  SUBDBG("EXIT: _peu_libpfm4_ntv_code_to_name returned: %d\n", ret);
694  return PAPI_ENOEVNT;
695  }
696 
697  if ((ret = _peu_libpfm4_ntv_code_to_descr(EventCode, info->long_descr, sizeof(info->long_descr), event_table)) != PAPI_OK) {
698  SUBDBG("EXIT: _peu_libpfm4_ntv_code_to_descr returned: %d\n", ret);
699  return PAPI_ENOEVNT;
700  }
701 
702  SUBDBG("EXIT: EventCode: %#x, name: %s, desc: %s\n", EventCode, info->symbol, info->long_descr);
703  return PAPI_OK;
704 }
705 
706 
723 int
724 _peu_libpfm4_ntv_enum_events( unsigned int *PapiEventCode,
725  int modifier,
726  struct native_event_table_t *event_table) {
727 
728  SUBDBG("ENTER: PapiEventCode: %p, *PapiEventCode: %#x, modifier: %d, event_table: %p\n", PapiEventCode, *PapiEventCode, modifier, event_table);
729 
730  int code,ret, pnum;
731  int max_umasks;
732  char event_string[BUFSIZ];
733  pfm_pmu_info_t pinfo;
734  pfm_event_info_t einfo;
735  struct native_event_t *our_event;
736 
737  /* return first event if so specified */
738  if ( modifier == PAPI_ENUM_FIRST ) {
739  attr_idx = 0; // set so if they want attribute information, it will start with the first attribute
740  code=get_first_event_next_pmu(-1, event_table->pmu_type);
741  if (code < 0 ) {
742  SUBDBG("EXIT: Invalid component first event code: %d\n", code);
743  return code;
744  }
745 
746  // get the event information from libpfm4 (must zero structure)
747  memset( &einfo, 0, sizeof( pfm_event_info_t ));
748  einfo.size = sizeof(pfm_event_info_t);
749  if ((ret = pfm_get_event_info(code, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
750  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
751  return PAPI_ENOIMPL;
752  }
753 
754  // get the pmu information from libpfm4 (must zero structure)
755  memset( &pinfo, 0, sizeof(pfm_pmu_info_t) );
756  pinfo.size = sizeof(pfm_pmu_info_t);
757  ret=pfm_get_pmu_info(einfo.pmu, &pinfo);
758  if (ret!=PFM_SUCCESS) {
759  SUBDBG("EXIT: pfm_get_pmu_info returned: %d\n", ret);
760  return ret;
761  }
762 
763  // build full event name
764  sprintf (event_string, "%s::%s", pinfo.name, einfo.name);
765  SUBDBG("code: %#x, pmu: %s, event: %s, event_string: %s\n", code, pinfo.name, einfo.name, event_string);
766 
767  // go allocate this event, need to create tables used by the get event info call that will probably follow
768  if ((our_event = allocate_native_event(event_string, code, event_table)) == NULL) {
769  // allocate may have created the event table but returned NULL to tell the caller the event string was invalid (attempt to encode it failed).
770  // if the caller wants to use this event to count something, it will report an error
771  // but if the caller is just interested in listing the event, then we need an event table with an event name and libpfm4 index
772  int evt_idx;
773  if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
774  SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
775  return PAPI_ENOEVNT;
776  }
777 
778  // give back the new event code
779  *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
780  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
781  return PAPI_OK;
782  }
783 
784  *PapiEventCode = our_event->libpfm4_idx;
785 
786  SUBDBG("EXIT: *PapiEventCode: %#x\n", *PapiEventCode);
787  return PAPI_OK;
788  }
789 
790  /* Handle looking for the next event */
791  if ( modifier == PAPI_ENUM_EVENTS ) {
792  attr_idx = 0; // set so if they want attribute information, it will start with the first attribute
793 
794  // get the next event code from libpfm4, if there are no more in this pmu find first event in next pmu
795  if ((code = pfm_get_event_next(*PapiEventCode)) < 0) {
796 
797  // get this events information from libpfm4, we need the pmu number of the last event we processed (table must be cleared)
798  memset( &einfo, 0, sizeof( pfm_event_info_t ));
799  einfo.size = sizeof(pfm_event_info_t);
800  if ((ret = pfm_get_event_info(*PapiEventCode, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
801  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
802  return PAPI_ENOIMPL;
803  }
804  SUBDBG("*PapiEventCode: %#x, event: %s\n", *PapiEventCode, einfo.name);
805 
806  // get the pmu number of the last event
807  pnum = einfo.pmu;
808 
809  while ( pnum<PFM_PMU_MAX) {
810  SUBDBG("pnum: %d\n", pnum);
811  code=get_first_event_next_pmu(pnum, event_table->pmu_type);
812  if (code < 0) {
813  SUBDBG("EXIT: No more pmu's to list, returning: %d\n", code);
814  return code;
815  }
816  break;
817  }
818  }
819 
820 
821  // get the event information from libpfm4 (must zero structure)
822  memset( &einfo, 0, sizeof( pfm_event_info_t ));
823  einfo.size = sizeof(pfm_event_info_t);
824  if ((ret = pfm_get_event_info(code, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
825  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
826  return PAPI_ENOIMPL;
827  }
828 
829  // get the pmu information from libpfm4 (must zero structure)
830  memset( &pinfo, 0, sizeof(pfm_pmu_info_t) );
831  pinfo.size = sizeof(pfm_pmu_info_t);
832  ret=pfm_get_pmu_info(einfo.pmu, &pinfo);
833  if (ret!=PFM_SUCCESS) {
834  SUBDBG("EXIT: pfm_get_pmu_info returned: %d\n", ret);
835  return ret;
836  }
837 
838  // build full event name
839  sprintf (event_string, "%s::%s", pinfo.name, einfo.name);
840  SUBDBG("code: %#x, pmu: %s, event: %s, event_string: %s\n", code, pinfo.name, einfo.name, event_string);
841 
842  // go allocate this event, need to create tables used by the get event info call that will follow
843  if ((our_event = allocate_native_event(event_string, code, event_table)) == NULL) {
844  // allocate may have created the event table but returned NULL to tell the caller the event string was invalid (attempt to encode it failed).
845  // if the caller wants to use this event to count something, it will report an error
846  // but if the caller is just interested in listing the event, then we need an event table with an event name and libpfm4 index
847  int evt_idx;
848  if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
849  SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
850  return PAPI_ENOEVNT;
851  }
852 
853  // give back the new event code
854  *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
855  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
856  return PAPI_OK;
857  }
858 
859  // give back the new event code
860  *PapiEventCode = our_event->libpfm4_idx;
861 
862  SUBDBG("EXIT: *PapiEventCode: %#x\n", *PapiEventCode);
863  return PAPI_OK;
864  }
865 
866  /* We don't handle PAPI_NTV_ENUM_UMASK_COMBOS */
867  if ( modifier == PAPI_NTV_ENUM_UMASK_COMBOS ) {
868  SUBDBG("EXIT: do not support umask combos yet\n");
869  return PAPI_ENOIMPL;
870  }
871 
872  /* Enumerate PAPI_NTV_ENUM_UMASKS (umasks on an event) */
873  if ( modifier == PAPI_NTV_ENUM_UMASKS ) {
874  // get this events information from libpfm4, we need the number of masks this event knows about (table must be cleared)
875  memset( &einfo, 0, sizeof( pfm_event_info_t ));
876  einfo.size = sizeof(pfm_event_info_t);
877  if ((ret = pfm_get_event_info(*PapiEventCode, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
878  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
879  return PAPI_ENOIMPL;
880  }
881 // SUBDBG("*PapiEventCode: %#x, einfo.name: %s, einfo.code: %#x, einfo.nattrs: %d\n", *PapiEventCode, einfo.name, einfo.code, einfo.nattrs);
882 
883  // set max number of masks
884  max_umasks = einfo.nattrs;
885 
886  // if we reached last attribute, return error to show we are done with this events masks
887  if (attr_idx == max_umasks) {
888  SUBDBG("EXIT: already processed all umasks: attr_idx: %d\n", attr_idx);
889  return PAPI_ENOEVNT;
890  }
891 
892  // find the event table for this event, we need the pmu name and event name without any masks
894  if (ntv_idx < 0) {
895  SUBDBG("EXIT: _papi_hwi_get_ntv_idx returned: %d\n", ntv_idx);
896  return ntv_idx;
897  }
898  char *ename = event_table->native_events[ntv_idx].pmu_plus_name;
899  if ((ename == NULL) || (strlen(ename) >= sizeof(event_string))) {
900  SUBDBG("EXIT: Event name will not fit into buffer\n");
901  return PAPI_EBUF;
902  }
903  strcpy (event_string, ename);
904  SUBDBG("event_string: %s\n", event_string);
905 
906  // go get the attribute information for this event
907  // libpfm4 likes the table cleared
908  pfm_event_attr_info_t ainfo;
909  memset (&ainfo, 0, sizeof(pfm_event_attr_info_t));
910  ainfo.size = sizeof(pfm_event_attr_info_t);
911  ret = pfm_get_event_attr_info(*PapiEventCode, attr_idx, PFM_OS_PERF_EVENT_EXT, &ainfo);
912  if (ret != PFM_SUCCESS) {
913  SUBDBG("EXIT: Attribute info not found, EventCode: %#x, attr_idx: %d, ret: %d\n", *PapiEventCode, attr_idx, _papi_libpfm4_error(ret));
914  return _papi_libpfm4_error(ret);
915  }
916  SUBDBG("*PapiEventCode: %#x, attr_idx: %d, type: %d, name: %s, description: %s\n", *PapiEventCode, attr_idx, ainfo.type, ainfo.name, ainfo.desc);
917 
918  if (strlen(event_string) + strlen(ainfo.name) + 35 > sizeof(event_string)) {
919  SUBDBG("EXIT: Event name and mask will not fit into buffer\n");
920  return PAPI_EBUF;
921  }
922 
923  strcat (event_string, ":");
924  strcat (event_string, ainfo.name);
925  switch (ainfo.type) {
926  case PFM_ATTR_UMASK:
927  break;
928  case PFM_ATTR_MOD_BOOL:
929  case PFM_ATTR_MOD_INTEGER:
930  // a few attributes require a non-zero value to encode correctly (most would accept zero here)
931  strcat(event_string,"=0");
932  break;
933  default:
934  SUBDBG("EXIT: Unsupported attribute type: %d", ainfo.type);
935  return PAPI_EATTR;
936  }
937 
938  // go allocate this event, need to create tables used by the get event info call that will follow
939  if ((our_event = allocate_native_event(event_string, *PapiEventCode, event_table)) == NULL) {
940  // allocate may have created the event table but returned NULL to tell the caller the event string was invalid.
941  // if the caller wants to use this event to count something, it must report the error
942  // but if the caller is just interested in listing the event (like this code), then find the table that was created and return its libpfm4 index
943  int evt_idx;
944  if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
945  SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
946  return PAPI_ENOEVNT;
947  }
948  // bump so next time we will use next attribute
949  attr_idx++;
950  // give back the new event code
951  *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
952  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
953  return PAPI_OK;
954  }
955 
956  // bump so next time we will use next attribute
957  attr_idx++;
958 
959  // give back the new event code
960  *PapiEventCode = our_event->libpfm4_idx;
961 
962  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
963  return PAPI_OK;
964  }
965 
966  /* Enumerate PAPI_NTV_ENUM_GROUPS (groups on an event) */
967  if ( modifier == PAPI_NTV_ENUM_GROUPS ) {
968  SUBDBG("EXIT: do not support enumerating groups in this component\n");
969  return PAPI_ENOIMPL;
970  }
971 
972  /* An unknown enumeration method was indicated */
973 
974  SUBDBG("EXIT: Invalid modifier argument provided\n");
975  return PAPI_ENOIMPL;
976 }
977 
978 
989 int
991  struct native_event_table_t *event_table) {
992  SUBDBG("ENTER: event_table: %p\n", event_table);
993 
994  int i;
995 
996  for (i=0 ; i<PAPI_PMU_MAX ; i++) {
997  if (my_vector->cmp_info.pmu_names[i] != NULL) {
998  free (my_vector->cmp_info.pmu_names[i]);
999  }
1000  }
1001 
1002  /* clean out and free the native events structure */
1004 
1005  /* free memory allocated with strdup or malloc */
1006  for( i=0; i<event_table->num_native_events; i++) {
1007  free(event_table->native_events[i].base_name);
1008  free(event_table->native_events[i].pmu_plus_name);
1009  free(event_table->native_events[i].pmu);
1010  free(event_table->native_events[i].allocated_name);
1011  free(event_table->native_events[i].mask_string);
1012  free(event_table->native_events[i].event_description);
1013  if (event_table->native_events[i].mask_description != NULL) {
1014  free(event_table->native_events[i].mask_description);
1015  }
1016  }
1017 
1018  free(event_table->native_events);
1019 
1021 
1022  SUBDBG("EXIT: PAPI_OK\n");
1023  return PAPI_OK;
1024 }
1025 
1026 
1038 int
1040  struct native_event_table_t *event_table,
1041  int pmu_type) {
1042 
1043  int detected_pmus=0;
1044  int i;
1045  int j=0;
1046  pfm_err_t retval = PFM_SUCCESS;
1047  unsigned int ncnt;
1048  pfm_pmu_info_t pinfo;
1049 
1050  /* allocate the native event structure */
1051 
1052  event_table->num_native_events=0;
1053  event_table->pmu_type=pmu_type;
1054 
1055  event_table->native_events=calloc(NATIVE_EVENT_CHUNK,
1056  sizeof(struct native_event_t));
1057  if (event_table->native_events==NULL) {
1058  return PAPI_ENOMEM;
1059  }
1061 
1062  /* Count number of present PMUs */
1063  detected_pmus=0;
1064  ncnt=0;
1065 
1066  my_vector->cmp_info.num_cntrs=0;
1067 
1068  SUBDBG("Detected pmus:\n");
1069  for(i=0;i<PFM_PMU_MAX;i++) {
1070  memset(&pinfo,0,sizeof(pfm_pmu_info_t));
1071  pinfo.size = sizeof(pfm_pmu_info_t);
1072  retval=pfm_get_pmu_info(i, &pinfo);
1073  if (retval!=PFM_SUCCESS) {
1074  continue;
1075  }
1076 
1077  if (pmu_is_present_and_right_type(&pinfo,pmu_type)) {
1078  SUBDBG("\t%d %s %s %d\n",i,pinfo.name,pinfo.desc,pinfo.type);
1079 
1080  detected_pmus++;
1081  ncnt+=pinfo.nevents;
1082 
1083  if ((j < PAPI_PMU_MAX) && (pinfo.name != NULL)) {
1084  my_vector->cmp_info.pmu_names[j++] = strdup(pinfo.name);
1085  }
1086  my_vector->cmp_info.num_cntrs += pinfo.num_cntrs+
1087  pinfo.num_fixed_cntrs;
1088  }
1089  }
1090  SUBDBG("%d native events detected on %d pmus\n",ncnt,detected_pmus);
1091 
1092  my_vector->cmp_info.num_native_events = ncnt;
1093 
1094  SUBDBG( "num_counters: %d\n", my_vector->cmp_info.num_cntrs );
1095 
1096  return PAPI_OK;
1097 }
1098 
#define PAPI_ENOEVNT
Definition: papi.h:258
sprintf(splash[splash_line++],"\tIozone: Performance Test of File I/O\n")
memset(eventId, 0, size)
int _papi_hwi_get_ntv_idx(unsigned int papi_evt_code)
static unsigned int papi_event_code
unsigned int _papi_hwi_get_papi_event_code()
struct native_event_t * native_events
char long_descr[PAPI_HUGE_STR_LEN]
Definition: papi.h:966
char symbol[PAPI_HUGE_STR_LEN]
Definition: papi.h:963
device[deviceId] domain[domainId] event
Definition: linux-cuda.c:306
return PAPI_OK
Definition: linux-nvml.c:458
#define PAPI_EBUF
Definition: papi.h:271
#define PMU_TYPE_OS
int _peu_libpfm4_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info, struct native_event_table_t *event_table)
int _peu_libpfm4_ntv_enum_events(unsigned int *PapiEventCode, int modifier, struct native_event_table_t *event_table)
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
int _papi_libpfm4_error(int pfm_error)
int _peu_libpfm4_init(papi_vector_t *my_vector, struct native_event_table_t *event_table, int pmu_type)
#define PAPI_HUGE_STR_LEN
Definition: papi.h:465
Return codes and api definitions.
long long ret
Definition: iozone.c:1346
static int attr_idx
int i
Definition: fileop.c:140
inline_static int _papi_hwi_lock(int lck)
Definition: threads.h:64
int _papi_hwi_native_to_eventcode(int cidx, int event_code, int ntv_idx, const char *event_name)
#define PAPI_PMU_MAX
Definition: papi.h:467
int _peu_libpfm4_ntv_name_to_code(char *name, unsigned int *event_code, struct native_event_table_t *event_table)
free(dummyfile[xx])
#define PAPI_EATTR
Definition: papi.h:273
int _peu_libpfm4_ntv_code_to_descr(unsigned int EventCode, char *ntv_descr, int len, struct native_event_table_t *event_table)
char * pmu_names[PAPI_PMU_MAX]
Definition: papi.h:647
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:78
static int get_first_event_next_pmu(int pmu_idx, int pmu_type)
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
static struct native_event_t * allocate_native_event(char *name, int libpfm4_index, struct native_event_table_t *event_table)
strcat(command, mountname)
#define PMU_TYPE_CORE
#define PAPI_ENOMEM
Definition: papi.h:252
#define NAMELIB_LOCK
Definition: papi_internal.h:93
#define PAPI_ENOIMPL
Definition: papi.h:270
strcpy(filename, default_filename)
int _peu_libpfm4_get_cidx()
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
#define PMU_TYPE_UNCORE
perf_event_attr_t attr
char * name
Definition: iozone.c:23648
static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type)
int _peu_libpfm4_ntv_code_to_name(unsigned int EventCode, char *ntv_name, int len, struct native_event_table_t *event_table)
int _peu_libpfm4_shutdown(papi_vector_t *my_vector, struct native_event_table_t *event_table)
static int find_existing_event(char *name, struct native_event_table_t *event_table)
long j
Definition: iozone.c:19135
ssize_t retval
Definition: libasync.c:338
#define NATIVE_EVENT_CHUNK
void _papi_hwi_set_papi_event_string(const char *event_string)
Definition: papi_internal.c:89
char * ptr
Definition: iozone.c:23586