Actual source code: pstimer.c

      1: // Copyright (c) 2019 University of Oregon
      2: // Distributed under the BSD Software License
      3: // (See accompanying file LICENSE.txt)

      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"

     25: #define MAX_TOOLS 1

     27: #if defined(_WIN32)||defined(WIN32)||defined(_WIN64)||defined(WIN64)||defined(__CYGWIN__)||defined(__APPLE__)
     28: #define PERFSTUBS_OFF
     29: #endif

     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);

     36: /* Globals for the plugin API */

     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 */

     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];

     66: #ifndef PERFSTUBS_OFF

     68: #ifdef PERFSTUBS_USE_STATIC

     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

     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

    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

    106: #endif //PERFSTUBS_OFF

    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) {
    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

    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 = (int) ((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: }

    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: }

    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: }

    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: }

    236: void ps_register_thread_(void) {
    237: #ifndef PERFSTUBS_OFF
    238:     if (thread_seen == 0) {
    239:         ps_register_thread_internal();
    240:     }
    241: #endif
    242: }

    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: }

    257: void ps_timer_destroy_(void *objects) {
    258:     #ifndef PERFSTUBS_OFF
    259:     free(objects);
    260:     #endif
    261: }

    263: void ps_timer_create_fortran_(void ** object, const char *timer_name) {
    264:     #ifndef PERFSTUBS_OFF
    265:     *object = ps_timer_create_(timer_name);
    266:     #endif
    267: }

    269: void ps_timer_start_(const void *timer) {
    270:     #ifndef PERFSTUBS_OFF
    271:     void ** objects = (void**)(timer);
    272:     int i;
    273:     for (i = 0; i < num_tools_registered ; i++) {
    274:         timer_start_functions[i](objects[i]);
    275:     }
    276:     #endif
    277: }

    279: void ps_timer_start_fortran_(const void **timer) {
    280:     #ifndef PERFSTUBS_OFF
    281:     ps_timer_start_(*timer);
    282:     #endif
    283: }

    285: void ps_timer_stop_(const void *timer) {
    286:     #ifndef PERFSTUBS_OFF
    287:     void ** objects = (void**)(timer);
    288:     int i;
    289:     for (i = 0; i < num_tools_registered ; i++) {
    290:         timer_stop_functions[i](objects[i]);
    291:     }
    292:     #endif
    293: }

    295: void ps_timer_stop_fortran_(const void **timer) {
    296:     #ifndef PERFSTUBS_OFF
    297:     ps_timer_stop_(*timer);
    298:     #endif
    299: }

    301: void ps_set_parameter_(const char * parameter_name, int64_t parameter_value) {
    302:     #ifndef PERFSTUBS_OFF
    303:     int i;
    304:     for (i = 0; i < num_tools_registered ; i++) {
    305:         set_parameter_functions[i](parameter_name, parameter_value);
    306:     }
    307:     #endif
    308: }

    310: void ps_dynamic_phase_start_(const char *phase_prefix, int iteration_index) {
    311:     #ifndef PERFSTUBS_OFF
    312:     int i;
    313:     for (i = 0; i < num_tools_registered ; i++) {
    314:         dynamic_phase_start_functions[i](phase_prefix, iteration_index);
    315:     }
    316:     #endif
    317: }

    319: void ps_dynamic_phase_stop_(const char *phase_prefix, int iteration_index) {
    320:     #ifndef PERFSTUBS_OFF
    321:     int i;
    322:     for (i = 0; i < num_tools_registered ; i++) {
    323:         dynamic_phase_stop_functions[i](phase_prefix, iteration_index);
    324:     }
    325:     #endif
    326: }

    328: void* ps_create_counter_(const char *name) {
    329:     #ifndef PERFSTUBS_OFF
    330:     void ** objects = (void**)calloc(num_tools_registered, sizeof(void*));
    331:     int i;
    332:     for (i = 0 ; i < num_tools_registered ; i++) {
    333:         objects[i] = (void*)create_counter_functions[i](name);
    334:     }
    335:     return (void*)(objects);
    336:     #else
    337:     return NULL;
    338:     #endif
    339: }

    341: void ps_create_counter_fortran_(void ** object, const char *name) {
    342:     #ifndef PERFSTUBS_OFF
    343:     *object = ps_create_counter_(name);
    344:     #endif
    345: }

    347: void ps_sample_counter_(const void *counter, const double value) {
    348:     #ifndef PERFSTUBS_OFF
    349:     void ** objects = (void**)(counter);
    350:     int i;
    351:     for (i = 0; i < num_tools_registered ; i++) {
    352:         sample_counter_functions[i](objects[i], value);
    353:     }
    354:     #endif
    355: }

    357: void ps_sample_counter_fortran_(const void **counter, const double value) {
    358:     #ifndef PERFSTUBS_OFF
    359:     ps_sample_counter_(*counter, value);
    360:     #endif
    361: }

    363: void ps_set_metadata_(const char *name, const char *value) {
    364:     #ifndef PERFSTUBS_OFF
    365:     int i;
    366:     for (i = 0; i < num_tools_registered ; i++) {
    367:         set_metadata_functions[i](name, value);
    368:     }
    369:     #endif
    370: }

    372: void ps_dump_data_(void) {
    373:     #ifndef PERFSTUBS_OFF
    374:     int i;
    375:     for (i = 0; i < num_tools_registered ; i++) {
    376:         dump_data_functions[i]();
    377:     }
    378:     #endif
    379: }

    381: void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) {
    382:     #ifndef PERFSTUBS_OFF
    383:     if (tool_id < num_tools_registered) {
    384:         get_timer_data_functions[tool_id](timer_data);
    385:     }
    386:     #endif
    387: }

    389: void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) {
    390:     #ifndef PERFSTUBS_OFF
    391:     if (tool_id < num_tools_registered) {
    392:         get_counter_data_functions[tool_id](counter_data);
    393:     }
    394:     #endif
    395: }

    397: void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id) {
    398:     #ifndef PERFSTUBS_OFF
    399:     if (tool_id < num_tools_registered) {
    400:         get_metadata_functions[tool_id](metadata);
    401:     }
    402:     #endif
    403: }

    405: void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) {
    406:     #ifndef PERFSTUBS_OFF
    407:     if (tool_id < num_tools_registered) {
    408:         free_timer_data_functions[tool_id](timer_data);
    409:     }
    410:     #endif
    411: }

    413: void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) {
    414:     #ifndef PERFSTUBS_OFF
    415:     if (tool_id < num_tools_registered) {
    416:         free_counter_data_functions[tool_id](counter_data);
    417:     }
    418:     #endif
    419: }

    421: void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id) {
    422:     #ifndef PERFSTUBS_OFF
    423:     if (tool_id < num_tools_registered) {
    424:         free_metadata_functions[tool_id](metadata);
    425:     }
    426:     #endif
    427: }