|
PAPI
5.3.0.0
|
00001 /* 00002 * File: pe_libpfm4_events.c 00003 * Author: Vince Weaver vincent.weaver @ maine.edu 00004 */ 00005 00006 #include <string.h> 00007 00008 #include "papi.h" 00009 #include "papi_internal.h" 00010 #include "papi_vector.h" 00011 00012 #include "papi_libpfm4_events.h" 00013 #include "pe_libpfm4_events.h" 00014 00015 #include "perfmon/pfmlib.h" 00016 #include "perfmon/pfmlib_perf_event.h" 00017 00018 #define NATIVE_EVENT_CHUNK 1024 00019 00032 static int find_existing_event(char *name, 00033 struct native_event_table_t *event_table) { 00034 00035 int i,event=PAPI_ENOEVNT; 00036 00037 SUBDBG("Looking for %s in %d events\n", 00038 name,event_table->num_native_events); 00039 00040 _papi_hwi_lock( NAMELIB_LOCK ); 00041 00042 for(i=0;i<event_table->num_native_events;i++) { 00043 00044 if (!strcmp(name,event_table->native_events[i].allocated_name)) { 00045 SUBDBG("Found %s (%#x)\n", 00046 event_table->native_events[i].allocated_name, 00047 event_table->native_events[i].libpfm4_idx); 00048 event=i; 00049 break; 00050 } 00051 } 00052 _papi_hwi_unlock( NAMELIB_LOCK ); 00053 00054 if (event<0) { SUBDBG("%s not allocated yet\n",name); } 00055 00056 return event; 00057 } 00058 00071 static struct native_event_t *find_existing_event_by_number(int eventnum, 00072 struct native_event_table_t *event_table) { 00073 00074 struct native_event_t *temp_event=NULL; 00075 00076 _papi_hwi_lock( NAMELIB_LOCK ); 00077 00078 temp_event=&(event_table->native_events[eventnum]); 00079 00080 _papi_hwi_unlock( NAMELIB_LOCK ); 00081 00082 SUBDBG("Found %p for %#x\n",temp_event,eventnum); 00083 00084 return temp_event; 00085 } 00086 00087 static int pmu_is_present_and_right_type(pfm_pmu_info_t *pinfo, int type) { 00088 00089 if (!pinfo->is_present) return 0; 00090 00091 if ((pinfo->type==PFM_PMU_TYPE_UNCORE) && (type&PMU_TYPE_UNCORE)) return 1; 00092 if ((pinfo->type==PFM_PMU_TYPE_CORE) && (type&PMU_TYPE_CORE)) return 1; 00093 if ((pinfo->type==PFM_PMU_TYPE_OS_GENERIC) && (type&PMU_TYPE_OS)) return 1; 00094 00095 return 0; 00096 } 00097 00098 00110 static int find_event(char *name, int pmu_type) { 00111 00112 int ret, actual_idx; 00113 pfm_pmu_info_t pinfo; 00114 pfm_event_info_t event_info; 00115 00116 SUBDBG("Looking for %s\n",name); 00117 00118 actual_idx=pfm_find_event(name); 00119 if (actual_idx<0) { 00120 return PFM_ERR_NOTFOUND; 00121 } 00122 00123 memset(&event_info,0,sizeof(pfm_event_info_t)); 00124 ret=pfm_get_event_info(actual_idx, PFM_OS_PERF_EVENT, &event_info); 00125 if (ret<0) { 00126 return PFM_ERR_NOTFOUND; 00127 } 00128 00129 memset(&pinfo,0,sizeof(pfm_pmu_info_t)); 00130 pfm_get_pmu_info(event_info.pmu, &pinfo); 00131 if (pmu_is_present_and_right_type(&pinfo,pmu_type)) { 00132 return actual_idx; 00133 } 00134 00135 return PFM_ERR_NOTFOUND; 00136 } 00137 00138 00150 static int find_event_no_aliases(char *name, int pmu_type) { 00151 00152 int j,i, ret; 00153 pfm_pmu_info_t pinfo; 00154 pfm_event_info_t event_info; 00155 char full_name[BUFSIZ]; 00156 00157 SUBDBG("Looking for %s\n",name); 00158 00159 pfm_for_all_pmus(j) { 00160 00161 memset(&pinfo,0,sizeof(pfm_pmu_info_t)); 00162 pfm_get_pmu_info(j, &pinfo); 00163 if (!pmu_is_present_and_right_type(&pinfo,pmu_type)) { 00164 continue; 00165 } 00166 00167 SUBDBG("Looking in pmu %d\n",j); 00168 i = pinfo.first_event; 00169 while(1) { 00170 memset(&event_info,0,sizeof(pfm_event_info_t)); 00171 ret=pfm_get_event_info(i, PFM_OS_PERF_EVENT, &event_info); 00172 if (ret<0) break; 00173 00174 sprintf(full_name,"%s::%s",pinfo.name,event_info.name); 00175 00176 if (!strcmp(name,full_name)) { 00177 SUBDBG("FOUND %s %s %#x\n",name,full_name,i); 00178 return i; 00179 } 00180 00181 if (!strcmp(name,event_info.name)) { 00182 SUBDBG("FOUND %s %s %#x\n",name,event_info.name,i); 00183 return i; 00184 } 00185 i=pfm_get_event_next(i); 00186 } 00187 } 00188 return PFM_ERR_NOTFOUND; 00189 } 00190 00191 00203 static int find_next_no_aliases(int code, int pmu_type) { 00204 00205 int current_pmu=0,current_event=0; 00206 pfm_err_t ret; 00207 pfm_pmu_info_t pinfo; 00208 pfm_event_info_t event_info; 00209 00210 /* Clear the structures, as libpfm4 requires it */ 00211 memset(&event_info,0,sizeof(pfm_event_info_t)); 00212 00213 ret=pfm_get_event_info(code, PFM_OS_PERF_EVENT, &event_info); 00214 if (ret!=PFM_SUCCESS) { 00215 return ret; 00216 } 00217 00218 current_pmu=event_info.pmu; 00219 current_event=pfm_get_event_next(code); 00220 00221 SUBDBG("Current is %#x guessing next is %#x\n",code,current_event); 00222 00223 while(1) { 00224 00225 memset(&event_info,0,sizeof(pfm_event_info_t)); 00226 ret=pfm_get_event_info(current_event, PFM_OS_PERF_EVENT, &event_info); 00227 if (ret==PFM_SUCCESS) { 00228 SUBDBG("Returning %#x\n",current_event); 00229 return current_event; 00230 } 00231 00232 /* next event not found, so try moving to next PMU */ 00233 00234 while(1) { 00235 00236 current_pmu++; 00237 SUBDBG("Incrementing PMU: %#x\n",current_pmu); 00238 00239 /* Off the end, so done iterating */ 00240 if (current_pmu>PFM_PMU_MAX) { 00241 return PFM_ERR_NOTFOUND; 00242 } 00243 00244 memset(&pinfo,0,sizeof(pfm_pmu_info_t)); 00245 pfm_get_pmu_info(current_pmu, &pinfo); 00246 if (pmu_is_present_and_right_type(&pinfo,pmu_type)) break; 00247 } 00248 00249 current_event=pinfo.first_event; 00250 00251 } 00252 00253 } 00254 00269 static struct native_event_t *allocate_native_event(char *name, 00270 int event_idx, 00271 struct native_event_table_t *event_table) { 00272 00273 int new_event; 00274 00275 pfm_err_t ret; 00276 unsigned int i; 00277 char *base_start; 00278 pfm_event_info_t info; 00279 pfm_pmu_info_t pinfo; 00280 char base[BUFSIZ],pmuplusbase[BUFSIZ]; 00281 char fullname[BUFSIZ]; 00282 00283 pfm_perf_encode_arg_t perf_arg; 00284 00285 struct perf_event_attr perf_attr; 00286 00287 /* get the event name from libpfm */ 00288 memset(&info,0,sizeof(pfm_event_info_t)); 00289 ret = pfm_get_event_info(event_idx, PFM_OS_PERF_EVENT, &info); 00290 if (ret!=PFM_SUCCESS) { 00291 return NULL; 00292 } 00293 00294 /* get the PMU info */ 00295 memset(&pinfo,0,sizeof(pfm_pmu_info_t)); 00296 pfm_get_pmu_info(info.pmu, &pinfo); 00297 00298 /* calculate the base name, meaning strip off pmu identifier */ 00299 strncpy(base,name,BUFSIZ); 00300 i=0; 00301 base_start=base; 00302 while(i<strlen(base)) { 00303 if (base[i]==':') { 00304 if (base[i+1]==':') { 00305 i++; 00306 base_start=&base[i+1]; 00307 } 00308 else { 00309 base[i]=0; 00310 } 00311 } 00312 i++; 00313 } 00314 00315 /* add the event */ 00316 _papi_hwi_lock( NAMELIB_LOCK ); 00317 00318 new_event=event_table->num_native_events; 00319 00320 event_table->native_events[new_event].base_name=strdup(base_start); 00321 00322 sprintf(fullname,"%s::%s",pinfo.name,info.name); 00323 event_table->native_events[new_event].pmu_plus_name=strdup(fullname); 00324 00325 sprintf(pmuplusbase,"%s::%s",pinfo.name,base_start); 00326 00327 event_table->native_events[new_event].component=0; 00328 event_table->native_events[new_event].pmu=strdup(pinfo.name); 00329 00330 event_table->native_events[new_event].libpfm4_idx= 00331 find_event_no_aliases(pmuplusbase,event_table->pmu_type); 00332 00333 SUBDBG("Using %#x as index instead of %#x for %s\n", 00334 event_table->native_events[new_event].libpfm4_idx, 00335 event_idx,pmuplusbase); 00336 00337 event_table->native_events[new_event].allocated_name=strdup(name); 00338 00339 /* is this needed? */ 00340 event_table->native_events[new_event].users=0; 00341 00342 00343 /* use name of the event to get the perf_event encoding */ 00344 00345 /* clear the attribute structure */ 00346 memset(&perf_arg,0,sizeof(pfm_perf_encode_arg_t)); 00347 00348 /* clear out the perf_attr struct */ 00349 memset(&perf_attr,0,sizeof(struct perf_event_attr)); 00350 perf_arg.attr=&perf_attr; 00351 00352 ret = pfm_get_os_event_encoding(name, 00353 PFM_PLM0 | PFM_PLM3, 00354 PFM_OS_PERF_EVENT, 00355 &perf_arg); 00356 00357 /* If we error out on UMASK then enumeration doesn't work */ 00358 if ((ret==PFM_SUCCESS) || (ret==PFM_ERR_UMASK)) { 00359 00360 event_table->native_events[new_event].config=perf_arg.attr->config; 00361 event_table->native_events[new_event].config1=perf_arg.attr->config1; 00362 event_table->native_events[new_event].type=perf_arg.attr->type; 00363 00364 SUBDBG( "pe_event: config 0x%"PRIx64" config1 0x%"PRIx64 00365 " type 0x%"PRIx32"\n", 00366 perf_arg.attr->config, 00367 perf_arg.attr->config1, 00368 perf_arg.attr->type); 00369 00370 SUBDBG("Creating event %s with perfidx %#x\n", 00371 name, 00372 event_table->native_events[new_event].libpfm4_idx); 00373 00374 event_table->num_native_events++; 00375 00376 /* If we've allocated too many native events, then allocate more room */ 00377 if (event_table->num_native_events >= 00378 event_table->allocated_native_events) { 00379 00380 SUBDBG("Allocating more room for native events (%d %ld)\n", 00381 (event_table->allocated_native_events+NATIVE_EVENT_CHUNK), 00382 (long)sizeof(struct native_event_t) * 00383 (event_table->allocated_native_events+NATIVE_EVENT_CHUNK)); 00384 00385 event_table->native_events=realloc(event_table->native_events, 00386 sizeof(struct native_event_t) * 00387 (event_table->allocated_native_events+NATIVE_EVENT_CHUNK)); 00388 event_table->allocated_native_events+=NATIVE_EVENT_CHUNK; 00389 } 00390 } 00391 00392 _papi_hwi_unlock( NAMELIB_LOCK ); 00393 00394 if (event_table->native_events==NULL) { 00395 return NULL; 00396 } 00397 00398 return &event_table->native_events[new_event]; 00399 00400 } 00401 00416 static int find_max_umask(struct native_event_t *current_event) { 00417 00418 pfm_event_attr_info_t ainfo; 00419 char *b; 00420 int a, ret, max =0; 00421 pfm_event_info_t info; 00422 char event_string[BUFSIZ],*ptr; 00423 char temp_string[BUFSIZ]; 00424 00425 SUBDBG("Trying to find max umask in %s\n",current_event->allocated_name); 00426 00427 strcpy(event_string,current_event->allocated_name); 00428 00429 /* Skip leading :: delimited PMU name and point to first umask */ 00430 if (strstr(event_string,"::")) { 00431 ptr=strstr(event_string,"::"); 00432 ptr+=2; 00433 b=strtok(ptr,":"); 00434 } 00435 else { 00436 b=strtok(event_string,":"); 00437 } 00438 00439 if (!b) { 00440 SUBDBG("No colon!\n"); 00441 return PFM_ERR_UMASK; /* Must be this value!! */ 00442 } 00443 00444 memset(&info,0,sizeof(pfm_event_info_t)); 00445 ret = pfm_get_event_info(current_event->libpfm4_idx, 00446 PFM_OS_PERF_EVENT, &info); 00447 if (ret!=PFM_SUCCESS) { 00448 SUBDBG("get_event_info failed\n"); 00449 return PFM_ERR_NOTFOUND; 00450 } 00451 00452 /* skip first */ 00453 b=strtok(NULL,":"); 00454 if (!b) { 00455 SUBDBG("Skipping first failed\n"); 00456 return PFM_ERR_UMASK; /* Must be this value!! */ 00457 } 00458 00459 while(b) { 00460 a=0; 00461 while(1) { 00462 00463 SUBDBG("get_event_attr %#x %d %p\n",current_event->libpfm4_idx,a,&ainfo); 00464 00465 memset(&ainfo,0,sizeof(pfm_event_attr_info_t)); 00466 00467 ret = pfm_get_event_attr_info(current_event->libpfm4_idx, a, 00468 PFM_OS_PERF_EVENT, &ainfo); 00469 00470 if (ret != PFM_SUCCESS) { 00471 SUBDBG("get_event_attr failed %s\n",pfm_strerror(ret)); 00472 return ret; 00473 } 00474 00475 SUBDBG("Trying %s with %s\n",ainfo.name,b); 00476 00477 if (ainfo.type == PFM_ATTR_MOD_BOOL) { 00478 sprintf(temp_string,"%s=0",ainfo.name); 00479 if (!strcasecmp(temp_string, b)) { 00480 SUBDBG("Found %s %d\n",b,a); 00481 if (a>max) max=a; 00482 goto found_attr; 00483 } 00484 } 00485 else if (ainfo.type == PFM_ATTR_MOD_INTEGER) { 00486 sprintf(temp_string,"%s=0",ainfo.name); 00487 if (!strcasecmp(temp_string, b)) { 00488 SUBDBG("Found %s %d\n",b,a); 00489 if (a>max) max=a; 00490 goto found_attr; 00491 } 00492 } 00493 else { 00494 if (!strcasecmp(ainfo.name, b)) { 00495 SUBDBG("Found %s %d\n",b,a); 00496 if (a>max) max=a; 00497 goto found_attr; 00498 } 00499 } 00500 a++; 00501 } 00502 00503 SUBDBG("attr=%s not found for event %s\n", b, info.name); 00504 00505 return PFM_ERR_ATTR; 00506 00507 found_attr: 00508 00509 b=strtok(NULL,":"); 00510 } 00511 00512 SUBDBG("Found max %d\n", max); 00513 00514 return max; 00515 } 00516 00517 00518 00527 static int 00528 get_event_first_active(int pmu_type) 00529 { 00530 int pidx, pmu_idx, ret; 00531 00532 pfm_pmu_info_t pinfo; 00533 00534 pmu_idx=0; 00535 00536 while(pmu_idx<PFM_PMU_MAX) { 00537 00538 /* clear the PMU structure (required by libpfm4) */ 00539 memset(&pinfo,0,sizeof(pfm_pmu_info_t)); 00540 ret=pfm_get_pmu_info(pmu_idx, &pinfo); 00541 00542 if ((ret==PFM_SUCCESS) && pmu_is_present_and_right_type(&pinfo,pmu_type)) { 00543 00544 pidx=pinfo.first_event; 00545 00546 SUBDBG("First event in %s is %d\n",pinfo.name,pidx); 00547 00548 if (pidx<0) { 00549 /* For some reason no events available */ 00550 /* despite the PMU being active. */ 00551 /* This can happen, for example with ix86arch */ 00552 /* inside of VMware */ 00553 } 00554 else { 00555 return pidx; 00556 } 00557 } 00558 00559 pmu_idx++; 00560 00561 } 00562 00563 return PAPI_ENOEVNT; 00564 00565 } 00566 00567 00568 00585 static int 00586 convert_libpfm4_to_string( int code, char **event_name, 00587 pfm_pmu_info_t *default_pmu) 00588 { 00589 00590 int ret; 00591 pfm_event_info_t gete; 00592 pfm_pmu_info_t pinfo; 00593 char name[BUFSIZ]; 00594 00595 SUBDBG("ENTER %#x\n",code); 00596 00597 /* Clear structures, as wanted by libpfm4 */ 00598 memset( &gete, 0, sizeof (pfm_event_info_t) ); 00599 00600 ret=pfm_get_event_info(code, PFM_OS_PERF_EVENT, &gete); 00601 if (ret!=PFM_SUCCESS) { 00602 return ret; 00603 } 00604 00605 memset( &pinfo, 0, sizeof(pfm_pmu_info_t) ); 00606 ret=pfm_get_pmu_info(gete.pmu, &pinfo); 00607 if (ret!=PFM_SUCCESS) { 00608 return ret; 00609 } 00610 00611 /* Only prepend PMU name if not on the "default" PMU */ 00612 00613 if (pinfo.pmu == default_pmu->pmu) { 00614 *event_name=strdup(gete.name); 00615 } 00616 else { 00617 sprintf(name,"%s::%s",pinfo.name,gete.name); 00618 *event_name=strdup(name); 00619 } 00620 00621 SUBDBG("Found name: %s\n",*event_name); 00622 00623 return PFM_SUCCESS; 00624 00625 } 00626 00627 00642 static int convert_pfmidx_to_native(int code, unsigned int *PapiEventCode, 00643 struct native_event_table_t *event_table) { 00644 00645 int ret; 00646 char *name=NULL; 00647 00648 ret=convert_libpfm4_to_string( code, &name, &event_table->default_pmu); 00649 if (ret!=PFM_SUCCESS) { 00650 return _papi_libpfm4_error(ret); 00651 } 00652 00653 SUBDBG("Converted %#x to %s\n",code,name); 00654 00655 ret=_pe_libpfm4_ntv_name_to_code(name,PapiEventCode,event_table); 00656 00657 SUBDBG("Converted %s to event %#x\n",name,*PapiEventCode); 00658 00659 if (name) free(name); 00660 00661 return ret; 00662 00663 } 00664 00665 00684 static int find_next_umask(struct native_event_t *current_event, 00685 int current,char *umask_name) { 00686 00687 char temp_string[BUFSIZ]; 00688 pfm_event_info_t event_info; 00689 pfm_event_attr_info_t ainfo; 00690 int num_masks=0; 00691 pfm_err_t ret; 00692 int i; 00693 00694 /* get number of attributes */ 00695 00696 memset(&event_info, 0, sizeof(event_info)); 00697 ret=pfm_get_event_info(current_event->libpfm4_idx, 00698 PFM_OS_PERF_EVENT, &event_info); 00699 if (ret!=PFM_SUCCESS) { 00700 return ret; 00701 } 00702 00703 SUBDBG("%d possible attributes for event %s\n", 00704 event_info.nattrs, 00705 event_info.name); 00706 00707 pfm_for_each_event_attr(i, &event_info) { 00708 00709 ainfo.size = sizeof(ainfo); 00710 00711 ret = pfm_get_event_attr_info(event_info.idx, i, PFM_OS_PERF_EVENT, 00712 &ainfo); 00713 if (ret != PFM_SUCCESS) { 00714 SUBDBG("Not found\n"); 00715 return PFM_ERR_NOTFOUND; 00716 } 00717 00718 if (ainfo.type == PFM_ATTR_UMASK) { 00719 SUBDBG("nm %d looking for %d\n",num_masks,current); 00720 if (num_masks==current+1) { 00721 SUBDBG("Found attribute %d: %s type: %d\n", 00722 i,ainfo.name,ainfo.type); 00723 00724 sprintf(temp_string,"%s",ainfo.name); 00725 strncpy(umask_name,temp_string,BUFSIZ); 00726 00727 return current+1; 00728 } 00729 num_masks++; 00730 } 00731 00732 if (ainfo.type == PFM_ATTR_MOD_BOOL) { 00733 SUBDBG("nm %d looking for %d\n",num_masks,current); 00734 00735 if (num_masks==current+1) { 00736 SUBDBG("Found attribute %d: %s type: %d\n", 00737 i,ainfo.name,ainfo.type); 00738 00739 sprintf(temp_string,"%s=0",ainfo.name); 00740 strncpy(umask_name,temp_string,BUFSIZ); 00741 00742 return current+1; 00743 } 00744 num_masks++; 00745 } 00746 00747 if (ainfo.type == PFM_ATTR_MOD_INTEGER) { 00748 SUBDBG("nm %d looking for %d\n",num_masks,current); 00749 if (num_masks==current+1) { 00750 SUBDBG("Found attribute %d: %s type: %d\n", 00751 i,ainfo.name,ainfo.type); 00752 00753 sprintf(temp_string,"%s=0",ainfo.name); 00754 strncpy(umask_name,temp_string,BUFSIZ); 00755 00756 return current+1; 00757 } 00758 num_masks++; 00759 } 00760 } 00761 00762 return PFM_ERR_ATTR; 00763 00764 } 00765 00766 00767 00768 /***********************************************************/ 00769 /* Exported functions */ 00770 /***********************************************************/ 00771 00772 00787 int 00788 _pe_libpfm4_ntv_name_to_code( char *name, unsigned int *event_code, 00789 struct native_event_table_t *event_table) 00790 { 00791 00792 int actual_idx; 00793 struct native_event_t *our_event; 00794 int event_num; 00795 00796 SUBDBG( "Converting %s\n", name); 00797 00798 event_num=find_existing_event(name,event_table); 00799 00800 if (event_num<0) { 00801 00802 /* event currently doesn't exist, so try to find it */ 00803 /* using libpfm4 */ 00804 00805 SUBDBG("Using pfm to look up event %s\n",name); 00806 00807 actual_idx=find_event(name, event_table->pmu_type); 00808 if (actual_idx<0) { 00809 return _papi_libpfm4_error(actual_idx); 00810 } 00811 00812 SUBDBG("Using %#x as the index\n",actual_idx); 00813 00814 /* We were found in libpfm4, so allocate our copy of the event */ 00815 00816 our_event=allocate_native_event(name,actual_idx,event_table); 00817 if (our_event==NULL) return PAPI_ENOEVNT; 00818 00819 event_num=find_existing_event(name,event_table); 00820 } 00821 00822 if (event_num>=0) { 00823 *event_code=event_num; 00824 SUBDBG("Found code: %#x\n",*event_code); 00825 return PAPI_OK; 00826 } 00827 00828 /* Failure here means allocate_native_event failed */ 00829 00830 SUBDBG("Event %s not found\n",name); 00831 00832 return PAPI_ENOEVNT; 00833 00834 } 00835 00836 00854 int 00855 _pe_libpfm4_ntv_code_to_name(unsigned int EventCode, 00856 char *ntv_name, int len, 00857 struct native_event_table_t *event_table) 00858 { 00859 00860 struct native_event_t *our_event; 00861 00862 SUBDBG("ENTER %#x\n",EventCode); 00863 00864 our_event=find_existing_event_by_number(EventCode,event_table); 00865 if (our_event==NULL) { 00866 return PAPI_ENOEVNT; 00867 } 00868 00869 strncpy(ntv_name,our_event->allocated_name,len); 00870 00871 if (strlen(our_event->allocated_name) > (unsigned)len) { 00872 return PAPI_EBUF; 00873 } 00874 00875 return PAPI_OK; 00876 } 00877 00878 00901 int 00902 _pe_libpfm4_ntv_code_to_descr( unsigned int EventCode, 00903 char *ntv_descr, int len, 00904 struct native_event_table_t *event_table) 00905 { 00906 int ret,a,first_mask=1; 00907 char *eventd, *tmp=NULL; 00908 pfm_event_info_t gete; 00909 00910 pfm_event_attr_info_t ainfo; 00911 char *b; 00912 char event_string[BUFSIZ],*ptr; 00913 char temp_string[BUFSIZ]; 00914 00915 struct native_event_t *our_event; 00916 00917 SUBDBG("ENTER %#x\n",EventCode); 00918 00919 our_event=find_existing_event_by_number(EventCode,event_table); 00920 if (our_event==NULL) { 00921 return PAPI_ENOEVNT; 00922 } 00923 00924 SUBDBG("Getting info on %#x\n",our_event->libpfm4_idx); 00925 00926 /* libpfm requires the structure be zeroed */ 00927 memset( &gete, 0, sizeof ( gete ) ); 00928 00929 ret=pfm_get_event_info(our_event->libpfm4_idx, PFM_OS_PERF_EVENT, &gete); 00930 if (ret<0) { 00931 SUBDBG("Return=%d\n",ret); 00932 return _papi_libpfm4_error(ret); 00933 } 00934 00935 eventd=strdup(gete.desc); 00936 00937 tmp = ( char * ) malloc( strlen( eventd ) + 1 ); 00938 if ( tmp == NULL ) { 00939 free( eventd ); 00940 return PAPI_ENOMEM; 00941 } 00942 00943 tmp[0] = '\0'; 00944 strcat( tmp, eventd ); 00945 free( eventd ); 00946 00947 /* Handle Umasks */ 00948 00949 /* attributes concactinated onto end of descr separated by ", masks" */ 00950 /* then comma separated */ 00951 00952 strcpy(event_string,our_event->allocated_name); 00953 00954 /* Point to first umask */ 00955 00956 /* Skip the pmu name :: if one exists */ 00957 if (strstr(event_string,"::")) { 00958 ptr=strstr(event_string,"::"); 00959 ptr+=2; 00960 b=strtok(ptr,":"); 00961 } 00962 else { 00963 b=strtok(event_string,":"); 00964 } 00965 00966 /* if no umask, then done */ 00967 if (!b) { 00968 SUBDBG("No colon!\n"); /* no umask */ 00969 goto descr_in_tmp; 00970 } 00971 00972 /* skip first */ 00973 b=strtok(NULL,":"); 00974 if (!b) { 00975 SUBDBG("Skipping first failed\n"); 00976 goto descr_in_tmp; 00977 } 00978 00979 /* loop through all umasks, seeing which match */ 00980 while(b) { 00981 a=0; 00982 while(1) { 00983 00984 SUBDBG("get_event_attr %#x %p\n",our_event->libpfm4_idx,&ainfo); 00985 00986 memset(&ainfo,0,sizeof(pfm_event_attr_info_t)); 00987 00988 ret = pfm_get_event_attr_info(our_event->libpfm4_idx, a, 00989 PFM_OS_PERF_EVENT, &ainfo); 00990 if (ret != PFM_SUCCESS) { 00991 free( tmp ); 00992 SUBDBG("get_event_attr failed %s\n",pfm_strerror(ret)); 00993 return _papi_libpfm4_error(ret); 00994 } 00995 00996 /* Plain UMASK case */ 00997 if (ainfo.type == PFM_ATTR_UMASK) { 00998 00999 SUBDBG("Trying %s with %s\n",ainfo.name,b); 01000 01001 if (!strcasecmp(ainfo.name, b)) { 01002 int new_length; 01003 01004 SUBDBG("Found %s\n",b); 01005 new_length=strlen(ainfo.desc); 01006 01007 if (first_mask) { 01008 tmp=realloc(tmp,strlen(tmp)+new_length+1+strlen(", masks:")); 01009 strcat(tmp,", masks:"); 01010 first_mask=0; 01011 } 01012 else { 01013 tmp=realloc(tmp,strlen(tmp)+new_length+1+strlen(",")); 01014 strcat(tmp,","); 01015 } 01016 strcat(tmp,ainfo.desc); 01017 01018 goto found_attr; 01019 } 01020 } 01021 01022 /* Boolean Case */ 01023 if (ainfo.type == PFM_ATTR_MOD_BOOL) { 01024 01025 sprintf(temp_string,"%s=0",ainfo.name); 01026 01027 SUBDBG("Trying %s with %s\n",temp_string,b); 01028 01029 if (!strcasecmp(temp_string, b)) { 01030 int new_length; 01031 01032 SUBDBG("Found %s\n",b); 01033 new_length=strlen(ainfo.desc); 01034 01035 if (first_mask) { 01036 tmp=realloc(tmp,strlen(tmp)+new_length+1+strlen(", masks:")); 01037 strcat(tmp,", masks:"); 01038 first_mask=0; 01039 } 01040 else { 01041 tmp=realloc(tmp,strlen(tmp)+new_length+1+strlen(",")); 01042 strcat(tmp,","); 01043 } 01044 strcat(tmp,ainfo.desc); 01045 01046 goto found_attr; 01047 } 01048 } 01049 01050 /* Integer Case */ 01051 if (ainfo.type == PFM_ATTR_MOD_INTEGER) { 01052 01053 sprintf(temp_string,"%s=0",ainfo.name); 01054 01055 SUBDBG("Trying %s with %s\n",temp_string,b); 01056 01057 if (!strcasecmp(temp_string, b)) { 01058 int new_length; 01059 01060 SUBDBG("Found %s\n",b); 01061 new_length=strlen(ainfo.desc); 01062 01063 if (first_mask) { 01064 tmp=realloc(tmp,strlen(tmp)+new_length+1+strlen(", masks:")); 01065 strcat(tmp,", masks:"); 01066 first_mask=0; 01067 } 01068 else { 01069 tmp=realloc(tmp,strlen(tmp)+new_length+1+strlen(",")); 01070 strcat(tmp,","); 01071 } 01072 strcat(tmp,ainfo.desc); 01073 01074 goto found_attr; 01075 } 01076 } 01077 01078 a++; 01079 } 01080 01081 SUBDBG("attr=%s not found for event %s\n", b, ainfo.name); 01082 01083 return PAPI_EATTR; 01084 01085 found_attr: 01086 01087 b=strtok(NULL,":"); 01088 } 01089 01090 /* We are done and the description to copy is in tmp */ 01091 descr_in_tmp: 01092 strncpy( ntv_descr, tmp, ( size_t ) len ); 01093 if ( ( int ) strlen( tmp ) > len - 1 ) 01094 ret = PAPI_EBUF; 01095 else 01096 ret = PAPI_OK; 01097 free( tmp ); 01098 01099 SUBDBG("PFM4 Code: %#x %s\n",EventCode,ntv_descr); 01100 01101 return ret; 01102 } 01103 01104 01105 int 01106 _pe_libpfm4_ntv_code_to_info(unsigned int EventCode, 01107 PAPI_event_info_t *info, 01108 struct native_event_table_t *event_table) 01109 { 01110 01111 01112 struct native_event_t *our_event; 01113 01114 SUBDBG("ENTER %#x\n",EventCode); 01115 01116 our_event=find_existing_event_by_number(EventCode,event_table); 01117 if (our_event==NULL) { 01118 return PAPI_ENOEVNT; 01119 } 01120 01121 strncpy(info->symbol, our_event->allocated_name, sizeof(info->symbol)); 01122 01123 if (strlen(our_event->allocated_name) > sizeof(info->symbol)) { 01124 return PAPI_EBUF; 01125 } 01126 01127 _pe_libpfm4_ntv_code_to_descr(EventCode,info->long_descr, 01128 sizeof(info->long_descr),event_table); 01129 01130 return PAPI_OK; 01131 } 01132 01133 01134 01151 int 01152 _pe_libpfm4_ntv_enum_events( unsigned int *PapiEventCode, 01153 int modifier, 01154 struct native_event_table_t *event_table) { 01155 01156 int code,ret; 01157 struct native_event_t *current_event; 01158 01159 SUBDBG("ENTER\n"); 01160 01161 /* return first event if so specified */ 01162 if ( modifier == PAPI_ENUM_FIRST ) { 01163 01164 unsigned int papi_event=0; 01165 01166 SUBDBG("ENUM_FIRST\n"); 01167 01168 code=get_event_first_active(event_table->pmu_type); 01169 SUBDBG("ENUM_FIRST code: %d\n",code); 01170 if (code < 0 ) { 01171 return code; 01172 } 01173 01174 /* convert the libpfm4 event to a PAPI event */ 01175 ret=convert_pfmidx_to_native(code, &papi_event,event_table); 01176 01177 *PapiEventCode=(unsigned int)papi_event; 01178 01179 SUBDBG("FOUND %#x (from %#x) ret=%d\n",*PapiEventCode,code,ret); 01180 01181 return ret; 01182 } 01183 01184 /* If we get this far, we're looking for a */ 01185 /* next-event. So gather info on the current one */ 01186 current_event=find_existing_event_by_number(*PapiEventCode, 01187 event_table); 01188 if (current_event==NULL) { 01189 SUBDBG("EVENTS %#x not found\n",*PapiEventCode); 01190 return PAPI_ENOEVNT; 01191 } 01192 01193 01194 /* Handle looking for the next event */ 01195 01196 if ( modifier == PAPI_ENUM_EVENTS ) { 01197 01198 unsigned int papi_event=0; 01199 01200 SUBDBG("PAPI_ENUM_EVENTS %#x\n",*PapiEventCode); 01201 01202 code=current_event->libpfm4_idx; 01203 01204 ret=find_next_no_aliases(code,event_table->pmu_type); 01205 SUBDBG("find_next_no_aliases() Returned %#x\n",ret); 01206 if (ret<0) { 01207 return ret; 01208 } 01209 01210 /* Convert libpfm4 event code to PAPI event code */ 01211 ret=convert_pfmidx_to_native(ret, &papi_event, event_table); 01212 if (ret<0) { 01213 SUBDBG("Couldn't convert to native %d %s\n", 01214 ret,PAPI_strerror(ret)); 01215 return ret; 01216 } 01217 01218 *PapiEventCode=(unsigned int)papi_event; 01219 01220 SUBDBG("Returning PAPI_OK\n"); 01221 01222 return ret; 01223 } 01224 01225 /* We don't handle PAPI_NTV_ENUM_UMASK_COMBOS */ 01226 if ( modifier == PAPI_NTV_ENUM_UMASK_COMBOS ) { 01227 return PAPI_ENOIMPL; 01228 } 01229 01230 /* Enumerate PAPI_NTV_ENUM_UMASKS (umasks on an event) */ 01231 if ( modifier == PAPI_NTV_ENUM_UMASKS ) { 01232 01233 int max_umask,next_umask; 01234 char umask_string[BUFSIZ],new_name[BUFSIZ]; 01235 01236 SUBDBG("Finding maximum mask in event %s\n", 01237 current_event->allocated_name); 01238 01239 max_umask=find_max_umask(current_event); 01240 SUBDBG("Found max %d\n",max_umask); 01241 01242 if (max_umask<0) { 01243 if (max_umask==PFM_ERR_UMASK) { 01244 max_umask=-1; /* needed for find_next_umask() to work */ 01245 /* indicates the event as passed had no */ 01246 /* umask in it. */ 01247 } 01248 else { 01249 return _papi_libpfm4_error(max_umask); 01250 } 01251 } 01252 01253 next_umask=find_next_umask(current_event,max_umask, 01254 umask_string); 01255 01256 SUBDBG("Found next %d\n",next_umask); 01257 01258 if (next_umask>=0) { 01259 01260 unsigned int papi_event; 01261 01262 sprintf(new_name,"%s:%s",current_event->base_name, 01263 umask_string); 01264 01265 SUBDBG("Found new name %s\n",new_name); 01266 01267 ret=_pe_libpfm4_ntv_name_to_code(new_name,&papi_event, 01268 event_table); 01269 if (ret!=PAPI_OK) { 01270 return PAPI_ENOEVNT; 01271 } 01272 01273 *PapiEventCode=(unsigned int)papi_event; 01274 SUBDBG("found code %#x\n",*PapiEventCode); 01275 01276 return PAPI_OK; 01277 } 01278 01279 SUBDBG("couldn't find umask\n"); 01280 01281 return _papi_libpfm4_error(next_umask); 01282 01283 } 01284 01285 /* An unknown enumeration method was indicated */ 01286 01287 return PAPI_ENOIMPL; 01288 } 01289 01290 01301 int 01302 _pe_libpfm4_shutdown(struct native_event_table_t *event_table) { 01303 01304 int i; 01305 01306 APIDBG("Entry\n"); 01307 01308 /* clean out and free the native events structure */ 01309 _papi_hwi_lock( NAMELIB_LOCK ); 01310 01311 /* free memory allocate with strdup */ 01312 for( i=0; i<event_table->num_native_events; i++) { 01313 free(event_table->native_events[i].base_name); 01314 free(event_table->native_events[i].pmu_plus_name); 01315 free(event_table->native_events[i].pmu); 01316 free(event_table->native_events[i].allocated_name); 01317 } 01318 01319 memset(event_table->native_events,0, 01320 sizeof(struct native_event_t)*event_table->allocated_native_events); 01321 event_table->num_native_events=0; 01322 event_table->allocated_native_events=0; 01323 free(event_table->native_events); 01324 01325 _papi_hwi_unlock( NAMELIB_LOCK ); 01326 01327 return PAPI_OK; 01328 } 01329 01330 01342 int 01343 _pe_libpfm4_init(papi_vector_t *my_vector, int cidx, 01344 struct native_event_table_t *event_table, 01345 int pmu_type) { 01346 01347 int detected_pmus=0, found_default=0; 01348 int i; 01349 pfm_err_t retval = PFM_SUCCESS; 01350 unsigned int ncnt; 01351 pfm_pmu_info_t pinfo; 01352 01353 /* allocate the native event structure */ 01354 01355 event_table->num_native_events=0; 01356 event_table->pmu_type=pmu_type; 01357 01358 event_table->native_events=calloc(NATIVE_EVENT_CHUNK, 01359 sizeof(struct native_event_t)); 01360 if (event_table->native_events==NULL) { 01361 return PAPI_ENOMEM; 01362 } 01363 event_table->allocated_native_events=NATIVE_EVENT_CHUNK; 01364 01365 /* Count number of present PMUs */ 01366 detected_pmus=0; 01367 ncnt=0; 01368 01369 /* need to init pinfo or pfmlib might complain */ 01370 memset(&(event_table->default_pmu), 0, sizeof(pfm_pmu_info_t)); 01371 /* init default pmu */ 01372 retval=pfm_get_pmu_info(0, &(event_table->default_pmu)); 01373 01374 SUBDBG("Detected pmus:\n"); 01375 for(i=0;i<PFM_PMU_MAX;i++) { 01376 memset(&pinfo,0,sizeof(pfm_pmu_info_t)); 01377 retval=pfm_get_pmu_info(i, &pinfo); 01378 if (retval!=PFM_SUCCESS) { 01379 continue; 01380 } 01381 01382 if (pmu_is_present_and_right_type(&pinfo,pmu_type)) { 01383 SUBDBG("\t%d %s %s %d\n",i,pinfo.name,pinfo.desc,pinfo.type); 01384 01385 detected_pmus++; 01386 ncnt+=pinfo.nevents; 01387 01388 if (pmu_type&PMU_TYPE_CORE) { 01389 01390 /* Hack to have "default" PMU */ 01391 if ( (pinfo.type==PFM_PMU_TYPE_CORE) && 01392 strcmp(pinfo.name,"ix86arch")) { 01393 01394 SUBDBG("\t %s is default\n",pinfo.name); 01395 memcpy(&(event_table->default_pmu), 01396 &pinfo,sizeof(pfm_pmu_info_t)); 01397 found_default++; 01398 } 01399 } 01400 if (pmu_type==PMU_TYPE_UNCORE) { 01401 /* To avoid confusion, no "default" CPU for uncore */ 01402 found_default=1; 01403 } 01404 } 01405 } 01406 SUBDBG("%d native events detected on %d pmus\n",ncnt,detected_pmus); 01407 01408 if (!found_default) { 01409 SUBDBG("Could not find default PMU\n"); 01410 return PAPI_ECMP; 01411 } 01412 01413 if (found_default>1) { 01414 PAPIERROR("Found too many default PMUs!\n"); 01415 return PAPI_ECMP; 01416 } 01417 01418 my_vector->cmp_info.num_native_events = ncnt; 01419 01420 my_vector->cmp_info.num_cntrs = event_table->default_pmu.num_cntrs+ 01421 event_table->default_pmu.num_fixed_cntrs; 01422 01423 SUBDBG( "num_counters: %d\n", my_vector->cmp_info.num_cntrs ); 01424 01425 /* Setup presets, only if Component 0 */ 01426 if (cidx==0) { 01427 retval = _papi_load_preset_table( (char *)event_table->default_pmu.name, 01428 event_table->default_pmu.pmu, cidx ); 01429 if ( retval ) { 01430 return retval; 01431 } 01432 } 01433 01434 return PAPI_OK; 01435 } 01436 01437 01452 int 01453 _pe_libpfm4_setup_counters( struct perf_event_attr *attr, 01454 int event, 01455 struct native_event_table_t *event_table) { 01456 01457 struct native_event_t *our_event; 01458 01459 our_event=find_existing_event_by_number(event,event_table); 01460 if (our_event==NULL) { 01461 return PAPI_ENOEVNT; 01462 } 01463 01464 attr->config=our_event->config; 01465 attr->config1=our_event->config1; 01466 attr->config2=our_event->config2; 01467 attr->type=our_event->type; 01468 01469 SUBDBG( "pe_event: config 0x%"PRIx64 01470 " config1 0x%"PRIx64 01471 " type 0x%"PRIx32"\n", 01472 attr->config, 01473 attr->config1, 01474 attr->type); 01475 01476 01477 return PAPI_OK; 01478 } 01479 01480 01481 01482 01483