int main(int argc, char ** argv){ MPI_Init(&argc, &argv); // Default values struct args args; args.procs.nn = 0; args.procs.ppn = 0; args.dgeom_size = 0; args.dgeom = NULL; args.bgeom_size = 0; args.bgeom = NULL; args.cgeom_size = 0; args.cgeom = NULL; args.testfn = NULL; args.write_test = 0; args.read_test = 0; args.report_type = REPORT_HUMAN; args.par_access = NC_INDEPENDENT; args.is_unlimited = 0; args.verify = 0; args.fill_value = 0; char * dg = NULL, * bg = NULL, *cg = NULL, *iot = "ind", *xf = "human"; option_help options [] = { {'n' , "nn" , "Number of nodes" , OPTION_OPTIONAL_ARGUMENT , 'd' , & args.procs.nn} , {'p' , "ppn" , "Number of processes" , OPTION_OPTIONAL_ARGUMENT , 'd' , & args.procs.ppn} , {'d' , "data-geometry" , "Data geometry (t:x:y:z)" , OPTION_OPTIONAL_ARGUMENT , 's' , & dg} , {'b' , "block-geometry" , "Block geometry (t:x:y:z)" , OPTION_OPTIONAL_ARGUMENT , 's' , & bg} , {'c' , "chunk-geometry" , "Chunk geometry (t:x:y:z|auto)" , OPTION_OPTIONAL_ARGUMENT , 's' , & cg} , {'r' , "read" , "Enable read benchmark" , OPTION_FLAG , 'd' , & args.read_test} , {'w' , "write" , "Enable write benchmark" , OPTION_FLAG , 'd' , & args.write_test} , {'t' , "io-type" , "Independent / Collective I/O (ind|coll)" , OPTION_OPTIONAL_ARGUMENT , 's' , & iot} , {'u' , "unlimited" , "Enable unlimited time dimension" , OPTION_FLAG , 'd' , & args.is_unlimited} , {'f' , "testfile" , "Filename of the testfile" , OPTION_OPTIONAL_ARGUMENT , 's' , & args.testfn} , {'x' , "output-format" , "Output-Format (parser|human)" , OPTION_OPTIONAL_ARGUMENT , 's' , & xf} , {'F' , "use-fill-value" , "Write a fill value" , OPTION_FLAG , 'd', & args.fill_value} , {0 , "verify" , "Verify that the data read is correct (reads the data again)", OPTION_FLAG , 'd' , & args.verify} , LAST_OPTION }; int rank; MPI_Comm_rank(MPI_COMM_WORLD, & rank); // check the correctness of the options only for rank 0 if (rank == 0){ printf("Benchtool (datatype: %s) \n", xstr(DATATYPE)); parseOptions(argc, argv, options); } MPI_Barrier(MPI_COMM_WORLD); if (rank != 0){ parseOptions(argc, argv, options); } parse_dims(dg, &args.dgeom, &args.dgeom_size); parse_dims(bg, &args.bgeom, &args.bgeom_size); if ((0 == strcmp(iot, "c")) | (0 == strcmp(iot, "coll")) | (0 == strcmp(iot,"collective"))) { args.par_access = NC_COLLECTIVE; } else if ((0 == strcmp(iot, "i")) | (0 == strcmp(iot, "ind")) | (0 == strcmp(iot, "independent"))) { args.par_access = NC_INDEPENDENT; } else { FATAL_ERR("Unsupported parallel access type %s\n", xf); } if (0 == strcmp(xf, "parser")) { args.report_type = REPORT_PARSER; }else if (0 == strcmp(xf, "human")) { args.report_type = REPORT_HUMAN; }else{ FATAL_ERR("Unsupported report type %s\n", xf); } if (0 == args.procs.nn) { char *end = NULL; const char* env = getenv("SLURM_NNODES"); if (NULL != env) { args.procs.nn = strtol(env, &end, 10); } if (0 == args.procs.nn) { args.procs.nn = 1; } } if (0 == args.procs.ppn) { char *end = NULL; const char* env = getenv("SLURM_NTASKS_PER_NODE"); if (NULL != env) { args.procs.ppn = strtol(env, &end, 10); } if (0 == args.procs.ppn) { args.procs.ppn = 1; } } if (NULL == args.testfn) { const char* testfn = "./testfn.nc"; args.testfn = (char*)malloc(sizeof(*args.testfn) * strlen(testfn) + 1); strcpy(args.testfn, testfn); } if (NULL == args.dgeom) { args.dgeom_size = NDIMS; args.dgeom = (size_t*)malloc(sizeof(*args.dgeom) * args.dgeom_size); args.dgeom[DT] = 100; args.dgeom[DX] = args.procs.nn * 100; args.dgeom[DY] = args.procs.ppn * 100; args.dgeom[DZ] = 10; } if (NDIMS != args.dgeom_size) { FATAL_ERR("Found %zu dimensions (expected %d).\n", args.dgeom_size, NDIMS); } // Automatic block layout if (NULL == args.bgeom) { args.bgeom_size = args.dgeom_size; args.bgeom = (size_t*)malloc(sizeof(*args.bgeom) * args.bgeom_size); args.bgeom[DT] = 1; args.bgeom[DX] = args.dgeom[DX] / args.procs.nn; args.bgeom[DY] = args.dgeom[DY] / args.procs.ppn; args.bgeom[DZ] = args.dgeom[DZ]; } if (cg != NULL && 0 == strcmp(cg, "auto")) { args.cgeom_size = args.bgeom_size; args.cgeom = (size_t*)malloc(sizeof(*args.cgeom) * args.cgeom_size); args.cgeom[DT] = 1; args.cgeom[DX] = args.bgeom[DX]; args.cgeom[DY] = args.bgeom[DY]; args.cgeom[DZ] = args.bgeom[DZ]; } else { parse_dims(cg, &args.cgeom, &args.cgeom_size); } if (NDIMS != args.bgeom_size) { FATAL_ERR("Found %zu dimensions (expected %d).\n", args.bgeom_size, NDIMS); } if (NULL != args.cgeom) { if (NDIMS != args.cgeom_size) { FATAL_ERR("Found %zu dimensions (expected %d).\n", args.cgeom_size, NDIMS); } } DEBUG_MESSAGE("dgeom (%zu:%zu:%zu:%zu)\n", args.dgeom[DT], args.dgeom[DX], args.dgeom[DY], args.dgeom[DZ]); DEBUG_MESSAGE("bgeom (%zu:%zu:%zu:%zu)\n", args.bgeom[DT], args.bgeom[DX], args.bgeom[DY], args.bgeom[DZ]); if (NULL != args.cgeom) { DEBUG_MESSAGE("cgeom (%zu:%zu:%zu:%zu)\n", args.cgeom[DT], args.cgeom[DX], args.cgeom[DY], args.cgeom[DZ]); } DEBUG_MESSAGE("(nn %zu, ppn %zu)\n", args.procs.nn, args.procs.ppn); DEBUG_MESSAGE("test filename %s\n", args.testfn); if (args.dgeom[DX] % args.procs.nn != 0) { FATAL_ERR("x must be a multiple of number of nodes.\n"); } if (args.dgeom[DY] % args.procs.ppn != 0) { FATAL_ERR("y must be a multiple of number of processes.\n"); } if (NULL != args.cgeom) { if (args.dgeom[DT] % args.cgeom[DT] != 0) { FATAL_ERR("Time range must be a multiple of time slice (range=%zu; slice=%zu)\n", args.dgeom[DT], args.cgeom[DT]); } } int nranks = 0; MPI_Comm_size(MPI_COMM_WORLD, &nranks); if (nranks != args.procs.nn * args.procs.ppn){ FATAL_ERR("Bad environment: np != nn * ppn; np(size of MPI_COMM_WORLD)=%d, nodes(nn)=%zu, ppn(procs per node)=%zu\n", nranks, args.procs.nn, args.procs.ppn); } if ((args.read_test == false) & (args.write_test == false) & (args.verify == false)) { args.write_test = true; } benchmark_t wbm; benchmark_init(&wbm); int header_printed = 0; benchmark_t rbm; benchmark_init(&rbm); if (args.write_test || args.verify) { benchmark_setup(&wbm, args.procs, NDIMS, args.dgeom, args.bgeom, args.cgeom, args.testfn, IO_MODE_WRITE, args.par_access, args.is_unlimited, args.fill_value); if(rank == 0){ print_header(& wbm); header_printed = 1; } } if (args.write_test) { benchmark_run(&wbm, NULL); report_t report; report_init(&report); report_setup(&report, &wbm); report_print(&report, args.report_type); report_destroy(&report); } if (args.read_test) { int ret; benchmark_setup(&rbm, args.procs, NDIMS, args.dgeom, args.bgeom, args.cgeom, args.testfn, IO_MODE_READ, args.par_access, args.is_unlimited, 0); if(rank == 0 && ! header_printed){ print_header(& rbm); header_printed = 1; } ret = benchmark_run(&rbm, args.verify ? wbm.block : NULL ); report_t report; report_init(&report); report_setup(&report, &rbm); report_print(&report, args.report_type); report_destroy(&report); }else if (args.verify) { int ret; benchmark_setup(& rbm, args.procs, NDIMS, args.dgeom, args.bgeom, args.cgeom, args.testfn, IO_MODE_READ, args.par_access, args.is_unlimited, 0); if(rank == 0 && ! header_printed){ print_header(& rbm); header_printed = 1; } ret = benchmark_run(& rbm, wbm.block); if (args.verify){ if (ret) { printf("TEST PASSED [%u]\n", wbm.rank); } else { printf("TEST FAILED [%u]\n", wbm.rank); } } } MPI_Finalize(); benchmark_destroy(&wbm); benchmark_destroy(&rbm); free(args.dgeom); free(args.bgeom); free(args.cgeom); free(args.testfn); return 0; }
void args_handle(config *cfg, int argc, char **argv) { int fl; while ((fl = getopt(argc, argv, "Acd:fhl:m:rsSx")) != -1) { switch (fl) { case 'A': /* no axis */ cfg->axis = false; break; case 'c': /* use colorblind-safe default colors */ cfg->colorblind = true; break; case 'd': /* dimensions */ parse_dims(cfg, optarg); break; case 'f': /* flip x/y */ cfg->flip_xy = true; break; case 'h': /* help */ usage(NULL); break; case 'l': /* log */ if (strchr(optarg, 'x')) { cfg->log_x = true; } if (strchr(optarg, 'y')) { cfg->log_y = true; } if (strchr(optarg, 'c')) { cfg->log_count = true; } break; case 'm': /* mode */ switch (optarg[0]) { case 'c': cfg->mode = MODE_COUNT; break; case 'd': cfg->mode = MODE_DOT; break; case 'l': cfg->mode = MODE_LINE; break; default: usage("Bad argument to -m: must be 'count', 'dot', or 'line'."); } break; case 'r': /* linear regression */ cfg->regression = true; break; case 's': /* SVG */ cfg->plot_type = PLOT_SVG; break; case 'S': /* disable stream mode */ cfg->stream_mode = false; break; case 'x': /* col 0 is X value */ cfg->x_column = true; break; case '?': default: usage(NULL); } } argc -= (optind - 1); argv += (optind - 1); if (argc > 1) { cfg->in_path = argv[1]; if (0 != strcmp("-", cfg->in_path)) { cfg->in = fopen(cfg->in_path, "r"); if (cfg->in == NULL) { err(1, "fopen"); } } } if (cfg->plot_type == PLOT_SVG) { init_svg(cfg); } else { init_ascii(cfg); } }