1*a0c7f9aaSSamuel Khuvis // Copyright (c) 2019 University of Oregon 2*a0c7f9aaSSamuel Khuvis // Distributed under the BSD Software License 3*a0c7f9aaSSamuel Khuvis // (See accompanying file LICENSE.txt) 4*a0c7f9aaSSamuel Khuvis 5*a0c7f9aaSSamuel Khuvis #pragma once 6*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_USE_TIMERS 7*a0c7f9aaSSamuel Khuvis 8*a0c7f9aaSSamuel Khuvis #include <stdint.h> 9*a0c7f9aaSSamuel Khuvis #include <stdlib.h> 10*a0c7f9aaSSamuel Khuvis #include <string.h> 11*a0c7f9aaSSamuel Khuvis #include <stdio.h> 12*a0c7f9aaSSamuel Khuvis #include "config.h" 13*a0c7f9aaSSamuel Khuvis #include "tool.h" 14*a0c7f9aaSSamuel Khuvis 15*a0c7f9aaSSamuel Khuvis /* These macros help generate unique variable names within a function 16*a0c7f9aaSSamuel Khuvis * based on the source code line number */ 17*a0c7f9aaSSamuel Khuvis #define CONCAT_(x,y) x##y 18*a0c7f9aaSSamuel Khuvis #define CONCAT(x,y) CONCAT_(x,y) 19*a0c7f9aaSSamuel Khuvis 20*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */ 21*a0c7f9aaSSamuel Khuvis /* Define the C API and PerfStubs glue class first */ 22*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */ 23*a0c7f9aaSSamuel Khuvis 24*a0c7f9aaSSamuel Khuvis /* Pretty functions will include the return type and argument types, 25*a0c7f9aaSSamuel Khuvis * not just the function name. If the compiler doesn't support it, 26*a0c7f9aaSSamuel Khuvis * just use the function name. */ 27*a0c7f9aaSSamuel Khuvis 28*a0c7f9aaSSamuel Khuvis #if defined(__GNUC__) 29*a0c7f9aaSSamuel Khuvis #define __PERFSTUBS_FUNCTION__ __PRETTY_FUNCTION__ 30*a0c7f9aaSSamuel Khuvis #else 31*a0c7f9aaSSamuel Khuvis #define __PERFSTUBS_FUNCTION__ __func__ 32*a0c7f9aaSSamuel Khuvis #endif 33*a0c7f9aaSSamuel Khuvis 34*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_UNKNOWN 0 35*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SUCCESS 1 36*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FAILURE 2 37*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FINALIZED 3 38*a0c7f9aaSSamuel Khuvis 39*a0c7f9aaSSamuel Khuvis extern int perfstubs_initialized; 40*a0c7f9aaSSamuel Khuvis 41*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */ 42*a0c7f9aaSSamuel Khuvis /* Now define the C API */ 43*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */ 44*a0c7f9aaSSamuel Khuvis 45*a0c7f9aaSSamuel Khuvis #if defined(PERFSTUBS_USE_TIMERS) 46*a0c7f9aaSSamuel Khuvis 47*a0c7f9aaSSamuel Khuvis /* regular C API */ 48*a0c7f9aaSSamuel Khuvis 49*a0c7f9aaSSamuel Khuvis #ifdef __cplusplus 50*a0c7f9aaSSamuel Khuvis extern "C" { 51*a0c7f9aaSSamuel Khuvis #endif 52*a0c7f9aaSSamuel Khuvis 53*a0c7f9aaSSamuel Khuvis void ps_initialize_(void); 54*a0c7f9aaSSamuel Khuvis void ps_finalize_(void); 55*a0c7f9aaSSamuel Khuvis void ps_register_thread_(void); 56*a0c7f9aaSSamuel Khuvis void ps_dump_data_(void); 57*a0c7f9aaSSamuel Khuvis void* ps_timer_create_(const char *timer_name); 58*a0c7f9aaSSamuel Khuvis void ps_timer_create_fortran_(void ** object, const char *timer_name); 59*a0c7f9aaSSamuel Khuvis void ps_timer_start_(const void *timer); 60*a0c7f9aaSSamuel Khuvis void ps_timer_start_fortran_(const void **timer); 61*a0c7f9aaSSamuel Khuvis void ps_timer_stop_(const void *timer); 62*a0c7f9aaSSamuel Khuvis void ps_timer_stop_fortran_(const void **timer); 63*a0c7f9aaSSamuel Khuvis void ps_set_parameter_(const char *parameter_name, int64_t parameter_value); 64*a0c7f9aaSSamuel Khuvis void ps_dynamic_phase_start_(const char *phasePrefix, int iterationIndex); 65*a0c7f9aaSSamuel Khuvis void ps_dynamic_phase_stop_(const char *phasePrefix, int iterationIndex); 66*a0c7f9aaSSamuel Khuvis void* ps_create_counter_(const char *name); 67*a0c7f9aaSSamuel Khuvis void ps_create_counter_fortran_(void ** object, const char *name); 68*a0c7f9aaSSamuel Khuvis void ps_sample_counter_(const void *counter, const double value); 69*a0c7f9aaSSamuel Khuvis void ps_sample_counter_fortran_(const void **counter, const double value); 70*a0c7f9aaSSamuel Khuvis void ps_set_metadata_(const char *name, const char *value); 71*a0c7f9aaSSamuel Khuvis 72*a0c7f9aaSSamuel Khuvis /* data query API */ 73*a0c7f9aaSSamuel Khuvis 74*a0c7f9aaSSamuel Khuvis void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id); 75*a0c7f9aaSSamuel Khuvis void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id); 76*a0c7f9aaSSamuel Khuvis void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id); 77*a0c7f9aaSSamuel Khuvis void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id); 78*a0c7f9aaSSamuel Khuvis void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id); 79*a0c7f9aaSSamuel Khuvis void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id); 80*a0c7f9aaSSamuel Khuvis 81*a0c7f9aaSSamuel Khuvis char* ps_make_timer_name_(const char * file, const char * func, int line); 82*a0c7f9aaSSamuel Khuvis 83*a0c7f9aaSSamuel Khuvis #ifdef __cplusplus 84*a0c7f9aaSSamuel Khuvis } 85*a0c7f9aaSSamuel Khuvis #endif 86*a0c7f9aaSSamuel Khuvis 87*a0c7f9aaSSamuel Khuvis /* Macro API for option of entirely disabling at compile time 88*a0c7f9aaSSamuel Khuvis * To use this API, set the Macro PERFSTUBS_USE_TIMERS on the command 89*a0c7f9aaSSamuel Khuvis * line or in a config.h file, however your project does it 90*a0c7f9aaSSamuel Khuvis */ 91*a0c7f9aaSSamuel Khuvis 92*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INITIALIZE() ps_initialize_(); 93*a0c7f9aaSSamuel Khuvis 94*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FINALIZE() ps_finalize_(); 95*a0c7f9aaSSamuel Khuvis 96*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_REGISTER_THREAD() ps_register_thread_(); 97*a0c7f9aaSSamuel Khuvis 98*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DUMP_DATA() ps_dump_data_(); 99*a0c7f9aaSSamuel Khuvis 100*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START(_timer, _timer_name) \ 101*a0c7f9aaSSamuel Khuvis static void * _timer = NULL; \ 102*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \ 103*a0c7f9aaSSamuel Khuvis if (_timer == NULL) { \ 104*a0c7f9aaSSamuel Khuvis _timer = ps_timer_create_(_timer_name); \ 105*a0c7f9aaSSamuel Khuvis } \ 106*a0c7f9aaSSamuel Khuvis ps_timer_start_(_timer); \ 107*a0c7f9aaSSamuel Khuvis }; 108*a0c7f9aaSSamuel Khuvis 109*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP(_timer) \ 110*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(_timer); \ 111*a0c7f9aaSSamuel Khuvis 112*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SET_PARAMETER(_parameter, _value) \ 113*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_set_parameter_(_parameter, _value); 114*a0c7f9aaSSamuel Khuvis 115*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_START(_phase_prefix, _iteration_index) \ 116*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) \ 117*a0c7f9aaSSamuel Khuvis ps_dynamic_phase_start_(_phase_prefix, _iteration_index); 118*a0c7f9aaSSamuel Khuvis 119*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_STOP(_phase_prefix, _iteration_index) \ 120*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) \ 121*a0c7f9aaSSamuel Khuvis ps_dynamic_phase_stop_(_phase_prefix, _iteration_index); 122*a0c7f9aaSSamuel Khuvis 123*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START_FUNC(_timer) \ 124*a0c7f9aaSSamuel Khuvis static void * _timer = NULL; \ 125*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \ 126*a0c7f9aaSSamuel Khuvis if (_timer == NULL) { \ 127*a0c7f9aaSSamuel Khuvis char * tmpstr = ps_make_timer_name_(__FILE__, \ 128*a0c7f9aaSSamuel Khuvis __PERFSTUBS_FUNCTION__, __LINE__); \ 129*a0c7f9aaSSamuel Khuvis _timer = ps_timer_create_(tmpstr); \ 130*a0c7f9aaSSamuel Khuvis free(tmpstr); \ 131*a0c7f9aaSSamuel Khuvis } \ 132*a0c7f9aaSSamuel Khuvis ps_timer_start_(_timer); \ 133*a0c7f9aaSSamuel Khuvis }; 134*a0c7f9aaSSamuel Khuvis 135*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP_FUNC(_timer) \ 136*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(_timer); 137*a0c7f9aaSSamuel Khuvis 138*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SAMPLE_COUNTER(_name, _value) \ 139*a0c7f9aaSSamuel Khuvis static void * CONCAT(__var,__LINE__) = NULL; \ 140*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \ 141*a0c7f9aaSSamuel Khuvis if (CONCAT(__var,__LINE__) == NULL) { \ 142*a0c7f9aaSSamuel Khuvis CONCAT(__var,__LINE__) = ps_create_counter_(_name); \ 143*a0c7f9aaSSamuel Khuvis } \ 144*a0c7f9aaSSamuel Khuvis ps_sample_counter_(CONCAT(__var,__LINE__), _value); \ 145*a0c7f9aaSSamuel Khuvis }; 146*a0c7f9aaSSamuel Khuvis 147*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_METADATA(_name, _value) \ 148*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_set_metadata_(_name, _value); 149*a0c7f9aaSSamuel Khuvis 150*a0c7f9aaSSamuel Khuvis #else // defined(PERFSTUBS_USE_TIMERS) 151*a0c7f9aaSSamuel Khuvis 152*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INITIALIZE() 153*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FINALIZE() 154*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_REGISTER_THREAD() 155*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DUMP_DATA() 156*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START(_timer, _timer_name) 157*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP(_timer_name) 158*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SET_PARAMETER(_parameter, _value) 159*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_START(_phase_prefix, _iteration_index) 160*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_STOP(_phase_prefix, _iteration_index) 161*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START_FUNC(_timer) 162*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP_FUNC(_timer) 163*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SAMPLE_COUNTER(_name, _value) 164*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_METADATA(_name, _value) 165*a0c7f9aaSSamuel Khuvis 166*a0c7f9aaSSamuel Khuvis #endif // defined(PERFSTUBS_USE_TIMERS) 167*a0c7f9aaSSamuel Khuvis 168*a0c7f9aaSSamuel Khuvis #ifdef __cplusplus 169*a0c7f9aaSSamuel Khuvis 170*a0c7f9aaSSamuel Khuvis #if defined(PERFSTUBS_USE_TIMERS) 171*a0c7f9aaSSamuel Khuvis 172*a0c7f9aaSSamuel Khuvis /* 173*a0c7f9aaSSamuel Khuvis * We allow the namespace to be changed, so that different libraries 174*a0c7f9aaSSamuel Khuvis * can include their own implementation and not have a namespace collision. 175*a0c7f9aaSSamuel Khuvis * For example, library A and executable B could both include the 176*a0c7f9aaSSamuel Khuvis * perfstubs_api code in their source tree, and change the namespace 177*a0c7f9aaSSamuel Khuvis * respectively, instead of linking in the perfstubs library. 178*a0c7f9aaSSamuel Khuvis */ 179*a0c7f9aaSSamuel Khuvis 180*a0c7f9aaSSamuel Khuvis #if defined(PERFSTUBS_NAMESPACE) 181*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INTERNAL_NAMESPACE PERFSTUBS_NAMESPACE 182*a0c7f9aaSSamuel Khuvis #else 183*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INTERNAL_NAMESPACE perfstubs_profiler 184*a0c7f9aaSSamuel Khuvis #endif 185*a0c7f9aaSSamuel Khuvis 186*a0c7f9aaSSamuel Khuvis #include <memory> 187*a0c7f9aaSSamuel Khuvis #include <sstream> 188*a0c7f9aaSSamuel Khuvis #include <string> 189*a0c7f9aaSSamuel Khuvis 190*a0c7f9aaSSamuel Khuvis namespace external 191*a0c7f9aaSSamuel Khuvis { 192*a0c7f9aaSSamuel Khuvis 193*a0c7f9aaSSamuel Khuvis namespace PERFSTUBS_INTERNAL_NAMESPACE 194*a0c7f9aaSSamuel Khuvis { 195*a0c7f9aaSSamuel Khuvis 196*a0c7f9aaSSamuel Khuvis class ScopedTimer 197*a0c7f9aaSSamuel Khuvis { 198*a0c7f9aaSSamuel Khuvis private: 199*a0c7f9aaSSamuel Khuvis const void * m_timer; 200*a0c7f9aaSSamuel Khuvis 201*a0c7f9aaSSamuel Khuvis public: 202*a0c7f9aaSSamuel Khuvis ScopedTimer(const void * timer) : m_timer(timer) 203*a0c7f9aaSSamuel Khuvis { 204*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_start_(m_timer); 205*a0c7f9aaSSamuel Khuvis } 206*a0c7f9aaSSamuel Khuvis ~ScopedTimer() 207*a0c7f9aaSSamuel Khuvis { 208*a0c7f9aaSSamuel Khuvis if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(m_timer); 209*a0c7f9aaSSamuel Khuvis } 210*a0c7f9aaSSamuel Khuvis }; 211*a0c7f9aaSSamuel Khuvis 212*a0c7f9aaSSamuel Khuvis } // namespace PERFSTUBS_INTERNAL_NAMESPACE 213*a0c7f9aaSSamuel Khuvis 214*a0c7f9aaSSamuel Khuvis } // namespace external 215*a0c7f9aaSSamuel Khuvis 216*a0c7f9aaSSamuel Khuvis namespace PSNS = external::PERFSTUBS_INTERNAL_NAMESPACE; 217*a0c7f9aaSSamuel Khuvis 218*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER(__name) \ 219*a0c7f9aaSSamuel Khuvis static void * CONCAT(__var,__LINE__) = ps_timer_create_(__name); \ 220*a0c7f9aaSSamuel Khuvis PSNS::ScopedTimer CONCAT(__var2,__LINE__)(CONCAT(__var,__LINE__)); 221*a0c7f9aaSSamuel Khuvis 222*a0c7f9aaSSamuel Khuvis /* The string created by ps_make_timer_name is a memory leak, but 223*a0c7f9aaSSamuel Khuvis * it is only created once per function, since it is called when the 224*a0c7f9aaSSamuel Khuvis * static variable is first initialized. */ 225*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER_FUNC() \ 226*a0c7f9aaSSamuel Khuvis static void * CONCAT(__var,__LINE__) = \ 227*a0c7f9aaSSamuel Khuvis ps_timer_create_(ps_make_timer_name_(__FILE__, \ 228*a0c7f9aaSSamuel Khuvis __PERFSTUBS_FUNCTION__, __LINE__)); \ 229*a0c7f9aaSSamuel Khuvis PSNS::ScopedTimer CONCAT(__var2,__LINE__)(CONCAT(__var,__LINE__)); 230*a0c7f9aaSSamuel Khuvis 231*a0c7f9aaSSamuel Khuvis #else // defined(PERFSTUBS_USE_TIMERS) 232*a0c7f9aaSSamuel Khuvis 233*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER(__name) 234*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER_FUNC() 235*a0c7f9aaSSamuel Khuvis 236*a0c7f9aaSSamuel Khuvis #endif // defined(PERFSTUBS_USE_TIMERS) 237*a0c7f9aaSSamuel Khuvis 238*a0c7f9aaSSamuel Khuvis #endif // ifdef __cplusplus 239