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