PAPI  5.0.1.0
freebsd.c
Go to the documentation of this file.
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 };
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines