|
PAPI
5.0.1.0
|
00001 /****************************/ 00002 /* THIS IS OPEN SOURCE CODE */ 00003 /****************************/ 00004 00005 /* 00006 * File: freebsd.c 00007 * Author: Harald Servat 00008 * redcrash@gmail.com 00009 */ 00010 00011 #include <sys/types.h> 00012 #include <sys/resource.h> 00013 #include <sys/sysctl.h> 00014 #include <sys/utsname.h> 00015 00016 #include "papi.h" 00017 00018 #include "papi_internal.h" 00019 00020 #include "papi_lock.h" 00021 #include "freebsd.h" 00022 #include "papi_vector.h" 00023 00024 #include "map.h" 00025 00026 #include "freebsd-memory.h" 00027 #include "x86_cpuid_info.h" 00028 00029 /* Global values referenced externally */ 00030 PAPI_os_info_t _papi_os_info; 00031 00032 /* Advance Declarations */ 00033 papi_vector_t _papi_freebsd_vector; 00034 long long _papi_freebsd_get_real_cycles(void); 00035 int _papi_freebsd_ntv_code_to_name(unsigned int EventCode, char *ntv_name, int len); 00036 00037 00038 /* For debugging */ 00039 00040 static void show_counter(char *string, int id, char *name, 00041 const char *function, char *file, int line) { 00042 00043 #if defined(DEBUG) 00044 pmc_value_t tmp_value; 00045 int ret = pmc_read (id, &tmp_value); 00046 00047 fprintf(stderr,"%s\n",string); 00048 if (ret < 0) { 00049 fprintf (stderr, "DEBUG: Unable to read counter %s (ID: %08x) " 00050 "on routine %s (file: %s, line: %d)\n", 00051 name, id, function,file,line); 00052 } else { 00053 fprintf (stderr, "DEBUG: Read counter %s (ID: %08x) - " 00054 "value %llu on routine %s (file: %s, line: %d)\n", 00055 name, id, (long long unsigned int)tmp_value, 00056 function, file, line); 00057 } 00058 #else 00059 (void) string; (void)name; 00060 (void)id; (void)function; (void)file; (void)line; 00061 #endif 00062 } 00063 00064 00065 static hwd_libpmc_context_t Context; 00066 00067 00068 /* 00069 * This function is an internal function and not exposed and thus 00070 * it can be called anything you want as long as the information 00071 * is setup in _papi_freebsd_init_component. Below is some, but not 00072 * all of the values that will need to be setup. For a complete 00073 * list check out papi_mdi_t, though some of the values are setup 00074 * and used above the component level. 00075 */ 00076 int init_mdi(void) 00077 { 00078 const struct pmc_cpuinfo *info; 00079 00080 SUBDBG("Entering\n"); 00081 00082 /* Initialize PMC library */ 00083 if (pmc_init() < 0) 00084 return PAPI_ESYS; 00085 00086 if (pmc_cpuinfo (&info) != 0) 00087 return PAPI_ESYS; 00088 00089 if (info != NULL) 00090 { 00091 /* Get CPU clock rate from HW.CLOCKRATE sysctl value, and 00092 MODEL from HW.MODEL */ 00093 int mib[5]; 00094 size_t len; 00095 int hw_clockrate; 00096 char hw_model[PAPI_MAX_STR_LEN]; 00097 00098 #if !defined(__i386__) && !defined(__amd64__) 00099 Context.use_rdtsc = FALSE; 00100 #else 00101 /* Ok, I386s/AMD64s can use RDTSC. But be careful, if the cpufreq 00102 module is loaded, then CPU frequency can vary and this method 00103 does not work properly! We'll use use_rdtsc to know if this 00104 method is available */ 00105 len = 5; 00106 Context.use_rdtsc = sysctlnametomib ("dev.cpufreq.0.%driver", mib, &len) == -1; 00107 #endif 00108 00109 len = 3; 00110 if (sysctlnametomib ("hw.clockrate", mib, &len) == -1) 00111 return PAPI_ESYS; 00112 len = sizeof(hw_clockrate); 00113 if (sysctl (mib, 2, &hw_clockrate, &len, NULL, 0) == -1) 00114 return PAPI_ESYS; 00115 00116 len = 3; 00117 if (sysctlnametomib ("hw.model", mib, &len) == -1) 00118 return PAPI_ESYS; 00119 len = PAPI_MAX_STR_LEN; 00120 if (sysctl (mib, 2, &hw_model, &len, NULL, 0) == -1) 00121 return PAPI_ESYS; 00122 00123 /*strcpy (_papi_hwi_system_info.hw_info.vendor_string, pmc_name_of_cputype(info->pm_cputype));*/ 00124 sprintf (_papi_hwi_system_info.hw_info.vendor_string, "%s (TSC:%c)", pmc_name_of_cputype(info->pm_cputype), Context.use_rdtsc?'Y':'N'); 00125 strcpy (_papi_hwi_system_info.hw_info.model_string, hw_model); 00126 _papi_hwi_system_info.hw_info.mhz = (float) hw_clockrate; 00127 _papi_hwi_system_info.hw_info.cpu_max_mhz = hw_clockrate; 00128 _papi_hwi_system_info.hw_info.cpu_min_mhz = hw_clockrate; 00129 _papi_hwi_system_info.hw_info.ncpu = info->pm_ncpu; 00130 _papi_hwi_system_info.hw_info.nnodes = 1; 00131 _papi_hwi_system_info.hw_info.totalcpus = info->pm_ncpu; 00132 /* Right now, PMC states that TSC is an additional counter. However 00133 it's only available as a system-wide counter and this requires 00134 root access */ 00135 _papi_freebsd_vector.cmp_info.num_cntrs = info->pm_npmc - 1; 00136 00137 if ( strstr(pmc_name_of_cputype(info->pm_cputype), "INTEL")) 00138 _papi_hwi_system_info.hw_info.vendor = PAPI_VENDOR_INTEL; 00139 else if ( strstr(pmc_name_of_cputype(info->pm_cputype), "AMD")) 00140 _papi_hwi_system_info.hw_info.vendor = PAPI_VENDOR_AMD; 00141 else 00142 fprintf(stderr,"We didn't actually find a supported vendor...\n\n\n"); 00143 } 00144 else 00145 return PAPI_ESYS; 00146 00147 return 1; 00148 } 00149 00150 00151 int init_presets(int cidx) 00152 { 00153 const struct pmc_cpuinfo *info; 00154 00155 SUBDBG("Entering\n"); 00156 00157 if (pmc_cpuinfo (&info) != 0) 00158 return PAPI_ESYS; 00159 00160 init_freebsd_libpmc_mappings(); 00161 00162 if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_P6") == 0) 00163 Context.CPUtype = CPU_P6; 00164 00165 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_PII") == 0) 00166 Context.CPUtype = CPU_P6_2; 00167 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_PIII") == 0) 00168 Context.CPUtype = CPU_P6_3; 00169 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_CL") == 0) 00170 Context.CPUtype = CPU_P6_C; 00171 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_PM") == 0) 00172 Context.CPUtype = CPU_P6_M; 00173 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "AMD_K7") == 0) 00174 Context.CPUtype = CPU_K7; 00175 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "AMD_K8") == 0) 00176 Context.CPUtype = CPU_K8; 00177 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_PIV") == 0) 00178 Context.CPUtype = CPU_P4; 00179 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_ATOM") == 0) 00180 Context.CPUtype = CPU_ATOM; 00181 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_CORE") == 0) 00182 Context.CPUtype = CPU_CORE; 00183 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_CORE2") == 0) 00184 Context.CPUtype = CPU_CORE2; 00185 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_CORE2EXTREME") == 0) 00186 Context.CPUtype = CPU_CORE2EXTREME; 00187 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_COREI7") == 0) 00188 Context.CPUtype = CPU_COREI7; 00189 else if (strcmp(pmc_name_of_cputype(info->pm_cputype), "INTEL_WESTMERE") == 0) 00190 Context.CPUtype = CPU_COREWESTMERE; 00191 else 00192 /* Unknown processor! */ 00193 Context.CPUtype = CPU_UNKNOWN; 00194 00195 00196 _papi_freebsd_vector.cmp_info.num_native_events = freebsd_number_of_events (Context.CPUtype); 00197 _papi_freebsd_vector.cmp_info.attach = 0; 00198 00199 _papi_load_preset_table((char *)pmc_name_of_cputype(info->pm_cputype), 00200 0,cidx); 00201 00202 return 0; 00203 } 00204 00205 /* 00206 * Component setup and shutdown 00207 */ 00208 00209 /* Initialize hardware counters, setup the function vector table 00210 * and get hardware information, this routine is called when the 00211 * PAPI process is initialized (IE PAPI_library_init) 00212 */ 00213 int _papi_freebsd_init_component(int cidx) 00214 { 00215 (void)cidx; 00216 00217 int retval; 00218 00219 SUBDBG("Entering\n"); 00220 00221 /* Internal function, doesn't necessarily need to be a function */ 00222 retval=init_presets(cidx); 00223 00224 return retval; 00225 } 00226 00227 00228 00229 00230 /* 00231 * This is called whenever a thread is initialized 00232 */ 00233 int _papi_freebsd_init_thread(hwd_context_t *ctx) 00234 { 00235 (void)ctx; 00236 SUBDBG("Entering\n"); 00237 return PAPI_OK; 00238 } 00239 00240 int _papi_freebsd_shutdown_thread(hwd_context_t *ctx) 00241 { 00242 (void)ctx; 00243 SUBDBG("Entering\n"); 00244 return PAPI_OK; 00245 } 00246 00247 int _papi_freebsd_shutdown_component(void) 00248 { 00249 SUBDBG("Entering\n"); 00250 return PAPI_OK; 00251 } 00252 00253 00254 /* 00255 * Control of counters (Reading/Writing/Starting/Stopping/Setup) 00256 * functions 00257 */ 00258 int _papi_freebsd_init_control_state(hwd_control_state_t *ptr) 00259 { 00260 /* We will default to gather counters in USER|KERNEL mode */ 00261 SUBDBG("Entering\n"); 00262 ptr->hwc_domain = PAPI_DOM_USER|PAPI_DOM_KERNEL; 00263 ptr->pmcs = NULL; 00264 ptr->counters = NULL; 00265 ptr->n_counters = 0; 00266 return PAPI_OK; 00267 } 00268 00269 int _papi_freebsd_update_control_state(hwd_control_state_t *ptr, NativeInfo_t *native, int count, hwd_context_t *ctx) 00270 { 00271 char name[1024]; 00272 int i; 00273 int res; 00274 (void)ctx; 00275 00276 SUBDBG("Entering\n"); 00277 00278 /* We're going to store which counters are being used in this EventSet. 00279 As this ptr structure can be reused within many PAPI_add_event calls, 00280 and domain can change we will reconstruct the table of counters 00281 (ptr->counters) everytime where here. 00282 */ 00283 if (ptr->counters != NULL && ptr->n_counters > 0) 00284 { 00285 for (i = 0; i < ptr->n_counters; i++) 00286 if (ptr->counters[i] != NULL) 00287 free (ptr->counters[i]); 00288 free (ptr->counters); 00289 } 00290 if (ptr->pmcs != NULL) 00291 free (ptr->pmcs); 00292 if (ptr->values != NULL) 00293 free (ptr->values); 00294 if (ptr->caps != NULL) 00295 free (ptr->caps); 00296 00297 ptr->n_counters = count; 00298 ptr->pmcs = (pmc_id_t*) malloc (sizeof(pmc_id_t)*count); 00299 ptr->caps = (uint32_t*) malloc (sizeof(uint32_t)*count); 00300 ptr->values = (pmc_value_t*) malloc (sizeof(pmc_value_t)*count); 00301 ptr->counters = (char **) malloc (sizeof(char*)*count); 00302 for (i = 0; i < count; i++) 00303 ptr->counters[i] = NULL; 00304 00305 for (i = 0; i < count; i++) 00306 { 00307 res = _papi_freebsd_ntv_code_to_name (native[i].ni_event, name, sizeof(name)); 00308 if (res != PAPI_OK) 00309 return res; 00310 00311 native[i].ni_position = i; 00312 00313 /* Domains can be applied to canonical events in libpmc (not "generic") */ 00314 if (Context.CPUtype != CPU_UNKNOWN) 00315 { 00316 if (ptr->hwc_domain == (PAPI_DOM_USER|PAPI_DOM_KERNEL)) 00317 { 00318 /* PMC defaults domain to OS & User. So simply copy the name of the counter */ 00319 ptr->counters[i] = strdup (name); 00320 if (ptr->counters[i] == NULL) 00321 return PAPI_ESYS; 00322 } 00323 else if (ptr->hwc_domain == PAPI_DOM_USER) 00324 { 00325 /* This is user-domain case. Just add unitmask=usr */ 00326 ptr->counters[i] = malloc ((strlen(name)+strlen(",usr")+1)*sizeof(char)); 00327 if (ptr->counters[i] == NULL) 00328 return PAPI_ESYS; 00329 sprintf (ptr->counters[i], "%s,usr", name); 00330 } 00331 else /* if (ptr->hwc_domain == PAPI_DOM_KERNEL) */ 00332 { 00333 /* This is the last case. Just add unitmask=os */ 00334 ptr->counters[i] = malloc ((strlen(name)+strlen(",os")+1)*sizeof(char)); 00335 if (ptr->counters[i] == NULL) 00336 return PAPI_ESYS; 00337 sprintf (ptr->counters[i], "%s,os", name); 00338 } 00339 } 00340 else 00341 { 00342 /* PMC defaults domain to OS & User. So simply copy the name of the counter */ 00343 ptr->counters[i] = strdup (name); 00344 if (ptr->counters[i] == NULL) 00345 return PAPI_ESYS; 00346 } 00347 } 00348 00349 return PAPI_OK; 00350 } 00351 00352 int _papi_freebsd_start(hwd_context_t *ctx, hwd_control_state_t *ctrl) 00353 { 00354 int i, ret; 00355 (void)ctx; 00356 00357 SUBDBG("Entering\n"); 00358 00359 for (i = 0; i < ctrl->n_counters; i++) 00360 { 00361 if ((ret = pmc_allocate (ctrl->counters[i], PMC_MODE_TC, 0, PMC_CPU_ANY, &(ctrl->pmcs[i]))) < 0) 00362 { 00363 #if defined(DEBUG) 00364 /* This shouldn't happen, it's tested previously on _papi_freebsd_allocate_registers */ 00365 fprintf (stderr, "DEBUG: %s FAILED to allocate '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00366 #endif 00367 return PAPI_ESYS; 00368 } 00369 if ((ret = pmc_capabilities (ctrl->pmcs[i],&(ctrl->caps[i]))) < 0) 00370 { 00371 #if defined(DEBUG) 00372 fprintf (stderr, "DEBUG: %s FAILED to get capabilites for '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00373 #endif 00374 ctrl->caps[i] = 0; 00375 } 00376 #if defined(DEBUG) 00377 fprintf (stderr, "DEBUG: %s got counter '%s' is %swrittable! [%d of %d]\n", FUNC, ctrl->counters[i], (ctrl->caps[i]&PMC_CAP_WRITE)?"":"NOT", i+1, ctrl->n_counters); 00378 #endif 00379 if ((ret = pmc_start (ctrl->pmcs[i])) < 0) 00380 { 00381 #if defined(DEBUG) 00382 fprintf (stderr, "DEBUG: %s FAILED to start '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00383 #endif 00384 return PAPI_ESYS; 00385 } 00386 } 00387 return PAPI_OK; 00388 } 00389 00390 int _papi_freebsd_read(hwd_context_t *ctx, hwd_control_state_t *ctrl, long long **events, int flags) 00391 { 00392 int i, ret; 00393 (void)ctx; 00394 (void)flags; 00395 00396 SUBDBG("Entering\n"); 00397 00398 for (i = 0; i < ctrl->n_counters; i++) 00399 if ((ret = pmc_read (ctrl->pmcs[i], &(ctrl->values[i]))) < 0) 00400 { 00401 #if defined(DEBUG) 00402 fprintf (stderr, "DEBUG: %s FAILED to read '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00403 #endif 00404 return PAPI_ESYS; 00405 } 00406 *events = (long long *)ctrl->values; 00407 00408 #if defined(DEBUG) 00409 for (i = 0; i < ctrl->n_counters; i++) 00410 fprintf (stderr, "DEBUG: %s counter '%s' has value %lld\n", 00411 FUNC, ctrl->counters[i], (long long)ctrl->values[i]); 00412 #endif 00413 return PAPI_OK; 00414 } 00415 00416 int _papi_freebsd_stop(hwd_context_t *ctx, hwd_control_state_t *ctrl) 00417 { 00418 int i, ret; 00419 (void)ctx; 00420 00421 SUBDBG("Entering\n"); 00422 00423 for (i = 0; i < ctrl->n_counters; i++) 00424 { 00425 if ((ret = pmc_stop (ctrl->pmcs[i])) < 0) 00426 { 00427 #if defined(DEBUG) 00428 fprintf (stderr, "DEBUG: %s FAILED to stop '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00429 #endif 00430 return PAPI_ESYS; 00431 } 00432 if ((ret = pmc_release (ctrl->pmcs[i])) < 0) 00433 { 00434 #if defined(DEBUG) 00435 /* This shouldn't happen, it's tested previously on _papi_freebsd_allocate_registers */ 00436 fprintf (stderr, "DEBUG: %s FAILED to release '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00437 #endif 00438 return PAPI_ESYS; 00439 } 00440 } 00441 return PAPI_OK; 00442 } 00443 00444 int _papi_freebsd_reset(hwd_context_t *ctx, hwd_control_state_t *ctrl) 00445 { 00446 int i, ret; 00447 (void)ctx; 00448 00449 SUBDBG("Entering\n"); 00450 00451 for (i = 0; i < ctrl->n_counters; i++) 00452 { 00453 /* Can we write on the counters? */ 00454 if (ctrl->caps[i] & PMC_CAP_WRITE) 00455 { 00456 show_counter("DEBUG: _papi_freebsd_reset is about " 00457 "to stop the counter i+1", 00458 ctrl->pmcs[i],ctrl->counters[i], 00459 __FUNCTION__,__FILE__,__LINE__); 00460 00461 if ((ret = pmc_stop (ctrl->pmcs[i])) < 0) 00462 { 00463 #if defined(DEBUG) 00464 fprintf (stderr, "DEBUG: %s FAILED to stop '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00465 #endif 00466 return PAPI_ESYS; 00467 } 00468 00469 show_counter( 00470 "DEBUG: _papi_freebsd_reset is about " 00471 "to write the counter i+1\n", 00472 ctrl->pmcs[i],ctrl->counters[i], 00473 __FUNCTION__,__FILE__,__LINE__); 00474 00475 if ((ret = pmc_write (ctrl->pmcs[i], 0)) < 0) 00476 { 00477 #if defined(DEBUG) 00478 fprintf (stderr, "DEBUG: %s FAILED to write '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00479 #endif 00480 return PAPI_ESYS; 00481 } 00482 00483 show_counter("DEBUG: _papi_freebsd_reset is about to " 00484 "start the counter %i+1", 00485 ctrl->pmcs[i],ctrl->counters[i], 00486 __FUNCTION__,__FILE__,__LINE__); 00487 00488 if ((ret = pmc_start (ctrl->pmcs[i])) < 0) 00489 { 00490 #if defined(DEBUG) 00491 fprintf (stderr, "DEBUG: %s FAILED to start '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00492 #endif 00493 return PAPI_ESYS; 00494 } 00495 00496 show_counter("DEBUG: _papi_freebsd_reset after " 00497 "starting the counter i+1", 00498 ctrl->pmcs[i],ctrl->counters[i], 00499 __FUNCTION__,__FILE__,__LINE__); 00500 00501 } 00502 else 00503 return PAPI_ECMP; 00504 } 00505 return PAPI_OK; 00506 } 00507 00508 int _papi_freebsd_write(hwd_context_t *ctx, hwd_control_state_t *ctrl, long long *from) 00509 { 00510 int i, ret; 00511 (void)ctx; 00512 00513 SUBDBG("Entering\n"); 00514 00515 for (i = 0; i < ctrl->n_counters; i++) 00516 { 00517 /* Can we write on the counters? */ 00518 if (ctrl->caps[i] & PMC_CAP_WRITE) 00519 { 00520 if ((ret = pmc_stop (ctrl->pmcs[i])) < 0) 00521 { 00522 #if defined(DEBUG) 00523 fprintf (stderr, "DEBUG: %s FAILED to stop '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00524 #endif 00525 return PAPI_ESYS; 00526 } 00527 if ((ret = pmc_write (ctrl->pmcs[i], from[i])) < 0) 00528 { 00529 #if defined(DEBUG) 00530 fprintf (stderr, "DEBUG: %s FAILED to write '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00531 #endif 00532 return PAPI_ESYS; 00533 } 00534 if ((ret = pmc_start (ctrl->pmcs[i])) < 0) 00535 { 00536 #if defined(DEBUG) 00537 fprintf (stderr, "DEBUG: %s FAILED to stop '%s' [%d of %d] ERROR = %d\n", FUNC, ctrl->counters[i], i+1, ctrl->n_counters, ret); 00538 #endif 00539 return PAPI_ESYS; 00540 } 00541 } 00542 else 00543 return PAPI_ECMP; 00544 } 00545 return PAPI_OK; 00546 } 00547 00548 /* 00549 * Overflow and profile functions 00550 */ 00551 void _papi_freebsd_dispatch_timer(int signal, hwd_siginfo_t * info, void *context) 00552 { 00553 (void)signal; 00554 (void)info; 00555 (void)context; 00556 /* Real function would call the function below with the proper args 00557 * _papi_hwi_dispatch_overflow_signal(...); 00558 */ 00559 SUBDBG("Entering\n"); 00560 return; 00561 } 00562 00563 int _papi_freebsd_stop_profiling(ThreadInfo_t *master, EventSetInfo_t *ESI) 00564 { 00565 (void)master; 00566 (void)ESI; 00567 SUBDBG("Entering\n"); 00568 return PAPI_OK; 00569 } 00570 00571 int _papi_freebsd_set_overflow(EventSetInfo_t *ESI, int EventIndex, int threshold) 00572 { 00573 (void)ESI; 00574 (void)EventIndex; 00575 (void)threshold; 00576 SUBDBG("Entering\n"); 00577 return PAPI_OK; 00578 } 00579 00580 int _papi_freebsd_set_profile(EventSetInfo_t *ESI, int EventIndex, int threashold) 00581 { 00582 (void)ESI; 00583 (void)EventIndex; 00584 (void)threashold; 00585 SUBDBG("Entering\n"); 00586 return PAPI_OK; 00587 } 00588 00589 /* 00590 * Functions for setting up various options 00591 */ 00592 00593 /* 00594 * This function has to set the bits needed to count different domains 00595 * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER 00596 * By default return PAPI_EINVAL if none of those are specified 00597 * and PAPI_OK with success 00598 * PAPI_DOM_USER is only user context is counted 00599 * PAPI_DOM_KERNEL is only the Kernel/OS context is counted 00600 * PAPI_DOM_OTHER is Exception/transient mode (like user TLB misses) 00601 * PAPI_DOM_ALL is all of the domains 00602 */ 00603 int _papi_freebsd_set_domain(hwd_control_state_t *cntrl, int domain) 00604 { 00605 int found = 0; 00606 00607 SUBDBG("Entering\n"); 00608 /* libpmc supports USER/KERNEL mode only when counters are native */ 00609 if (Context.CPUtype != CPU_UNKNOWN) 00610 { 00611 if (domain & (PAPI_DOM_USER|PAPI_DOM_KERNEL)) 00612 { 00613 cntrl->hwc_domain = domain & (PAPI_DOM_USER|PAPI_DOM_KERNEL); 00614 found = 1; 00615 } 00616 return found?PAPI_OK:PAPI_EINVAL; 00617 } 00618 else 00619 return PAPI_ECMP; 00620 } 00621 00622 00623 /* This function sets various options in the component 00624 * The valid codes being passed in are PAPI_SET_DEFDOM, 00625 * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT 00626 */ 00627 int _papi_freebsd_ctl (hwd_context_t *ctx, int code, _papi_int_option_t *option) 00628 { 00629 (void)ctx; 00630 SUBDBG("Entering\n"); 00631 switch (code) 00632 { 00633 case PAPI_DOMAIN: 00634 case PAPI_DEFDOM: 00635 /*return _papi_freebsd_set_domain(&option->domain.ESI->machdep, option->domain.domain);*/ 00636 return _papi_freebsd_set_domain(option->domain.ESI->ctl_state, option->domain.domain); 00637 case PAPI_GRANUL: 00638 case PAPI_DEFGRN: 00639 return PAPI_ECMP; 00640 default: 00641 return PAPI_EINVAL; 00642 } 00643 } 00644 00645 00646 /* 00647 * Timing Routines 00648 * These functions should return the highest resolution timers available. 00649 */ 00650 long long _papi_freebsd_get_real_usec(void) 00651 { 00652 /* Hey, I've seen somewhere a define called __x86_64__! Should I support it? */ 00653 #if !defined(__i386__) && !defined(__amd64__) 00654 /* This will surely work, but with low precision and high overhead */ 00655 struct rusage res; 00656 00657 SUBDBG("Entering\n"); 00658 if ((getrusage(RUSAGE_SELF, &res) == -1)) 00659 return PAPI_ESYS; 00660 return (res.ru_utime.tv_sec * 1000000) + res.ru_utime.tv_usec; 00661 #else 00662 SUBDBG("Entering\n"); 00663 if (Context.use_rdtsc) 00664 { 00665 return _papi_freebsd_get_real_cycles() / _papi_hwi_system_info.hw_info.cpu_max_mhz; 00666 } 00667 else 00668 { 00669 struct rusage res; 00670 if ((getrusage(RUSAGE_SELF, &res) == -1)) 00671 return PAPI_ESYS; 00672 return (res.ru_utime.tv_sec * 1000000) + res.ru_utime.tv_usec; 00673 } 00674 #endif 00675 } 00676 00677 00678 long long _papi_freebsd_get_real_cycles(void) 00679 { 00680 /* Hey, I've seen somewhere a define called __x86_64__! Should I support it? */ 00681 #if !defined(__i386__) && !defined(__amd64__) 00682 SUBDBG("Entering\n"); 00683 /* This will surely work, but with low precision and high overhead */ 00684 return ((long long) _papi_freebsd_get_real_usec() * _papi_hwi_system_info.hw_info.cpu_max_mhz); 00685 #else 00686 SUBDBG("Entering\n"); 00687 if (Context.use_rdtsc) 00688 { 00689 long long cycles; 00690 __asm __volatile(".byte 0x0f, 0x31" : "=A" (cycles)); 00691 return cycles; 00692 } 00693 else 00694 { 00695 return ((long long) _papi_freebsd_get_real_usec() * _papi_hwi_system_info.hw_info.cpu_max_mhz); 00696 } 00697 #endif 00698 } 00699 00700 00701 00702 long long _papi_freebsd_get_virt_usec(void) 00703 { 00704 struct rusage res; 00705 00706 SUBDBG("Entering\n"); 00707 00708 if ((getrusage(RUSAGE_SELF, &res) == -1)) 00709 return PAPI_ESYS; 00710 return (res.ru_utime.tv_sec * 1000000) + res.ru_utime.tv_usec; 00711 } 00712 00713 /* 00714 * Native Event functions 00715 */ 00716 00717 00718 int _papi_freebsd_ntv_enum_events(unsigned int *EventCode, int modifier) 00719 { 00720 int res; 00721 char name[1024]; 00722 unsigned int nextCode = 1 + *EventCode; 00723 00724 SUBDBG("Entering\n"); 00725 00726 if (modifier==PAPI_ENUM_FIRST) { 00727 00728 *EventCode=0; 00729 00730 return PAPI_OK; 00731 } 00732 00733 if (modifier==PAPI_ENUM_EVENTS) { 00734 00735 res = _papi_freebsd_ntv_code_to_name(nextCode, name, sizeof(name)); 00736 if (res != PAPI_OK) { 00737 return res; 00738 } else { 00739 *EventCode = nextCode; 00740 } 00741 return PAPI_OK; 00742 } 00743 00744 return PAPI_ENOEVNT; 00745 00746 } 00747 00748 int _papi_freebsd_ntv_name_to_code(char *name, unsigned int *event_code) { 00749 00750 SUBDBG("Entering\n"); 00751 00752 int i; 00753 00754 for(i = 0; i < _papi_freebsd_vector.cmp_info.num_native_events; i++) { 00755 if (strcmp (name, _papi_hwd_native_info[Context.CPUtype].info[i].name) == 0) { 00756 *event_code = i; 00757 return PAPI_OK; 00758 } 00759 } 00760 return PAPI_ENOEVNT; 00761 } 00762 00763 int _papi_freebsd_ntv_code_to_name(unsigned int EventCode, char *ntv_name, 00764 int len) 00765 { 00766 SUBDBG("Entering\n"); 00767 00768 int nidx; 00769 00770 nidx = EventCode & PAPI_NATIVE_AND_MASK; 00771 00772 if (nidx >= _papi_freebsd_vector.cmp_info.num_native_events) { 00773 return PAPI_ENOEVNT; 00774 } 00775 00776 strncpy (ntv_name, 00777 _papi_hwd_native_info[Context.CPUtype].info[nidx].name, len); 00778 if (strlen(_papi_hwd_native_info[Context.CPUtype].info[nidx].name) > (size_t)len-1) { 00779 return PAPI_EBUF; 00780 } 00781 return PAPI_OK; 00782 } 00783 00784 int _papi_freebsd_ntv_code_to_descr(unsigned int EventCode, char *descr, int len) 00785 { 00786 SUBDBG("Entering\n"); 00787 int nidx; 00788 00789 nidx = EventCode & PAPI_NATIVE_AND_MASK; 00790 if (nidx >= _papi_freebsd_vector.cmp_info.num_native_events) { 00791 return PAPI_ENOEVNT; 00792 } 00793 00794 strncpy (descr, _papi_hwd_native_info[Context.CPUtype].info[nidx].description, len); 00795 if (strlen(_papi_hwd_native_info[Context.CPUtype].info[nidx].description) > (size_t)len-1) { 00796 return PAPI_EBUF; 00797 } 00798 return PAPI_OK; 00799 } 00800 00801 00802 /* 00803 * Counter Allocation Functions, only need to implement if 00804 * the component needs smart counter allocation. 00805 */ 00806 00807 /* Here we'll check if PMC can provide all the counters the user want */ 00808 int _papi_freebsd_allocate_registers (EventSetInfo_t *ESI) 00809 { 00810 char name[1024]; 00811 int failed, allocated_counters, i, j, ret; 00812 pmc_id_t *pmcs; 00813 00814 SUBDBG("Entering\n"); 00815 00816 failed = 0; 00817 pmcs = (pmc_id_t*) malloc(sizeof(pmc_id_t)*ESI->NativeCount); 00818 if (pmcs != NULL) 00819 { 00820 allocated_counters = 0; 00821 /* Check if we can allocate all the counters needed */ 00822 for (i = 0; i < ESI->NativeCount; i++) 00823 { 00824 ret = _papi_freebsd_ntv_code_to_name (ESI->NativeInfoArray[i].ni_event, name, sizeof(name)); 00825 if (ret != PAPI_OK) 00826 return ret; 00827 if ( (ret = pmc_allocate (name, PMC_MODE_TC, 0, PMC_CPU_ANY, &pmcs[i])) < 0) 00828 { 00829 #if defined(DEBUG) 00830 fprintf (stderr, "DEBUG: %s FAILED to allocate '%s' (0x%08x) [%d of %d] ERROR = %d\n", FUNC, name, ESI->NativeInfoArray[i].ni_event, i+1, ESI->NativeCount, ret); 00831 #endif 00832 failed = 1; 00833 break; 00834 } 00835 else 00836 { 00837 #if defined(DEBUG) 00838 fprintf (stderr, "DEBUG: %s SUCCEEDED allocating '%s' (0x%08x) [%d of %d]\n", FUNC, name, ESI->NativeInfoArray[i].ni_event, i+1, ESI->NativeCount); 00839 #endif 00840 allocated_counters++; 00841 } 00842 } 00843 /* Free the counters */ 00844 for (j = 0; j < allocated_counters; j++) 00845 pmc_release (pmcs[j]); 00846 free (pmcs); 00847 } 00848 else 00849 failed = 1; 00850 00851 return failed?PAPI_ECNFLCT:PAPI_OK; 00852 } 00853 00854 /* 00855 * Shared Library Information and other Information Functions 00856 */ 00857 int _papi_freebsd_update_shlib_info(papi_mdi_t *mdi){ 00858 SUBDBG("Entering\n"); 00859 (void)mdi; 00860 return PAPI_OK; 00861 } 00862 00863 00864 00865 int 00866 _papi_freebsd_detect_hypervisor(char *virtual_vendor_name) { 00867 00868 int retval=0; 00869 00870 #if defined(__i386__)||defined(__x86_64__) 00871 retval=_x86_detect_hypervisor(virtual_vendor_name); 00872 #else 00873 (void) virtual_vendor_name; 00874 #endif 00875 00876 return retval; 00877 } 00878 00879 00880 00881 int 00882 _papi_freebsd_get_system_info( papi_mdi_t *mdi ) { 00883 00884 int retval; 00885 00886 retval=_freebsd_get_memory_info(&mdi->hw_info, mdi->hw_info.model ); 00887 00888 /* Get virtualization info */ 00889 mdi->hw_info.virtualized=_papi_freebsd_detect_hypervisor(mdi->hw_info.virtual_vendor_string); 00890 00891 00892 return PAPI_OK; 00893 00894 } 00895 00896 int 00897 _papi_hwi_init_os(void) { 00898 00899 struct utsname uname_buffer; 00900 00901 /* Internal function, doesn't necessarily need to be a function */ 00902 init_mdi(); 00903 00904 uname(&uname_buffer); 00905 00906 strncpy(_papi_os_info.name,uname_buffer.sysname,PAPI_MAX_STR_LEN); 00907 00908 strncpy(_papi_os_info.version,uname_buffer.release,PAPI_MAX_STR_LEN); 00909 00910 _papi_os_info.itimer_sig = PAPI_INT_MPX_SIGNAL; 00911 _papi_os_info.itimer_num = PAPI_INT_ITIMER; 00912 _papi_os_info.itimer_ns = PAPI_INT_MPX_DEF_US * 1000; /* Not actually supported */ 00913 _papi_os_info.itimer_res_ns = 1; 00914 00915 _papi_freebsd_get_system_info(&_papi_hwi_system_info); 00916 00917 return PAPI_OK; 00918 } 00919 00920 papi_vector_t _papi_freebsd_vector = { 00921 .cmp_info = { 00922 /* default component information (unspecified values are initialized to 0) */ 00923 .name = "FreeBSD", 00924 .description = "FreeBSD CPU counters", 00925 .default_domain = PAPI_DOM_USER, 00926 .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL, 00927 .default_granularity = PAPI_GRN_THR, 00928 .available_granularities = PAPI_GRN_THR, 00929 00930 .hardware_intr = 1, 00931 .kernel_multiplex = 1, 00932 .kernel_profile = 1, 00933 .num_mpx_cntrs = HWPMC_NUM_COUNTERS, /* ?? */ 00934 .hardware_intr_sig = PAPI_INT_SIGNAL, 00935 00936 /* component specific cmp_info initializations */ 00937 .fast_real_timer = 1, 00938 .fast_virtual_timer = 0, 00939 .attach = 0, 00940 .attach_must_ptrace = 0, 00941 } , 00942 .size = { 00943 .context = sizeof( hwd_context_t ), 00944 .control_state = sizeof( hwd_control_state_t ), 00945 .reg_value = sizeof( hwd_register_t ), 00946 .reg_alloc = sizeof( hwd_reg_alloc_t ) 00947 }, 00948 00949 .dispatch_timer = _papi_freebsd_dispatch_timer, 00950 .start = _papi_freebsd_start, 00951 .stop = _papi_freebsd_stop, 00952 .read = _papi_freebsd_read, 00953 .reset = _papi_freebsd_reset, 00954 .write = _papi_freebsd_write, 00955 .stop_profiling = _papi_freebsd_stop_profiling, 00956 .init_component = _papi_freebsd_init_component, 00957 .init_thread = _papi_freebsd_init_thread, 00958 .init_control_state = _papi_freebsd_init_control_state, 00959 .update_control_state = _papi_freebsd_update_control_state, 00960 .ctl = _papi_freebsd_ctl, 00961 .set_overflow = _papi_freebsd_set_overflow, 00962 .set_profile = _papi_freebsd_set_profile, 00963 .set_domain = _papi_freebsd_set_domain, 00964 00965 .ntv_enum_events = _papi_freebsd_ntv_enum_events, 00966 .ntv_name_to_code = _papi_freebsd_ntv_name_to_code, 00967 .ntv_code_to_name = _papi_freebsd_ntv_code_to_name, 00968 .ntv_code_to_descr = _papi_freebsd_ntv_code_to_descr, 00969 00970 .allocate_registers = _papi_freebsd_allocate_registers, 00971 00972 .shutdown_thread = _papi_freebsd_shutdown_thread, 00973 .shutdown_component = _papi_freebsd_shutdown_component, 00974 }; 00975 00976 papi_os_vector_t _papi_os_vector = { 00977 .get_dmem_info = _papi_freebsd_get_dmem_info, 00978 .get_real_cycles = _papi_freebsd_get_real_cycles, 00979 .get_real_usec = _papi_freebsd_get_real_usec, 00980 .get_virt_usec = _papi_freebsd_get_virt_usec, 00981 .update_shlib_info = _papi_freebsd_update_shlib_info, 00982 .get_system_info = _papi_freebsd_get_system_info, 00983 };