1 // Copyright (c) 2019 University of Oregon 2 // Distributed under the BSD Software License 3 // (See accompanying file LICENSE.txt) 4 5 #ifndef _GNU_SOURCE 6 #define _GNU_SOURCE // needed to define RTLD_DEFAULT 7 #endif 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <math.h> 11 #ifdef __linux__ 12 #include <dlfcn.h> 13 #else 14 #define PERFSTUBS_USE_STATIC 1 15 #endif 16 #define PERFSTUBS_USE_TIMERS 17 #include "timer.h" 18 19 #define MAX_TOOLS 1 20 21 #if defined(_WIN32)||defined(WIN32)||defined(_WIN64)||defined(WIN64)||defined(__CYGWIN__)||defined(__APPLE__) 22 #define PERFSTUBS_OFF 23 #endif 24 25 /* Make sure that the Timer singleton is constructed when the 26 * library is loaded. This will ensure (on linux, anyway) that 27 * we can assert that we have m_Initialized on the main thread. */ 28 //static void __attribute__((constructor)) initialize_library(void); 29 30 /* Globals for the plugin API */ 31 32 int perfstubs_initialized = PERFSTUBS_UNKNOWN; 33 int num_tools_registered = 0; 34 /* Keep track of whether the thread has been registered */ 35 #ifndef PERFSTUBS_OFF 36 __thread int thread_seen = 0; 37 #endif 38 /* Function pointers */ 39 40 ps_initialize_t initialize_functions[MAX_TOOLS]; 41 ps_register_thread_t register_thread_functions[MAX_TOOLS]; 42 ps_finalize_t finalize_functions[MAX_TOOLS]; 43 ps_dump_data_t dump_data_functions[MAX_TOOLS]; 44 ps_timer_create_t timer_create_functions[MAX_TOOLS]; 45 ps_timer_start_t timer_start_functions[MAX_TOOLS]; 46 ps_timer_stop_t timer_stop_functions[MAX_TOOLS]; 47 ps_set_parameter_t set_parameter_functions[MAX_TOOLS]; 48 ps_dynamic_phase_start_t dynamic_phase_start_functions[MAX_TOOLS]; 49 ps_dynamic_phase_stop_t dynamic_phase_stop_functions[MAX_TOOLS]; 50 ps_create_counter_t create_counter_functions[MAX_TOOLS]; 51 ps_sample_counter_t sample_counter_functions[MAX_TOOLS]; 52 ps_set_metadata_t set_metadata_functions[MAX_TOOLS]; 53 ps_get_timer_data_t get_timer_data_functions[MAX_TOOLS]; 54 ps_get_counter_data_t get_counter_data_functions[MAX_TOOLS]; 55 ps_get_metadata_t get_metadata_functions[MAX_TOOLS]; 56 ps_free_timer_data_t free_timer_data_functions[MAX_TOOLS]; 57 ps_free_counter_data_t free_counter_data_functions[MAX_TOOLS]; 58 ps_free_metadata_t free_metadata_functions[MAX_TOOLS]; 59 60 #ifndef PERFSTUBS_OFF 61 62 #ifdef PERFSTUBS_USE_STATIC 63 64 #if defined(__clang__) && defined(__APPLE__) 65 #define PS_WEAK_PRE 66 #define PS_WEAK_POST __attribute__((weak_import)) 67 #define PS_WEAK_POST_NULL __attribute__((weak_import)) 68 #else 69 #define PS_WEAK_PRE __attribute__((weak)) 70 #define PS_WEAK_POST 71 #define PS_WEAK_POST_NULL 72 #endif 73 74 PS_WEAK_PRE void ps_tool_initialize(void) PS_WEAK_POST; 75 PS_WEAK_PRE void ps_tool_register_thread(void) PS_WEAK_POST; 76 PS_WEAK_PRE void ps_tool_finalize(void) PS_WEAK_POST; 77 PS_WEAK_PRE void ps_tool_dump_data(void) PS_WEAK_POST; 78 PS_WEAK_PRE void* ps_tool_timer_create(const char *) PS_WEAK_POST; 79 PS_WEAK_PRE void ps_tool_timer_start(const void *) PS_WEAK_POST; 80 PS_WEAK_PRE void ps_tool_timer_stop(const void *) PS_WEAK_POST; 81 PS_WEAK_PRE void ps_tool_set_parameter(const char *, int64_t) PS_WEAK_POST; 82 PS_WEAK_PRE void ps_tool_dynamic_phase_start(const char *, int) PS_WEAK_POST; 83 PS_WEAK_PRE void ps_tool_dynamic_phase_stop(const char *, int) PS_WEAK_POST; 84 PS_WEAK_PRE void* ps_tool_create_counter(const char *) PS_WEAK_POST; 85 PS_WEAK_PRE void ps_tool_sample_counter(const void *, double) PS_WEAK_POST; 86 PS_WEAK_PRE void ps_tool_set_metadata(const char *, const char *) PS_WEAK_POST; 87 PS_WEAK_PRE void ps_tool_get_timer_data(ps_tool_timer_data_t *) PS_WEAK_POST; 88 PS_WEAK_PRE void ps_tool_get_counter_data(ps_tool_counter_data_t *) PS_WEAK_POST; 89 PS_WEAK_PRE void ps_tool_get_metadata(ps_tool_metadata_t *) PS_WEAK_POST; 90 PS_WEAK_PRE void ps_tool_free_timer_data(ps_tool_timer_data_t *) PS_WEAK_POST; 91 PS_WEAK_PRE void ps_tool_free_counter_data(ps_tool_counter_data_t *) PS_WEAK_POST; 92 PS_WEAK_PRE void ps_tool_free_metadata(ps_tool_metadata_t *) PS_WEAK_POST; 93 #endif 94 95 96 // Disable pedantic, see https://stackoverflow.com/a/36385690 97 #pragma GCC diagnostic push // Save actual diagnostics state 98 #pragma GCC diagnostic ignored "-Wpedantic" // Disable pedantic 99 100 #endif //PERFSTUBS_OFF 101 102 void initialize_library() { 103 #ifndef PERFSTUBS_OFF 104 #ifdef PERFSTUBS_USE_STATIC 105 /* The initialization function is the only required one */ 106 initialize_functions[0] = &ps_tool_initialize; 107 if (initialize_functions[0] == NULL) { 108 return; 109 } 110 printf("Found ps_tool_initialize(), registering tool\n"); 111 register_thread_functions[0] = &ps_tool_register_thread; 112 finalize_functions[0] = &ps_tool_finalize; 113 dump_data_functions[0] = &ps_tool_dump_data; 114 timer_create_functions[0] = &ps_tool_timer_create; 115 timer_start_functions[0] = &ps_tool_timer_start; 116 timer_stop_functions[0] = &ps_tool_timer_stop; 117 set_parameter_functions[0] = &ps_tool_set_parameter; 118 dynamic_phase_start_functions[0] = &ps_tool_dynamic_phase_start; 119 dynamic_phase_stop_functions[0] = &ps_tool_dynamic_phase_stop; 120 create_counter_functions[0] = &ps_tool_create_counter; 121 sample_counter_functions[0] = &ps_tool_sample_counter; 122 set_metadata_functions[0] = &ps_tool_set_metadata; 123 get_timer_data_functions[0] = &ps_tool_get_timer_data; 124 get_counter_data_functions[0] = &ps_tool_get_counter_data; 125 get_metadata_functions[0] = &ps_tool_get_metadata; 126 free_timer_data_functions[0] = &ps_tool_free_timer_data; 127 free_counter_data_functions[0] = &ps_tool_free_counter_data; 128 free_metadata_functions[0] = &ps_tool_free_metadata; 129 #else 130 initialize_functions[0] = 131 (ps_initialize_t)dlsym(RTLD_DEFAULT, "ps_tool_initialize"); 132 if (initialize_functions[0] == NULL) { 133 perfstubs_initialized = PERFSTUBS_FAILURE; 134 return; 135 } 136 printf("Found ps_tool_initialize(), registering tool\n"); 137 finalize_functions[0] = 138 (ps_finalize_t)dlsym(RTLD_DEFAULT, "ps_tool_finalize"); 139 register_thread_functions[0] = 140 (ps_register_thread_t)dlsym(RTLD_DEFAULT, "ps_tool_register_thread"); 141 dump_data_functions[0] = 142 (ps_dump_data_t)dlsym(RTLD_DEFAULT, "ps_tool_dump_data"); 143 timer_create_functions[0] = 144 (ps_timer_create_t)dlsym(RTLD_DEFAULT, 145 "ps_tool_timer_create"); 146 timer_start_functions[0] = 147 (ps_timer_start_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_start"); 148 timer_stop_functions[0] = 149 (ps_timer_stop_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_stop"); 150 set_parameter_functions[0] = 151 (ps_set_parameter_t)dlsym(RTLD_DEFAULT, "ps_tool_set_parameter"); 152 dynamic_phase_start_functions[0] = (ps_dynamic_phase_start_t)dlsym( 153 RTLD_DEFAULT, "ps_tool_dynamic_phase_start"); 154 dynamic_phase_stop_functions[0] = (ps_dynamic_phase_stop_t)dlsym( 155 RTLD_DEFAULT, "ps_tool_dynamic_phase_stop"); 156 create_counter_functions[0] = (ps_create_counter_t)dlsym( 157 RTLD_DEFAULT, "ps_tool_create_counter"); 158 sample_counter_functions[0] = (ps_sample_counter_t)dlsym( 159 RTLD_DEFAULT, "ps_tool_sample_counter"); 160 set_metadata_functions[0] = 161 (ps_set_metadata_t)dlsym(RTLD_DEFAULT, "ps_tool_set_metadata"); 162 get_timer_data_functions[0] = (ps_get_timer_data_t)dlsym( 163 RTLD_DEFAULT, "ps_tool_get_timer_data"); 164 get_counter_data_functions[0] = (ps_get_counter_data_t)dlsym( 165 RTLD_DEFAULT, "ps_tool_get_counter_data"); 166 get_metadata_functions[0] = (ps_get_metadata_t)dlsym( 167 RTLD_DEFAULT, "ps_tool_get_metadata"); 168 free_timer_data_functions[0] = (ps_free_timer_data_t)dlsym( 169 RTLD_DEFAULT, "ps_tool_free_timer_data"); 170 free_counter_data_functions[0] = (ps_free_counter_data_t)dlsym( 171 RTLD_DEFAULT, "ps_tool_free_counter_data"); 172 free_metadata_functions[0] = (ps_free_metadata_t)dlsym( 173 RTLD_DEFAULT, "ps_tool_free_metadata"); 174 #endif 175 perfstubs_initialized = PERFSTUBS_SUCCESS; 176 /* Increment the number of tools */ 177 num_tools_registered = 1; 178 #endif //PERFSTUBS_OFF 179 } 180 #ifndef PERFSTUBS_OFF 181 #pragma GCC diagnostic pop // Restore diagnostics state 182 #endif 183 184 char * ps_make_timer_name_(const char * file, 185 const char * func, int line) { 186 #ifndef PERFSTUBS_OFF 187 /* The length of the line number as a string is floor(log10(abs(num))) */ 188 int string_length = (strlen(file) + strlen(func) + floor(log10(abs(line))) + 11); 189 char * name = (char*)calloc(string_length, sizeof(char)); 190 sprintf(name, "%s [{%s} {%d,0}]", func, file, line); 191 return (name); 192 #else 193 return NULL; 194 #endif 195 } 196 197 // used internally to the class 198 void ps_register_thread_internal(void) { 199 #ifndef PERFSTUBS_OFF 200 int i; 201 for (i = 0 ; i < num_tools_registered ; i++) { 202 register_thread_functions[i](); 203 } 204 thread_seen = 1; 205 #endif 206 } 207 208 /* Initialization */ 209 void ps_initialize_(void) { 210 #ifndef PERFSTUBS_OFF 211 int i; 212 initialize_library(); 213 for (i = 0 ; i < num_tools_registered ; i++) { 214 initialize_functions[i](); 215 } 216 /* No need to register the main thread */ 217 thread_seen = 1; 218 #endif 219 } 220 221 void ps_finalize_(void) { 222 #ifndef PERFSTUBS_OFF 223 int i; 224 for (i = 0 ; i < num_tools_registered ; i++) { 225 finalize_functions[i](); 226 } 227 #endif 228 } 229 230 void ps_register_thread_(void) { 231 #ifndef PERFSTUBS_OFF 232 if (thread_seen == 0) { 233 ps_register_thread_internal(); 234 } 235 #endif 236 } 237 238 void* ps_timer_create_(const char *timer_name) { 239 #ifndef PERFSTUBS_OFF 240 void ** objects = (void**)calloc(num_tools_registered, sizeof(void*)); 241 int i; 242 for (i = 0 ; i < num_tools_registered ; i++) { 243 objects[i] = (void*)timer_create_functions[i](timer_name); 244 } 245 return (void*)(objects); 246 #else 247 return NULL; 248 #endif 249 } 250 251 void ps_timer_create_fortran_(void ** object, const char *timer_name) { 252 #ifndef PERFSTUBS_OFF 253 *object = ps_timer_create_(timer_name); 254 #endif 255 } 256 257 void ps_timer_start_(const void *timer) { 258 #ifndef PERFSTUBS_OFF 259 void ** objects = (void**)(timer); 260 int i; 261 for (i = 0; i < num_tools_registered ; i++) { 262 timer_start_functions[i](objects[i]); 263 } 264 #endif 265 } 266 267 void ps_timer_start_fortran_(const void **timer) { 268 #ifndef PERFSTUBS_OFF 269 ps_timer_start_(*timer); 270 #endif 271 } 272 273 void ps_timer_stop_(const void *timer) { 274 #ifndef PERFSTUBS_OFF 275 void ** objects = (void**)(timer); 276 int i; 277 for (i = 0; i < num_tools_registered ; i++) { 278 timer_stop_functions[i](objects[i]); 279 } 280 #endif 281 } 282 283 void ps_timer_stop_fortran_(const void **timer) { 284 #ifndef PERFSTUBS_OFF 285 ps_timer_stop_(*timer); 286 #endif 287 } 288 289 void ps_set_parameter_(const char * parameter_name, int64_t parameter_value) { 290 #ifndef PERFSTUBS_OFF 291 int i; 292 for (i = 0; i < num_tools_registered ; i++) { 293 set_parameter_functions[i](parameter_name, parameter_value); 294 } 295 #endif 296 } 297 298 void ps_dynamic_phase_start_(const char *phase_prefix, int iteration_index) { 299 #ifndef PERFSTUBS_OFF 300 int i; 301 for (i = 0; i < num_tools_registered ; i++) { 302 dynamic_phase_start_functions[i](phase_prefix, iteration_index); 303 } 304 #endif 305 } 306 307 void ps_dynamic_phase_stop_(const char *phase_prefix, int iteration_index) { 308 #ifndef PERFSTUBS_OFF 309 int i; 310 for (i = 0; i < num_tools_registered ; i++) { 311 dynamic_phase_stop_functions[i](phase_prefix, iteration_index); 312 } 313 #endif 314 } 315 316 void* ps_create_counter_(const char *name) { 317 #ifndef PERFSTUBS_OFF 318 void ** objects = (void**)calloc(num_tools_registered, sizeof(void*)); 319 int i; 320 for (i = 0 ; i < num_tools_registered ; i++) { 321 objects[i] = (void*)create_counter_functions[i](name); 322 } 323 return (void*)(objects); 324 #else 325 return NULL; 326 #endif 327 } 328 329 void ps_create_counter_fortran_(void ** object, const char *name) { 330 #ifndef PERFSTUBS_OFF 331 *object = ps_create_counter_(name); 332 #endif 333 } 334 335 void ps_sample_counter_(const void *counter, const double value) { 336 #ifndef PERFSTUBS_OFF 337 void ** objects = (void**)(counter); 338 int i; 339 for (i = 0; i < num_tools_registered ; i++) { 340 sample_counter_functions[i](objects[i], value); 341 } 342 #endif 343 } 344 345 void ps_sample_counter_fortran_(const void **counter, const double value) { 346 #ifndef PERFSTUBS_OFF 347 ps_sample_counter_(*counter, value); 348 #endif 349 } 350 351 void ps_set_metadata_(const char *name, const char *value) { 352 #ifndef PERFSTUBS_OFF 353 int i; 354 for (i = 0; i < num_tools_registered ; i++) { 355 set_metadata_functions[i](name, value); 356 } 357 #endif 358 } 359 360 void ps_dump_data_(void) { 361 #ifndef PERFSTUBS_OFF 362 int i; 363 for (i = 0; i < num_tools_registered ; i++) { 364 dump_data_functions[i](); 365 } 366 #endif 367 } 368 369 void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) { 370 #ifndef PERFSTUBS_OFF 371 if (tool_id < num_tools_registered) { 372 get_timer_data_functions[tool_id](timer_data); 373 } 374 #endif 375 } 376 377 void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) { 378 #ifndef PERFSTUBS_OFF 379 if (tool_id < num_tools_registered) { 380 get_counter_data_functions[tool_id](counter_data); 381 } 382 #endif 383 } 384 385 void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id) { 386 #ifndef PERFSTUBS_OFF 387 if (tool_id < num_tools_registered) { 388 get_metadata_functions[tool_id](metadata); 389 } 390 #endif 391 } 392 393 void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) { 394 #ifndef PERFSTUBS_OFF 395 if (tool_id < num_tools_registered) { 396 free_timer_data_functions[tool_id](timer_data); 397 } 398 #endif 399 } 400 401 void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) { 402 #ifndef PERFSTUBS_OFF 403 if (tool_id < num_tools_registered) { 404 free_counter_data_functions[tool_id](counter_data); 405 } 406 #endif 407 } 408 409 void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id) { 410 #ifndef PERFSTUBS_OFF 411 if (tool_id < num_tools_registered) { 412 free_metadata_functions[tool_id](metadata); 413 } 414 #endif 415 } 416