From 36a0e71f2db0e80d3f05cf21f2c44523e4972330 Mon Sep 17 00:00:00 2001 From: Boris Karasev Date: Wed, 29 Mar 2017 20:01:05 +0600 Subject: [PATCH] ompi/timings: preparing to production state Adds: - enabling/disabling of timings throught environment variable `OMPI_TIMING_ENABLE` - output format: [file name]:[function name]:[description]: avg/min/max - dynamically extending array of results for case then inited size was exhausted - catch and collect errors - cleanup Note: For use feature need to configure with `--enable-timings` and set env `OMPI_TIMING_ENABLE = 1` Signed-off-by: Boris Karasev --- ompi/runtime/ompi_mpi_init.c | 2 + ompi/util/timings.h | 305 +++++++++++++++++++++++------------ opal/util/timings.h | 279 ++++++++++++++++---------------- 3 files changed, 341 insertions(+), 245 deletions(-) diff --git a/ompi/runtime/ompi_mpi_init.c b/ompi/runtime/ompi_mpi_init.c index b3e3b15fa8..e9beebb4e9 100644 --- a/ompi/runtime/ompi_mpi_init.c +++ b/ompi/runtime/ompi_mpi_init.c @@ -950,6 +950,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided) } opal_mutex_unlock(&ompi_mpi_bootstrap_mutex); ompi_hook_base_mpi_init_error(argc, argv, requested, provided); + OMPI_TIMING_FINALIZE; return ret; } @@ -976,6 +977,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided) * and clear timing structure */ OMPI_TIMING_NEXT("barrier-finish"); OMPI_TIMING_OUT; + OMPI_TIMING_FINALIZE; opal_mutex_unlock(&ompi_mpi_bootstrap_mutex); diff --git a/ompi/util/timings.h b/ompi/util/timings.h index 80df42cfed..339a6c2697 100644 --- a/ompi/util/timings.h +++ b/ompi/util/timings.h @@ -4,123 +4,212 @@ #include "opal/util/timings.h" /* TODO: we need access to MPI_* functions */ -#if (0 && OPAL_ENABLE_TIMING) +#if (OPAL_ENABLE_TIMING) -/* TODO: replace with opal_timing function */ -static inline double OMPI_TIMING_GET_TS(void) -{ - struct timespec ts; - double ret; - clock_gettime(CLOCK_MONOTONIC, &ts); - ret = ts.tv_sec + 1E-9 * ts.tv_nsec; - return ret; +typedef struct { + char desc[OPAL_TIMING_STR_LEN]; + double ts; + char *file; + char *prefix; +} ompi_timing_val_t; + + typedef struct { + ompi_timing_val_t *val; + int use; + struct ompi_timing_list_t *next; + } ompi_timing_list_t; + + typedef struct ompi_timing_t { + double ts; + const char *prefix; + int size; + int cnt; + int error; + int enabled; + opal_timing_ts_func_t get_ts; + ompi_timing_list_t *timing; + ompi_timing_list_t *cur_timing; + } ompi_timing_t; + +#define OMPI_TIMING_INIT(_size) \ + ompi_timing_t OMPI_TIMING; \ + OMPI_TIMING.prefix = __FUNCTION__; \ + OMPI_TIMING.size = _size; \ + OMPI_TIMING.get_ts = opal_timing_ts_func(OPAL_TIMING_AUTOMATIC_TIMER); \ + OMPI_TIMING.cnt = 0; \ + OMPI_TIMING.error = 0; \ + OMPI_TIMING.ts = OMPI_TIMING.get_ts(); \ + OMPI_TIMING.enabled = 0; \ + { \ + char *ptr; \ + ptr = getenv("OMPI_TIMING_ENABLE"); \ + if (NULL != ptr) { \ + OMPI_TIMING.enabled = atoi(ptr); \ + } \ + if (OMPI_TIMING.enabled) { \ + setenv("OPAL_TIMING_ENABLE", "1", 1); \ + OMPI_TIMING.timing = (ompi_timing_list_t*)malloc(sizeof(ompi_timing_list_t)); \ + memset(OMPI_TIMING.timing, 0, sizeof(ompi_timing_list_t)); \ + OMPI_TIMING.timing->val = (ompi_timing_val_t*)malloc(sizeof(ompi_timing_val_t) * _size); \ + OMPI_TIMING.cur_timing = OMPI_TIMING.timing; \ + } \ + } + +#define OMPI_TIMING_ITEM_EXTEND ({ \ + if (OMPI_TIMING.enabled) { \ + OMPI_TIMING.cur_timing->next = (struct ompi_timing_list_t*)malloc(sizeof(ompi_timing_list_t)); \ + OMPI_TIMING.cur_timing = (ompi_timing_list_t*)OMPI_TIMING.cur_timing->next; \ + memset(OMPI_TIMING.cur_timing, 0, sizeof(ompi_timing_list_t)); \ + OMPI_TIMING.cur_timing->val = malloc(sizeof(ompi_timing_val_t) * OMPI_TIMING.size); \ + } \ +}) + +#define OMPI_TIMING_FINALIZE ({ \ + if (OMPI_TIMING.enabled) { \ + ompi_timing_list_t *t = OMPI_TIMING.timing, *tmp; \ + while ( NULL != t) { \ + tmp = t; \ + t = t->next; \ + free(tmp->val); \ + free(tmp); \ + } \ + OMPI_TIMING.timing = NULL; \ + OMPI_TIMING.cur_timing = NULL; \ + OMPI_TIMING.cnt = 0; \ + } \ +}) + +#define OMPI_TIMING_NEXT(fmt, ...) ({ \ + if (!OMPI_TIMING.error && OMPI_TIMING.enabled) { \ + char *f = strrchr(__FILE__, '/') + 1; \ + int len = 0; \ + if (OMPI_TIMING.cur_timing->use >= OMPI_TIMING.size){ \ + OMPI_TIMING_ITEM_EXTEND; \ + } \ + len = snprintf(OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use].desc, \ + OPAL_TIMING_STR_LEN, fmt, ##__VA_ARGS__); \ + if (len >= OPAL_TIMING_STR_LEN) { \ + OMPI_TIMING.error = 1; \ + } \ + OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use].file = f; \ + OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use].prefix = __FUNCTION__; \ + OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use++].ts = \ + OMPI_TIMING.get_ts() - OMPI_TIMING.ts; \ + OMPI_TIMING.cnt++; \ + OMPI_TIMING.ts = OMPI_TIMING.get_ts(); \ + } \ +}) + +#define OMPI_TIMING_APPEND(filename,func,desc,ts) { \ + if (OMPI_TIMING.cur_timing->use >= OMPI_TIMING.size){ \ + OMPI_TIMING_ITEM_EXTEND; \ + } \ + int len = snprintf(OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use].desc, \ + OPAL_TIMING_STR_LEN, "%s", desc); \ + if (len >= OPAL_TIMING_STR_LEN) { \ + OMPI_TIMING.error = 1; \ + } \ + OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use].prefix = func; \ + OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use].file = filename; \ + OMPI_TIMING.cur_timing->val[OMPI_TIMING.cur_timing->use++].ts = \ + OMPI_TIMING.get_ts() - OMPI_TIMING.ts; \ + OMPI_TIMING.cnt++; \ + OMPI_TIMING.ts = OMPI_TIMING.get_ts(); \ } -/* TODO: - * - create a structure to hold this variables - * - use dyncamically extendable arrays - */ -#define OMPI_TIMING_INIT(inum) \ - double OMPI_TIMING_ts = OMPI_TIMING_GET_TS(); \ - const char *OMPI_TIMING_prefix = __FUNCTION__; \ - int OMPI_TIMING_cnt = 0; \ - int OMPI_TIMING_inum = inum; \ - double OMPI_TIMING_in[inum] = { 0.0 }; \ - double OMPI_TIMING_max[inum] = { 0.0 }; \ - double OMPI_TIMING_min[inum] = { 0.0 }; \ - double OMPI_TIMING_avg[inum] = { 0.0 }; \ - char *OMPI_TIMING_desc[inum] = { 0 }; \ - - -/* TODO: provide printf-like interfase allowing to build a string - * at runtime, like OPAL_TIMING_NEXT() - */ -#define OMPI_TIMING_NEXT(desc) { \ - char *ptr = strrchr(__FILE__, '/'); \ - if( NULL == ptr ){ \ - ptr = __FILE__; \ - } else { \ - ptr++; \ - } \ - if( OMPI_TIMING_inum <= OMPI_TIMING_cnt ){ \ - printf("OMPI_TIMING [%s:%d %s]: interval count overflow!!\n", \ - ptr, __LINE__, __FUNCTION__); \ - abort(); \ - } \ - OMPI_TIMING_in[OMPI_TIMING_cnt] = OMPI_TIMING_GET_TS() - OMPI_TIMING_ts; \ - OMPI_TIMING_desc[OMPI_TIMING_cnt++] = desc; \ - OMPI_TIMING_ts = OMPI_TIMING_GET_TS(); \ +#define OMPI_TIMING_IMPORT_OPAL_PREFIX(_prefix, func) { \ + if (!OMPI_TIMING.error && OMPI_TIMING.enabled) { \ + int cnt = OPAL_TIMING_ENV_CNT(func); \ + int i; \ + OMPI_TIMING.error = OPAL_TIMING_ENV_ERROR_PREFIX(_prefix, func); \ + for(i = 0; i < cnt; i++){ \ + char *desc, *filename; \ + double ts = OPAL_TIMING_ENV_GETDESC_PREFIX(_prefix, &filename, func, i, &desc); \ + OMPI_TIMING_APPEND(filename, func, desc, ts); \ + } \ + } \ } -#define OMPI_TIMING_APPEND(desc,ts) { \ - char *ptr = strrchr(__FILE__, '/'); \ - if( NULL == ptr ){ \ - ptr = __FILE__; \ - } else { \ - ptr++; \ - } \ - if( OMPI_TIMING_inum <= OMPI_TIMING_cnt ){ \ - printf("OMPI_TIMING [%s:%d %s]: interval count overflow!!\n", \ - ptr, __LINE__, __FUNCTION__); \ - abort(); \ - } \ - OMPI_TIMING_in[OMPI_TIMING_cnt] = ts; \ - OMPI_TIMING_desc[OMPI_TIMING_cnt++] = desc; \ -} - -#define OMPI_TIMING_IMPORT_OPAL(func) { \ - char *enabled; \ - int cnt = OPAL_TIMING_ENV_CNT(func); \ - if( 0 < cnt ) { \ - char ename[256]; \ - sprintf(ename, "OMPI_TIMING_%s", OMPI_TIMING_prefix); \ - setenv(ename, "1", 1); \ - } \ - int i; \ - for(i = 0; i < cnt; i++){ \ - char *desc; \ - double ts = OPAL_TIMING_ENV_GETDESC(prefix, i, &desc); \ - OMPI_TIMING_APPEND(desc, ts); \ - } \ -} +#define OMPI_TIMING_IMPORT_OPAL(func) \ + OMPI_TIMING_IMPORT_OPAL_PREFIX("", func) -#define OMPI_TIMING_OUT { \ - int i, size, rank; \ - MPI_Comm_size(MPI_COMM_WORLD, &size); \ - MPI_Comm_rank(MPI_COMM_WORLD, &rank); \ - char ename[1024]; \ - sprintf(ename, "OMPI_TIMING_%s", OMPI_TIMING_prefix); \ - char *ptr = getenv(ename); \ - \ - if( NULL != ptr ) { \ - OMPI_TIMING_ts = OMPI_TIMING_GET_TS(); \ - MPI_Reduce(OMPI_TIMING_in, OMPI_TIMING_avg, OMPI_TIMING_cnt, MPI_DOUBLE, \ - MPI_SUM, 0, MPI_COMM_WORLD); \ - MPI_Reduce(OMPI_TIMING_in, OMPI_TIMING_min, OMPI_TIMING_cnt, MPI_DOUBLE, \ - MPI_MIN, 0, MPI_COMM_WORLD); \ - MPI_Reduce(OMPI_TIMING_in, OMPI_TIMING_max, OMPI_TIMING_cnt, MPI_DOUBLE, \ - MPI_MAX, 0, MPI_COMM_WORLD); \ - \ - if( 0 == rank ){ \ - printf("------------------ %s ------------------\n", \ - OMPI_TIMING_prefix); \ - for(i=0; i< OMPI_TIMING_cnt; i++){ \ - OMPI_TIMING_avg[i] /= size; \ - printf("[%s:%s]: %lf / %lf / %lf\n", \ - OMPI_TIMING_prefix,OMPI_TIMING_desc[i], \ - OMPI_TIMING_avg[i], OMPI_TIMING_min[i], OMPI_TIMING_max[i]); \ - } \ - printf("[%s:overhead]: %lf \n", OMPI_TIMING_prefix, \ - OMPI_TIMING_GET_TS() - OMPI_TIMING_ts); \ - } \ - } \ -} + +#define OMPI_TIMING_OUT ({ \ + if (OMPI_TIMING.enabled) { \ + int i, size, rank; \ + MPI_Comm_size(MPI_COMM_WORLD, &size); \ + MPI_Comm_rank(MPI_COMM_WORLD, &rank); \ + int error = 0; \ + \ + MPI_Reduce(&OMPI_TIMING.error, &error, 1, \ + MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); \ + \ + if (error) { \ + if (0 == rank) { \ + printf("==OMPI_TIMING== error: something went wrong, timings doesn't work\n"); \ + } \ + } \ + else { \ + double *avg = (double*)malloc(sizeof(double) * OMPI_TIMING.cnt); \ + double *min = (double*)malloc(sizeof(double) * OMPI_TIMING.cnt); \ + double *max = (double*)malloc(sizeof(double) * OMPI_TIMING.cnt); \ + char **desc = (char**)malloc(sizeof(char*) * OMPI_TIMING.cnt); \ + char **prefix = (char**)malloc(sizeof(char*) * OMPI_TIMING.cnt); \ + char **file = (char**)malloc(sizeof(char*) * OMPI_TIMING.cnt); \ + \ + if( OMPI_TIMING.cnt > 0 ) { \ + OMPI_TIMING.ts = OMPI_TIMING.get_ts(); \ + ompi_timing_list_t *timing = OMPI_TIMING.timing; \ + i = 0; \ + do { \ + int use; \ + for (use = 0; use < timing->use; use++) { \ + MPI_Reduce(&timing->val[use].ts, avg + i, 1, \ + MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); \ + MPI_Reduce(&timing->val[use].ts, min + i, 1, \ + MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); \ + MPI_Reduce(&timing->val[use].ts, max + i, 1, \ + MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); \ + desc[i] = timing->val[use].desc; \ + prefix[i] = timing->val[use].prefix; \ + file[i] = timing->val[use].file; \ + i++; \ + } \ + timing = (ompi_timing_list_t*)timing->next; \ + } while (timing != NULL); \ + \ + if( 0 == rank ){ \ + if (OMPI_TIMING.timing->next) { \ + printf("==OMPI_TIMING== warning: added the extra timings allocation that might misrepresent the results.\n" \ + "==OMPI_TIMING== Increase the inited size of timings to avoid extra allocation during runtime.\n"); \ + } \ + \ + printf("------------------ %s ------------------\n", \ + OMPI_TIMING.prefix); \ + for(i=0; i< OMPI_TIMING.cnt; i++){ \ + avg[i] /= size; \ + printf("[%s:%s:%s]: %lf / %lf / %lf\n", \ + file[i], prefix[i], desc[i], avg[i], min[i], max[i]); \ + } \ + printf("[%s:overhead]: %lf \n", OMPI_TIMING.prefix, \ + OMPI_TIMING.get_ts() - OMPI_TIMING.ts); \ + } \ + } \ + free(avg); \ + free(min); \ + free(max); \ + free(desc); \ + free(prefix); \ + free(file); \ + } \ + } \ +}) #else -#define OMPI_TIMING_INIT(inum) +#define OMPI_TIMING_INIT(size) -#define OMPI_TIMING_NEXT(desc) +#define OMPI_TIMING_NEXT(fmt, ...) #define OMPI_TIMING_APPEND(desc,ts) @@ -128,6 +217,8 @@ static inline double OMPI_TIMING_GET_TS(void) #define OMPI_TIMING_IMPORT_OPAL(func) +#define OMPI_TIMING_FINALIZE + #endif #endif diff --git a/opal/util/timings.h b/opal/util/timings.h index d67931ba59..2bd41b6a4a 100644 --- a/opal/util/timings.h +++ b/opal/util/timings.h @@ -28,6 +28,7 @@ typedef enum { typedef double (*opal_timing_ts_func_t)(void); #define OPAL_TIMING_STR_LEN 256 + typedef struct { char id[OPAL_TIMING_STR_LEN], cntr_env[OPAL_TIMING_STR_LEN]; int enabled, error; @@ -38,54 +39,46 @@ typedef struct { opal_timing_ts_func_t opal_timing_ts_func(opal_timer_type_t type); +#define OPAL_TIMING_ENV_START_TYPE(func, type, prefix) ({ \ + opal_timing_env_t h; \ + char *ptr = NULL; \ + char *_prefix = prefix; \ + int n; \ + if( NULL == prefix ){ \ + _prefix = ""; \ + } \ + h.error = 0; \ + n = snprintf(h.id, OPAL_TIMING_STR_LEN, "%s%s", _prefix, func); \ + if( n > OPAL_TIMING_STR_LEN ){ \ + h.error = 1; \ + } \ + n = sprintf(h.cntr_env,"OMPI_TIMING_%s%s_CNT", prefix, h.id); \ + if( n > OPAL_TIMING_STR_LEN ){ \ + h.error = 1; \ + } \ + ptr = getenv(h.id); \ + if( NULL == ptr || strcmp(ptr, "1")){ \ + h.enabled = 0; \ + } \ + h.get_ts = opal_timing_ts_func(type); \ + ptr = getenv("OPAL_TIMING_ENABLE"); \ + if (NULL != ptr) { \ + h.enabled = atoi(ptr); \ + } \ + h.cntr = 0; \ + ptr = getenv(h.id); \ + if( NULL != ptr ){ \ + h.cntr = atoi(ptr); \ + } \ + h.ts = h.get_ts(); \ + if ( 0 != h.error ){ \ + h.enabled = 0; \ + } \ + h; \ +}) -/* TODO: turn as much as possible into macro's - * once debugged - */ - -static inline opal_timing_env_t -OPAL_TIMING_ENV_START_TYPE(char *func, opal_timer_type_t type, char *prefix) -{ - opal_timing_env_t h; - int n; - - /* TODO: remove this when tested! */ - h.enabled = 0; - return h; - - if( NULL == prefix ){ - prefix = ""; - } - - h.error = 0; - n = snprintf(h.id, OPAL_TIMING_STR_LEN, "%s%s", prefix, func); - if( n > OPAL_TIMING_STR_LEN ){ - /* TODO: output truncated: - * disable this timing and set the error - * sign - */ - } - - /* TODO same length check here */ - sprintf(h.cntr_env,"%s_CNT", h.id); - h.get_ts = opal_timing_ts_func(type); - h.ts = h.get_ts(); - h.enabled = 1; - - char *ptr = getenv(h.id); - if( NULL == ptr || strcmp(ptr, "1")){ - h.enabled = 0; - } - ptr = getenv(h.cntr_env); - h.cntr = 0; - if( NULL != ptr ){ - h.cntr = atoi(ptr); - } - return h; -} - -#define OPAL_TIMING_ENV_INIT(name) \ - opal_timing_env_t name ## _val, *name = &(name ## _val); \ +#define OPAL_TIMING_ENV_INIT(name) \ + opal_timing_env_t name ## _val, *name = &(name ## _val); \ *name = OPAL_TIMING_ENV_START_TYPE(__FUNCTION__, OPAL_TIMING_AUTOMATIC_TIMER, ""); /* We use function names for identification @@ -94,104 +87,115 @@ OPAL_TIMING_ENV_START_TYPE(char *func, opal_timer_type_t type, char *prefix) * conflict. * Use prefix to do a finer-grained identification if needed */ -#define OPAL_TIMING_ENV_INIT_PREFIX(prefix, name) \ - opal_timing_env_t name ## _val, *name = &(name ## _val); \ - name = OPAL_TIMING_ENV_START_TYPE(__FUNCTION__, OPAL_TIMING_AUTOMATIC_TIMER, prefix); +#define OPAL_TIMING_ENV_INIT_PREFIX(prefix, name) \ + opal_timing_env_t name ## _val, *name = &(name ## _val); \ + *name = OPAL_TIMING_ENV_START_TYPE(__FUNCTION__, OPAL_TIMING_AUTOMATIC_TIMER, prefix); - -/* TODO: according to https://en.wikipedia.org/wiki/C99 - * varadic macroses are part of C99 and C11. Is it safe to use them here? - */ -static inline void -OPAL_TIMING_ENV_NEXT(opal_timing_env_t *h, char *fmt, ... ) -{ - if( !h->enabled ){ - return; - } - /* enabled codepath */ - va_list ap; - int n; - char buf[256], buf2[256]; - double time = h->get_ts() - h->ts; - - sprintf(buf, "%s_DESC_%d", h->id, h->cntr); - /* TODO: check that write succeded */ - - va_start(ap, fmt); - n= vsnprintf(buf2, 256, fmt, ap); - /* TODO: check that write succeded */ - va_end(ap); - - setenv(buf, buf2, 1); - - sprintf(buf, "%s_VAL_%d", h->id, h->cntr); - /* TODO: check that write succeded */ - sprintf(buf2, "%lf", time); - /* TODO: check that write succeded */ - setenv(buf, buf2, 1); - - h->cntr++; - sprintf(buf, "%d", h->cntr); - setenv(h->cntr_env, buf, 1); - - /* We don't include env operations into the consideration. - * Hopefully this will help to make measurements more accurate. - */ - h->ts = h->get_ts(); -} +#define OPAL_TIMING_ENV_NEXT(h, fmt, ...) ({ \ + int n; \ + char buf1[OPAL_TIMING_STR_LEN], buf2[OPAL_TIMING_STR_LEN]; \ + double time; \ + char *filename; \ + if( h->enabled ){ \ + /* enabled codepath */ \ + time = h->get_ts() - h->ts; \ + n = snprintf(buf1, OPAL_TIMING_STR_LEN, "OMPI_TIMING_%s_DESC_%d", h->id, h->cntr); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + n = snprintf(buf2, OPAL_TIMING_STR_LEN, fmt, ## __VA_ARGS__ ); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + setenv(buf1, buf2, 1); \ + n = snprintf(buf1, OPAL_TIMING_STR_LEN, "OMPI_TIMING_%s_VAL_%d", h->id, h->cntr); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + n = snprintf(buf2, OPAL_TIMING_STR_LEN, "%lf", time); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + setenv(buf1, buf2, 1); \ + filename = strrchr(__FILE__, '/') + 1; \ + n = snprintf(buf1, OPAL_TIMING_STR_LEN, "OMPI_TIMING_%s_FILE_%d", h->id, h->cntr); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + n = snprintf(buf2, OPAL_TIMING_STR_LEN, "%s", filename); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + setenv(buf1, buf2, 1); \ + h->cntr++; \ + sprintf(buf1, "%d", h->cntr); \ + setenv(h->cntr_env, buf1, 1); \ + /* We don't include env operations into the consideration. + * Hopefully this will help to make measurements more accurate. + */ \ + h->ts = h->get_ts(); \ + } \ + if (h->error) { \ + n = snprintf(buf1, OPAL_TIMING_STR_LEN, "OMPI_TIMING_%s_ERROR", h->id);\ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + n = snprintf(buf2, OPAL_TIMING_STR_LEN, "%d", h->error); \ + if ( n > OPAL_TIMING_STR_LEN ){ \ + h->error = 1; \ + } \ + setenv(buf1, buf2, 1); \ + } \ +}) /* This function supposed to be called from the code that will * do the postprocessing, i.e. OMPI timing portion that will * do the reduction of accumulated values */ -/* TODO: turn into a macro */ -static inline int OPAL_TIMING_ENV_CNT_PREFIX(char *prefix, char *func) -{ - char ename[256]; - sprintf(ename, "%s%s_CNT", prefix, func); - char *ptr = getenv(ename); - if( !ptr ){ - return 0; - } - return atoi(ptr); -} +#define OPAL_TIMING_ENV_CNT_PREFIX(prefix, func) ({ \ + char ename[OPAL_TIMING_STR_LEN]; \ + int cnt = 0; \ + char *ptr = NULL; \ + int n = snprintf(ename, OPAL_TIMING_STR_LEN, "OMPI_TIMING_%s%s_CNT", prefix, func); \ + if ( n <= OPAL_TIMING_STR_LEN ){ \ + ptr = getenv(ename); \ + if( NULL != ptr ){ cnt = atoi(ptr); }; \ + } \ + cnt; \ +}) -#define OPAL_TIMING_ENV_CNT(func) \ - OPAL_TIMING_ENV_CNT_PREFIX("", char *func) +#define OPAL_TIMING_ENV_ERROR_PREFIX(prefix, func) ({ \ + char ename[OPAL_TIMING_STR_LEN]; \ + int error = 0; \ + char *ptr = NULL; \ + int n = snprintf(ename, OPAL_TIMING_STR_LEN, "OMPI_TIMING_%s%s_ERROR", prefix, func); \ + if ( n <= OPAL_TIMING_STR_LEN ){ \ + ptr = getenv(ename); \ + if( NULL != ptr ){ error = atoi(ptr); }; \ + } \ + error; \ +}) -/* TODO: make a macro */ -static inline double -OPAL_TIMING_ENV_GETDESC_PREFIX(char *prefix, char *func, int i, char **desc) -{ - char vname[256]; - double ts; - sprintf(vname, "%s_INT_%d_DESC", prefix, i); - *desc = getenv(vname); - sprintf(vname, "%s_INT_%d_VAL",prefix, i); - char *ptr = getenv(vname); - sscanf(ptr,"%lf", &ts); - return ts; -} +#define OPAL_TIMING_ENV_CNT(func) \ + OPAL_TIMING_ENV_CNT_PREFIX("", func) -#define OPAL_TIMING_ENV_GETDESC(func, index, desc) \ - OPAL_TIMING_ENV_GETDESC_PREFIX("", func, index, desc) +#define OPAL_TIMING_ENV_GETDESC_PREFIX(prefix, filename, func, i, desc) ({ \ + char vname[OPAL_TIMING_STR_LEN]; \ + double ts = 0.0; \ + sprintf(vname, "OMPI_TIMING_%s%s_FILE_%d", prefix, func, i); \ + *filename = getenv(vname); \ + sprintf(vname, "OMPI_TIMING_%s%s_DESC_%d", prefix, func, i); \ + *desc = getenv(vname); \ + sprintf(vname, "OMPI_TIMING_%s%s_VAL_%d", prefix, func, i); \ + char *ptr = getenv(vname); \ + if ( NULL != ptr ) { \ + sscanf(ptr,"%lf", &ts); \ + } \ + ts; \ +}) -#define OSHTMNG_ENV_APPEND(prefix) { \ - char *enabled; \ - int cnt = OSHTMNG_ENV_COUNT(prefix); \ - enabled = getenv(prefix); \ - if( NULL != enabled && !strcmp(enabled, "1") ) { \ - char ename[256]; \ - sprintf(ename, "OSHTMNG_%s", OSHTMNG_prefix); \ - setenv(ename, "1", 1); \ - } \ - int i; \ - for(i = 0; i < cnt; i++){ \ - char *desc; \ - double ts = OSHTMNG_ENV_GETBYIDX(prefix, i, &desc); \ - OSHTMNG_END1(desc, ts); \ - } \ -} +#define OPAL_TIMING_ENV_GETDESC(file, func, index, desc) \ + OPAL_TIMING_ENV_GETDESC_PREFIX("", file, func, index, desc) #else @@ -201,9 +205,6 @@ OPAL_TIMING_ENV_GETDESC_PREFIX(char *prefix, char *func, int i, char **desc) #define OPAL_TIMING_ENV_INIT_PREFIX(prefix) -/* TODO: according to https://en.wikipedia.org/wiki/C99 - * varadic macroses are part of C99 and C11. Is it safe to use them here? - */ #define OPAL_TIMING_ENV_NEXT(h, fmt, ... ) #define OPAL_TIMING_ENV_CNT_PREFIX(prefix, func) @@ -214,6 +215,8 @@ OPAL_TIMING_ENV_GETDESC_PREFIX(char *prefix, char *func, int i, char **desc) #define OPAL_TIMING_ENV_GETDESC(func, index, desc) +#define OPAL_TIMING_ENV_ERROR_PREFIX(prefix, func) + #endif #endif