PAPI 7.1.0.0
Loading...
Searching...
No Matches
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
29#define NATIVE_EVENT_CHUNK 1024
30
31// used to step through the attributes when enumerating events
32static int attr_idx;
33
34/* alias flags to handle amd_fam17h, amd_fam17h_zen1 both present PMUs*/
36
49static int find_existing_event(const char *name,
50 struct native_event_table_t *event_table) {
51 SUBDBG("Entry: name: %s, event_table: %p, num_native_events: %d\n", name, event_table, event_table->num_native_events);
52
53 int i,event=PAPI_ENOEVNT;
54
56
57 for(i=0;i<event_table->num_native_events;i++) {
58 // Most names passed in will contain the pmu name, so first we compare to the allocated name (it has pmu name on front)
59 if (!strcmp(name,event_table->native_events[i].allocated_name)) {
60 SUBDBG("Found allocated_name: %s, libpfm4_idx: %#x, papi_event_code: %#x\n",
61 event_table->native_events[i].allocated_name, event_table->native_events[i].libpfm4_idx, event_table->native_events[i].papi_event_code);
62 event=i;
63 break;
64 }
65 // 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)
66 if (!strcmp(name,event_table->native_events[i].base_name)) {
67 int nameLen = strlen(event_table->native_events[i].base_name);
68 // the name we are looking for must be the same length as this event table entry name for them to match
69 if (strlen(name) != nameLen + strlen(event_table->native_events[i].mask_string) + 1) {
70 continue;
71 }
72 if(!strcmp(name+nameLen+1, event_table->native_events[i].mask_string)) {
73 SUBDBG("Found base_name: %s, mask_string: %s, libpfm4_idx: %#x, papi_event_code: %#x\n",
74 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);
75 event=i;
76 break;
77 }
78 }
79 }
81
82 SUBDBG("EXIT: returned: %#x\n", event);
83 return event;
84}
85
86
87static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type) {
88 SUBDBG("ENTER: pinfo: %s %p, pinfo->is_present: %d, "
89 "pinfo->type: %#x, type: %#x\n",
90 pinfo->name, pinfo, pinfo->is_present, pinfo->type, type);
91 if (!pinfo->is_present) {
92// SUBDBG("EXIT: not present\n");
93 return 0;
94 }
95
96 if ((pinfo->type==PFM_PMU_TYPE_UNCORE) && (type&PMU_TYPE_UNCORE)) {
97// SUBDBG("EXIT: found PFM_PMU_TYPE_UNCORE\n");
98 return 1;
99 }
100 if ((pinfo->type==PFM_PMU_TYPE_CORE) && (type&PMU_TYPE_CORE)) {
101// SUBDBG("EXIT: found PFM_PMU_TYPE_CORE\n");
102 return 1;
103 }
104 if ((pinfo->type==PFM_PMU_TYPE_OS_GENERIC) && (type&PMU_TYPE_OS)) {
105// SUBDBG("EXIT: found PFM_PMU_TYPE_OS_GENERIC\n");
106 return 1;
107 }
108
109// SUBDBG("EXIT: not right type\n");
110 return 0;
111}
112
113
131 const char *name,
132 int libpfm4_index, int cidx,
133 struct native_event_table_t *event_table) {
134
135 SUBDBG("ENTER: name: %s, libpfm4_index: %#x, event_table: %p, "
136 "event_table->pmu_type: %d\n",
137 name, libpfm4_index, event_table, event_table->pmu_type);
138
139 int nevt_idx;
140 int event_num;
141 int encode_failed=0;
142
143 pfm_err_t ret;
144 char *event_string=NULL;
145 char *pmu_name;
146 char *event;
147 char *masks;
148 char fullname[BUFSIZ];
149 struct native_event_t *ntv_evt;
150
151 pfm_perf_encode_arg_t perf_arg;
152 pfm_event_info_t einfo;
153 pfm_event_attr_info_t ainfo;
154 pfm_pmu_info_t pinfo;
155
156 // if no place to put native events, report that allocate failed
157 if (event_table->native_events==NULL) {
158 SUBDBG("EXIT: no place to put native events\n");
159 return NULL;
160 }
161
162 // find out if this event is already known
163 event_num=find_existing_event(name, event_table);
164
165 /* add the event to our event table */
167
168 // if we already know this event name,
169 // it was created as part of setting up the preset tables
170 // we need to use the event table which is already created
171 if (event_num >= 0) {
172 nevt_idx = event_num;
173 ntv_evt = &(event_table->native_events[event_num]);
174 } else {
175 // set to use a new event table
176 // (count of used events not bumped
177 // until we are sure setting it up does not get an errror)
178 nevt_idx = event_table->num_native_events;
179 ntv_evt = &(event_table->native_events[nevt_idx]);
180 }
181
182 SUBDBG("event_num: %d, nevt_idx: %d, ntv_evt: %p\n",
183 event_num, nevt_idx, ntv_evt);
184
185 /* clear the argument and attribute structures */
186 memset(&perf_arg,0,sizeof(pfm_perf_encode_arg_t));
187 memset(&(ntv_evt->attr),0,sizeof(struct perf_event_attr));
188
189 // set argument structure fields so the encode
190 // function can give us what we need
191 perf_arg.attr=&ntv_evt->attr;
192 perf_arg.fstr=&event_string;
193
194 // set the size of the perf attr struct before getting pfm encoding
195 ntv_evt->attr.size = sizeof(struct perf_event_attr);
196
197 /* use user provided name of the event to get the */
198 /* perf_event encoding and a fully qualified event string */
199 ret = pfm_get_os_event_encoding(name,
201 PFM_OS_PERF_EVENT_EXT,
202 &perf_arg);
203
204 // If the encode function failed, skip processing of the event_string
205 if ((ret != PFM_SUCCESS) || (event_string == NULL)) {
206 SUBDBG("encode failed for event: %s, returned: %d\n",
207 name, ret);
208
209 // we need to remember that this event encoding failed
210 // but still create the native event table
211 // the event table is used by the list so we put what we
212 // can get into it
213 // but the failure doing the encode causes us to
214 // return null to our caller
215 encode_failed = 1;
216
217 // Noting the encode_failed error in the attr.config allows
218 // any later validate attempts to return an error value
219
220 // ??? .config is 64-bits? --vmw
221 ntv_evt->attr.config = 0xFFFFFF;
222
223 // we also want to make it look like a cpu number
224 // was not provided as an event mask
225 perf_arg.cpu = -1;
226
227 // Why don't we just return NULL here? --vmw
228 //return NULL;
229 }
230
231 // free string allocated by pfm_get_os_event_encoding
232 free(*(perf_arg.fstr));
233 // get a copy of the event name and break it up into its parts
234 event_string = strdup(name);
235
236 SUBDBG("event_string: %s\n", event_string);
237
238 // get the pmu name, event name and mask list pointers
239 // from the event string
240 event = strstr (event_string, "::");
241 if (event != NULL) {
242 *event = 0; // null terminate pmu name
243 event += 2; // event name follows '::'
244 pmu_name = strdup(event_string);
245 } else {
246 // no pmu name in event string
247 pmu_name = malloc(2);
248 pmu_name[0] = 0;
249 event = event_string;
250 }
251 masks = strstr (event, ":");
252 if (masks != NULL) {
253 *masks = 0; // null terminate event name
254 masks += 1; // masks follow :
255 } else {
256 masks = "";
257 }
258
259 // build event name to find, put a pmu name on it if we have one
260 if (strlen(pmu_name) == 0) {
261 sprintf(fullname,"%s", event);
262 } else {
263 sprintf(fullname,"%s::%s", pmu_name, event);
264 }
265
266 SUBDBG("pmu_name: %s, event: %s, masks: %s, fullname: %s\n",
267 pmu_name, event, masks, fullname);
268
269 // if the libpfm4 index was not provided,
270 // try to get one based on the event name passed in.
271
272 /* This may return a value for a disabled PMU */
273 if (libpfm4_index == -1) {
274 libpfm4_index = pfm_find_event(fullname);
275 if (libpfm4_index < 0) {
276 free(event_string);
277 free(pmu_name);
279 SUBDBG("EXIT: error from libpfm4 find event\n");
280 return NULL;
281 }
282 SUBDBG("libpfm4_index: %#x\n", libpfm4_index);
283 }
284
285 // get this events information from libpfm4,
286 // if unavailable return event not found (structure be zeroed)
287 memset( &einfo, 0, sizeof( pfm_event_info_t ));
288 einfo.size = sizeof(pfm_event_info_t);
289 if ((ret = pfm_get_event_info(libpfm4_index,
290 PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
291 free(event_string);
292 free(pmu_name);
294 SUBDBG("EXIT: pfm_get_event_info failed with %d\n", ret);
295 return NULL;
296 }
297
298 // if pmu type is not one supported by this component,
299 // return event not found (structure be zeroed)
300 memset(&pinfo,0,sizeof(pfm_pmu_info_t));
301 pinfo.size = sizeof(pfm_pmu_info_t);
302 pfm_get_pmu_info(einfo.pmu, &pinfo);
303 if (pmu_is_present_and_right_type(&pinfo, event_table->pmu_type) == 0) {
304 free(event_string);
305 free(pmu_name);
307 SUBDBG("EXIT: PMU not supported by this component: einfo.pmu: %d, PFM_PMU_TYPE_CORE: %d\n", einfo.pmu, PFM_PMU_TYPE_CORE);
308 return NULL;
309 }
310
311 ntv_evt->allocated_name=strdup(name);
312 ntv_evt->mask_string=strdup(masks);
313 ntv_evt->component=cidx;
314 ntv_evt->pmu=pmu_name;
315 ntv_evt->base_name=strdup(event);
316 ntv_evt->pmu_plus_name=strdup(fullname);
317 ntv_evt->libpfm4_idx=libpfm4_index;
318 ntv_evt->event_description=strdup(einfo.desc);
319 ntv_evt->users=0; /* is this needed? */
320 ntv_evt->cpu=perf_arg.cpu;
321
322 SUBDBG("ntv_evt->mask_string: %p (%s)\n",
323 ntv_evt->mask_string, ntv_evt->mask_string);
324 char *msk_ptr = strdup(masks); // get a work copy of the mask string before we free the space it was in
325 free(event_string);
326
327 char mask_desc[PAPI_HUGE_STR_LEN] = "";
328
329 // if there is any mask data, collect their descriptions
330 if ((msk_ptr != NULL) && (strlen(msk_ptr) > 0)) {
331 // go get the descriptions for each of the
332 // masks provided with this event
333 char *ptr = msk_ptr;
334 SUBDBG("ptr: %p (%s)\n", ptr, ptr);
335 while (ptr != NULL) {
336 char *ptrm = strstr(ptr, ":");
337 if (ptrm != NULL) {
338 *ptrm = '\0';
339 ptrm++;
340 }
341
342 // get the length of the mask name
343 char *wrk = strchr(ptr, '=');
344 unsigned int msk_name_len;
345 if (wrk != NULL) {
346 msk_name_len = wrk - ptr;
347 SUBDBG("Found =, length=%d\n",msk_name_len);
348 } else {
349 msk_name_len = strlen (ptr);
350 SUBDBG("No =, length=%d\n",msk_name_len);
351 }
352
353 int i, mask_found=0;
354 for (i=0 ; i<einfo.nattrs ; i++) {
355 // get this events attribute information
356 // from libpfm4, if unavailable return
357 // event not found (table must be cleared)
358 memset (&ainfo, 0,
359 sizeof(pfm_event_attr_info_t));
360 ainfo.size = sizeof(pfm_event_attr_info_t);
361 ret = pfm_get_event_attr_info(libpfm4_index,
362 i, PFM_OS_PERF_EVENT_EXT, &ainfo);
363 if (ret != PFM_SUCCESS) {
364 free (msk_ptr);
365 free(pmu_name);
366 SUBDBG("EXIT: error libpfm4 find event: Attribute info not found, libpfm4_index: %#x, ret: %d\n", libpfm4_index, _papi_libpfm4_error(ret));
368 return NULL;
369 }
370
371 // if this is the one we want,
372 // append its description
373 if ((msk_name_len == strlen(ainfo.name)) &&
374 (strncmp(ptr, ainfo.name, msk_name_len) == 0)) {
375 mask_found=1;
376 SUBDBG("Found mask: libpfm4=%s -- matches %s -- i: %d, %d %zu\n",
377 ainfo.name, ptr, i, msk_name_len, strlen(ainfo.name));
378 // find out how much space is left in the mask description work buffer we are building
379 unsigned int mskleft = sizeof(mask_desc) - strlen(mask_desc);
380 // if no space left, just discard this mask description
381 if (mskleft <= 1) {
382 SUBDBG("EXIT: Attribute description discarded: %s\n", ainfo.desc);
383 break;
384 }
385 // if description buffer is not empty, put in mask description separator
386 if (strlen(mask_desc) > 0) {
387 strcat (mask_desc, ":");
388 mskleft--;
389 }
390 // if new description will not all fit in buffer, report truncation
391 if (mskleft < (strlen(ainfo.desc) + 1)) {
392 SUBDBG("EXIT: Attribute description truncated: %s\n", ainfo.desc);
393 }
394 // move as much of this description as will fit
395 strncat (mask_desc, ainfo.desc, mskleft-1);
396 mask_desc[mskleft-1] = '\0';
397 break;
398 }
399 }
400
401 /* See if we had a mask that wasn't found */
402 if (!mask_found) {
403 free(msk_ptr);
404 free(pmu_name);
405 SUBDBG("EXIT: error libpfm4 find event: Mask not found: %s.\n", ptr);
407 return NULL;
408 }
409
410 // if we have filled the work buffer, we can quit now
411 if ( (sizeof(mask_desc) - strlen(mask_desc)) <= 1) {
412 break;
413 }
414 ptr = ptrm;
415 }
416 }
417 ntv_evt->mask_description=strdup(mask_desc);
418 SUBDBG("ntv_evt->mask_description: %p (%s)\n", ntv_evt->mask_description, ntv_evt->mask_description);
419
420 // give back space if we got any
421 if (msk_ptr != NULL) {
422 free (msk_ptr);
423 }
424
425 // create a papi table for this native event, put the index into the event sets array of native events into the papi table
426 int new_event_code = _papi_hwi_native_to_eventcode(cidx, libpfm4_index, nevt_idx, ntv_evt->allocated_name);
427 _papi_hwi_set_papi_event_string((const char *)ntv_evt->allocated_name);
428 _papi_hwi_set_papi_event_code(new_event_code, 1);
429
430 ntv_evt->papi_event_code=new_event_code;
431
432 SUBDBG("Using %#x as index for %s\n", ntv_evt->libpfm4_idx, fullname);
433 SUBDBG("num_native_events: %d, allocated_native_events: %d\n", event_table->num_native_events, event_table->allocated_native_events);
434 SUBDBG("Native Event: papi_event_code: %#x, libpfm4_idx: %#x, pmu: %s, base_name: %s, mask_string: %s, allocated_name: %s\n",
435 ntv_evt->papi_event_code, ntv_evt->libpfm4_idx, ntv_evt->pmu, ntv_evt->base_name, ntv_evt->mask_string, ntv_evt->allocated_name);
436 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",
437 nevt_idx, &(event_table->native_events[nevt_idx]), ntv_evt->cpu, ntv_evt->attr.config,
438 ntv_evt->attr.config1, ntv_evt->attr.config2, ntv_evt->attr.type,
439 ntv_evt->attr.exclude_user, ntv_evt->attr.exclude_kernel, ntv_evt->attr.exclude_guest);
440
441 /* If we've used all of the allocated native events, */
442 /* then allocate more room */
443 if (event_table->num_native_events >=
444 event_table->allocated_native_events-1) {
445
446 SUBDBG("Allocating more room for native events (%d %ld)\n",
448 (long)sizeof(struct native_event_t) *
450
451 event_table->native_events=realloc(event_table->native_events,
452 sizeof(struct native_event_t) *
454
456
457 // we got new space so we need to reset
458 // the pointer to the correct native event in the new space
459 ntv_evt = &(event_table->native_events[nevt_idx]);
460 }
461
462
463 // if getting more space for native events failed,
464 // report that allocate failed
465 if (event_table->native_events==NULL) {
466 SUBDBG("EXIT: attempt to get more space for "
467 "native events failed\n");
468 return NULL;
469 }
470
471 // if we created a new event, bump the number used
472 if (event_num < 0) {
473 event_table->num_native_events++;
474 }
475
477
478 if (encode_failed != 0) {
479 SUBDBG("EXIT: encoding event failed\n");
480 return NULL;
481 }
482
483 SUBDBG("EXIT: new_event: %p\n", ntv_evt);
484 return ntv_evt;
485}
486
487
502static int
503get_first_event_next_pmu(int pmu_idx, int pmu_type)
504{
505 SUBDBG("ENTER: pmu_idx: %d, pmu_type: %d\n", pmu_idx, pmu_type);
506 int pidx, ret;
507
508 pfm_pmu_info_t pinfo;
509
510 // start looking at the next pmu in the list
511 pmu_idx++;
512
513 /* We loop forever here and exit if pfm_get_pmu_info() fails. */
514 /* Before we only went up to PFM_PMU_MAX but this is set at */
515 /* compile time and might not reflect the number of PMUs if */
516 /* PAPI is dynamically linked against libpfm4. */
517 while(1) {
518
519 /* clear the PMU structure (required by libpfm4) */
520 memset(&pinfo,0,sizeof(pfm_pmu_info_t));
521 pinfo.size = sizeof(pfm_pmu_info_t);
522 ret=pfm_get_pmu_info(pmu_idx, &pinfo);
523
524 if (ret==PFM_ERR_INVAL) {
525 break;
526 }
527
528 if ((ret==PFM_SUCCESS) && amd64_fam17h_zen1_present && strcmp(pinfo.name, "amd64_fam17h") == 0) {
529 /* Skip as if invalid; we want the PMU amd64_fam17h_zen1 instead. */
530 pmu_idx++;
531 continue;
532 }
533
534 if ((ret==PFM_SUCCESS) && pmu_is_present_and_right_type(&pinfo,pmu_type)) {
535
536 pidx=pinfo.first_event;
537 SUBDBG("First event in pmu: %s is %#x\n", pinfo.name, pidx);
538
539 if (pidx<0) {
540 /* For some reason no events available */
541 /* despite the PMU being active. */
542 /* This can happen, for example with ix86arch */
543 /* inside of VMware */
544 }
545 else {
546 SUBDBG("EXIT: pidx: %#x\n", pidx);
547 return pidx;
548 }
549 }
550
551 pmu_idx++;
552
553 }
554
555 SUBDBG("EXIT: PAPI_ENOEVNT\n");
556 return PAPI_ENOEVNT;
557
558}
559
560
561/***********************************************************/
562/* Exported functions */
563/***********************************************************/
564
581int
582_pe_libpfm4_ntv_name_to_code( const char *name, unsigned int *event_code,
583 int cidx,
584 struct native_event_table_t *event_table)
585{
586 SUBDBG( "ENTER: name: %s, event_code: %p, *event_code: %#x, event_table: %p\n", name, event_code, *event_code, event_table);
587
588 struct native_event_t *our_event;
589 int event_num;
590
591 // if we already know this event name, just return its native code
592 event_num=find_existing_event(name, event_table);
593 if (event_num >= 0) {
594 *event_code=event_table->native_events[event_num].libpfm4_idx;
595 // the following call needs to happen to prevent the internal layer from creating a new papi native event table
597 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);
598 return PAPI_OK;
599 }
600
601 // Try to allocate this event to see if it is known by libpfm4, if allocate fails tell the caller it is not valid
602 our_event=allocate_native_event(name, -1, cidx, event_table);
603 if (our_event==NULL) {
604 SUBDBG("EXIT: Allocating event: '%s' failed\n", name);
605 return PAPI_ENOEVNT;
606 }
607
608 *event_code = our_event->libpfm4_idx;
609 SUBDBG("EXIT: Found code: %#x\n",*event_code);
610 return PAPI_OK;
611}
612
613
631int
632_pe_libpfm4_ntv_code_to_name(unsigned int EventCode,
633 char *ntv_name, int len,
634 struct native_event_table_t *event_table)
635{
636 SUBDBG("ENTER: EventCode: %#x, ntv_name: %p, len: %d, event_table: %p\n", EventCode, ntv_name, len, event_table);
637
638 int eidx;
639 int papi_event_code;
640
641 // get the attribute index for this papi event
643
644 // a papi event code less than 0 is invalid, return error
645 if (papi_event_code <= 0) {
646 SUBDBG("EXIT: PAPI_ENOEVNT\n");
647 return PAPI_ENOEVNT;
648 }
649
650 // find our native event table for this papi event code (search list backwards because it improves chances of finding it quickly)
651 for (eidx=event_table->num_native_events-1 ; eidx>=0 ; eidx--) {
652 if ((papi_event_code == event_table->native_events[eidx].papi_event_code) && (EventCode == ((unsigned)event_table->native_events[eidx].libpfm4_idx))) {
653 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);
654 break;
655 }
656 }
657
658 // if we did not find a match, return an error
659 if (eidx < 0) {
660 // If we did not find a match in our native event table, then the code passed in has not been
661 // allocated yet It should not be possible to get to this code. The user has to call the papi
662 // code_to_name api with a papi event code for a native event. But the only way to get one of
663 // those is to call either name_to_code or enum_cmp_events first. When one of these calls is
664 // done we allocate the event so it should always be there.
665
666 SUBDBG("EXIT: PAPI_ENOEVNT\n");
667 return PAPI_ENOEVNT;
668 }
669
670 // if this event is defined by the default pmu, then use only the event name
671 // if it is not defined by the default pmu, then use both the pmu name and event name
672 char *ename;
673 if ((event_table->default_pmu.name) && (strcmp(event_table->default_pmu.name, event_table->native_events[eidx].pmu) == 0)) {
674 ename = event_table->native_events[eidx].base_name;
675 } else {
676 ename = event_table->native_events[eidx].pmu_plus_name;
677 }
678
679 // if it will not fit, return error
680 if (strlen (ename) >= (unsigned)len) {
681 SUBDBG("EXIT: event name %s will not fit in buffer provided\n", ename);
682 return PAPI_EBUF;
683 }
684 strcpy (ntv_name, ename);
685
686 // if this event had masks, also add their names
687 char *mname = event_table->native_events[eidx].mask_string;
688 if ((mname != NULL) && (strlen(mname) > 0)) {
689 if ((strlen(ename) + 8 + strlen(mname)) >= (unsigned)len) {
690 SUBDBG("EXIT: Not enough room for event and mask descriptions: need: %u, have: %u", (unsigned)(strlen(ename) + 8 + strlen(mname)), (unsigned)len);
691 return PAPI_EBUF;
692 }
693 strcat (ntv_name, ":");
694 strcat (ntv_name, mname);
695 }
696
697 SUBDBG("EXIT: event name: %s\n", ntv_name);
698 return PAPI_OK;
699}
700
701
724int
725_pe_libpfm4_ntv_code_to_descr( unsigned int EventCode,
726 char *ntv_descr, int len,
727 struct native_event_table_t *event_table)
728{
729 SUBDBG("ENTER: EventCode: %#x, ntv_descr: %p, len: %d: event_table: %p\n", EventCode, ntv_descr, len, event_table);
730
731 int eidx;
732 int papi_event_code;
733 char *mdesc;
734 char *edesc;
735
736 // get the attribute index for this papi event
738
739 // a papi event code less than 0 is invalid, return error
740 if (papi_event_code <= 0) {
741 SUBDBG("EXIT: PAPI_ENOEVNT\n");
742 return PAPI_ENOEVNT;
743 }
744
745 // find our native event table for this papi event code (search list backwards because it improves chances of finding it quickly)
746 for (eidx=event_table->num_native_events-1 ; eidx>=0 ; eidx--) {
747 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);
748 if ((papi_event_code == event_table->native_events[eidx].papi_event_code) && (EventCode == ((unsigned)event_table->native_events[eidx].libpfm4_idx))) {
749 break;
750 }
751 }
752
753 // if we did not find a match, return an error
754 if (eidx < 0) {
755 // If we did not find a match in our native event table, then the code passed in has not been
756 // allocated yet It should not be possible to get to this code. The user has to call the papi
757 // code_to_name api with a papi event code for a native event. But the only way to get one of
758 // those is to call either name_to_code or enum_cmp_events first. When one of these calls is
759 // done we allocate the event so it should always be there.
760
761 SUBDBG("EXIT: PAPI_ENOEVNT\n");
762 return PAPI_ENOEVNT;
763 }
764
765 edesc = event_table->native_events[eidx].event_description;
766
767 // if it will not fit, return error
768 if (strlen (edesc) >= (unsigned)len) {
769 SUBDBG("EXIT: event name %s will not fit in buffer provided\n", edesc);
770 return PAPI_EBUF;
771 }
772 strcpy (ntv_descr, edesc);
773
774 // if this event had masks, also add their descriptions
775 mdesc = event_table->native_events[eidx].mask_description;
776 if ((mdesc != NULL) && (strlen(mdesc) > 0)) {
777 if ((strlen(edesc) + 8 + strlen(mdesc)) >= (unsigned)len) {
778 SUBDBG("EXIT: Not enough room for event and mask descriptions: need: %u, have: %u", (unsigned)(strlen(edesc) + 8 + strlen(mdesc)), (unsigned)len);
779 return PAPI_EBUF;
780 }
781 strcat (ntv_descr, ", masks:");
782 strcat (ntv_descr, mdesc);
783 }
784
785 SUBDBG("EXIT: event description: %s\n", ntv_descr);
786 return PAPI_OK;
787}
788
789
790int
791_pe_libpfm4_ntv_code_to_info(unsigned int EventCode,
792 PAPI_event_info_t *info,
793 struct native_event_table_t *event_table)
794{
795 SUBDBG("ENTER: EventCode: %#x, info: %p, event_table: %p\n", EventCode, info, event_table);
796
797 int ret;
798
799 // get the event name first
800 if ((ret = _pe_libpfm4_ntv_code_to_name(EventCode, info->symbol, sizeof(info->symbol), event_table)) != PAPI_OK) {
801 SUBDBG("EXIT: _pe_libpfm4_ntv_code_to_name returned: %d\n", ret);
802 return PAPI_ENOEVNT;
803 }
804
805 if ((ret = _pe_libpfm4_ntv_code_to_descr(EventCode, info->long_descr, sizeof(info->long_descr), event_table)) != PAPI_OK) {
806 SUBDBG("EXIT: _pe_libpfm4_ntv_code_to_descr returned: %d\n", ret);
807 return PAPI_ENOEVNT;
808 }
809
810 SUBDBG("EXIT: EventCode: %#x, name: %s, desc: %s\n", EventCode, info->symbol, info->long_descr);
811 return PAPI_OK;
812}
813
814
831int
832_pe_libpfm4_ntv_enum_events( unsigned int *PapiEventCode,
833 int modifier, int cidx,
834 struct native_event_table_t *event_table) {
835
836 SUBDBG("ENTER: PapiEventCode: %p, *PapiEventCode: %#x, modifier: %d, event_table: %p\n", PapiEventCode, *PapiEventCode, modifier, event_table);
837
838 int code,ret, pnum;
839 int max_umasks;
840 char event_string[BUFSIZ];
841 pfm_pmu_info_t pinfo;
842 pfm_event_info_t einfo;
843 struct native_event_t *our_event;
844
845 /* return first event if so specified */
846 if ( modifier == PAPI_ENUM_FIRST ) {
847 attr_idx = 0; // set so if they want attribute information, it will start with the first attribute
848 code=get_first_event_next_pmu(-1, event_table->pmu_type);
849 if (code < 0 ) {
850 SUBDBG("EXIT: Invalid component first event code: %d\n", code);
851 return code;
852 }
853
854 // get the event information from libpfm4 (must zero structure)
855 memset( &einfo, 0, sizeof( pfm_event_info_t ));
856 einfo.size = sizeof(pfm_event_info_t);
857 if ((ret = pfm_get_event_info(code, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
858 SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
859 return PAPI_ENOIMPL;
860 }
861
862 // get the pmu information from libpfm4 (must zero structure)
863 memset( &pinfo, 0, sizeof(pfm_pmu_info_t) );
864 pinfo.size = sizeof(pfm_pmu_info_t);
865 ret=pfm_get_pmu_info(einfo.pmu, &pinfo);
866 if (ret!=PFM_SUCCESS) {
867 SUBDBG("EXIT: pfm_get_pmu_info returned: %d\n", ret);
868 return ret;
869 }
870
871 // build full event name
872 sprintf (event_string, "%s::%s", pinfo.name, einfo.name);
873 SUBDBG("code: %#x, pmu: %s, event: %s, event_string: %s\n", code, pinfo.name, einfo.name, event_string);
874
875 // go allocate this event, need to create tables used by the get event info call that will probably follow
876 if ((our_event = allocate_native_event(event_string, code, cidx, event_table)) == NULL) {
877 // allocate may have created the event table but returned NULL to tell the caller the event string was invalid (attempt to encode it failed).
878 // if the caller wants to use this event to count something, it will report an error
879 // but if the caller is just interested in listing the event, then we need an event table with an event name and libpfm4 index
880 int evt_idx;
881 if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
882 SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
883 return PAPI_ENOEVNT;
884 }
885
886 // give back the new event code
887 *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
888 SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
889 return PAPI_OK;
890 }
891
892 *PapiEventCode = our_event->libpfm4_idx;
893
894 SUBDBG("EXIT: *PapiEventCode: %#x\n", *PapiEventCode);
895 return PAPI_OK;
896 }
897
898 /* Handle looking for the next event */
899 if ( modifier == PAPI_ENUM_EVENTS ) {
900 attr_idx = 0; // set so if they want attribute information, it will start with the first attribute
901
902 // get the next event code from libpfm4, if there are no more in this pmu find first event in next pmu
903 if ((code = pfm_get_event_next(*PapiEventCode)) < 0) {
904
905 // get this events information from libpfm4, we need the pmu number of the last event we processed (table must be cleared)
906 memset( &einfo, 0, sizeof( pfm_event_info_t ));
907 einfo.size = sizeof(pfm_event_info_t);
908 if ((ret = pfm_get_event_info(*PapiEventCode, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
909 SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
910 return PAPI_ENOIMPL;
911 }
912 SUBDBG("*PapiEventCode: %#x, event: %s\n", *PapiEventCode, einfo.name);
913
914 // get the pmu number of the last event
915 pnum = einfo.pmu;
916
917 SUBDBG("pnum: %d\n", pnum);
918 code=get_first_event_next_pmu(pnum, event_table->pmu_type);
919 if (code < 0) {
920 SUBDBG("EXIT: No more PMUs to list, returning: %d\n", code);
921 return code;
922 }
923 }
924
925
926 // get the event information from libpfm4 (must zero structure)
927 memset( &einfo, 0, sizeof( pfm_event_info_t ));
928 einfo.size = sizeof(pfm_event_info_t);
929 if ((ret = pfm_get_event_info(code, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
930 SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
931 return PAPI_ENOIMPL;
932 }
933
934 // get the pmu information from libpfm4 (must zero structure)
935 memset( &pinfo, 0, sizeof(pfm_pmu_info_t) );
936 pinfo.size = sizeof(pfm_pmu_info_t);
937 ret=pfm_get_pmu_info(einfo.pmu, &pinfo);
938 if (ret!=PFM_SUCCESS) {
939 SUBDBG("EXIT: pfm_get_pmu_info returned: %d\n", ret);
940 return ret;
941 }
942
943 // build full event name
944 sprintf (event_string, "%s::%s", pinfo.name, einfo.name);
945 SUBDBG("code: %#x, pmu: %s, event: %s, event_string: %s\n", code, pinfo.name, einfo.name, event_string);
946
947 // go allocate this event, need to create tables used by the get event info call that will follow
948 if ((our_event = allocate_native_event(event_string, code, cidx, event_table)) == NULL) {
949 // allocate may have created the event table but returned NULL to tell the caller the event string was invalid (attempt to encode it failed).
950 // if the caller wants to use this event to count something, it will report an error
951 // but if the caller is just interested in listing the event, then we need an event table with an event name and libpfm4 index
952 int evt_idx;
953 if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
954 SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
955 return PAPI_ENOEVNT;
956 }
957
958 // give back the new event code
959 *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
960 SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
961 return PAPI_OK;
962 }
963
964 // give back the new event code
965 *PapiEventCode = our_event->libpfm4_idx;
966
967 SUBDBG("EXIT: *PapiEventCode: %#x\n", *PapiEventCode);
968 return PAPI_OK;
969 }
970
971 /* We don't handle PAPI_NTV_ENUM_UMASK_COMBOS */
972 if ( modifier == PAPI_NTV_ENUM_UMASK_COMBOS ) {
973 SUBDBG("EXIT: do not support umask combos yet\n");
974 return PAPI_ENOIMPL;
975 }
976
977 /* Enumerate PAPI_NTV_ENUM_UMASKS (umasks on an event) */
978 if ( modifier == PAPI_NTV_ENUM_UMASKS ) {
979 // get this events information from libpfm4, we need the number of masks this event knows about (table must be cleared)
980 memset( &einfo, 0, sizeof( pfm_event_info_t ));
981 einfo.size = sizeof(pfm_event_info_t);
982 if ((ret = pfm_get_event_info(*PapiEventCode, PFM_OS_PERF_EVENT_EXT, &einfo)) != PFM_SUCCESS) {
983 SUBDBG("EXIT: pfm_get_event_info returned: %d\n", ret);
984 return PAPI_ENOIMPL;
985 }
986// SUBDBG("*PapiEventCode: %#x, einfo.name: %s, einfo.code: %#x, einfo.nattrs: %d\n", *PapiEventCode, einfo.name, einfo.code, einfo.nattrs);
987
988 // set max number of masks
989 max_umasks = einfo.nattrs;
990
991 // if we reached last attribute, return error to show we are done with this events masks
992 if (attr_idx == max_umasks) {
993 SUBDBG("EXIT: already processed all umasks: attr_idx: %d\n", attr_idx);
994 return PAPI_ENOEVNT;
995 }
996
997 // find the event table for this event, we need the pmu name and event name without any masks
999 if (ntv_idx < 0) {
1000 SUBDBG("EXIT: _papi_hwi_get_ntv_idx returned: %d\n", ntv_idx);
1001 return ntv_idx;
1002 }
1003 char *ename = event_table->native_events[ntv_idx].pmu_plus_name;
1004 if ((ename == NULL) || (strlen(ename) >= sizeof(event_string))) {
1005 SUBDBG("EXIT: Event name will not fit into buffer\n");
1006 return PAPI_EBUF;
1007 }
1008 strcpy (event_string, ename);
1009 SUBDBG("event_string: %s\n", event_string);
1010
1011 // go get the attribute information for this event
1012 // libpfm4 likes the table cleared
1013 pfm_event_attr_info_t ainfo;
1014 memset (&ainfo, 0, sizeof(pfm_event_attr_info_t));
1015 ainfo.size = sizeof(pfm_event_attr_info_t);
1016 ret = pfm_get_event_attr_info(*PapiEventCode, attr_idx, PFM_OS_PERF_EVENT_EXT, &ainfo);
1017 if (ret != PFM_SUCCESS) {
1018 SUBDBG("EXIT: Attribute info not found, EventCode: %#x, attr_idx: %d, ret: %d\n", *PapiEventCode, attr_idx, _papi_libpfm4_error(ret));
1019 return _papi_libpfm4_error(ret);
1020 }
1021 SUBDBG("*PapiEventCode: %#x, attr_idx: %d, type: %d, name: %s, description: %s\n", *PapiEventCode, attr_idx, ainfo.type, ainfo.name, ainfo.desc);
1022
1023 if (strlen(event_string) + strlen(ainfo.name) + 35 > sizeof(event_string)) {
1024 SUBDBG("EXIT: Event name and mask will not fit into buffer\n");
1025 return PAPI_EBUF;
1026 }
1027
1028 strcat (event_string, ":");
1029 strcat (event_string, ainfo.name);
1030 switch (ainfo.type) {
1031 case PFM_ATTR_UMASK:
1032 break;
1033 case PFM_ATTR_MOD_BOOL:
1034 case PFM_ATTR_MOD_INTEGER:
1035 // a few attributes require a non-zero value to encode correctly (most would accept zero here)
1036 strcat(event_string,"=0");
1037 break;
1038 default:
1039 SUBDBG("EXIT: Unsupported attribute type: %d", ainfo.type);
1040 return PAPI_EATTR;
1041 }
1042
1043 // go allocate this event, need to create tables used by the get event info call that will follow
1044 if ((our_event = allocate_native_event(event_string, *PapiEventCode, cidx, event_table)) == NULL) {
1045 // allocate may have created the event table but returned NULL to tell the caller the event string was invalid.
1046 // if the caller wants to use this event to count something, it must report the error
1047 // 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
1048 int evt_idx;
1049 if ((evt_idx = find_existing_event(event_string, event_table)) < 0) {
1050 SUBDBG("EXIT: Allocating event: '%s' failed\n", event_string);
1051 return PAPI_ENOEVNT;
1052 }
1053 // bump so next time we will use next attribute
1054 attr_idx++;
1055 // give back the new event code
1056 *PapiEventCode = event_table->native_events[evt_idx].libpfm4_idx;
1057 SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
1058 return PAPI_OK;
1059 }
1060
1061 // bump so next time we will use next attribute
1062 attr_idx++;
1063
1064 // give back the new event code
1065 *PapiEventCode = our_event->libpfm4_idx;
1066
1067 SUBDBG("EXIT: event code: %#x\n", *PapiEventCode);
1068 return PAPI_OK;
1069 }
1070
1071 /* Enumerate PAPI_NTV_ENUM_GROUPS (groups on an event) */
1072 if ( modifier == PAPI_NTV_ENUM_GROUPS ) {
1073 SUBDBG("EXIT: do not support enumerating groups in this component\n");
1074 return PAPI_ENOIMPL;
1075 }
1076
1077 /* An unknown enumeration method was indicated */
1078
1079 SUBDBG("EXIT: Invalid modifier argument provided\n");
1080 return PAPI_ENOIMPL;
1081}
1082
1083
1094int
1096 struct native_event_table_t *event_table) {
1097 SUBDBG("ENTER: event_table: %p\n", event_table);
1098
1099 int i;
1100
1101 for (i=0 ; i<PAPI_PMU_MAX ; i++) {
1102 if (my_vector->cmp_info.pmu_names[i] != NULL) {
1103 free (my_vector->cmp_info.pmu_names[i]);
1104 }
1105 }
1106
1107 /* clean out and free the native events structure */
1109
1110 /* free memory allocated with strdup or malloc */
1111 for( i=0; i<event_table->num_native_events; i++) {
1112 free(event_table->native_events[i].base_name);
1113 free(event_table->native_events[i].pmu_plus_name);
1114 free(event_table->native_events[i].pmu);
1115 free(event_table->native_events[i].allocated_name);
1116 free(event_table->native_events[i].mask_string);
1117 free(event_table->native_events[i].event_description);
1118 if (event_table->native_events[i].mask_description != NULL) {
1119 free(event_table->native_events[i].mask_description);
1120 }
1121 }
1122
1123 free(event_table->native_events);
1124
1126
1127 SUBDBG("EXIT: PAPI_OK\n");
1128 return PAPI_OK;
1129}
1130
1131
1145int
1147 struct native_event_table_t *event_table,
1148 int pmu_type) {
1149
1150 int detected_pmus=0, found_default=0;
1151 int i;
1152 int j=0;
1153 unsigned int ncnt;
1154
1155 pfm_err_t retval = PFM_SUCCESS;
1156 pfm_pmu_info_t pinfo;
1157 unsigned int strSize;
1158
1159 /* allocate the native event structure */
1160 event_table->num_native_events=0;
1161 event_table->pmu_type=pmu_type;
1162
1163 event_table->native_events=calloc(NATIVE_EVENT_CHUNK,
1164 sizeof(struct native_event_t));
1165 if (event_table->native_events==NULL) {
1166 return PAPI_ENOMEM;
1167 }
1168
1170
1171 /* Count number of present PMUs */
1172 detected_pmus=0;
1173 ncnt=0;
1174
1175 /* init default pmu */
1176 /* need to init pinfo or pfmlib might complain */
1177 memset(&(event_table->default_pmu), 0, sizeof(pfm_pmu_info_t));
1178 event_table->default_pmu.size = sizeof(pfm_pmu_info_t);
1179 retval=pfm_get_pmu_info(0, &(event_table->default_pmu));
1180
1181 SUBDBG("Prescan for aliases.\n");
1182 /* We have to see if we have aliases in there as separate PMUs, */
1183 /* we don't want both PMUs with all the events duplicated. */
1184 /* For aliases, either is valid alone, but if both are present */
1185 /* specify a preference in the code. */
1186 /* Alias: amd64_fam17h_zen1 over amd64_fam17h. */
1187 /* Alias flags are static ints global to this file. */
1188 i=0;
1189 while(1) {
1190 memset(&pinfo,0,sizeof(pfm_pmu_info_t));
1191 pinfo.size = sizeof(pfm_pmu_info_t);
1192 retval=pfm_get_pmu_info(i, &pinfo);
1193
1194 /* We're done if we hit an invalid PMU entry */
1195 /* We can't check against PFM_PMU_MAX as that might not */
1196 /* match if libpfm4 is dynamically linked */
1197
1198 if (retval==PFM_ERR_INVAL) {
1199 break;
1200 }
1201
1202 if ( (retval==PFM_SUCCESS) && (pinfo.name != NULL) &&
1203 (pmu_is_present_and_right_type(&pinfo,pmu_type)) &&
1204 (strcmp(pinfo.name,"amd64_fam17h_zen1") == 0) ) {
1206 }
1207 i++;
1208 }
1209
1210 SUBDBG("Detected pmus:\n");
1211 i=0;
1212 while(1) {
1213 memset(&pinfo,0,sizeof(pfm_pmu_info_t));
1214 pinfo.size = sizeof(pfm_pmu_info_t);
1215 retval=pfm_get_pmu_info(i, &pinfo);
1216
1217 /* We're done if we hit an invalid PMU entry */
1218 /* We can't check against PFM_PMU_MAX as that might not */
1219 /* match if libpfm4 is dynamically linked */
1220
1221 if (retval==PFM_ERR_INVAL) {
1222 break;
1223 }
1224
1225 if ((retval==PFM_SUCCESS) && (pinfo.name != NULL) &&
1226 (pmu_is_present_and_right_type(&pinfo,pmu_type))) {
1227
1228 /* skip if it is amd64_fam17h and zen1 is also present. */
1229 if (strcmp(pinfo.name,"amd64_fam17h") == 0 && amd64_fam17h_zen1_present) {
1230 i++;
1231 continue;
1232 }
1233
1234 SUBDBG("\t%d %s %s %d\n",i,
1235 pinfo.name,pinfo.desc,pinfo.type);
1236
1237 detected_pmus++;
1238 ncnt+=pinfo.nevents;
1239
1240 if (j < PAPI_PMU_MAX) {
1241 component->cmp_info.pmu_names[j++] =
1242 strdup(pinfo.name);
1243 }
1244
1245 if (pmu_type & PMU_TYPE_CORE) {
1246
1247 /* Hack to have "default core" PMU */
1248 if ( (pinfo.type==PFM_PMU_TYPE_CORE) &&
1249 strcmp(pinfo.name,"ix86arch")) {
1250 memcpy(&(event_table->default_pmu),
1251 &pinfo,sizeof(pfm_pmu_info_t));
1252 found_default++;
1253 }
1254
1255 /* For ARM processors, */
1256 if ( (pinfo.type==PFM_PMU_TYPE_CORE) &&
1258 if (strlen(_papi_hwi_system_info.hw_info.model_string) == 0) {
1259 strSize = sizeof(_papi_hwi_system_info.hw_info.model_string);
1260 strncpy( _papi_hwi_system_info.hw_info.model_string, pinfo.desc, strSize - 1);
1261 }
1262 }
1263 }
1264
1265 if (pmu_type==PMU_TYPE_UNCORE) {
1266 /* To avoid confusion, no "default" CPU for uncore */
1267 found_default=1;
1268 }
1269 }
1270 i++;
1271 }
1272 SUBDBG("%d native events detected on %d pmus\n",ncnt,detected_pmus);
1273
1274 if (detected_pmus==0) {
1275 SUBDBG("Could not find any PMUs\n");
1276 return PAPI_ENOSUPP;
1277 }
1278
1279 if (!found_default) {
1280 return PAPI_ECMP;
1281 }
1282
1283 if (found_default>1) {
1284 return PAPI_ECOUNT;
1285 }
1286
1287 component->cmp_info.num_native_events = ncnt;
1288
1289 component->cmp_info.num_cntrs = event_table->default_pmu.num_cntrs+
1290 event_table->default_pmu.num_fixed_cntrs;
1291
1292 SUBDBG( "num_counters: %d\n", component->cmp_info.num_cntrs );
1293
1294 /* Setup presets, only if Component 0 and default core PMU */
1295 if ((cidx==0) && (found_default)) {
1296 retval = _papi_load_preset_table( (char *)event_table->default_pmu.name,
1297 event_table->default_pmu.pmu, cidx );
1298 if ( retval!=PAPI_OK ) {
1299 return PAPI_ENOEVNT;
1300 }
1301 }
1302
1303 return PAPI_OK;
1304}
1305
1317int
1319 struct native_event_table_t *event_table,
1320 int pmu_type) {
1321
1322 int detected_pmus=0;
1323 int i;
1324 int j=0;
1325 pfm_err_t retval = PFM_SUCCESS;
1326 unsigned int ncnt;
1327 pfm_pmu_info_t pinfo;
1328
1329 (void)cidx;
1330
1331 /* allocate the native event structure */
1332
1333 event_table->num_native_events=0;
1334 event_table->pmu_type=pmu_type;
1335
1336 event_table->native_events=calloc(NATIVE_EVENT_CHUNK,
1337 sizeof(struct native_event_t));
1338 if (event_table->native_events==NULL) {
1339 return PAPI_ENOMEM;
1340 }
1342
1343 /* Count number of present PMUs */
1344 detected_pmus=0;
1345 ncnt=0;
1346
1347 my_vector->cmp_info.num_cntrs=0;
1348
1349 SUBDBG("Detected pmus:\n");
1350 i=0;
1351 while(1) {
1352 memset(&pinfo,0,sizeof(pfm_pmu_info_t));
1353 pinfo.size = sizeof(pfm_pmu_info_t);
1354 retval=pfm_get_pmu_info(i, &pinfo);
1355
1356 /* We're done if we hit an invalid PMU entry */
1357 /* We can't check against PFM_PMU_MAX */
1358 /* as that might not match if libpfm4 is dynamically linked */
1359
1360 if (retval==PFM_ERR_INVAL) {
1361 break;
1362 }
1363
1364 if ((retval==PFM_SUCCESS) && (pinfo.name != NULL) &&
1365 (pmu_is_present_and_right_type(&pinfo,pmu_type))) {
1366
1367 SUBDBG("\t%d %s %s %d\n",i,pinfo.name,pinfo.desc,pinfo.type);
1368
1369 detected_pmus++;
1370 ncnt+=pinfo.nevents;
1371
1372 if ((j < PAPI_PMU_MAX) && (pinfo.name != NULL)) {
1373 my_vector->cmp_info.pmu_names[j++] = strdup(pinfo.name);
1374 }
1375 my_vector->cmp_info.num_cntrs += pinfo.num_cntrs+
1376 pinfo.num_fixed_cntrs;
1377 }
1378 i++;
1379 }
1380 SUBDBG("%d native events detected on %d pmus\n",ncnt,detected_pmus);
1381
1382 my_vector->cmp_info.num_native_events = ncnt;
1383
1384 SUBDBG( "num_counters: %d\n", my_vector->cmp_info.num_cntrs );
1385
1386 return PAPI_OK;
1387}
1388
int i
convert libpfm error codes to PAPI error codes
Initialize the libpfm4 code.
Take an event code and convert it to a description.
Take an event code and convert it to a name.
Walk through all events in a pre-defined order.
Take an event name and convert it to an event code.
Shutdown any initialization done by the libpfm4 code.
Initialize the libpfm4 code.
Allocates a native event.
looks up an event, returns it if it exists
return the first available event that's on an active PMU
#define PAPI_ENUM_EVENTS
Definition: f90papi.h:224
#define PAPI_OK
Definition: f90papi.h:73
#define PAPI_NTV_ENUM_UMASK_COMBOS
Definition: f90papi.h:108
#define PAPI_ENUM_FIRST
Definition: f90papi.h:85
#define PAPI_ENOEVNT
Definition: f90papi.h:139
#define PAPI_VENDOR_ARM_ARM
Definition: f90papi.h:102
#define PAPI_ECOUNT
Definition: f90papi.h:195
#define PAPI_ENOSUPP
Definition: f90papi.h:244
#define PAPI_PMU_MAX
Definition: f90papi.h:101
#define PAPI_NTV_ENUM_UMASKS
Definition: f90papi.h:66
#define PAPI_ECMP
Definition: f90papi.h:214
#define PAPI_ENOMEM
Definition: f90papi.h:16
#define PAPI_EATTR
Definition: f90papi.h:97
#define PAPI_EBUF
Definition: f90papi.h:253
#define PAPI_ENOIMPL
Definition: f90papi.h:219
#define PAPI_HUGE_STR_LEN
Definition: f90papi.h:120
uint16_t type
Return codes and api definitions.
@ PAPI_NTV_ENUM_GROUPS
Definition: papi.h:514
#define SUBDBG(format, args...)
Definition: papi_debug.h:64
int _papi_hwi_native_to_eventcode(int cidx, int event_code, int ntv_idx, const char *event_name)
unsigned int _papi_hwi_get_papi_event_code()
void _papi_hwi_set_papi_event_string(const char *event_string)
Definition: papi_internal.c:93
void _papi_hwi_set_papi_event_code(unsigned int event_code, int update_flag)
int _papi_hwi_get_ntv_idx(unsigned int papi_evt_code)
#define NAMELIB_LOCK
Definition: papi_internal.h:93
#define PMU_TYPE_OS
#define PMU_TYPE_CORE
#define PMU_TYPE_UNCORE
int _papi_load_preset_table(char *pmu_str, int pmu_type, int cidx)
Definition: papi_preset.c:771
static int cidx
#define NATIVE_EVENT_CHUNK
static int amd64_fam17h_zen1_present
static int attr_idx
int _pe_libpfm4_ntv_code_to_info(unsigned int EventCode, PAPI_event_info_t *info, struct native_event_table_t *event_table)
static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type)
papi_mdi_t _papi_hwi_system_info
Definition: papi_internal.c:56
#define PFM_PLM3
Definition: pfmlib.h:53
int pfm_err_t
Definition: pfmlib.h:151
#define PFM_PLM0
Definition: pfmlib.h:50
pfm_err_t pfm_find_event(const char *str, unsigned int *idx)
const char * name
Definition: rocs.c:225
char * pmu_names[PAPI_PMU_MAX]
Definition: papi.h:648
char symbol[PAPI_HUGE_STR_LEN]
Definition: papi.h:960
char long_descr[PAPI_HUGE_STR_LEN]
Definition: papi.h:963
int vendor
Definition: papi.h:781
char model_string[PAPI_MAX_STR_LEN]
Definition: papi.h:784
perf_event_attr_t attr
pfm_pmu_info_t default_pmu
struct native_event_t * native_events
PAPI_hw_info_t hw_info
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
inline_static int _papi_hwi_lock(int lck)
Definition: threads.h:69
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:83
int retval
Definition: zero_fork.c:53