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