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 <karasev.b@gmail.com>
Этот коммит содержится в:
родитель
e3acf2a339
Коммит
36a0e71f2d
@ -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);
|
||||
|
||||
|
@ -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; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* 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++; \
|
||||
#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); \
|
||||
} \
|
||||
if( OMPI_TIMING_inum <= OMPI_TIMING_cnt ){ \
|
||||
printf("OMPI_TIMING [%s:%d %s]: interval count overflow!!\n", \
|
||||
ptr, __LINE__, __FUNCTION__); \
|
||||
abort(); \
|
||||
})
|
||||
|
||||
#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_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(); \
|
||||
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(); \
|
||||
}
|
||||
|
||||
#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; \
|
||||
#define OMPI_TIMING_IMPORT_OPAL_PREFIX(_prefix, func) { \
|
||||
if (!OMPI_TIMING.error && OMPI_TIMING.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; \
|
||||
OMPI_TIMING.error = OPAL_TIMING_ENV_ERROR_PREFIX(_prefix, func); \
|
||||
for(i = 0; i < cnt; i++){ \
|
||||
char *desc; \
|
||||
double ts = OPAL_TIMING_ENV_GETDESC(prefix, i, &desc); \
|
||||
OMPI_TIMING_APPEND(desc, ts); \
|
||||
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_IMPORT_OPAL(func) \
|
||||
OMPI_TIMING_IMPORT_OPAL_PREFIX("", func)
|
||||
|
||||
#define OMPI_TIMING_OUT { \
|
||||
|
||||
|
||||
#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); \
|
||||
char ename[1024]; \
|
||||
sprintf(ename, "OMPI_TIMING_%s", OMPI_TIMING_prefix); \
|
||||
char *ptr = getenv(ename); \
|
||||
int error = 0; \
|
||||
\
|
||||
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); \
|
||||
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++){ \
|
||||
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]); \
|
||||
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); \
|
||||
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
|
||||
|
@ -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,51 +39,43 @@ typedef struct {
|
||||
|
||||
opal_timing_ts_func_t opal_timing_ts_func(opal_timer_type_t type);
|
||||
|
||||
|
||||
/* 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_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; \
|
||||
})
|
||||
|
||||
#define OPAL_TIMING_ENV_INIT(name) \
|
||||
opal_timing_env_t name ## _val, *name = &(name ## _val); \
|
||||
@ -96,102 +89,113 @@ OPAL_TIMING_ENV_START_TYPE(char *func, opal_timer_type_t type, char *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);
|
||||
*name = OPAL_TIMING_ENV_START_TYPE(__FUNCTION__, OPAL_TIMING_AUTOMATIC_TIMER, prefix);
|
||||
|
||||
#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();
|
||||
}
|
||||
*/ \
|
||||
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_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; \
|
||||
})
|
||||
|
||||
#define OPAL_TIMING_ENV_CNT(func) \
|
||||
OPAL_TIMING_ENV_CNT_PREFIX("", char *func)
|
||||
OPAL_TIMING_ENV_CNT_PREFIX("", func)
|
||||
|
||||
/* 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_GETDESC(func, index, desc) \
|
||||
OPAL_TIMING_ENV_GETDESC_PREFIX("", func, index, desc)
|
||||
|
||||
#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); \
|
||||
#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); \
|
||||
} \
|
||||
int i; \
|
||||
for(i = 0; i < cnt; i++){ \
|
||||
char *desc; \
|
||||
double ts = OSHTMNG_ENV_GETBYIDX(prefix, i, &desc); \
|
||||
OSHTMNG_END1(desc, ts); \
|
||||
} \
|
||||
}
|
||||
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
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user