PFUNC 1.0
pfunc/perf.hpp
Go to the documentation of this file.
00001 #ifndef PFUNC_PERF_T_HPP
00002 #define PFUNC_PERF_T_HPP
00003 
00004 #if PFUNC_USE_PAPI == 1 
00005 
00006 #include <pfunc/config.h>
00007 #include <papi.h>
00008 #include <pfunc/thread.hpp>
00009 #include <pfunc/environ.hpp>
00010 
00011 namespace pfunc {
00026 struct virtual_perf_data {
00027   typedef long long event_value_type;
00028 
00030   virtual ~virtual_perf_data () {}
00031 
00033   virtual int get_num_events () const = 0;
00034 
00036   virtual int* get_events () const = 0;
00037 
00039   virtual event_value_type** get_event_storage () const = 0;
00040 };
00041 
00042 namespace detail {
00043   struct perf {
00044     static int* event_codes;
00045     static int num_events;
00046 
00047     static bool initialize (const int* _event_codes, const int _num_events) {
00048       num_events = _num_events;
00049       event_codes = new int [num_events];
00050 
00051       /* Step 1: Copy the codes over */
00052       for (int i=0; i<num_events; ++i) event_codes[i] = _event_codes[i];
00053 
00054       /* Step 2: Initialize the library */
00055       int error;
00056       if (!PAPI_is_initialized ()) {
00057         if (PAPI_VER_CURRENT != (error = PAPI_library_init (PAPI_VER_CURRENT))) {
00058           printf ("PAPI_library_init failed: %d\n", error);
00059           return false;
00060         }
00061       }
00062 
00063       /* Step 3: Initialize the threading support */
00064       if (PAPI_OK != (error = PAPI_thread_init (pthread_self))) {
00065         printf ("PAPI_thread_init failed: %d\n", error);
00066          return false;
00067       }
00068 
00069       /* Step 4: Check if we need to multiplex */
00070       bool multiplex = false;
00071       if (num_events > PAPI_num_hwctrs ()) multiplex = true;
00072 
00073       /* Step 5: Check if each of the events is supported */
00074       for (int i=0; i<num_events; ++i)  {
00075         if (PAPI_OK != (error = PAPI_query_event (event_codes[i]))) {
00076           char event_name [1024];
00077           PAPI_event_code_to_name(event_codes[i], event_name);
00078           printf ("PAPI_query_event failed: %d (%s)\n", error, event_name);
00079           return false;
00080         }
00081       }
00082       
00083       /* Step 6: We have reached till here -- so if multiplex was needed, start */
00084       if (multiplex) {
00085         if (PAPI_OK != (error = PAPI_multiplex_init ())) {
00086           printf ("PAPI_multiplex_init failed: %d\n", error);
00087           return false;
00088         }
00089       }
00090 
00091       return true;
00092     }
00093 
00094     static void destroy () { delete [] event_codes; }
00095 
00096     static int create_events () {
00097       ALIGN64 int event_set = PAPI_NULL;
00098 
00099       /* Step 1: Create the event set */
00100       if (PAPI_OK != PAPI_create_eventset (&event_set)) return -1;
00101 
00102       /* Step 2: Check if this event needs to be multiplexed */
00103       if (num_events > PAPI_num_hwctrs ()) 
00104         if (PAPI_OK != PAPI_set_multiplex (event_set)) return -1;
00105 
00106       /* Step 3: Add all the events to this event set */
00107       for (int i=0; i<num_events; ++i) {
00108         char event_name [1024];
00109         PAPI_event_code_to_name(event_codes[i], event_name);
00110         if (PAPI_OK != PAPI_add_event (event_set, event_codes [i])) {
00111           printf ("PAPI could not add %s\n", event_name);
00112           return -1;
00113         } 
00114       }
00115 
00116       return event_set; 
00117     }
00118 
00119     static bool start_events (const int& event_set) {
00120       return (PAPI_OK == PAPI_start (event_set)) ? true : false;
00121     }
00122 
00123     static bool stop_events (const int& event_set, 
00124                              volatile long long int* event_values) {
00125       return (PAPI_OK == PAPI_stop (event_set, (long long*) event_values)) 
00126                                                                     ? true : false;
00127     }
00128 
00129     static int get_num_events (void) { return num_events; }
00130 
00131   }; // struct perf
00132 
00134   int perf::num_events = 0;
00135   int* perf::event_codes = NULL;
00136 
00137 } /* namespace detail */ } /* namespace pfunc */
00138 
00139 #endif /* PFUNC_USE_PAPI */
00140 
00141 #endif // PFUNC_PERF_T_HPP