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_start_(const void *timer); 60 void ps_timer_start_fortran_(const void **timer); 61 void ps_timer_stop_(const void *timer); 62 void ps_timer_stop_fortran_(const void **timer); 63 void ps_set_parameter_(const char *parameter_name, int64_t parameter_value); 64 void ps_dynamic_phase_start_(const char *phasePrefix, int iterationIndex); 65 void ps_dynamic_phase_stop_(const char *phasePrefix, int iterationIndex); 66 void* ps_create_counter_(const char *name); 67 void ps_create_counter_fortran_(void ** object, const char *name); 68 void ps_sample_counter_(const void *counter, const double value); 69 void ps_sample_counter_fortran_(const void **counter, const double value); 70 void ps_set_metadata_(const char *name, const char *value); 71 72 /* data query API */ 73 74 void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id); 75 void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id); 76 void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id); 77 void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id); 78 void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id); 79 void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id); 80 81 char* ps_make_timer_name_(const char * file, const char * func, int line); 82 83 #ifdef __cplusplus 84 } 85 #endif 86 87 /* Macro API for option of entirely disabling at compile time 88 * To use this API, set the Macro PERFSTUBS_USE_TIMERS on the command 89 * line or in a config.h file, however your project does it 90 */ 91 92 #define PERFSTUBS_INITIALIZE() ps_initialize_(); 93 94 #define PERFSTUBS_FINALIZE() ps_finalize_(); 95 96 #define PERFSTUBS_REGISTER_THREAD() ps_register_thread_(); 97 98 #define PERFSTUBS_DUMP_DATA() ps_dump_data_(); 99 100 #define PERFSTUBS_TIMER_START(_timer, _timer_name) \ 101 static void * _timer = NULL; \ 102 if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \ 103 if (_timer == NULL) { \ 104 _timer = ps_timer_create_(_timer_name); \ 105 } \ 106 ps_timer_start_(_timer); \ 107 }; 108 109 #define PERFSTUBS_TIMER_STOP(_timer) \ 110 if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(_timer); \ 111 112 #define PERFSTUBS_SET_PARAMETER(_parameter, _value) \ 113 if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_set_parameter_(_parameter, _value); 114 115 #define PERFSTUBS_DYNAMIC_PHASE_START(_phase_prefix, _iteration_index) \ 116 if (perfstubs_initialized == PERFSTUBS_SUCCESS) \ 117 ps_dynamic_phase_start_(_phase_prefix, _iteration_index); 118 119 #define PERFSTUBS_DYNAMIC_PHASE_STOP(_phase_prefix, _iteration_index) \ 120 if (perfstubs_initialized == PERFSTUBS_SUCCESS) \ 121 ps_dynamic_phase_stop_(_phase_prefix, _iteration_index); 122 123 #define PERFSTUBS_TIMER_START_FUNC(_timer) \ 124 static void * _timer = NULL; \ 125 if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \ 126 if (_timer == NULL) { \ 127 char * tmpstr = ps_make_timer_name_(__FILE__, \ 128 __PERFSTUBS_FUNCTION__, __LINE__); \ 129 _timer = ps_timer_create_(tmpstr); \ 130 free(tmpstr); \ 131 } \ 132 ps_timer_start_(_timer); \ 133 }; 134 135 #define PERFSTUBS_TIMER_STOP_FUNC(_timer) \ 136 if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(_timer); 137 138 #define PERFSTUBS_SAMPLE_COUNTER(_name, _value) \ 139 static void * CONCAT(__var,__LINE__) = NULL; \ 140 if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \ 141 if (CONCAT(__var,__LINE__) == NULL) { \ 142 CONCAT(__var,__LINE__) = ps_create_counter_(_name); \ 143 } \ 144 ps_sample_counter_(CONCAT(__var,__LINE__), _value); \ 145 }; 146 147 #define PERFSTUBS_METADATA(_name, _value) \ 148 if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_set_metadata_(_name, _value); 149 150 #else // defined(PERFSTUBS_USE_TIMERS) 151 152 #define PERFSTUBS_INITIALIZE() 153 #define PERFSTUBS_FINALIZE() 154 #define PERFSTUBS_REGISTER_THREAD() 155 #define PERFSTUBS_DUMP_DATA() 156 #define PERFSTUBS_TIMER_START(_timer, _timer_name) 157 #define PERFSTUBS_TIMER_STOP(_timer_name) 158 #define PERFSTUBS_SET_PARAMETER(_parameter, _value) 159 #define PERFSTUBS_DYNAMIC_PHASE_START(_phase_prefix, _iteration_index) 160 #define PERFSTUBS_DYNAMIC_PHASE_STOP(_phase_prefix, _iteration_index) 161 #define PERFSTUBS_TIMER_START_FUNC(_timer) 162 #define PERFSTUBS_TIMER_STOP_FUNC(_timer) 163 #define PERFSTUBS_SAMPLE_COUNTER(_name, _value) 164 #define PERFSTUBS_METADATA(_name, _value) 165 166 #endif // defined(PERFSTUBS_USE_TIMERS) 167 168 #ifdef __cplusplus 169 170 #if defined(PERFSTUBS_USE_TIMERS) 171 172 /* 173 * We allow the namespace to be changed, so that different libraries 174 * can include their own implementation and not have a namespace collision. 175 * For example, library A and executable B could both include the 176 * perfstubs_api code in their source tree, and change the namespace 177 * respectively, instead of linking in the perfstubs library. 178 */ 179 180 #if defined(PERFSTUBS_NAMESPACE) 181 #define PERFSTUBS_INTERNAL_NAMESPACE PERFSTUBS_NAMESPACE 182 #else 183 #define PERFSTUBS_INTERNAL_NAMESPACE perfstubs_profiler 184 #endif 185 186 #include <memory> 187 #include <sstream> 188 #include <string> 189 190 namespace external 191 { 192 193 namespace PERFSTUBS_INTERNAL_NAMESPACE 194 { 195 196 class ScopedTimer 197 { 198 private: 199 const void * m_timer; 200 201 public: 202 ScopedTimer(const void * timer) : m_timer(timer) 203 { 204 if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_start_(m_timer); 205 } 206 ~ScopedTimer() 207 { 208 if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(m_timer); 209 } 210 }; 211 212 } // namespace PERFSTUBS_INTERNAL_NAMESPACE 213 214 } // namespace external 215 216 namespace PSNS = external::PERFSTUBS_INTERNAL_NAMESPACE; 217 218 #define PERFSTUBS_SCOPED_TIMER(__name) \ 219 static void * CONCAT(__var,__LINE__) = ps_timer_create_(__name); \ 220 PSNS::ScopedTimer CONCAT(__var2,__LINE__)(CONCAT(__var,__LINE__)); 221 222 /* The string created by ps_make_timer_name is a memory leak, but 223 * it is only created once per function, since it is called when the 224 * static variable is first initialized. */ 225 #define PERFSTUBS_SCOPED_TIMER_FUNC() \ 226 static void * CONCAT(__var,__LINE__) = \ 227 ps_timer_create_(ps_make_timer_name_(__FILE__, \ 228 __PERFSTUBS_FUNCTION__, __LINE__)); \ 229 PSNS::ScopedTimer CONCAT(__var2,__LINE__)(CONCAT(__var,__LINE__)); 230 231 #else // defined(PERFSTUBS_USE_TIMERS) 232 233 #define PERFSTUBS_SCOPED_TIMER(__name) 234 #define PERFSTUBS_SCOPED_TIMER_FUNC() 235 236 #endif // defined(PERFSTUBS_USE_TIMERS) 237 238 #endif // ifdef __cplusplus 239