From 12fc7df0d1db56be5653bc2cefafeef33809e6bb Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Jun 2002 16:31:35 -0500 Subject: [svn-r5531] Purpose: Feature Add Description: Added support for testing only the "write" operations. Use the "-w" or "--write-only" flags for this. Platforms tested: Linux (parallel) & Modi4 (parallel) --- perform/pio_engine.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++---- perform/pio_perf.c | 179 +++++++++++++++++------------ perform/pio_perf.h | 1 + 3 files changed, 405 insertions(+), 91 deletions(-) diff --git a/perform/pio_engine.c b/perform/pio_engine.c index 928129c..3b65f85 100644 --- a/perform/pio_engine.c +++ b/perform/pio_engine.c @@ -117,8 +117,13 @@ static herr_t do_fclose(iotype iot, file_descr *fd); static void do_cleanupfile(iotype iot, char *fname); /* GPFS-specific functions */ +static void access_range(int handle, off_t start, off_t length, int is_write); +static void free_range(int handle, off_t start, off_t length); +static void clear_file_cache(int handle); +static void cancel_hints(int handle); static void start_data_shipping(int handle, int num_insts); static void stop_data_shipping(int handle); +static void invalidate_file_cache(const char *filename); /* * Function: do_pio @@ -265,30 +270,31 @@ do_pio(parameters param) set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, STOP); VRFY((hrc == SUCCESS), "do_fclose failed"); - MPI_Barrier(pio_comm_g); + if (!param.h5_write_only) { + /* + * Read performance measurement + */ + MPI_Barrier(pio_comm_g); - /* - * Read performance measurement - */ - /* Open file for read */ - set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, START); - hrc = do_fopen(¶m, fname, &fd, PIO_READ); + /* Open file for read */ + set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, START); + hrc = do_fopen(¶m, fname, &fd, PIO_READ); - VRFY((hrc == SUCCESS), "do_fopen failed"); + VRFY((hrc == SUCCESS), "do_fopen failed"); - set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, START); - hrc = do_read(&res, &fd, ¶m, ndsets, nelmts, blk_size, buf_size, buffer); - set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, STOP); - VRFY((hrc == SUCCESS), "do_read failed"); + set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, START); + hrc = do_read(&res, &fd, ¶m, ndsets, nelmts, blk_size, buf_size, buffer); + set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, STOP); + VRFY((hrc == SUCCESS), "do_read failed"); - /* Close file for read */ - hrc = do_fclose(iot, &fd); + /* Close file for read */ + hrc = do_fclose(iot, &fd); - set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, STOP); - VRFY((hrc == SUCCESS), "do_fclose failed"); + set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, STOP); + VRFY((hrc == SUCCESS), "do_fclose failed"); + } MPI_Barrier(pio_comm_g); - do_cleanupfile(iot, fname); } @@ -1374,6 +1380,197 @@ do_cleanupfile(iotype iot, char *fname) #ifdef H5_HAVE_GPFS + /* Descriptions here come from the IBM GPFS Manual */ + +/* + * Function: access_range + * Purpose: Declares an access range within a file for an + * application. + * + * The application will access file offsets within the given + * range, and will not access offsets outside the range. + * Violating this hint may produce worse performance than if + * no hint was specified. + * + * This hint is useful in situations where a file is + * partitioned coarsely among several nodes. If the ranges + * do not overlap, each node can specify which range of the + * file it will access, with a performance improvement in + * some cases, such as for sequential writing within a + * range. + * + * Subsequent GPFS_ACCESS_RANGE hints will replace a hint + * passed earlier. + * + * START - The start of the access range offset, in + * bytes, from the beginning of the file. + * LENGTH - Length of the access range. 0 indicates to + * the end of the file. + * Return: Nothing + * Programmer: Bill Wendling, 03. June 2002 + * Modifications: + */ +static void +access_range(int handle, off_t start, off_t length, int is_write) +{ + struct { + gpfsFcntlHeader_t hdr; + gpfsAccessRange_t access; + } access_range; + + access_range.hdr.totalLength = sizeof(access_range); + access_range.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + access_range.hdr.fcntlReserved = 0; + access_range.start.structLen = sizeof(gpfsAccessRange_t); + access_range.start.structType = GPFS_ACCESS_RANGE; + access_range.start.start = start; + access_range.start.length = length; + access_range.start.isWrite = is_write; + + if (gpfs_fcntl(handle, &access_range) != 0) { + fprintf(stderr, + "gpfs_fcntl DS start directive failed. errno=%d errorOffset=%d\n", + errno, ds_start.hdr.errorOffset); + exit(EXIT_FAILURE); + } +} + +/* + * Function: free_range + * Purpose: Undeclares an access range within a file for an + * application. + * + * The application will no longer access file offsets within + * the given range. GPFS flushes the data at the file + * offsets and removes it from the cache. + * + * Multi-node applications that have finished one phase of + * their computation may wish to use this hint before the + * file is accessed in a conflicting mode from another node + * in a later phase. The potential performance benefit is + * that GPFS can avoid later synchronous cache consistency + * operations. + * + * START - The start of the access range offset, in + * bytes from the beginning of the file. + * LENGTH - Length of the access range. 0 indicates to + * the end of the file. + * Return: Nothing + * Programmer: Bill Wendling, 03. June 2002 + * Modifications: + */ +static void +free_range(int handle, off_t start, off_t length) +{ + struct { + gpfsFcntlHeader_t hdr; + gpfsFreeRange_t range; + } free_range; + + /* Issue the invalidate hint */ + free_range.hdr.totalLength = sizeof(free_range); + free_range.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + free_range.hdr.fcntlReserved = 0; + free_range.range.structLen = sizeof(gpfsFreeRange_t); + free_range.range.structType = GPFS_FREE_RANGE; + free_range.range.start = start; + free_range.range.length = length; + + if (gpfs_fcntl(handle, &free_range) != 0) { + fprintf(stderr, + "gpfs_fcntl free range failed for range %d:%d. errno=%d errorOffset=%d\n", + start, length, errno, free_range.hdr.errorOffset); + exit(EXIT_FAILURE); + } +} + +/* + * Function: clear_file_cache + * Purpose: Indicates file access in the near future is not expected. + * + * The application does not expect to make any further + * accesses to the file in the near future, so GPFS removes + * any data or metadata pertaining to the file from its + * cache. + * + * Multi-node applications that have finished one phase of + * their computation may wish to use this hint before the + * file is accessed in a conflicting mode from another node + * in a later phase. The potential performance benefit is + * that GPFS can avoid later synchronous cache consistency + * operations. + * Return: Nothing + * Programmer: Bill Wendling, 03. June 2002 + * Modifications: + */ +static void +clear_file_cache(int handle) +{ + struct { + gpfsFcntlHeader_t hdr; + gpfsClearFileCache_t clear; + } clear_cache; + + clear_cache.hdr.totalLength = sizeof(clear_cache); + clear_cache.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + clear_cache.hdr.fcntlReserved = 0; + clear_cache.start.structLen = sizeof(gpfsClearFileCache_t); + clear_cache.start.structType = GPFS_CLEAR_FILE_CACHE; + + if (gpfs_fcntl(handle, &clear_cache) != 0) { + fprintf(stderr, + "gpfs_fcntl clear file cache directive failed. errno=%d errorOffset=%d\n", + errno, clear_cache.hdr.errorOffset); + exit(EXIT_FAILURE); + } +} + +/* + * Function: cancel_hints + * Purpose: Indicates to remove any hints against the open file + * handle. + * + * GPFS removes any hints that may have been issued against + * this open file handle: + * + * - The hint status of the file is restored ot what it + * would have been immediately after being opened, but + * does not affect the contents of the GPFS file + * cache. Cancelling an earlier hint that resulted in + * data being removed from the GPFS file cache does + * not bring that data back int othe cache; data + * re-enters the cache only pon access by the + * application or by user-driven or automatic + * prefetching. + * - Only the GPFS_MULTIPLE_ACCESS_RANGE hint has a + * state that might be removed by the + * GPFS_CANCEL_HINTS directive. + * Return: Nothing + * Programmer: Bill Wendling, 03. June 2002 + * Modifications: + */ +static void +cancel_hints(int handle) +{ + struct { + gpfsFcntlHeader_t hdr; + gpfsCancelHints_t cancel; + } cancel_hints; + + cancel_hints.hdr.totalLength = sizeof(cancel_hints); + cancel_hints.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + cancel_hints.hdr.fcntlReserved = 0; + cancel_hints.start.structLen = sizeof(gpfsCancelHints_t); + cancel_hints.start.structType = GPFS_CANCEL_HINTS; + + if (gpfs_fcntl(handle, &cancel_hints) != 0) { + fprintf(stderr, + "gpfs_fcntl cancel hints directive failed. errno=%d errorOffset=%d\n", + errno, ds_start.hdr.errorOffset); + exit(EXIT_FAILURE); + } +} + /* * Function: start_data_shipping * Purpose: Start up data shipping. The second parameter is the total @@ -1436,18 +1633,97 @@ stop_data_shipping(int handle) errno, ds_stop.hdr.errorOffset); } +/* + * Function: invalidate_file_cache + * Purpose: Invalidate all cached data held on behalf of a file on + * this node. + * Return: Nothing + * Programmer: Bill Wendling, 03. June 2002 + * Modifications: + */ +static void +invalidate_file_cache(const char *filename) +{ + int handle; + struct { + gpfsFcntlHeader_t hdr; + gpfsClearFileCache_t inv; + } inv_cache_hint; + + /* Open the file. If the open fails, the file cannot be cached. */ + handle = open(filename, O_RDONLY, 0); + + if (handle == -1) + return; + + /* Issue the invalidate hint */ + inv_cache_hint.hdr.totalLength = sizeof(inv_cache_hint); + inv_cache_hint.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + inv_cache_hint.hdr.fcntlReserved = 0; + inv_cache_hint.inv.structLen = sizeof(gpfsClearFileCache_t); + inv_cache_hint.inv.structType = GPFS_CLEAR_FILE_CACHE; + + if (gpfs_fcntl(handle, &inv_cache_hint) != 0) { + fprintf(stderr, + "gpfs_fcntl clear cache hint failed for file '%s'.", + filename); + fprintf(stderr, " errno=%d errorOffset=%d\n", + errno, inv_cache_hint.hdr.errorOffset); + exit(1); + } + + /* Close the file */ + if (close(handle) == -1) { + fprintf(stderr, + "could not close file '%s' after flushing file cache,", + filename); + fprintf(stderr, "errno=%d\n", errno); + exit(1); + } +} + #else -/* H5_HAVE_GPFS isn't defined */ +/* H5_HAVE_GPFS isn't defined...stub functions */ static void -start_data_shipping(int handle, int num_insts) +access_range(int UNUSED handle, off_t UNUSED start, off_t UNUSED length, int UNUSED is_write) { return; } static void -stop_data_shipping(int handle) +free_range(int UNUSED handle, off_t UNUSED start, off_t UNUSED length) +{ + return; +} + +static void +clear_file_cache(int UNUSED handle) +{ + return; +} + +static void +cancel_hints(int UNUSED handle) +{ + return; +} + +static void +start_data_shipping(int UNUSED handle, int UNUSED num_insts) +{ + return; +} + +static void +stop_data_shipping(int UNUSED handle) +{ + return; +} + +static void +invalidate_file_cache(const char UNUSED *filename) { return; } diff --git a/perform/pio_perf.c b/perform/pio_perf.c index 73ff4eb..9427888 100644 --- a/perform/pio_perf.c +++ b/perform/pio_perf.c @@ -79,6 +79,13 @@ /* report 0.0 in case t is zero too */ #define MB_PER_SEC(bytes,t) (((t)==0.0) ? 0.0 : ((((double)bytes) / ONE_MB) / (t))) +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ +#ifndef FALSE +#define FALSE (!TRUE) +#endif /* FALSE */ + /* global variables */ FILE *output; /* output file */ int comm_world_rank_g; /* my rank in MPI_COMM_RANK */ @@ -103,9 +110,9 @@ static const char *progname = "pio_perf"; * adding more, make sure that they don't clash with each other. */ #if 1 -static const char *s_opts = "ha:A:B:cD:f:P:p:X:x:nd:F:i:o:stT:"; +static const char *s_opts = "ha:A:B:cD:f:P:p:X:x:nd:F:i:o:stT:w"; #else -static const char *s_opts = "ha:A:bB:cD:f:P:p:X:x:nd:F:i:o:stT:"; +static const char *s_opts = "ha:A:bB:cD:f:P:p:X:x:nd:F:i:o:stT:w"; #endif /* 1 */ static struct long_options l_opts[] = { { "help", no_arg, 'h' }, @@ -222,6 +229,14 @@ static struct long_options l_opts[] = { { "thre", require_arg, 'T' }, { "thr", require_arg, 'T' }, { "th", require_arg, 'T' }, + { "write-only", require_arg, 'w' }, + { "write-onl", require_arg, 'w' }, + { "write-on", require_arg, 'w' }, + { "write-o", require_arg, 'w' }, + { "write", require_arg, 'w' }, + { "writ", require_arg, 'w' }, + { "wri", require_arg, 'w' }, + { "wr", require_arg, 'w' }, { NULL, 0, '\0' } }; @@ -243,6 +258,7 @@ struct options { off_t h5_threshold; /* threshold for alignment in HDF5 file */ int h5_use_chunks; /* Make HDF5 dataset chunked */ int h5_no_fill; /* Disable HDF5 writing fill values */ + int h5_write_only; /* Perform the write tests only */ }; typedef struct _minmax { @@ -380,6 +396,7 @@ run_test_loop(struct options *opts) parms.h5_thresh = opts->h5_threshold; parms.h5_use_chunks = opts->h5_use_chunks; parms.h5_no_fill = opts->h5_no_fill; + parms.h5_write_only = opts->h5_write_only; /* start with max_num_procs and decrement it by half for each loop. */ /* if performance needs restart, fewer processes may be needed. */ @@ -490,10 +507,13 @@ run_test(iotype iot, parameters parms, struct options *opts) write_mm_table = calloc(parms.num_iters , sizeof(minmax)); write_gross_mm_table = calloc(parms.num_iters , sizeof(minmax)); write_raw_mm_table = calloc(parms.num_iters , sizeof(minmax)); - read_mpi_mm_table = calloc(parms.num_iters , sizeof(minmax)); - read_mm_table = calloc(parms.num_iters , sizeof(minmax)); - read_gross_mm_table = calloc(parms.num_iters , sizeof(minmax)); - read_raw_mm_table = calloc(parms.num_iters , sizeof(minmax)); + + if (!parms.h5_write_only) { + read_mpi_mm_table = calloc(parms.num_iters , sizeof(minmax)); + read_mm_table = calloc(parms.num_iters , sizeof(minmax)); + read_gross_mm_table = calloc(parms.num_iters , sizeof(minmax)); + read_raw_mm_table = calloc(parms.num_iters , sizeof(minmax)); + } /* Do IO iteration times, collecting statistics each time */ for (i = 0; i < parms.num_iters; ++i) { @@ -526,29 +546,32 @@ run_test(iotype iot, parameters parms, struct options *opts) write_raw_mm_table[i] = write_raw_mm; - /* gather all of the "mpi read" times */ - t = get_time(res.timers, HDF5_MPI_READ); - get_minmax(&read_mpi_mm, t); + if (!parms.h5_write_only) { + /* gather all of the "mpi read" times */ + t = get_time(res.timers, HDF5_MPI_READ); + get_minmax(&read_mpi_mm, t); - read_mpi_mm_table[i] = read_mpi_mm; + read_mpi_mm_table[i] = read_mpi_mm; - /* gather all of the "read" times */ - t = get_time(res.timers, HDF5_FINE_READ_FIXED_DIMS); - get_minmax(&read_mm, t); + /* gather all of the "read" times */ + t = get_time(res.timers, HDF5_FINE_READ_FIXED_DIMS); + get_minmax(&read_mm, t); - read_mm_table[i] = read_mm; + read_mm_table[i] = read_mm; - /* gather all of the "read" times from open to close */ - t = get_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS); - get_minmax(&read_gross_mm, t); + /* gather all of the "read" times from open to close */ + t = get_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS); + get_minmax(&read_gross_mm, t); - read_gross_mm_table[i] = read_gross_mm; + read_gross_mm_table[i] = read_gross_mm; - /* gather all of the raw "read" times */ - t = get_time(res.timers, HDF5_RAW_READ_FIXED_DIMS); - get_minmax(&read_raw_mm, t); + /* gather all of the raw "read" times */ + t = get_time(res.timers, HDF5_RAW_READ_FIXED_DIMS); + get_minmax(&read_raw_mm, t); + + read_raw_mm_table[i] = read_raw_mm; + } - read_raw_mm_table[i] = read_raw_mm; pio_time_destroy(res.timers); } @@ -599,59 +622,67 @@ run_test(iotype iot, parameters parms, struct options *opts) output_results(opts,"Write Open-Close",write_gross_mm_table,parms.num_iters,raw_size); - /* Read statistics */ - /* Print the raw data throughput if desired */ - if(opts->print_raw) { - /* accumulate and output the max, min, and average "raw read" times */ + if (!parms.h5_write_only) { + /* Read statistics */ + /* Print the raw data throughput if desired */ + if (opts->print_raw) { + /* accumulate and output the max, min, and average "raw read" times */ + if (pio_debug_level >= 3) { + /* output all of the times for all iterations */ + print_indent(3); + output_report("Raw Data Read details:\n"); + output_all_info(read_raw_mm_table, parms.num_iters, 4); + } + + output_results(opts, "Raw Data Read", read_raw_mm_table, + parms.num_iters, raw_size); + } /* end if */ + + /* show mpi read statics */ if (pio_debug_level >= 3) { /* output all of the times for all iterations */ print_indent(3); - output_report("Raw Data Read details:\n"); - output_all_info(read_raw_mm_table, parms.num_iters, 4); + output_report("MPI Read details:\n"); + output_all_info(read_mpi_mm_table, parms.num_iters, 4); } - output_results(opts,"Raw Data Read",read_raw_mm_table,parms.num_iters,raw_size); - } /* end if */ + /* We don't currently output the MPI read results */ - /* show mpi read statics */ - if (pio_debug_level >= 3) { - /* output all of the times for all iterations */ - print_indent(3); - output_report("MPI Read details:\n"); - output_all_info(read_mpi_mm_table, parms.num_iters, 4); - } - - /* We don't currently output the MPI read results */ + /* accumulate and output the max, min, and average "read" times */ + if (pio_debug_level >= 3) { + /* output all of the times for all iterations */ + print_indent(3); + output_report("Read details:\n"); + output_all_info(read_mm_table, parms.num_iters, 4); + } - /* accumulate and output the max, min, and average "read" times */ - if (pio_debug_level >= 3) { - /* output all of the times for all iterations */ - print_indent(3); - output_report("Read details:\n"); - output_all_info(read_mm_table, parms.num_iters, 4); - } + output_results(opts, "Read", read_mm_table, parms.num_iters, raw_size); - output_results(opts,"Read",read_mm_table,parms.num_iters,raw_size); + /* accumulate and output the max, min, and average "gross read" times */ + if (pio_debug_level >= 3) { + /* output all of the times for all iterations */ + print_indent(3); + output_report("Read Open-Close details:\n"); + output_all_info(read_gross_mm_table, parms.num_iters, 4); + } - /* accumulate and output the max, min, and average "gross read" times */ - if (pio_debug_level >= 3) { - /* output all of the times for all iterations */ - print_indent(3); - output_report("Read Open-Close details:\n"); - output_all_info(read_gross_mm_table, parms.num_iters, 4); + output_results(opts, "Read Open-Close", read_gross_mm_table, + parms.num_iters, raw_size); } - output_results(opts,"Read Open-Close",read_gross_mm_table,parms.num_iters,raw_size); - /* clean up our mess */ free(write_mpi_mm_table); - free(read_mpi_mm_table); free(write_mm_table); - free(read_mm_table); free(write_gross_mm_table); - free(read_gross_mm_table); free(write_raw_mm_table); - free(read_raw_mm_table); + + if (!parms.h5_write_only) { + free(read_mpi_mm_table); + free(read_mm_table); + free(read_gross_mm_table); + free(read_raw_mm_table); + } + return ret_value; } @@ -1004,13 +1035,14 @@ parse_command_line(int argc, char *argv[]) cl_opts->min_num_procs = 1; cl_opts->max_xfer_size = 1 * ONE_MB; cl_opts->min_xfer_size = 128 * ONE_KB; - cl_opts->block_size = 0; /* no interleaved I/O */ - cl_opts->print_times = 0; /* Printing times is off by default */ - cl_opts->print_raw = 0; /* Printing raw data throughput is off by default */ - cl_opts->h5_alignment = 1; /* No alignment for HDF5 objects by default */ - cl_opts->h5_threshold = 1; /* No threshold for aligning HDF5 objects by default */ - cl_opts->h5_use_chunks = 0; /* Don't chunk the HDF5 dataset by default */ - cl_opts->h5_no_fill = 0; /* Write fill values by default */ + cl_opts->block_size = 0; /* no interleaved I/O */ + cl_opts->print_times = FALSE; /* Printing times is off by default */ + cl_opts->print_raw = FALSE; /* Printing raw data throughput is off by default */ + cl_opts->h5_alignment = 1; /* No alignment for HDF5 objects by default */ + cl_opts->h5_threshold = 1; /* No threshold for aligning HDF5 objects by default */ + cl_opts->h5_use_chunks = FALSE; /* Don't chunk the HDF5 dataset by default */ + cl_opts->h5_no_fill = FALSE; /* Write fill values by default */ + cl_opts->h5_write_only = FALSE; /* Do both read and write by default */ while ((opt = get_option(argc, (const char **)argv, s_opts, l_opts)) != EOF) { switch ((char)opt) { @@ -1059,8 +1091,9 @@ parse_command_line(int argc, char *argv[]) case 'B': cl_opts->block_size = parse_size_directive(opt_arg); break; - case 'c': /* Turn on chunked HDF5 dataset creation */ - cl_opts->h5_use_chunks = 1; + case 'c': + /* Turn on chunked HDF5 dataset creation */ + cl_opts->h5_use_chunks = TRUE; break; case 'd': cl_opts->num_dsets = atoi(opt_arg); @@ -1099,11 +1132,11 @@ parse_command_line(int argc, char *argv[]) switch (*buf) { case 'r': /* Turn on raw data throughput info */ - cl_opts->print_raw = 1; + cl_opts->print_raw = TRUE; break; case 't': /* Turn on time printing */ - cl_opts->print_times = 1; + cl_opts->print_times = TRUE; break; default: fprintf(stderr, "pio_perf: invalid --debug option %s\n", buf); @@ -1130,7 +1163,7 @@ parse_command_line(int argc, char *argv[]) break; case 'n': /* Turn off writing fill values */ #ifdef H5_HAVE_NOFILL - cl_opts->h5_no_fill = 1; + cl_opts->h5_no_fill = TRUE; #else fprintf(stderr, "pio_perf: --no-fill not supported\n"); usage(progname); @@ -1155,6 +1188,9 @@ parse_command_line(int argc, char *argv[]) case 'X': cl_opts->max_xfer_size = parse_size_directive(opt_arg); break; + case 'w': + cl_opts->h5_write_only = TRUE; + break; case 'h': case '?': default: @@ -1262,6 +1298,7 @@ usage(const char *prog) printf(" -p N, --min-num-processes=N Minimum number of processes to use [default: 1]\n"); printf(" -T S, --threshold=S Threshold for alignment of objects in HDF5 file\n"); printf(" [default: 1]\n"); + printf(" -w, --write-only Perform write tests not the read tests\n"); printf(" -X S, --max-xfer-size=S Maximum transfer buffer size [default: 1M]\n"); printf(" -x S, --min-xfer-size=S Minimum transfer buffer size [default: 128K]\n"); printf("\n"); diff --git a/perform/pio_perf.h b/perform/pio_perf.h index 89713c1..83ab7d9 100644 --- a/perform/pio_perf.h +++ b/perform/pio_perf.h @@ -36,6 +36,7 @@ typedef struct parameters_ { hsize_t h5_thresh; /* HDF5 object alignment threshold */ unsigned h5_use_chunks; /* Make HDF5 dataset chunked */ unsigned h5_no_fill; /* Disable HDF5 writing fill values */ + unsigned h5_write_only; /* Perform the write tests only */ } parameters; typedef struct results_ { -- cgit v0.12