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(void) { 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) return; 114 printf("Found ps_tool_initialize(), registering tool\n"); 115 register_thread_functions[0] = &ps_tool_register_thread; 116 finalize_functions[0] = &ps_tool_finalize; 117 dump_data_functions[0] = &ps_tool_dump_data; 118 timer_create_functions[0] = &ps_tool_timer_create; 119 timer_start_functions[0] = &ps_tool_timer_start; 120 timer_stop_functions[0] = &ps_tool_timer_stop; 121 set_parameter_functions[0] = &ps_tool_set_parameter; 122 dynamic_phase_start_functions[0] = &ps_tool_dynamic_phase_start; 123 dynamic_phase_stop_functions[0] = &ps_tool_dynamic_phase_stop; 124 create_counter_functions[0] = &ps_tool_create_counter; 125 sample_counter_functions[0] = &ps_tool_sample_counter; 126 set_metadata_functions[0] = &ps_tool_set_metadata; 127 get_timer_data_functions[0] = &ps_tool_get_timer_data; 128 get_counter_data_functions[0] = &ps_tool_get_counter_data; 129 get_metadata_functions[0] = &ps_tool_get_metadata; 130 free_timer_data_functions[0] = &ps_tool_free_timer_data; 131 free_counter_data_functions[0] = &ps_tool_free_counter_data; 132 free_metadata_functions[0] = &ps_tool_free_metadata; 133 #else 134 initialize_functions[0] = 135 (ps_initialize_t)dlsym(RTLD_DEFAULT, "ps_tool_initialize"); 136 if (initialize_functions[0] == NULL) { 137 perfstubs_initialized = PERFSTUBS_FAILURE; 138 return; 139 } 140 printf("Found ps_tool_initialize(), registering tool\n"); 141 finalize_functions[0] = 142 (ps_finalize_t)dlsym(RTLD_DEFAULT, "ps_tool_finalize"); 143 register_thread_functions[0] = 144 (ps_register_thread_t)dlsym(RTLD_DEFAULT, "ps_tool_register_thread"); 145 dump_data_functions[0] = 146 (ps_dump_data_t)dlsym(RTLD_DEFAULT, "ps_tool_dump_data"); 147 timer_create_functions[0] = 148 (ps_timer_create_t)dlsym(RTLD_DEFAULT, 149 "ps_tool_timer_create"); 150 timer_start_functions[0] = 151 (ps_timer_start_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_start"); 152 timer_stop_functions[0] = 153 (ps_timer_stop_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_stop"); 154 set_parameter_functions[0] = 155 (ps_set_parameter_t)dlsym(RTLD_DEFAULT, "ps_tool_set_parameter"); 156 dynamic_phase_start_functions[0] = (ps_dynamic_phase_start_t)dlsym( 157 RTLD_DEFAULT, "ps_tool_dynamic_phase_start"); 158 dynamic_phase_stop_functions[0] = (ps_dynamic_phase_stop_t)dlsym( 159 RTLD_DEFAULT, "ps_tool_dynamic_phase_stop"); 160 create_counter_functions[0] = (ps_create_counter_t)dlsym( 161 RTLD_DEFAULT, "ps_tool_create_counter"); 162 sample_counter_functions[0] = (ps_sample_counter_t)dlsym( 163 RTLD_DEFAULT, "ps_tool_sample_counter"); 164 set_metadata_functions[0] = 165 (ps_set_metadata_t)dlsym(RTLD_DEFAULT, "ps_tool_set_metadata"); 166 get_timer_data_functions[0] = (ps_get_timer_data_t)dlsym( 167 RTLD_DEFAULT, "ps_tool_get_timer_data"); 168 get_counter_data_functions[0] = (ps_get_counter_data_t)dlsym( 169 RTLD_DEFAULT, "ps_tool_get_counter_data"); 170 get_metadata_functions[0] = (ps_get_metadata_t)dlsym( 171 RTLD_DEFAULT, "ps_tool_get_metadata"); 172 free_timer_data_functions[0] = (ps_free_timer_data_t)dlsym( 173 RTLD_DEFAULT, "ps_tool_free_timer_data"); 174 free_counter_data_functions[0] = (ps_free_counter_data_t)dlsym( 175 RTLD_DEFAULT, "ps_tool_free_counter_data"); 176 free_metadata_functions[0] = (ps_free_metadata_t)dlsym( 177 RTLD_DEFAULT, "ps_tool_free_metadata"); 178 #endif 179 perfstubs_initialized = PERFSTUBS_SUCCESS; 180 /* Increment the number of tools */ 181 num_tools_registered = 1; 182 #endif //PERFSTUBS_OFF 183 } 184 #ifndef PERFSTUBS_OFF 185 #pragma GCC diagnostic pop // Restore diagnostics state 186 #endif 187 188 char * ps_make_timer_name_(const char * file, 189 const char * func, int line) { 190 #ifndef PERFSTUBS_OFF 191 /* The length of the line number as a string is floor(log10(abs(num))) */ 192 int string_length = (int) ((strlen(file) + strlen(func) + floor(log10(abs(line))) + 11)); 193 char * name = (char*)calloc(string_length, sizeof(char)); 194 sprintf(name, "%s [{%s} {%d,0}]", func, file, line); 195 return (name); 196 #else 197 return NULL; 198 #endif 199 } 200 201 // used internally to the class 202 void ps_register_thread_internal(void) { 203 #ifndef PERFSTUBS_OFF 204 int i; 205 for (i = 0 ; i < num_tools_registered ; i++) register_thread_functions[i](); 206 thread_seen = 1; 207 #endif 208 } 209 210 /* Initialization */ 211 void ps_initialize_(void) { 212 #ifndef PERFSTUBS_OFF 213 int i; 214 initialize_library(); 215 for (i = 0 ; i < num_tools_registered ; i++) initialize_functions[i](); 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++) finalize_functions[i](); 225 #endif 226 } 227 228 void ps_register_thread_(void) { 229 #ifndef PERFSTUBS_OFF 230 if (thread_seen == 0) ps_register_thread_internal(); 231 #endif 232 } 233 234 void* ps_timer_create_(const char *timer_name) { 235 #ifndef PERFSTUBS_OFF 236 void ** objects = (void**)calloc(num_tools_registered, sizeof(void*)); 237 int i; 238 for (i = 0 ; i < num_tools_registered ; i++) objects[i] = timer_create_functions[i](timer_name); 239 return (void*)(objects); 240 #else 241 return NULL; 242 #endif 243 } 244 245 void ps_timer_destroy_(void *objects) { 246 #ifndef PERFSTUBS_OFF 247 free(objects); 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++) timer_start_functions[i](objects[i]); 262 #endif 263 } 264 265 void ps_timer_start_fortran_(const void **timer) { 266 #ifndef PERFSTUBS_OFF 267 ps_timer_start_(*timer); 268 #endif 269 } 270 271 void ps_timer_stop_(const void *timer) { 272 #ifndef PERFSTUBS_OFF 273 void ** objects = (void**)(timer); 274 int i; 275 for (i = 0; i < num_tools_registered ; i++) timer_stop_functions[i](objects[i]); 276 #endif 277 } 278 279 void ps_timer_stop_fortran_(const void **timer) { 280 #ifndef PERFSTUBS_OFF 281 ps_timer_stop_(*timer); 282 #endif 283 } 284 285 void ps_set_parameter_(const char * parameter_name, int64_t parameter_value) { 286 #ifndef PERFSTUBS_OFF 287 int i; 288 for (i = 0; i < num_tools_registered ; i++) set_parameter_functions[i](parameter_name, parameter_value); 289 #endif 290 } 291 292 void ps_dynamic_phase_start_(const char *phase_prefix, int iteration_index) { 293 #ifndef PERFSTUBS_OFF 294 int i; 295 for (i = 0; i < num_tools_registered ; i++) dynamic_phase_start_functions[i](phase_prefix, iteration_index); 296 #endif 297 } 298 299 void ps_dynamic_phase_stop_(const char *phase_prefix, int iteration_index) { 300 #ifndef PERFSTUBS_OFF 301 int i; 302 for (i = 0; i < num_tools_registered ; i++) dynamic_phase_stop_functions[i](phase_prefix, iteration_index); 303 #endif 304 } 305 306 void* ps_create_counter_(const char *name) { 307 #ifndef PERFSTUBS_OFF 308 void ** objects = (void**)calloc(num_tools_registered, sizeof(void*)); 309 int i; 310 for (i = 0 ; i < num_tools_registered ; i++) objects[i] = create_counter_functions[i](name); 311 return (void*)(objects); 312 #else 313 return NULL; 314 #endif 315 } 316 317 void ps_create_counter_fortran_(void ** object, const char *name) { 318 #ifndef PERFSTUBS_OFF 319 *object = ps_create_counter_(name); 320 #endif 321 } 322 323 void ps_sample_counter_(const void *counter, const double value) { 324 #ifndef PERFSTUBS_OFF 325 void ** objects = (void**)(counter); 326 int i; 327 for (i = 0; i < num_tools_registered ; i++) sample_counter_functions[i](objects[i], value); 328 #endif 329 } 330 331 void ps_sample_counter_fortran_(const void **counter, const double value) { 332 #ifndef PERFSTUBS_OFF 333 ps_sample_counter_(*counter, value); 334 #endif 335 } 336 337 void ps_set_metadata_(const char *name, const char *value) { 338 #ifndef PERFSTUBS_OFF 339 int i; 340 for (i = 0; i < num_tools_registered ; i++) set_metadata_functions[i](name, value); 341 #endif 342 } 343 344 void ps_dump_data_(void) { 345 #ifndef PERFSTUBS_OFF 346 int i; 347 for (i = 0; i < num_tools_registered ; i++) dump_data_functions[i](); 348 #endif 349 } 350 351 void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) { 352 #ifndef PERFSTUBS_OFF 353 if (tool_id < num_tools_registered) get_timer_data_functions[tool_id](timer_data); 354 #endif 355 } 356 357 void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) { 358 #ifndef PERFSTUBS_OFF 359 if (tool_id < num_tools_registered) get_counter_data_functions[tool_id](counter_data); 360 #endif 361 } 362 363 void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id) { 364 #ifndef PERFSTUBS_OFF 365 if (tool_id < num_tools_registered) get_metadata_functions[tool_id](metadata); 366 #endif 367 } 368 369 void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) { 370 #ifndef PERFSTUBS_OFF 371 if (tool_id < num_tools_registered) free_timer_data_functions[tool_id](timer_data); 372 #endif 373 } 374 375 void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) { 376 #ifndef PERFSTUBS_OFF 377 if (tool_id < num_tools_registered) free_counter_data_functions[tool_id](counter_data); 378 #endif 379 } 380 381 void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id) { 382 #ifndef PERFSTUBS_OFF 383 if (tool_id < num_tools_registered) free_metadata_functions[tool_id](metadata); 384 #endif 385 } 386