/* * Copyright (c) 2021-2022 Triad National Security, LLC. * All rights reserved. * * Copyright (c) 2021 Nanook Consulting All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /* Timed test of basic fence with no data exchange (barrier) */ #include "pmix.h" #include "test_common.h" static int parse_fence_client(int *, int, char **, test_params *, validation_params *); static void client_help(char *binary) { fprintf(stderr, "Usage: %s [OPTION...]\n", binary); fprintf(stderr, " -h Display this message\n"); fprintf(stderr, " --time-fence Time the fence calls (best on a quiet system)\n"); fprintf(stderr, " (Default: off, specifying -m or -r also enables timing)\n"); fprintf(stderr, " -m num Fence time multiplier (similar to an error bar, default: 100)\n"); fprintf(stderr, " note: specifying -m activates fence timing (--time-fence)\n"); fprintf(stderr, " -r num Fence timeout ratio (used to calculate sleep time before fence calls, default: 100)\n"); fprintf(stderr, " note: specifying -r activates fence timing (--time-fence)\n"); /* fprintf(stderr, " -c fence[_nb] callback shall include all collected data\n"); fprintf(stderr, " -nb use non-blocking fence\n"); */ } // client-specific command parser logic static int parse_fence_client(int *index, int argc, char **argv, test_params *lparams, validation_params *v_params) { PMIX_HIDE_UNUSED_PARAMS(argc, v_params); if (0 == strcmp(argv[*index], "-h") || 0 == strcmp(argv[*index], "--help")) { // produce client-specific help client_help(argv[0]); exit(0); } else if (0 == strcmp(argv[*index], "--time-fence")) { lparams->time_fence = true; // multiplier for fence timeout threshold called 'fence timeout ratio' (1 of 2) } else if (0 == strcmp(argv[*index], "--fence-timeout-ratio") || 0 == strcmp(argv[*index], "-r") ) { (*index)++; lparams->time_fence = true; if (NULL != argv[*index]) { lparams->fence_timeout_ratio = strtod(argv[*index], NULL); } // multiplier for fence timeout threshold called 'fence time multiplier' (2 of 2) } else if (0 == strcmp(argv[*index], "--fence-time-multiplier") || 0 == strcmp(argv[*index], "-m") ) { (*index)++; lparams->time_fence = true; if (NULL != argv[*index]) { lparams->fence_time_multiplier = strtod(argv[*index], NULL); } } else { return PMIX_ERR_NOT_SUPPORTED; } return PMIX_SUCCESS; } int main(int argc, char *argv[]) { int rc; size_t ninfo = 0; test_params l_params; validation_params v_params; pmix_proc_t job_proc, this_proc; struct timeval start, end; unsigned long usecs_elapsed, sleep_time_ms; double secs_elapsed, fence_time, sleep_time, padded_fence_time; // pass in function pointer for custom argument processing, if no custom processing, will be null pmixt_pre_init(argc, argv, &l_params, &v_params, &parse_fence_client); /* initialization */ PMIXT_CHECK(PMIx_Init(&this_proc, NULL, ninfo), l_params, v_params); /* Handles everything that needs to happen after PMIx_Init() */ pmixt_post_init(&this_proc, &l_params, &v_params); PMIX_PROC_CONSTRUCT(&job_proc); PMIX_LOAD_NSPACE(job_proc.nspace, this_proc.nspace); job_proc.rank = PMIX_RANK_WILDCARD; if (l_params.time_fence) { // establishes baseline fence time before entering loop fence_time = avg_fence_time(); // padded_fence_time is the time permitted just for the fence call padded_fence_time = l_params.fence_time_multiplier * fence_time; sleep_time = l_params.fence_timeout_ratio * padded_fence_time; sleep_time_ms = (long)(sleep_time * 1000.0); TEST_VERBOSE(("Rank %d fence timeout ratio: %lf fence time multiplier: %lf", this_proc.rank, l_params.fence_timeout_ratio, l_params.fence_time_multiplier)); // Synchronize before timing rc = PMIx_Fence(NULL, 0, NULL, 0); if (0 != rc) { TEST_ERROR_EXIT(("PMIx_Fence Problem: ret val = %d", rc)); } if (0 == this_proc.rank){ sleep_ms(sleep_time_ms); } gettimeofday(&start, NULL); rc = PMIx_Fence(&job_proc, 1, NULL, 0); gettimeofday(&end, NULL); if (0 != rc) { TEST_ERROR_EXIT(("PMIx_Fence Problem: ret val = %d", rc)); } usecs_elapsed = ((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec)); secs_elapsed = (double) usecs_elapsed / 1E6; TEST_VERBOSE(("Rank %d fence time: %lf padded_fence_time: %lf sleep_time: %lf secs_elapsed: %lf", this_proc.rank, fence_time, padded_fence_time, sleep_time, secs_elapsed)); // secs_elapsed for rank 0 must be less than padded_fence_time if (0 == this_proc.rank) { if (secs_elapsed > padded_fence_time) { TEST_ERROR(("%s: PMIx_Fence timeout: Rank 0 elapsed fence time: %lf exceeded cutoff of: %lf", this_proc.nspace, secs_elapsed, padded_fence_time)); pmixt_exit(PMIX_ERR_TIMEOUT); } } else { // secs_elapsed for other ranks must be within sleep_time +/- padded_fence_time if (secs_elapsed < (sleep_time - padded_fence_time) ) { TEST_ERROR(("%s: PMIx_Fence failed: Rank %d did not wait for Rank 0," " elapsed time: %lf", this_proc.nspace, this_proc.rank, secs_elapsed)); pmixt_exit(PMIX_ERR_TIMEOUT); } else if (secs_elapsed > (sleep_time + padded_fence_time) ) { TEST_ERROR(("%s: PMIx_Fence timeout: Rank %d elapsed fence time: %lf exceeded cutoff of: %lf", this_proc.nspace, this_proc.rank, secs_elapsed, sleep_time + padded_fence_time)); pmixt_exit(PMIX_ERR_TIMEOUT); } } } else { rc = PMIx_Fence(&job_proc, 1, NULL, 0); if (0 != rc) { TEST_ERROR_EXIT(("PMIx_Fence Problem: ret val = %d", rc)); } } PMIX_PROC_DESTRUCT(&job_proc); /* finalize */ PMIXT_CHECK(PMIx_Finalize(NULL, 0), l_params, v_params); /* Handles cleanup */ pmixt_post_finalize(&this_proc, &l_params, &v_params); }