PAPI  5.4.1.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pe_libpfm4_events.c
Go to the documentation of this file.
1 /*
2 * File: pe_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 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 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 "pe_libpfm4_events.h"
24 #include "perf_event_lib.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  int nameLen = strlen(event_table->native_events[i].base_name);
66  // the name we are looking for must be the same length as this event table entry name for them to match
67  if (strlen(name) != nameLen + strlen(event_table->native_events[i].mask_string) + 1) {
68  continue;
69  }
70  if(!strcmp(name+nameLen+1, event_table->native_events[i].mask_string)) {
71  SUBDBG("Found base_name: %s, mask_string: %s, libpfm4_idx: %#x, papi_event_code: %#x\n",
72  event_table->native_events[i].base_name, event_table->native_events[i].mask_string , event_table->native_events[i].libpfm4_idx, event_table->native_events[i].papi_event_code);
73  event=i;
74  break;
75  }
76  }
77  }
79 
80  SUBDBG("EXIT: returned: %#x\n", event);
81  return event;
82 }
83 
84 
85 static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type) {
86 // SUBDBG("ENTER: pinfo: %p, pinfo->is_present: %d, pinfo->type: %#x, type: %#x\n", pinfo, pinfo->is_present, pinfo->type, type);
87  if (!pinfo->is_present) {
88 // SUBDBG("EXIT: not present\n");
89  return 0;
90  }
91 
92  if ((pinfo->type==PFM_PMU_TYPE_UNCORE) && (type&PMU_TYPE_UNCORE)) {
93 // SUBDBG("EXIT: found PFM_PMU_TYPE_UNCORE\n");
94  return 1;
95  }
96  if ((pinfo->type==PFM_PMU_TYPE_CORE) && (type&PMU_TYPE_CORE)) {
97 // SUBDBG("EXIT: found PFM_PMU_TYPE_CORE\n");
98  return 1;
99  }
100  if ((pinfo->type==PFM_PMU_TYPE_OS_GENERIC) && (type&PMU_TYPE_OS)) {
101 // SUBDBG("EXIT: found PFM_PMU_TYPE_OS_GENERIC\n");
102  return 1;
103  }
104 
105 // SUBDBG("EXIT: not right type\n");
106  return 0;
107 }
108 
109 
124 static struct native_event_t *allocate_native_event(char *name, int libpfm4_index,
125  struct native_event_table_t *event_table) {
126 
127  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);
128 
129  int nevt_idx;
130  int event_num;
131  int encode_failed=0;
132 
133  pfm_err_t ret;
134  char *event_string=NULL;
135  char *pmu_name;
136  char *event;
137  char *masks;
138  char fullname[BUFSIZ];
139  struct native_event_t *ntv_evt;
140 
141  pfm_perf_encode_arg_t perf_arg;
142  pfm_event_info_t einfo;
143  pfm_event_attr_info_t ainfo;
144  pfm_pmu_info_t pinfo;
145 
146  // if no place to put native events, report that allocate failed
147  if (event_table->native_events==NULL) {
148  SUBDBG("EXIT: no place to put native events\n");
149  return NULL;
150  }
151 
152  // find out if this event is already known
153  event_num=find_existing_event(name, event_table);
154 
155  /* add the event to our event table */
157 
158  // if we already know this event name, it was created as part of setting up the preset tables
159  // we need to use the event table which is already created
160  if (event_num >= 0) {
161  nevt_idx = event_num;
162  ntv_evt = &(event_table->native_events[event_num]);
163  } else {
164  // 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)
165  nevt_idx = event_table->num_native_events;
166  ntv_evt = &(event_table->native_events[nevt_idx]);
167  }
168 
169  SUBDBG("event_num: %d, nevt_idx: %d, ntv_evt: %p\n", event_num, nevt_idx, ntv_evt);
170 
171  /* clear the argument and attribute structures */
172  memset(&perf_arg,0,sizeof(pfm_perf_encode_arg_t));
173  memset(&(ntv_evt->attr),0,sizeof(struct perf_event_attr));
174 
175  // set argument structure fields so the encode function can give us what we need
176  perf_arg.attr=&ntv_evt->attr;
177 
178  /* use user provided name of the event to get the perf_event encoding and a fully qualified event string */
179  ret = pfm_get_os_event_encoding(name,
180  PFM_PLM0 | PFM_PLM3,
181  PFM_OS_PERF_EVENT_EXT,
182  &perf_arg);
183 
184  // If the encode function failed, skip processing of the event_string
185  if (ret != PFM_SUCCESS) {
186  SUBDBG("encode failed for event: %s, returned: %d\n", name, ret);
187 
188  // we need to remember that this event encoding failed but still create the native event table
189  // the event table is used by the list so we put what we can get into it
190  // but the failure doing the encode causes us to return null to our caller
191  encode_failed = 1;
192 
193  // Noting the encode_failed error in the attr.config allows
194  // any later validate attempts to return an error value
195  ntv_evt->attr.config = 0xFFFFFF;
196 
197  // we also want to make it look like a cpu number was not provided as an event mask
198  perf_arg.cpu = -1;
199  }
200 
201  // get a copy of the event name and break it up into its parts
202  event_string = strdup(name);
203 
204  SUBDBG("event_string: %s\n", event_string);
205 
206  // get the pmu name, event name and mask list pointers from the event string
207  event = strstr (event_string, "::");
208  if (event != NULL) {
209  *event = 0; // null terminate pmu name
210  event += 2; // event name follows '::'
211  pmu_name = strdup(event_string);
212  } else {
213  // no pmu name in event string
214  pmu_name = malloc(2);
215  pmu_name[0] = 0;
216  event = event_string;
217  }
218  masks = strstr (event, ":");
219  if (masks != NULL) {
220  *masks = 0; // null terminate event name
221  masks += 1; // masks follow :
222  } else {
223  masks = "";
224  }
225 
226  // build event name to find, put a pmu name on it if we have one
227  if(strlen(pmu_name) == 0) {
228  sprintf(fullname,"%s", event);
229  } else {
230  sprintf(fullname,"%s::%s", pmu_name, event);
231  }
232  SUBDBG("pmu_name: %s, event: %s, masks: %s, fullname: %s\n", pmu_name, event, masks, fullname);
233 
234  // if the libpfm4 index was not provided, try to get one based on the event name passed in.
235  if (libpfm4_index == -1) {
236  libpfm4_index = pfm_find_event(fullname);
237  if (libpfm4_index < 0) {
238  free(event_string);
239  free(pmu_name);
241  SUBDBG("EXIT: error from libpfm4 find event\n");
242  return NULL;
243  }
244  SUBDBG("libpfm4_index: %#x\n", libpfm4_index);
245  }
246 
247  // get this events information from libpfm4, if unavailable return event not found (structure be zeroed)
248  memset( &einfo, 0, sizeof( pfm_event_info_t ));
249  einfo.size = sizeof(pfm_event_info_t);
250  if ((ret = pfm_get_event_info(libpfm4_index, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
251  free(event_string);
252  free(pmu_name);
254  SUBDBG("EXIT: pfm_get_event_info failed with %d\n", ret);
255  return NULL;
256  }
257 
258  // if pmu type is not one supported by this component, return event not found (structure be zeroed)
259  memset(&pinfo,0,sizeof(pfm_pmu_info_t));
260  pinfo.size = sizeof(pfm_pmu_info_t);
261  pfm_get_pmu_info(einfo.pmu, &pinfo);
262  if (pmu_is_present_and_right_type(&pinfo, event_table->pmu_type) == 0) {
263  free(event_string);
264  free(pmu_name);
266  SUBDBG("EXIT: PMU not supported by this component: einfo.pmu: %d, PFM_PMU_TYPE_CORE: %d\n", einfo.pmu, PFM_PMU_TYPE_CORE);
267  return NULL;
268  }
269 
270  ntv_evt->allocated_name=strdup(name);
271  ntv_evt->mask_string=strdup(masks);
272  ntv_evt->component=_pe_libpfm4_get_cidx();
273  ntv_evt->pmu=pmu_name;
274  ntv_evt->base_name=strdup(event);
275  ntv_evt->pmu_plus_name=strdup(fullname);
276  ntv_evt->libpfm4_idx=libpfm4_index;
277  ntv_evt->event_description=strdup(einfo.desc);
278  ntv_evt->users=0; /* is this needed? */
279  ntv_evt->cpu=perf_arg.cpu;
280 
281  SUBDBG("ntv_evt->mask_string: %p (%s)\n", ntv_evt->mask_string, ntv_evt->mask_string);
282  char *msk_ptr = strdup(masks); // get a work copy of the mask string before we free the space it was in
283  free(event_string);
284 
285  // if there is any mask data, collect their descriptions
286  if ((msk_ptr != NULL) && (strlen(msk_ptr) > 0)) {
287  // go get the descriptions for each of the masks provided with this event
288  char mask_desc[PAPI_HUGE_STR_LEN] = "";
289  char *ptr = msk_ptr;
290  SUBDBG("ptr: %p (%s)\n", ptr, ptr);
291  while (ptr != NULL) {
292  char *ptrm = strstr(ptr, ":");
293  if (ptrm != NULL) {
294  *ptrm = '\0';
295  ptrm++;
296  }
297 
298  // get the length of the mask name
299  char *wrk = strchr(ptr, '=');
300  unsigned int msk_name_len;
301  if (wrk != NULL) {
302  msk_name_len = wrk - ptr;
303  } else {
304  msk_name_len = strlen (ptr);
305  }
306 
307  int i;
308  for (i=0 ; i<einfo.nattrs ; i++) {
309  // get this events attribute information from libpfm4, if unavailable return event not found (table must be cleared)
310  memset (&ainfo, 0, sizeof(pfm_event_attr_info_t));
311  ainfo.size = sizeof(pfm_event_attr_info_t);
312  ret = pfm_get_event_attr_info(libpfm4_index, i, PFM_OS_PERF_EVENT_EXT, &ainfo);
313  if (ret != PFM_SUCCESS) {
314  free (msk_ptr);
315  SUBDBG("EXIT: Attribute info not found, libpfm4_index: %#x, ret: %d\n", libpfm4_index, _papi_libpfm4_error(ret));
316  return NULL;
317  }
318 
319  // if this is the one we want, append its description
320  if ((msk_name_len == strlen(ainfo.name)) && (strncmp(ptr, ainfo.name, msk_name_len) == 0)) {
321  SUBDBG("Found mask: %s, i: %d\n", ainfo.name, i);
322  // find out how much space is left in the mask description work buffer we are building
323  unsigned int mskleft = sizeof(mask_desc) - strlen(mask_desc);
324  // if no space left, just discard this mask description
325  if (mskleft <= 1) {
326  SUBDBG("EXIT: Attribute description discarded: %s\n", ainfo.desc);
327  break;
328  }
329  // if description buffer is not empty, put in mask description separator
330  if (strlen(mask_desc) > 0) {
331  strcat (mask_desc, ":");
332  mskleft--;
333  }
334  // if new description will not all fit in buffer, report truncation
335  if (mskleft < (strlen(ainfo.desc) + 1)) {
336  SUBDBG("EXIT: Attribute description truncated: %s\n", ainfo.desc);
337  }
338  // move as much of this description as will fit
339  strncat (mask_desc, ainfo.desc, mskleft-1);
340  mask_desc[mskleft-1] = '\0';
341  break;
342  }
343  }
344 
345  // if we have filled the work buffer, we can quit now
346  if ( (sizeof(mask_desc) - strlen(mask_desc)) <= 1) {
347  break;
348  }
349  ptr = ptrm;
350  }
351  ntv_evt->mask_description=strdup(mask_desc);
352  SUBDBG("ntv_evt->mask_description: %p (%s)\n", ntv_evt->mask_description, ntv_evt->mask_description);
353  }
354 
355  // give back space if we got any
356  if (msk_ptr != NULL) {
357  free (msk_ptr);
358  }
359 
360  // create a papi table for this native event, put the index into the event sets array of native events into the papi table
361  int new_event_code = _papi_hwi_native_to_eventcode(_pe_libpfm4_get_cidx(), libpfm4_index, nevt_idx, ntv_evt->allocated_name);
362  _papi_hwi_set_papi_event_string((const char *)ntv_evt->allocated_name);
363  _papi_hwi_set_papi_event_code(new_event_code, 1);
364 
365  ntv_evt->papi_event_code=new_event_code;
366 
367  SUBDBG("Using %#x as index for %s\n", ntv_evt->libpfm4_idx, fullname);
368  SUBDBG("num_native_events: %d, allocated_native_events: %d\n", event_table->num_native_events, event_table->allocated_native_events);
369  SUBDBG("Native Event: papi_event_code: %#x, libpfm4_idx: %#x, pmu: %s, base_name: %s, mask_string: %s, allocated_name: %s\n",
370  ntv_evt->papi_event_code, ntv_evt->libpfm4_idx, ntv_evt->pmu, ntv_evt->base_name, ntv_evt->mask_string, ntv_evt->allocated_name);
371  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",
372  nevt_idx, &(event_table->native_events[nevt_idx]), ntv_evt->cpu, ntv_evt->attr.config,
373  ntv_evt->attr.config1, ntv_evt->attr.config2, ntv_evt->attr.type,
374  ntv_evt->attr.exclude_user, ntv_evt->attr.exclude_kernel, ntv_evt->attr.exclude_guest);
375 
376  /* If we've used all of the allocated native events, then allocate more room */
377  if (event_table->num_native_events >=
378  event_table->allocated_native_events-1) {
379 
380  SUBDBG("Allocating more room for native events (%d %ld)\n",
382  (long)sizeof(struct native_event_t) *
384 
385  event_table->native_events=realloc(event_table->native_events,
386  sizeof(struct native_event_t) *
389 
390  // we got new space so we need to reset the pointer to the correct native event in the new space
391  ntv_evt = &(event_table->native_events[nevt_idx]);
392  }
393 
395 
396  // if getting more space for native events failed, report that allocate failed
397  if (event_table->native_events==NULL) {
398  SUBDBG("EXIT: attempt to get more space for native events failed\n");
399  return NULL;
400  }
401 
402  // if we created a new event, bump the number used
403  if (event_num < 0) {
404  event_table->num_native_events++;
405  }
406 
407  if (encode_failed != 0) {
408  SUBDBG("EXIT: encoding event failed\n");
409  return NULL;
410  }
411 
412  SUBDBG("EXIT: new_event: %p\n", ntv_evt);
413  return ntv_evt;
414 }
415 
416 
425 static int
426 get_first_event_next_pmu(int pmu_idx, int pmu_type)
427 {
428  SUBDBG("ENTER: pmu_idx: %d, pmu_type: %d\n", pmu_idx, pmu_type);
429  int pidx, ret;
430 
431  pfm_pmu_info_t pinfo;
432 
433  // start looking at the next pmu in the list
434  pmu_idx++;
435 
436  while(pmu_idx<PFM_PMU_MAX) {
437 
438  /* clear the PMU structure (required by libpfm4) */
439  memset(&pinfo,0,sizeof(pfm_pmu_info_t));
440  pinfo.size = sizeof(pfm_pmu_info_t);
441  ret=pfm_get_pmu_info(pmu_idx, &pinfo);
442 
443  if ((ret==PFM_SUCCESS) && pmu_is_present_and_right_type(&pinfo,pmu_type)) {
444 
445  pidx=pinfo.first_event;
446  SUBDBG("First event in pmu: %s is %#x\n", pinfo.name, pidx);
447 
448  if (pidx<0) {
449  /* For some reason no events available */
450  /* despite the PMU being active. */
451  /* This can happen, for example with ix86arch */
452  /* inside of VMware */
453  }
454  else {
455  SUBDBG("EXIT: pidx: %#x\n", pidx);
456  return pidx;
457  }
458  }
459 
460  pmu_idx++;
461 
462  }
463 
464  SUBDBG("EXIT: PAPI_ENOEVNT\n");
465  return PAPI_ENOEVNT;
466 
467 }
468 
469 
470 /***********************************************************/
471 /* Exported functions */
472 /***********************************************************/
473 
488 int
489 _pe_libpfm4_ntv_name_to_code( char *name, unsigned int *event_code,
490  struct native_event_table_t *event_table)
491 {
492  SUBDBG( "ENTER: name: %s, event_code: %p, *event_code: %#x, event_table: %p\n", name, event_code, *event_code, event_table);
493 
494  struct native_event_t *our_event;
495  int event_num;
496 
497  // if we already know this event name, just return its native code
498  event_num=find_existing_event(name, event_table);
499  if (event_num >= 0) {
500  *event_code=event_table->native_events[event_num].libpfm4_idx;
501  // the following call needs to happen to prevent the internal layer from creating a new papi native event table
502  _papi_hwi_set_papi_event_code(event_table->native_events[event_num].papi_event_code, 1);
503  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);
504  return PAPI_OK;
505  }
506 
507  // Try to allocate this event to see if it is known by libpfm4, if allocate fails tell the caller it is not valid
508  our_event=allocate_native_event(name, -1, event_table);
509  if (our_event==NULL) {
510  SUBDBG("EXIT: Allocating event: '%s' failed\n", name);
511  return PAPI_ENOEVNT;
512  }
513 
514  *event_code = our_event->libpfm4_idx;
515  SUBDBG("EXIT: Found code: %#x\n",*event_code);
516  return PAPI_OK;
517 }
518 
519 
537 int
538 _pe_libpfm4_ntv_code_to_name(unsigned int EventCode,
539  char *ntv_name, int len,
540  struct native_event_table_t *event_table)
541 {
542  SUBDBG("ENTER: EventCode: %#x, ntv_name: %p, len: %d, event_table: %p\n", EventCode, ntv_name, len, event_table);
543 
544  int eidx;
545  int papi_event_code;
546 
547  // get the attribute index for this papi event
548  papi_event_code = _papi_hwi_get_papi_event_code();
549 
550  // a papi event code less than 0 is invalid, return error
551  if (papi_event_code <= 0) {
552  SUBDBG("EXIT: PAPI_ENOEVNT\n");
553  return PAPI_ENOEVNT;
554  }
555 
556  // find our native event table for this papi event code (search list backwards because it improves chances of finding it quickly)
557  for (eidx=event_table->num_native_events-1 ; eidx>=0 ; eidx--) {
558  if ((papi_event_code == event_table->native_events[eidx].papi_event_code) && (EventCode == ((unsigned)event_table->native_events[eidx].libpfm4_idx))) {
559  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);
560  break;
561  }
562  }
563 
564  // if we did not find a match, return an error
565  if (eidx < 0) {
566  // If we did not find a match in our native event table, then the code passed in has not been
567  // allocated yet It should not be possible to get to this code. The user has to call the papi
568  // code_to_name api with a papi event code for a native event. But the only way to get one of
569  // those is to call either name_to_code or enum_cmp_events first. When one of these calls is
570  // done we allocate the event so it should always be there.
571 
572  SUBDBG("EXIT: PAPI_ENOEVNT\n");
573  return PAPI_ENOEVNT;
574  }
575 
576  // if this event is defined by the default pmu, then use only the event name
577  // if it is not defined by the default pmu, then use both the pmu name and event name
578  char *ename;
579  if (strcmp(event_table->default_pmu.name, event_table->native_events[eidx].pmu) == 0) {
580  ename = event_table->native_events[eidx].base_name;
581  } else {
582  ename = event_table->native_events[eidx].pmu_plus_name;
583  }
584 
585  // if it will not fit, return error
586  if (strlen (ename) >= (unsigned)len) {
587  SUBDBG("EXIT: event name %s will not fit in buffer provided\n", ename);
588  return PAPI_EBUF;
589  }
590  strcpy (ntv_name, ename);
591 
592  // if this event had masks, also add their names
593  char *mname = event_table->native_events[eidx].mask_string;
594  if ((mname != NULL) && (strlen(mname) > 0)) {
595  if ((strlen(ename) + 8 + strlen(mname)) >= (unsigned)len) {
596  SUBDBG("EXIT: Not enough room for event and mask descriptions: need: %u, have: %u", (unsigned)(strlen(ename) + 8 + strlen(mname)), (unsigned)len);
597  return PAPI_EBUF;
598  }
599  strcat (ntv_name, ":");
600  strcat (ntv_name, mname);
601  }
602 
603  SUBDBG("EXIT: event name: %s\n", ntv_name);
604  return PAPI_OK;
605 }
606 
607 
630 int
631 _pe_libpfm4_ntv_code_to_descr( unsigned int EventCode,
632  char *ntv_descr, int len,
633  struct native_event_table_t *event_table)
634 {
635  SUBDBG("ENTER: EventCode: %#x, ntv_descr: %p, len: %d: event_table: %p\n", EventCode, ntv_descr, len, event_table);
636 
637  int eidx;
638  int papi_event_code;
639 
640  // get the attribute index for this papi event
641  papi_event_code = _papi_hwi_get_papi_event_code();
642 
643  // a papi event code less than 0 is invalid, return error
644  if (papi_event_code <= 0) {
645  SUBDBG("EXIT: PAPI_ENOEVNT\n");
646  return PAPI_ENOEVNT;
647  }
648 
649  // find our native event table for this papi event code (search list backwards because it improves chances of finding it quickly)
650  for (eidx=event_table->num_native_events-1 ; eidx>=0 ; eidx--) {
651  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);
652  if ((papi_event_code == event_table->native_events[eidx].papi_event_code) && (EventCode == ((unsigned)event_table->native_events[eidx].libpfm4_idx))) {
653  break;
654  }
655  }
656 
657  // if we did not find a match, return an error
658  if (eidx < 0) {
659  // If we did not find a match in our native event table, then the code passed in has not been
660  // allocated yet It should not be possible to get to this code. The user has to call the papi
661  // code_to_name api with a papi event code for a native event. But the only way to get one of
662  // those is to call either name_to_code or enum_cmp_events first. When one of these calls is
663  // done we allocate the event so it should always be there.
664 
665  SUBDBG("EXIT: PAPI_ENOEVNT\n");
666  return PAPI_ENOEVNT;
667  }
668 
669  char *edesc = event_table->native_events[eidx].event_description;
670 
671  // if it will not fit, return error
672  if (strlen (edesc) >= (unsigned)len) {
673  SUBDBG("EXIT: event name %s will not fit in buffer provided\n", edesc);
674  return PAPI_EBUF;
675  }
676  strcpy (ntv_descr, edesc);
677 
678  // if this event had masks, also add their descriptions
679  char *mdesc = event_table->native_events[eidx].mask_description;
680  if ((mdesc != NULL) && (strlen(mdesc) > 0)) {
681  if ((strlen(edesc) + 8 + strlen(mdesc)) >= (unsigned)len) {
682  SUBDBG("EXIT: Not enough room for event and mask descriptions: need: %u, have: %u", (unsigned)(strlen(edesc) + 8 + strlen(mdesc)), (unsigned)len);
683  return PAPI_EBUF;
684  }
685  strcat (ntv_descr, ", masks:");
686  strcat (ntv_descr, mdesc);
687  }
688 
689  SUBDBG("EXIT: event description: %s\n", ntv_descr);
690  return PAPI_OK;
691 }
692 
693 
694 int
695 _pe_libpfm4_ntv_code_to_info(unsigned int EventCode,
696  PAPI_event_info_t *info,
697  struct native_event_table_t *event_table)
698 {
699  SUBDBG("ENTER: EventCode: %#x, info: %p, event_table: %p\n", EventCode, info, event_table);
700 
701  int ret;
702 
703  // get the event name first
704  if ((ret = _pe_libpfm4_ntv_code_to_name(EventCode, info->symbol, sizeof(info->symbol), event_table)) != PAPI_OK) {
705  SUBDBG("EXIT: _pe_libpfm4_ntv_code_to_name returned: %d\n", ret);
706  return PAPI_ENOEVNT;
707  }
708 
709  if ((ret = _pe_libpfm4_ntv_code_to_descr(EventCode, info->long_descr, sizeof(info->long_descr), event_table)) != PAPI_OK) {
710  SUBDBG("EXIT: _pe_libpfm4_ntv_code_to_descr returned: %d\n", ret);
711  return PAPI_ENOEVNT;
712  }
713 
714  SUBDBG("EXIT: EventCode: %#x, name: %s, desc: %s\n", EventCode, info->symbol, info->long_descr);
715  return PAPI_OK;
716 }
717 
718 
735 int
736 _pe_libpfm4_ntv_enum_events( unsigned int *PapiEventCode,
737  int modifier,
738  struct native_event_table_t *event_table) {
739 
740  SUBDBG("ENTER: PapiEventCode: %p, *PapiEventCode: %#x, modifier: %d, event_table: %p\n", PapiEventCode, *PapiEventCode, modifier, event_table);
741 
742  int code,ret, pnum;
743  int max_umasks;
744  char event_string[BUFSIZ];
745  pfm_pmu_info_t pinfo;
746  pfm_event_info_t einfo;
747  struct native_event_t *our_event;
748 
749  /* return first event if so specified */
750  if ( modifier == PAPI_ENUM_FIRST ) {
751  attr_idx = 0; // set so if they want attribute information, it will start with the first attribute
752  code=get_first_event_next_pmu(-1, event_table->pmu_type);
753  if (code < 0 ) {
754  SUBDBG("EXIT: Invalid component first event code: %d\n", code);
755  return code;
756  }
757 
758  // get the event information from libpfm4 (must zero structure)
759  memset( &einfo, 0, sizeof( pfm_event_info_t ));
760  einfo.size = sizeof(pfm_event_info_t);
761  if ((ret = pfm_get_event_info(code, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
762  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
763  return PAPI_ENOIMPL;
764  }
765 
766  // get the pmu information from libpfm4 (must zero structure)
767  memset( &pinfo, 0, sizeof(pfm_pmu_info_t) );
768  pinfo.size = sizeof(pfm_pmu_info_t);
769  ret=pfm_get_pmu_info(einfo.pmu, &pinfo);
770  if (ret!=PFM_SUCCESS) {
771  SUBDBG("EXIT: pfm_get_pmu_info returned: %d\n", ret);
772  return ret;
773  }
774 
775  // build full event name
776  sprintf (event_string, "%s::%s", pinfo.name, einfo.name);
777  SUBDBG("code: %#x, pmu: %s, event: %s, event_string: %s\n", code, pinfo.name, einfo.name, event_string);
778 
779  // go allocate this event, need to create tables used by the get event info call that will probably follow
780  if ((our_event = allocate_native_event(event_string, code, event_table)) == NULL) {
781  // allocate may have created the event table but returned NULL to tell the caller the event string was invalid (attempt to encode it failed).
782  // if the caller wants to use this event to count something, it will report an error
783  // but if the caller is just interested in listing the event, then we need an event table with an event name and libpfm4 index
784  int evt_idx;
785  if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
786  SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
787  return PAPI_ENOEVNT;
788  }
789 
790  // give back the new event code
791  *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
792  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
793  return PAPI_OK;
794  }
795 
796  *PapiEventCode = our_event->libpfm4_idx;
797 
798  SUBDBG("EXIT: *PapiEventCode: %#x\n", *PapiEventCode);
799  return PAPI_OK;
800  }
801 
802  /* Handle looking for the next event */
803  if ( modifier == PAPI_ENUM_EVENTS ) {
804  attr_idx = 0; // set so if they want attribute information, it will start with the first attribute
805 
806  // get the next event code from libpfm4, if there are no more in this pmu find first event in next pmu
807  if ((code = pfm_get_event_next(*PapiEventCode)) < 0) {
808 
809  // get this events information from libpfm4, we need the pmu number of the last event we processed (table must be cleared)
810  memset( &einfo, 0, sizeof( pfm_event_info_t ));
811  einfo.size = sizeof(pfm_event_info_t);
812  if ((ret = pfm_get_event_info(*PapiEventCode, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
813  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
814  return PAPI_ENOIMPL;
815  }
816  SUBDBG("*PapiEventCode: %#x, event: %s\n", *PapiEventCode, einfo.name);
817 
818  // get the pmu number of the last event
819  pnum = einfo.pmu;
820 
821  while ( pnum<PFM_PMU_MAX) {
822  SUBDBG("pnum: %d\n", pnum);
823  code=get_first_event_next_pmu(pnum, event_table->pmu_type);
824  if (code < 0) {
825  SUBDBG("EXIT: No more pmu's to list, returning: %d\n", code);
826  return code;
827  }
828  break;
829  }
830  }
831 
832 
833  // get the event information from libpfm4 (must zero structure)
834  memset( &einfo, 0, sizeof( pfm_event_info_t ));
835  einfo.size = sizeof(pfm_event_info_t);
836  if ((ret = pfm_get_event_info(code, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
837  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
838  return PAPI_ENOIMPL;
839  }
840 
841  // get the pmu information from libpfm4 (must zero structure)
842  memset( &pinfo, 0, sizeof(pfm_pmu_info_t) );
843  pinfo.size = sizeof(pfm_pmu_info_t);
844  ret=pfm_get_pmu_info(einfo.pmu, &pinfo);
845  if (ret!=PFM_SUCCESS) {
846  SUBDBG("EXIT: pfm_get_pmu_info returned: %d\n", ret);
847  return ret;
848  }
849 
850  // build full event name
851  sprintf (event_string, "%s::%s", pinfo.name, einfo.name);
852  SUBDBG("code: %#x, pmu: %s, event: %s, event_string: %s\n", code, pinfo.name, einfo.name, event_string);
853 
854  // go allocate this event, need to create tables used by the get event info call that will follow
855  if ((our_event = allocate_native_event(event_string, code, event_table)) == NULL) {
856  // allocate may have created the event table but returned NULL to tell the caller the event string was invalid (attempt to encode it failed).
857  // if the caller wants to use this event to count something, it will report an error
858  // but if the caller is just interested in listing the event, then we need an event table with an event name and libpfm4 index
859  int evt_idx;
860  if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
861  SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
862  return PAPI_ENOEVNT;
863  }
864 
865  // give back the new event code
866  *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
867  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
868  return PAPI_OK;
869  }
870 
871  // give back the new event code
872  *PapiEventCode = our_event->libpfm4_idx;
873 
874  SUBDBG("EXIT: *PapiEventCode: %#x\n", *PapiEventCode);
875  return PAPI_OK;
876  }
877 
878  /* We don't handle PAPI_NTV_ENUM_UMASK_COMBOS */
879  if ( modifier == PAPI_NTV_ENUM_UMASK_COMBOS ) {
880  SUBDBG("EXIT: do not support umask combos yet\n");
881  return PAPI_ENOIMPL;
882  }
883 
884  /* Enumerate PAPI_NTV_ENUM_UMASKS (umasks on an event) */
885  if ( modifier == PAPI_NTV_ENUM_UMASKS ) {
886  // get this events information from libpfm4, we need the number of masks this event knows about (table must be cleared)
887  memset( &einfo, 0, sizeof( pfm_event_info_t ));
888  einfo.size = sizeof(pfm_event_info_t);
889  if ((ret = pfm_get_event_info(*PapiEventCode, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
890  SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
891  return PAPI_ENOIMPL;
892  }
893 // SUBDBG("*PapiEventCode: %#x, einfo.name: %s, einfo.code: %#x, einfo.nattrs: %d\n", *PapiEventCode, einfo.name, einfo.code, einfo.nattrs);
894 
895  // set max number of masks
896  max_umasks = einfo.nattrs;
897 
898  // if we reached last attribute, return error to show we are done with this events masks
899  if (attr_idx == max_umasks) {
900  SUBDBG("EXIT: already processed all umasks: attr_idx: %d\n", attr_idx);
901  return PAPI_ENOEVNT;
902  }
903 
904  // find the event table for this event, we need the pmu name and event name without any masks
906  if (ntv_idx < 0) {
907  SUBDBG("EXIT: _papi_hwi_get_ntv_idx returned: %d\n", ntv_idx);
908  return ntv_idx;
909  }
910  char *ename = event_table->native_events[ntv_idx].pmu_plus_name;
911  if ((ename == NULL) || (strlen(ename) >= sizeof(event_string))) {
912  SUBDBG("EXIT: Event name will not fit into buffer\n");
913  return PAPI_EBUF;
914  }
915  strcpy (event_string, ename);
916  SUBDBG("event_string: %s\n", event_string);
917 
918  // go get the attribute information for this event
919  // libpfm4 likes the table cleared
920  pfm_event_attr_info_t ainfo;
921  memset (&ainfo, 0, sizeof(pfm_event_attr_info_t));
922  ainfo.size = sizeof(pfm_event_attr_info_t);
923  ret = pfm_get_event_attr_info(*PapiEventCode, attr_idx, PFM_OS_PERF_EVENT_EXT, &ainfo);
924  if (ret != PFM_SUCCESS) {
925  SUBDBG("EXIT: Attribute info not found, EventCode: %#x, attr_idx: %d, ret: %d\n", *PapiEventCode, attr_idx, _papi_libpfm4_error(ret));
926  return _papi_libpfm4_error(ret);
927  }
928  SUBDBG("*PapiEventCode: %#x, attr_idx: %d, type: %d, name: %s, description: %s\n", *PapiEventCode, attr_idx, ainfo.type, ainfo.name, ainfo.desc);
929 
930  if (strlen(event_string) + strlen(ainfo.name) + 35 > sizeof(event_string)) {
931  SUBDBG("EXIT: Event name and mask will not fit into buffer\n");
932  return PAPI_EBUF;
933  }
934 
935  strcat (event_string, ":");
936  strcat (event_string, ainfo.name);
937  switch (ainfo.type) {
938  case PFM_ATTR_UMASK:
939  break;
940  case PFM_ATTR_MOD_BOOL:
941  case PFM_ATTR_MOD_INTEGER:
942  // a few attributes require a non-zero value to encode correctly (most would accept zero here)
943  strcat(event_string,"=0");
944  break;
945  default:
946  SUBDBG("EXIT: Unsupported attribute type: %d", ainfo.type);
947  return PAPI_EATTR;
948  }
949 
950  // go allocate this event, need to create tables used by the get event info call that will follow
951  if ((our_event = allocate_native_event(event_string, *PapiEventCode, event_table)) == NULL) {
952  // allocate may have created the event table but returned NULL to tell the caller the event string was invalid.
953  // if the caller wants to use this event to count something, it must report the error
954  // 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
955  int evt_idx;
956  if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
957  SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
958  return PAPI_ENOEVNT;
959  }
960  // bump so next time we will use next attribute
961  attr_idx++;
962  // give back the new event code
963  *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
964  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
965  return PAPI_OK;
966  }
967 
968  // bump so next time we will use next attribute
969  attr_idx++;
970 
971  // give back the new event code
972  *PapiEventCode = our_event->libpfm4_idx;
973 
974  SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
975  return PAPI_OK;
976  }
977 
978  /* Enumerate PAPI_NTV_ENUM_GROUPS (groups on an event) */
979  if ( modifier == PAPI_NTV_ENUM_GROUPS ) {
980  SUBDBG("EXIT: do not support enumerating groups in this component\n");
981  return PAPI_ENOIMPL;
982  }
983 
984  /* An unknown enumeration method was indicated */
985 
986  SUBDBG("EXIT: Invalid modifier argument provided\n");
987  return PAPI_ENOIMPL;
988 }
989 
990 
1001 int
1003  struct native_event_table_t *event_table) {
1004  SUBDBG("ENTER: event_table: %p\n", event_table);
1005 
1006  int i;
1007 
1008  for (i=0 ; i<PAPI_PMU_MAX ; i++) {
1009  if (my_vector->cmp_info.pmu_names[i] != NULL) {
1010  free (my_vector->cmp_info.pmu_names[i]);
1011  }
1012  }
1013 
1014  /* clean out and free the native events structure */
1016 
1017  /* free memory allocated with strdup or malloc */
1018  for( i=0; i<event_table->num_native_events; i++) {
1019  free(event_table->native_events[i].base_name);
1020  free(event_table->native_events[i].pmu_plus_name);
1021  free(event_table->native_events[i].pmu);
1022  free(event_table->native_events[i].allocated_name);
1023  free(event_table->native_events[i].mask_string);
1024  free(event_table->native_events[i].event_description);
1025  if (event_table->native_events[i].mask_description != NULL) {
1026  free(event_table->native_events[i].mask_description);
1027  }
1028  }
1029 
1030  free(event_table->native_events);
1031 
1033 
1034  SUBDBG("EXIT: PAPI_OK\n");
1035  return PAPI_OK;
1036 }
1037 
1038 
1050 int
1052  struct native_event_table_t *event_table,
1053  int pmu_type) {
1054 
1055  int detected_pmus=0, found_default=0;
1056  int i;
1057  int j=0;
1058  pfm_err_t retval = PFM_SUCCESS;
1059  unsigned int ncnt;
1060  pfm_pmu_info_t pinfo;
1061 
1062  /* allocate the native event structure */
1063 
1064  event_table->num_native_events=0;
1065  event_table->pmu_type=pmu_type;
1066 
1067  event_table->native_events=calloc(NATIVE_EVENT_CHUNK,
1068  sizeof(struct native_event_t));
1069  if (event_table->native_events==NULL) {
1070  return PAPI_ENOMEM;
1071  }
1073 
1074  /* Count number of present PMUs */
1075  detected_pmus=0;
1076  ncnt=0;
1077 
1078  /* init default pmu */
1079  /* need to init pinfo or pfmlib might complain */
1080  memset(&(event_table->default_pmu), 0, sizeof(pfm_pmu_info_t));
1081  event_table->default_pmu.size = sizeof(pfm_pmu_info_t);
1082  retval=pfm_get_pmu_info(0, &(event_table->default_pmu));
1083 
1084  SUBDBG("Detected pmus:\n");
1085  for(i=0;i<PFM_PMU_MAX;i++) {
1086  memset(&pinfo,0,sizeof(pfm_pmu_info_t));
1087  pinfo.size = sizeof(pfm_pmu_info_t);
1088  retval=pfm_get_pmu_info(i, &pinfo);
1089  if ((retval!=PFM_SUCCESS) || (pinfo.name == NULL)) {
1090  continue;
1091  }
1092 
1093  if (pmu_is_present_and_right_type(&pinfo,pmu_type)) {
1094  SUBDBG("\t%d %s %s %d\n",i,pinfo.name,pinfo.desc,pinfo.type);
1095 
1096  detected_pmus++;
1097  ncnt+=pinfo.nevents;
1098 
1099  if (j < PAPI_PMU_MAX) {
1100  my_vector->cmp_info.pmu_names[j++] = strdup(pinfo.name);
1101  }
1102 
1103  if (pmu_type&PMU_TYPE_CORE) {
1104 
1105  /* Hack to have "default" PMU */
1106  if ( (pinfo.type==PFM_PMU_TYPE_CORE) &&
1107  strcmp(pinfo.name,"ix86arch")) {
1108 
1109  SUBDBG("\t %s is default\n",pinfo.name);
1110  memcpy(&(event_table->default_pmu),
1111  &pinfo,sizeof(pfm_pmu_info_t));
1112  found_default++;
1113  }
1114  }
1115  if (pmu_type==PMU_TYPE_UNCORE) {
1116  /* To avoid confusion, no "default" CPU for uncore */
1117  found_default=1;
1118  }
1119  }
1120  }
1121  SUBDBG("%d native events detected on %d pmus\n",ncnt,detected_pmus);
1122 
1123  if (!found_default) {
1124  SUBDBG("Could not find default PMU\n");
1125  return PAPI_ECMP;
1126  }
1127 
1128  if (found_default>1) {
1129  PAPIERROR("Found too many default PMUs!\n");
1130  return PAPI_ECMP;
1131  }
1132 
1133  my_vector->cmp_info.num_native_events = ncnt;
1134 
1135  my_vector->cmp_info.num_cntrs = event_table->default_pmu.num_cntrs+
1136  event_table->default_pmu.num_fixed_cntrs;
1137 
1138  SUBDBG( "num_counters: %d\n", my_vector->cmp_info.num_cntrs );
1139 
1140  /* Setup presets, only if Component 0 */
1141  if (cidx==0) {
1142  retval = _papi_load_preset_table( (char *)event_table->default_pmu.name,
1143  event_table->default_pmu.pmu, cidx );
1144  if ( retval ) {
1145  return retval;
1146  }
1147  }
1148 
1149  return PAPI_OK;
1150 }
1151 
#define PAPI_ENOEVNT
Definition: papi.h:258
sprintf(splash[splash_line++],"\tIozone: Performance Test of File I/O\n")
static int get_first_event_next_pmu(int pmu_idx, int pmu_type)
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()
int _pe_libpfm4_ntv_enum_events(unsigned int *PapiEventCode, int modifier, struct native_event_table_t *event_table)
struct native_event_t * native_events
int _pe_libpfm4_ntv_name_to_code(char *name, unsigned int *event_code, struct native_event_table_t *event_table)
char long_descr[PAPI_HUGE_STR_LEN]
Definition: papi.h:966
#define NATIVE_EVENT_CHUNK
char symbol[PAPI_HUGE_STR_LEN]
Definition: papi.h:963
return PAPI_OK
Definition: linux-nvml.c:458
#define PAPI_EBUF
Definition: papi.h:271
#define PMU_TYPE_OS
int _pe_libpfm4_get_cidx(void)
Definition: perf_event.c:71
int _pe_libpfm4_init(papi_vector_t *my_vector, int cidx, struct native_event_table_t *event_table, int pmu_type)
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
int _papi_libpfm4_error(int pfm_error)
#define PAPI_HUGE_STR_LEN
Definition: papi.h:465
Return codes and api definitions.
static int attr_idx
long long ret
Definition: iozone.c:1346
int _pe_libpfm4_ntv_code_to_name(unsigned int EventCode, char *ntv_name, int len, struct native_event_table_t *event_table)
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
static struct native_event_t * allocate_native_event(char *name, int libpfm4_index, struct native_event_table_t *event_table)
static int find_existing_event(char *name, struct native_event_table_t *event_table)
free(dummyfile[xx])
#define PAPI_EATTR
Definition: papi.h:273
static int cidx
Definition: event_info.c:40
char * pmu_names[PAPI_PMU_MAX]
Definition: papi.h:647
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:78
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
void PAPIERROR(char *format,...)
#define PAPI_ECMP
Definition: papi.h:254
strcat(command, mountname)
#define PMU_TYPE_CORE
int _papi_load_preset_table(char *pmu_str, int pmu_type, int cidx)
Definition: papi_preset.c:771
#define PAPI_ENOMEM
Definition: papi.h:252
#define NAMELIB_LOCK
Definition: papi_internal.h:94
#define PAPI_ENOIMPL
Definition: papi.h:270
strcpy(filename, default_filename)
int _pe_libpfm4_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info, struct native_event_table_t *event_table)
int _pe_libpfm4_ntv_code_to_descr(unsigned int EventCode, char *ntv_descr, int len, struct native_event_table_t *event_table)
static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type)
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
#define PMU_TYPE_UNCORE
int _pe_libpfm4_shutdown(papi_vector_t *my_vector, struct native_event_table_t *event_table)
perf_event_attr_t attr
char * name
Definition: iozone.c:23648
pfm_pmu_info_t default_pmu
long j
Definition: iozone.c:19135
ssize_t retval
Definition: libasync.c:338
void _papi_hwi_set_papi_event_string(const char *event_string)
Definition: papi_internal.c:89
char * ptr
Definition: iozone.c:23586