1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * All rights reserved.                                                      *
4  *                                                                           *
5  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6  * terms governing use, modification, and redistribution, is contained in    *
7  * the COPYING file, which can be found at the root of the source code       *
8  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
9  * If you do not have access to either file, you may request a copy from     *
10  * help@hdfgroup.org.                                                        *
11  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12 
13 /*
14  * Serial HDF5 Performance Testing Code
15  * --------------------------------------
16  *
17  * Portable code to test performance on the different platforms we support.
18  * This is what the report should look like:
19  *
20  *  nprocs = Max#Procs
21  *      IO API = POSIXIO
22  *          # Files = 1, # of dsets = 1000, Elements per dset = 37000
23  *              Write Results = x MB/s
24  *              Read Results = x MB/s
25  *          # Files = 1, # of dsets = 3000, Elements per dset = 37000
26  *              Write Results = x MB/s
27  *              Read Results = x MB/s
28  *
29  *          . . .
30  *
31  *
32  *      IO API = HDF5
33  *          # Files = 1, # of dsets = 1000, Elements per dset = 37000
34  *              Write Results = x MB/s
35  *              Read Results = x MB/s
36  *          # Files = 1, # of dsets = 3000, Elements per dset = 37000
37  *              Write Results = x MB/s
38  *              Read Results = x MB/s
39  *
40  *          . . .
41  *
42  *
43  *      . . .
44  *
45  */
46 
47 /* system header files */
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 
52 #include "hdf5.h"
53 
54 
55 /* our header files */
56 #include "sio_perf.h"
57 
58 /* useful macros */
59 #define TAB_SPACE           4
60 
61 #define ONE_KB              1024
62 #define ONE_MB              (ONE_KB * ONE_KB)
63 #define ONE_GB              (ONE_MB * ONE_KB)
64 
65 #define SIO_POSIX           0x1
66 #define SIO_HDF5            0x4
67 
68 /* report 0.0 in case t is zero too */
69 #define MB_PER_SEC(bytes,t) (H5_DBL_ABS_EQUAL(t, (double)0.0F) ? (double)0.0F : ((((double)bytes) / (double)ONE_MB) / (t)))
70 
71 #ifndef TRUE
72 #define TRUE    1
73 #endif  /* TRUE */
74 #ifndef FALSE
75 #define FALSE   (!TRUE)
76 #endif  /* FALSE */
77 
78 /* global variables */
79 FILE       *output;             /* output file                          */
80 int         sio_debug_level = 0;/* The debug level:
81                                  *   0 - Off
82                                  *   1 - Minimal
83                                  *   2 - Some more
84                                  *   3 - Maximal
85                                  *   4 - Maximal & then some
86                                  */
87 
88 /* local variables */
89 static const char  *progname = "h5perf_serial";
90 
91 /*
92  * Command-line options: The user can specify short or long-named
93  * parameters. The long-named ones can be partially spelled. When
94  * adding more, make sure that they don't clash with each other.
95  */
96 
97 /*
98  * It seems that only the options that accept additional information
99  * such as dataset size (-e) require the colon next to it.
100  */
101 #if 1
102 static const char *s_opts = "a:A:B:c:Cd:D:e:F:ghi:Imno:p:P:r:stT:v:wx:X:";
103 #else
104 static const char *s_opts = "a:A:bB:c:Cd:D:e:F:ghi:Imno:p:P:r:stT:wx:X:";
105 #endif  /* 1 */
106 static struct long_options l_opts[] = {
107     { "align", require_arg, 'a' },
108     { "alig", require_arg, 'a' },
109     { "ali", require_arg, 'a' },
110     { "al", require_arg, 'a' },
111     { "api", require_arg, 'A' },
112     { "ap", require_arg, 'A' },
113 #if 0
114     /* a sighting of the elusive binary option */
115     { "binary", no_arg, 'b' },
116     { "binar", no_arg, 'b' },
117     { "bina", no_arg, 'b' },
118     { "bin", no_arg, 'b' },
119     { "bi", no_arg, 'b' },
120 #endif  /* 0 */
121     { "block-size", require_arg, 'B' },
122     { "block-siz", require_arg, 'B' },
123     { "block-si", require_arg, 'B' },
124     { "block-s", require_arg, 'B' },
125     { "block-", require_arg, 'B' },
126     { "block", require_arg, 'B' },
127     { "bloc", require_arg, 'B' },
128     { "blo", require_arg, 'B' },
129     { "bl", require_arg, 'B' },
130     { "chunk", no_arg, 'c' },
131     { "chun", no_arg, 'c' },
132     { "chu", no_arg, 'c' },
133     { "ch", no_arg, 'c' },
134     { "collective", no_arg, 'C' },
135     { "collectiv", no_arg, 'C' },
136     { "collecti", no_arg, 'C' },
137     { "collect", no_arg, 'C' },
138     { "collec", no_arg, 'C' },
139     { "colle", no_arg, 'C' },
140     { "coll", no_arg, 'C' },
141     { "col", no_arg, 'C' },
142     { "co", no_arg, 'C' },
143     { "debug", require_arg, 'D' },
144     { "debu", require_arg, 'D' },
145     { "deb", require_arg, 'D' },
146     { "de", require_arg, 'D' },
147     { "file-driver", require_arg, 'v' },
148     { "file-drive", require_arg, 'v' },
149     { "file-driv", require_arg, 'v' },
150     { "file-dri", require_arg, 'v' },
151     { "file-dr", require_arg, 'v' },
152     { "file-d", require_arg, 'v' },
153     { "file-", require_arg, 'v' },
154     { "file", require_arg, 'v' },
155     { "fil", require_arg, 'v' },
156     { "fi", require_arg, 'v' },
157     { "geometry", no_arg, 'g' },
158     { "geometr", no_arg, 'g' },
159     { "geomet", no_arg, 'g' },
160     { "geome", no_arg, 'g' },
161     { "geom", no_arg, 'g' },
162     { "geo", no_arg, 'g' },
163     { "ge", no_arg, 'g' },
164     { "help", no_arg, 'h' },
165     { "hel", no_arg, 'h' },
166     { "he", no_arg, 'h' },
167     { "interleaved", require_arg, 'I' },
168     { "interleave", require_arg, 'I' },
169     { "interleav", require_arg, 'I' },
170     { "interlea", require_arg, 'I' },
171     { "interle", require_arg, 'I' },
172     { "interl", require_arg, 'I' },
173     { "inter", require_arg, 'I' },
174     { "inte", require_arg, 'I' },
175     { "int", require_arg, 'I' },
176     { "in", require_arg, 'I' },
177     { "max-num-processes", require_arg, 'P' },
178     { "max-num-processe", require_arg, 'P' },
179     { "max-num-process", require_arg, 'P' },
180     { "max-num-proces", require_arg, 'P' },
181     { "max-num-proce", require_arg, 'P' },
182     { "max-num-proc", require_arg, 'P' },
183     { "max-num-pro", require_arg, 'P' },
184     { "max-num-pr", require_arg, 'P' },
185     { "max-num-p", require_arg, 'P' },
186     { "min-num-processes", require_arg, 'p' },
187     { "min-num-processe", require_arg, 'p' },
188     { "min-num-process", require_arg, 'p' },
189     { "min-num-proces", require_arg, 'p' },
190     { "min-num-proce", require_arg, 'p' },
191     { "min-num-proc", require_arg, 'p' },
192     { "min-num-pro", require_arg, 'p' },
193     { "min-num-pr", require_arg, 'p' },
194     { "min-num-p", require_arg, 'p' },
195     { "max-xfer-size", require_arg, 'X' },
196     { "max-xfer-siz", require_arg, 'X' },
197     { "max-xfer-si", require_arg, 'X' },
198     { "max-xfer-s", require_arg, 'X' },
199     { "max-xfer", require_arg, 'X' },
200     { "max-xfe", require_arg, 'X' },
201     { "max-xf", require_arg, 'X' },
202     { "max-x", require_arg, 'X' },
203     { "min-xfer-size", require_arg, 'x' },
204     { "min-xfer-siz", require_arg, 'x' },
205     { "min-xfer-si", require_arg, 'x' },
206     { "min-xfer-s", require_arg, 'x' },
207     { "min-xfer", require_arg, 'x' },
208     { "min-xfe", require_arg, 'x' },
209     { "min-xf", require_arg, 'x' },
210     { "min-x", require_arg, 'x' },
211     { "num-bytes", require_arg, 'e' },
212     { "num-byte", require_arg, 'e' },
213     { "num-byt", require_arg, 'e' },
214     { "num-by", require_arg, 'e' },
215     { "num-b", require_arg, 'e' },
216     { "num-dsets", require_arg, 'd' },
217     { "num-dset", require_arg, 'd' },
218     { "num-dse", require_arg, 'd' },
219     { "num-ds", require_arg, 'd' },
220     { "num-d", require_arg, 'd' },
221     { "num-files", require_arg, 'F' },
222     { "num-file", require_arg, 'F' },
223     { "num-fil", require_arg, 'F' },
224     { "num-fi", require_arg, 'F' },
225     { "num-f", require_arg, 'F' },
226     { "num-iterations", require_arg, 'i' },
227     { "num-iteration", require_arg, 'i' },
228     { "num-iteratio", require_arg, 'i' },
229     { "num-iterati", require_arg, 'i' },
230     { "num-iterat", require_arg, 'i' },
231     { "num-itera", require_arg, 'i' },
232     { "num-iter", require_arg, 'i' },
233     { "num-ite", require_arg, 'i' },
234     { "num-it", require_arg, 'i' },
235     { "num-i", require_arg, 'i' },
236     { "order", require_arg, 'r' },
237     { "orde", require_arg, 'r' },
238     { "ord", require_arg, 'r' },
239     { "or", require_arg, 'r' },
240     { "output", require_arg, 'o' },
241     { "outpu", require_arg, 'o' },
242     { "outp", require_arg, 'o' },
243     { "out", require_arg, 'o' },
244     { "ou", require_arg, 'o' },
245     { "extendable", no_arg, 't' },
246     { "extendabl", no_arg, 't' },
247     { "extendab", no_arg, 't' },
248     { "extenda", no_arg, 't' },
249     { "extend", no_arg, 't' },
250     { "exten", no_arg, 't' },
251     { "exte", no_arg, 't' },
252     { "ext", no_arg, 't' },
253     { "ex", no_arg, 't' },
254     { "threshold", require_arg, 'T' },
255     { "threshol", require_arg, 'T' },
256     { "thresho", require_arg, 'T' },
257     { "thresh", require_arg, 'T' },
258     { "thres", require_arg, 'T' },
259     { "thre", require_arg, 'T' },
260     { "thr", require_arg, 'T' },
261     { "th", require_arg, 'T' },
262     { "write-only", require_arg, 'w' },
263     { "write-onl", require_arg, 'w' },
264     { "write-on", require_arg, 'w' },
265     { "write-o", require_arg, 'w' },
266     { "write", require_arg, 'w' },
267     { "writ", require_arg, 'w' },
268     { "wri", require_arg, 'w' },
269     { "wr", require_arg, 'w' },
270     { NULL, 0, '\0' }
271 };
272 
273 struct options {
274     long io_types;              /* bitmask of which I/O types to test   */
275     const char *output_file;    /* file to print report to              */
276     long num_dsets;             /* number of datasets                   */
277     long num_files;             /* number of files                      */
278     off_t num_bpp;              /* number of bytes per proc per dset    */
279     int num_iters;              /* number of iterations                 */
280     off_t dset_size[MAX_DIMS];  /* Dataset size                           */
281     size_t buf_size[MAX_DIMS];  /* Buffer size                           */
282     size_t chk_size[MAX_DIMS];  /* Chunk size                           */
283     int order[MAX_DIMS];  /* Dimension access order                           */
284     int dset_rank;             /* Rank                   */
285     int buf_rank;             /* Rank                   */
286     int order_rank;             /* Rank                   */
287     int chk_rank;             /* Rank                   */
288     int print_times;       	/* print times as well as throughputs   */
289     int print_raw;         	/* print raw data throughput info       */
290     off_t h5_alignment;         /* alignment in HDF5 file               */
291     off_t h5_threshold;         /* threshold for alignment in HDF5 file */
292     int h5_use_chunks;     	/* Make HDF5 dataset chunked            */
293     int h5_write_only;        	/* Perform the write tests only         */
294     int h5_extendable;        	/* Perform the write tests only         */
295     int verify;        		/* Verify data correctness              */
296     vfdtype     vfd;            /* File driver */
297 
298 };
299 
300 typedef struct _minmax {
301     double min;
302     double max;
303     double sum;
304     int num;
305 } minmax;
306 
307 /* local functions */
308 static off_t parse_size_directive(const char *size);
309 static struct options *parse_command_line(int argc, char *argv[]);
310 static void run_test_loop(struct options *options);
311 static int run_test(iotype iot, parameters parms, struct options *opts);
312 static void output_all_info(minmax *mm, int count, int indent_level);
313 static void get_minmax(minmax *mm, double val);
314 static minmax accumulate_minmax_stuff(minmax *mm, int count);
315 static void output_results(const struct options *options, const char *name,
316                            minmax *table, int table_size, off_t data_size);
317 static void output_report(const char *fmt, ...);
318 static void print_indent(register int indent);
319 static void usage(const char *prog);
320 static void report_parameters(struct options *opts);
321 
322 /*
323  * Function:    main
324  * Purpose:     Start things up.
325  * Return:      EXIT_SUCCESS or EXIT_FAILURE
326  * Programmer:  Bill Wendling, 30. October 2001
327  * Modifications:
328  */
329 int
main(int argc,char ** argv)330 main(int argc, char **argv)
331 {
332     int exit_value = EXIT_SUCCESS;
333     struct options *opts = NULL;
334 
335 #ifndef STANDALONE
336     /* Initialize h5tools lib */
337     h5tools_init();
338 #endif
339 
340     output = stdout;
341 
342     opts = parse_command_line(argc, argv);
343 
344     if (!opts) {
345         exit_value = EXIT_FAILURE;
346         goto finish;
347     }
348 
349     if (opts->output_file) {
350         if ((output = HDfopen(opts->output_file, "w")) == NULL) {
351             fprintf(stderr, "%s: cannot open output file\n", progname);
352             perror(opts->output_file);
353             goto finish;
354         }
355     }
356 
357     report_parameters(opts);
358 
359     run_test_loop(opts);
360 
361 finish:
362     free(opts);
363     return exit_value;
364 }
365 
366 /*
367  * Function:    run_test_loop
368  * Purpose:     Run the I/O tests. Write the results to OUTPUT.
369  *
370  *            - The slowest changing part of the test is the number of
371  *              processors to use. For each loop iteration, we divide that
372  *              number by 2 and rerun the test.
373  *
374  *            - The second slowest is what type of IO API to perform. We have
375  *              three choices: POSIXIO, and HDF5.
376  *
377  *            - Then we change the size of the buffer. This information is
378  *              inferred from the number of datasets to create and the number
379  *              of integers to put into each dataset. The backend code figures
380  *              this out.
381  *
382  * Return:      Nothing
383  * Programmer:  Bill Wendling, 30. October 2001
384  * Modifications:
385  *    Added multidimensional testing (Christian Chilan, April, 2008)
386  */
387 static void
run_test_loop(struct options * opts)388 run_test_loop(struct options *opts)
389 {
390     parameters parms;
391     int i;
392     size_t      buf_bytes;
393 
394     /* load options into parameter structure */
395     parms.num_files = opts->num_files;
396     parms.num_dsets = opts->num_dsets;
397     parms.num_iters = opts->num_iters;
398     parms.rank = opts->dset_rank;
399     parms.h5_align = opts->h5_alignment;
400     parms.h5_thresh = opts->h5_threshold;
401     parms.h5_use_chunks = opts->h5_use_chunks;
402     parms.h5_extendable = opts->h5_extendable;
403     parms.h5_write_only = opts->h5_write_only;
404     parms.verify = opts->verify;
405     parms.vfd = opts->vfd;
406 
407     /* load multidimensional options */
408     parms.num_bytes = 1;
409     buf_bytes = 1;
410     for (i=0; i<parms.rank; i++){
411         parms.buf_size[i] = opts->buf_size[i];
412         parms.dset_size[i] = opts->dset_size[i];
413         parms.chk_size[i] = opts->chk_size[i];
414         parms.order[i] = opts->order[i];
415         parms.num_bytes *= opts->dset_size[i];
416         buf_bytes *= opts->buf_size[i];
417     }
418 
419     /* print size information */
420     output_report("Transfer Buffer Size (bytes): %d\n", buf_bytes);
421     output_report("File Size(MB): %.2f\n",((double)parms.num_bytes) / ONE_MB);
422 
423     print_indent(0);
424     if (opts->io_types & SIO_POSIX)
425         run_test(POSIXIO, parms, opts);
426 
427     print_indent(0);
428     if (opts->io_types & SIO_HDF5)
429         run_test(HDF5, parms, opts);
430 }
431 
432 /*
433  * Function:    run_test
434  * Purpose:     Inner loop call to actually run the I/O test.
435  * Return:      Nothing
436  * Programmer:  Bill Wendling, 18. December 2001
437  * Modifications:
438  */
439 static int
run_test(iotype iot,parameters parms,struct options * opts)440 run_test(iotype iot, parameters parms, struct options *opts)
441 {
442     results         res;
443     register int    i, ret_value = SUCCESS;
444     off_t           raw_size;
445     minmax         *write_sys_mm_table=NULL;
446     minmax         *write_mm_table=NULL;
447     minmax         *write_gross_mm_table=NULL;
448     minmax         *write_raw_mm_table=NULL;
449     minmax         *read_sys_mm_table=NULL;
450     minmax         *read_mm_table=NULL;
451     minmax         *read_gross_mm_table=NULL;
452     minmax         *read_raw_mm_table=NULL;
453     minmax          write_sys_mm = {0.0F, 0.0F, 0.0F, 0};
454     minmax          write_mm = {0.0F, 0.0F, 0.0F, 0};
455     minmax          write_gross_mm = {0.0F, 0.0F, 0.0F, 0};
456     minmax          write_raw_mm = {0.0F, 0.0F, 0.0F, 0};
457     minmax          read_sys_mm = {0.0F, 0.0F, 0.0F, 0};
458     minmax          read_mm = {0.0F, 0.0F, 0.0F, 0};
459     minmax          read_gross_mm = {0.0F, 0.0F, 0.0F, 0};
460     minmax          read_raw_mm = {0.0F, 0.0F, 0.0F, 0};
461 
462     raw_size = (off_t)parms.num_bytes;
463     parms.io_type = iot;
464     print_indent(2);
465     output_report("IO API = ");
466 
467     switch (iot) {
468         case POSIXIO:
469             output_report("POSIX\n");
470             break;
471         case HDF5:
472             output_report("HDF5\n");
473             break;
474         default:
475             /* unknown request */
476             HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)iot);
477             HDassert(0 && "Unknown IO tpe");
478             break;
479     }
480 
481     /* allocate space for tables minmax and that it is sufficient */
482     /* to initialize all elements to zeros by calloc.             */
483     write_sys_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
484     write_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
485     write_gross_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
486     write_raw_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
487 
488     if (!parms.h5_write_only) {
489         read_sys_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
490         read_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
491         read_gross_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
492         read_raw_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
493     }
494 
495     /* Do IO iteration times, collecting statistics each time */
496     for (i = 0; i < parms.num_iters; ++i) {
497         double t;
498         res = do_sio(parms);
499 
500         /* gather all of the "sys write" times */
501         t = get_time(res.timers, HDF5_MPI_WRITE);
502         get_minmax(&write_sys_mm, t);
503 
504         write_sys_mm_table[i] = write_sys_mm;
505 
506         /* gather all of the "write" times */
507         t = get_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS);
508         get_minmax(&write_mm, t);
509 
510         write_mm_table[i] = write_mm;
511 
512         /* gather all of the "write" times from open to close */
513         t = get_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS);
514         get_minmax(&write_gross_mm, t);
515 
516         write_gross_mm_table[i] = write_gross_mm;
517 
518         /* gather all of the raw "write" times */
519         t = get_time(res.timers, HDF5_RAW_WRITE_FIXED_DIMS);
520         get_minmax(&write_raw_mm, t);
521 
522         write_raw_mm_table[i] = write_raw_mm;
523 
524         if (!parms.h5_write_only) {
525             /* gather all of the "mpi read" times */
526             t = get_time(res.timers, HDF5_MPI_READ);
527             get_minmax(&read_sys_mm, t);
528 
529             read_sys_mm_table[i] = read_sys_mm;
530 
531             /* gather all of the "read" times */
532             t = get_time(res.timers, HDF5_FINE_READ_FIXED_DIMS);
533             get_minmax(&read_mm, t);
534 
535             read_mm_table[i] = read_mm;
536 
537             /* gather all of the "read" times from open to close */
538             t = get_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS);
539             get_minmax(&read_gross_mm, t);
540 
541             read_gross_mm_table[i] = read_gross_mm;
542 
543             /* gather all of the raw "read" times */
544             t = get_time(res.timers, HDF5_RAW_READ_FIXED_DIMS);
545             get_minmax(&read_raw_mm, t);
546 
547             read_raw_mm_table[i] = read_gross_mm;
548         }
549         io_time_destroy(res.timers);
550     }
551 
552     /*
553      * Show various statistics
554      */
555     /* Write statistics	*/
556     /* Print the raw data throughput if desired */
557     if (opts->print_raw) {
558         /* accumulate and output the max, min, and average "raw write" times */
559         if (sio_debug_level >= 3) {
560             /* output all of the times for all iterations */
561             print_indent(3);
562             output_report("Raw Data Write details:\n");
563             output_all_info(write_raw_mm_table, parms.num_iters, 4);
564         }
565 
566         output_results(opts,"Raw Data Write",write_raw_mm_table,parms.num_iters,raw_size);
567     } /* end if */
568 
569     /* show sys write statics */
570 #if 0
571     if (sio_debug_level >= 3) {
572         /* output all of the times for all iterations */
573         print_indent(3);
574         output_report("MPI Write details:\n");
575         output_all_info(write_sys_mm_table, parms.num_iters, 4);
576     }
577 #endif
578     /* We don't currently output the MPI write results */
579 
580     /* accumulate and output the max, min, and average "write" times */
581     if (sio_debug_level >= 3) {
582         /* output all of the times for all iterations */
583         print_indent(3);
584         output_report("Write details:\n");
585         output_all_info(write_mm_table, parms.num_iters, 4);
586     }
587 
588     output_results(opts,"Write",write_mm_table,parms.num_iters,raw_size);
589 
590     /* accumulate and output the max, min, and average "gross write" times */
591     if (sio_debug_level >= 3) {
592         /* output all of the times for all iterations */
593         print_indent(3);
594         output_report("Write Open-Close details:\n");
595         output_all_info(write_gross_mm_table, parms.num_iters, 4);
596     }
597 
598     output_results(opts,"Write Open-Close",write_gross_mm_table,parms.num_iters,raw_size);
599 
600     if (!parms.h5_write_only) {
601         /* Read statistics	*/
602         /* Print the raw data throughput if desired */
603         if (opts->print_raw) {
604             /* accumulate and output the max, min, and average "raw read" times */
605             if (sio_debug_level >= 3) {
606                 /* output all of the times for all iterations */
607                 print_indent(3);
608                 output_report("Raw Data Read details:\n");
609                 output_all_info(read_raw_mm_table, parms.num_iters, 4);
610             }
611 
612             output_results(opts, "Raw Data Read", read_raw_mm_table,
613                            parms.num_iters, raw_size);
614         } /* end if */
615 
616         /* show mpi read statics */
617 #if 0
618         if (sio_debug_level >= 3) {
619             /* output all of the times for all iterations */
620             print_indent(3);
621             output_report("MPI Read details:\n");
622             output_all_info(read_sys_mm_table, parms.num_iters, 4);
623         }
624 #endif
625         /* We don't currently output the MPI read results */
626 
627         /* accumulate and output the max, min, and average "read" times */
628         if (sio_debug_level >= 3) {
629             /* output all of the times for all iterations */
630             print_indent(3);
631             output_report("Read details:\n");
632             output_all_info(read_mm_table, parms.num_iters, 4);
633         }
634 
635         output_results(opts, "Read", read_mm_table, parms.num_iters, raw_size);
636 
637         /* accumulate and output the max, min, and average "gross read" times */
638         if (sio_debug_level >= 3) {
639             /* output all of the times for all iterations */
640             print_indent(3);
641             output_report("Read Open-Close details:\n");
642             output_all_info(read_gross_mm_table, parms.num_iters, 4);
643         }
644 
645         output_results(opts, "Read Open-Close", read_gross_mm_table,
646                        parms.num_iters, raw_size);
647     }
648 
649     /* clean up our mess */
650     free(write_sys_mm_table);
651     free(write_mm_table);
652     free(write_gross_mm_table);
653     free(write_raw_mm_table);
654 
655     if (!parms.h5_write_only) {
656         free(read_sys_mm_table);
657         free(read_mm_table);
658         free(read_gross_mm_table);
659         free(read_raw_mm_table);
660     }
661 
662     return ret_value;
663 }
664 
665 /*
666  * Function:    output_all_info
667  * Purpose:
668  * Return:      Nothing
669  * Programmer:  Bill Wendling, 29. January 2002
670  * Modifications:
671  */
672 static void
output_all_info(minmax * mm,int count,int indent_level)673 output_all_info(minmax *mm, int count, int indent_level)
674 {
675     int i;
676 
677     for (i = 0; i < count; ++i) {
678         print_indent(indent_level);
679         output_report("Iteration %d:\n", i + 1);
680         print_indent(indent_level + 1);
681         output_report("Minimum Time: %.2fs\n", mm[i].min);
682         print_indent(indent_level + 1);
683         output_report("Maximum Time: %.2fs\n", mm[i].max);
684     }
685 }
686 
687 /*
688  * Function:    get_minmax
689  * Purpose:     Gather all the min, max and total of val.
690  * Return:      Nothing
691  * Programmer:  Bill Wendling, 21. December 2001
692  * Modifications:
693  *    Use MPI_Allreduce to do it. -akc, 2002/01/11
694  */
695 
696 static void
get_minmax(minmax * mm,double val)697 get_minmax(minmax *mm, double val)
698 {
699     mm->max = val;
700     mm->min = val;
701     mm->sum = val;
702 }
703 
704 /*
705  * Function:    accumulate_minmax_stuff
706  * Purpose:     Accumulate the minimum, maximum, and average of the times
707  *              across all processes.
708  * Return:      TOTAL_MM - the total of all of these.
709  * Programmer:  Bill Wendling, 21. December 2001
710  * Modifications:
711  *              Changed to use seconds instead of MB/s - QAK, 5/9/02
712  */
713 static minmax
accumulate_minmax_stuff(minmax * mm,int count)714 accumulate_minmax_stuff(minmax *mm, int count)
715 {
716     int i;
717     minmax total_mm;
718 
719     total_mm.sum = 0.0F;
720     total_mm.max = -DBL_MAX;
721     total_mm.min = DBL_MAX;
722     total_mm.num = count;
723 
724     for (i = 0; i < count; ++i) {
725         double m = mm[i].max;
726 
727         total_mm.sum += m;
728 
729         if (m < total_mm.min)
730             total_mm.min = m;
731 
732         if (m > total_mm.max)
733             total_mm.max = m;
734     }
735 
736     return total_mm;
737 }
738 
739 
740 /*
741  * Function:    output_results
742  * Purpose:     Print information about the time & bandwidth for a given
743  *                  minmax & # of iterations.
744  * Return:      Nothing
745  * Programmer:  Quincey Koziol, 9. May 2002
746  * Modifications:
747  */
748 static void
output_results(const struct options * opts,const char * name,minmax * table,int table_size,off_t data_size)749 output_results(const struct options *opts, const char *name, minmax *table,
750     int table_size,off_t data_size)
751 {
752     minmax          total_mm;
753 
754     total_mm = accumulate_minmax_stuff(table, table_size);
755 
756     print_indent(3);
757     output_report("%s (%d iteration(s)):\n", name,table_size);
758 
759     /* Note: The maximum throughput uses the minimum amount of time & vice versa */
760 
761     print_indent(4);
762     output_report("Maximum Throughput: %6.2f MB/s", MB_PER_SEC(data_size,total_mm.min));
763     if(opts->print_times)
764         output_report(" (%7.3f s)\n", total_mm.min);
765     else
766         output_report("\n");
767 
768     print_indent(4);
769     output_report("Average Throughput: %6.2f MB/s",
770                   MB_PER_SEC(data_size,total_mm.sum / total_mm.num));
771     if(opts->print_times)
772         output_report(" (%7.3f s)\n", (total_mm.sum / total_mm.num));
773     else
774         output_report("\n");
775 
776     print_indent(4);
777     output_report("Minimum Throughput: %6.2f MB/s", MB_PER_SEC(data_size,total_mm.max));
778     if(opts->print_times)
779         output_report(" (%7.3f s)\n", total_mm.max);
780     else
781         output_report("\n");
782 }
783 
784 /*
785  * Function:    output_report
786  * Purpose:     Print a line of the report. Only do so if I'm the 0 process.
787  * Return:      Nothing
788  * Programmer:  Bill Wendling, 19. December 2001
789  * Modifications:
790  */
791 static void
output_report(const char * fmt,...)792 output_report(const char *fmt, ...)
793 {
794         va_list ap;
795 
796         va_start(ap, fmt);
797         vfprintf(output, fmt, ap);
798         va_end(ap);
799 }
800 
801 /*
802  * Function:    print_indent
803  * Purpose:     Print spaces to indent a new line of text for pretty printing
804  *              things.
805  * Return:      Nothing
806  * Programmer:  Bill Wendling, 29. October 2001
807  * Modifications:
808  */
809 static void
print_indent(register int indent)810 print_indent(register int indent)
811 {
812 	indent *= TAB_SPACE;
813 
814 	for (; indent > 0; --indent)
815 	    fputc(' ', output);
816 }
817 
818 static void
recover_size_and_print(long long val,const char * end)819 recover_size_and_print(long long val, const char *end)
820 {
821     if (val >= ONE_KB && (val % ONE_KB) == 0) {
822         if (val >= ONE_MB && (val % ONE_MB) == 0) {
823             if (val >= ONE_GB && (val % ONE_GB) == 0)
824                 HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""GB%s", val / ONE_GB, end);
825             else
826                 HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""MB%s", val / ONE_MB, end);
827         } else {
828             HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""KB%s", val / ONE_KB, end);
829         }
830     } else {
831         HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""%s", val, end);
832     }
833 }
834 
835 static void
print_io_api(long io_types)836 print_io_api(long io_types)
837 {
838     if (io_types & SIO_POSIX)
839 	HDfprintf(output, "posix ");
840     if (io_types & SIO_HDF5)
841 	HDfprintf(output, "hdf5 ");
842     HDfprintf(output, "\n");
843 }
844 
845 static void
report_parameters(struct options * opts)846 report_parameters(struct options *opts)
847 {
848     int i, rank;
849     rank = opts->dset_rank;
850 
851     print_version("HDF5 Library");	/* print library version */
852     HDfprintf(output, "==== Parameters ====\n");
853 
854     HDfprintf(output, "IO API=");
855     print_io_api(opts->io_types);
856 
857     HDfprintf(output, "Number of iterations=%d\n",
858               opts->num_iters);
859 
860     HDfprintf(output, "Dataset size=");
861 
862     for (i=0; i<rank; i++)
863         recover_size_and_print((long long)opts->dset_size[i], " ");
864     HDfprintf(output, "\n");
865 
866 
867     HDfprintf(output, "Transfer buffer size=");
868     for (i=0; i<rank; i++)
869         recover_size_and_print((long long)opts->buf_size[i], " ");
870     HDfprintf(output, "\n");
871 
872     HDfprintf(output, "Dimension access order=");
873     for (i=0; i<rank; i++)
874         recover_size_and_print((long long)opts->order[i], " ");
875     HDfprintf(output, "\n");
876 
877     if (opts->io_types & SIO_HDF5) {
878 
879         HDfprintf(output, "HDF5 data storage method=");
880 
881         if (opts->h5_use_chunks){
882 
883             HDfprintf(output, "Chunked\n");
884             HDfprintf(output, "HDF5 chunk size=");
885             for (i=0; i<rank; i++)
886                 recover_size_and_print((long long)opts->chk_size[i], " ");
887             HDfprintf(output, "\n");
888 
889             HDfprintf(output, "HDF5 dataset dimensions=");
890             if (opts->h5_extendable) {
891                 HDfprintf(output, "Extendable\n");
892             }
893             else {
894                 HDfprintf(output, "Fixed\n");
895             }
896         }
897         else {
898             HDfprintf(output, "Contiguous\n");
899         }
900 
901         HDfprintf(output, "HDF5 file driver=");
902         if (opts->vfd==sec2) {
903             HDfprintf(output, "sec2\n");
904         } else if (opts->vfd==stdio) {
905             HDfprintf(output, "stdio\n");
906         } else if (opts->vfd==core) {
907             HDfprintf(output, "core\n");
908         } else if (opts->vfd==split) {
909             HDfprintf(output, "split\n");
910         } else if (opts->vfd==multi) {
911             HDfprintf(output, "multi\n");
912         } else if (opts->vfd==family) {
913             HDfprintf(output, "family\n");
914         } else if (opts->vfd==direct) {
915             HDfprintf(output, "direct\n");
916         }
917     }
918 
919     {
920         char *prefix = HDgetenv("HDF5_PREFIX");
921 
922         HDfprintf(output, "Env HDF5_PREFIX=%s\n",
923                   (prefix ? prefix : "not set"));
924     }
925 
926     HDfprintf(output, "==== End of Parameters ====\n");
927     HDfprintf(output, "\n");
928 }
929 
930 /*
931  * Function:    parse_command_line
932  * Purpose:     Parse the command line options and return a STRUCT OPTIONS
933  *              structure which will need to be freed by the calling function.
934  * Return:      Pointer to an OPTIONS structure
935  * Programmer:  Bill Wendling, 31. October 2001
936  * Modifications:
937  *    Added multidimensional testing (Christian Chilan, April, 2008)
938  */
939 static struct options *
parse_command_line(int argc,char * argv[])940 parse_command_line(int argc, char *argv[])
941 {
942     register int opt;
943     struct options *cl_opts;
944     int i, default_rank, actual_rank, ranks[4];
945 
946     cl_opts = (struct options *)HDmalloc(sizeof(struct options));
947 
948     cl_opts->output_file = NULL;
949     cl_opts->io_types =  0;    /* will set default after parsing options */
950     cl_opts->num_iters = 1;
951 
952     default_rank = 2;
953 
954     cl_opts->dset_rank = 0;
955     cl_opts->buf_rank = 0;
956     cl_opts->chk_rank = 0;
957     cl_opts->order_rank = 0;
958 
959     for(i = 0; i < MAX_DIMS; i++) {
960         cl_opts->buf_size[i] = (size_t)((i + 1) * 10);
961         cl_opts->dset_size[i] = (hsize_t)((i + 1) * 100);
962         cl_opts->chk_size[i] = (size_t)((i + 1) * 10);
963         cl_opts->order[i] = i + 1;
964     }
965 
966     cl_opts->vfd = sec2;
967 
968     cl_opts->print_times = FALSE;   /* Printing times is off by default */
969     cl_opts->print_raw = FALSE;     /* Printing raw data throughput is off by default */
970     cl_opts->h5_alignment = 1;      /* No alignment for HDF5 objects by default */
971     cl_opts->h5_threshold = 1;      /* No threshold for aligning HDF5 objects by default */
972     cl_opts->h5_use_chunks = FALSE; /* Don't chunk the HDF5 dataset by default */
973     cl_opts->h5_write_only = FALSE; /* Do both read and write by default */
974     cl_opts->h5_extendable = FALSE; /* Use extendable dataset */
975     cl_opts->verify = FALSE;        /* No Verify data correctness by default */
976 
977     while ((opt = get_option(argc, (const char **)argv, s_opts, l_opts)) != EOF) {
978         switch ((char)opt) {
979         case 'a':
980             cl_opts->h5_alignment = parse_size_directive(opt_arg);
981             break;
982         case 'A':
983             {
984                 const char *end = opt_arg;
985                 while (end && *end != '\0') {
986                     char buf[10];
987 
988                     HDmemset(buf, '\0', sizeof(buf));
989 
990                     for (i = 0; *end != '\0' && *end != ','; ++end)
991                         if (isalnum(*end) && i < 10)
992                             buf[i++] = *end;
993 
994                     if (!HDstrcasecmp(buf, "hdf5")) {
995                         cl_opts->io_types |= SIO_HDF5;
996                     } else if (!HDstrcasecmp(buf, "posix")) {
997                         cl_opts->io_types |= SIO_POSIX;
998                     } else {
999                         fprintf(stderr, "sio_perf: invalid --api option %s\n",
1000                                 buf);
1001                         exit(EXIT_FAILURE);
1002                     }
1003 
1004                     if (*end == '\0')
1005                         break;
1006 
1007                     end++;
1008                 }
1009             }
1010 
1011             break;
1012 #if 0
1013         case 'b':
1014             /* the future "binary" option */
1015             break;
1016 #endif  /* 0 */
1017         case 'c':
1018             /* Turn on chunked HDF5 dataset creation */
1019             cl_opts->h5_use_chunks = 1;
1020             {
1021                 const char *end = opt_arg;
1022                 int j = 0;
1023 
1024                 while (end && *end != '\0') {
1025                     char buf[10];
1026 
1027                     HDmemset(buf, '\0', sizeof(buf));
1028 
1029                     for (i = 0; *end != '\0' && *end != ','; ++end)
1030                         if (isalnum(*end) && i < 10)
1031                             buf[i++] = *end;
1032 
1033                     cl_opts->chk_size[j] = parse_size_directive(buf);
1034 
1035                     j++;
1036 
1037                     if (*end == '\0')
1038                         break;
1039 
1040                     end++;
1041                 }
1042                 cl_opts->chk_rank = j;
1043             }
1044 
1045             break;
1046 
1047 
1048         case 'D':
1049             {
1050                 const char *end = opt_arg;
1051 
1052                 while (end && *end != '\0') {
1053                     char buf[10];
1054 
1055                     HDmemset(buf, '\0', sizeof(buf));
1056 
1057                     for (i = 0; *end != '\0' && *end != ','; ++end)
1058                         if (isalnum(*end) && i < 10)
1059                             buf[i++] = *end;
1060 
1061                     if (strlen(buf) > 1 || isdigit(buf[0])) {
1062                         size_t j;
1063 
1064                         for (j = 0; j < 10 && buf[j] != '\0'; ++j)
1065                             if (!isdigit(buf[j])) {
1066                                 fprintf(stderr, "sio_perf: invalid --debug option %s\n",
1067                                         buf);
1068                                 exit(EXIT_FAILURE);
1069                             }
1070 
1071                         sio_debug_level = atoi(buf);
1072 
1073                         if (sio_debug_level > 4)
1074                             sio_debug_level = 4;
1075                         else if (sio_debug_level < 0)
1076                             sio_debug_level = 0;
1077                     } else {
1078                         switch (*buf) {
1079                         case 'r':
1080                             /* Turn on raw data throughput info */
1081                             cl_opts->print_raw = TRUE;
1082                             break;
1083                         case 't':
1084                             /* Turn on time printing */
1085                             cl_opts->print_times = TRUE;
1086                             break;
1087             case 'v':
1088                             /* Turn on verify data correctness*/
1089                 cl_opts->verify = TRUE;
1090                 break;
1091                         default:
1092                             fprintf(stderr, "sio_perf: invalid --debug option %s\n", buf);
1093                             exit(EXIT_FAILURE);
1094                         }
1095                     }
1096 
1097                     if (*end == '\0')
1098                         break;
1099 
1100                     end++;
1101                 }
1102             }
1103 
1104             break;
1105         case 'e':
1106             {
1107                 const char *end = opt_arg;
1108                 int j = 0;
1109 
1110                 while (end && *end != '\0') {
1111                     char buf[10];
1112 
1113                     HDmemset(buf, '\0', sizeof(buf));
1114 
1115                     for (i = 0; *end != '\0' && *end != ','; ++end)
1116                         if (isalnum(*end) && i < 10)
1117                             buf[i++] = *end;
1118 
1119                     cl_opts->dset_size[j] = parse_size_directive(buf);
1120 
1121                     j++;
1122 
1123                     if (*end == '\0')
1124                         break;
1125 
1126                     end++;
1127                 }
1128                 cl_opts->dset_rank = j;
1129             }
1130 
1131             break;
1132 
1133         case 'i':
1134             cl_opts->num_iters = atoi(opt_arg);
1135             break;
1136         case 'o':
1137             cl_opts->output_file = opt_arg;
1138             break;
1139         case 'T':
1140             cl_opts->h5_threshold = parse_size_directive(opt_arg);
1141             break;
1142         case 'v':
1143             if (!HDstrcasecmp(opt_arg, "sec2")) {
1144                 cl_opts->vfd=sec2;
1145             } else if (!HDstrcasecmp(opt_arg, "stdio")) {
1146                 cl_opts->vfd=stdio;
1147             } else if (!HDstrcasecmp(opt_arg, "core")) {
1148                 cl_opts->vfd=core;
1149             } else if (!HDstrcasecmp(opt_arg, "split")) {
1150                 cl_opts->vfd=split;
1151             } else if (!HDstrcasecmp(opt_arg, "multi")) {
1152                 cl_opts->vfd=multi;
1153             } else if (!HDstrcasecmp(opt_arg, "family")) {
1154                 cl_opts->vfd=family;
1155             } else if (!HDstrcasecmp(opt_arg, "direct")) {
1156                 cl_opts->vfd=direct;
1157             } else {
1158                 fprintf(stderr, "sio_perf: invalid --api option %s\n",
1159                                 opt_arg);
1160                 exit(EXIT_FAILURE);
1161             }
1162             break;
1163         case 'w':
1164             cl_opts->h5_write_only = TRUE;
1165             break;
1166         case 't':
1167             cl_opts->h5_extendable = TRUE;
1168             break;
1169         case 'x':
1170             {
1171                 const char *end = opt_arg;
1172                 int j = 0;
1173 
1174                 while (end && *end != '\0') {
1175                     char buf[10];
1176 
1177                     HDmemset(buf, '\0', sizeof(buf));
1178 
1179                     for (i = 0; *end != '\0' && *end != ','; ++end)
1180                         if (isalnum(*end) && i < 10)
1181                             buf[i++] = *end;
1182 
1183                     cl_opts->buf_size[j] = parse_size_directive(buf);
1184 
1185                     j++;
1186 
1187                     if (*end == '\0')
1188                         break;
1189 
1190                     end++;
1191                 }
1192                 cl_opts->buf_rank = j;
1193             }
1194 
1195             break;
1196 
1197         case 'r':
1198             {
1199                 const char *end = opt_arg;
1200                 int j = 0;
1201 
1202                 while (end && *end != '\0') {
1203                     char buf[10];
1204 
1205                     HDmemset(buf, '\0', sizeof(buf));
1206 
1207                     for (i = 0; *end != '\0' && *end != ','; ++end)
1208                         if (isalnum(*end) && i < 10)
1209                             buf[i++] = *end;
1210 
1211                     cl_opts->order[j] = (int)parse_size_directive(buf);
1212 
1213                     j++;
1214 
1215                     if (*end == '\0')
1216                         break;
1217 
1218                     end++;
1219                 }
1220 
1221                 cl_opts->order_rank = j;
1222             }
1223 
1224             break;
1225 
1226         case 'h':
1227         case '?':
1228         default:
1229             usage(progname);
1230             free(cl_opts);
1231             return NULL;
1232         }
1233     }
1234 
1235     /* perform rank consistency analysis */
1236     actual_rank = 0;
1237 
1238     ranks[0] = cl_opts->dset_rank;
1239     ranks[1] = cl_opts->buf_rank;
1240     ranks[2] = cl_opts->order_rank;
1241     ranks[3] = cl_opts->chk_rank;
1242 
1243     for (i=0; i<4; i++) {
1244         if (ranks[i]>0) {
1245             if (!actual_rank) {
1246                 actual_rank = ranks[i];
1247             }
1248             else {
1249                 if (actual_rank != ranks[i])
1250                     exit(EXIT_FAILURE);
1251             }
1252         }
1253     }
1254 
1255     if (!actual_rank)
1256         actual_rank = default_rank;
1257 
1258     cl_opts->dset_rank = actual_rank;
1259     cl_opts->buf_rank = actual_rank;
1260     cl_opts->order_rank = actual_rank;
1261     cl_opts->chk_rank = actual_rank;
1262 
1263     for (i=0; i<actual_rank; i++) {
1264         if (cl_opts->order[i] > actual_rank) {
1265             exit(EXIT_FAILURE);
1266         }
1267     }
1268 
1269     /* set default if none specified yet */
1270     if (!cl_opts->io_types)
1271         cl_opts->io_types = SIO_HDF5 | SIO_POSIX; /* run all API */
1272 
1273     /* verify parameters sanity.  Adjust if needed. */
1274     /* cap xfer_size with bytes per process */
1275     if (cl_opts->num_iters <= 0)
1276         cl_opts->num_iters = 1;
1277 
1278     return cl_opts;
1279 }
1280 
1281 /*
1282  * Function:    parse_size_directive
1283  * Purpose:     Parse the size directive passed on the commandline. The size
1284  *              directive is an integer followed by a size indicator:
1285  *
1286  *                  K, k - Kilobyte
1287  *                  M, m - Megabyte
1288  *                  G, g - Gigabyte
1289  *
1290  * Return:      The size as a off_t because this is related to file size.
1291  *              If an unknown size indicator is used, then the program will
1292  *              exit with EXIT_FAILURE as the return value.
1293  * Programmer:  Bill Wendling, 18. December 2001
1294  * Modifications:
1295  */
1296 
1297 static off_t
parse_size_directive(const char * size)1298 parse_size_directive(const char *size)
1299 {
1300     off_t s;
1301     char *endptr;
1302 
1303     s = HDstrtoull(size, &endptr, 10);
1304 
1305     if (endptr && *endptr) {
1306         while (*endptr != '\0' && (*endptr == ' ' || *endptr == '\t'))
1307             ++endptr;
1308 
1309         switch (*endptr) {
1310             case 'K':
1311             case 'k':
1312                 s *= ONE_KB;
1313                 break;
1314 
1315             case 'M':
1316             case 'm':
1317                 s *= ONE_MB;
1318                 break;
1319 
1320             case 'G':
1321             case 'g':
1322                 s *= ONE_GB;
1323                 break;
1324 
1325             default:
1326                 fprintf(stderr, "Illegal size specifier '%c'\n", *endptr);
1327                 exit(EXIT_FAILURE);
1328         }
1329     }
1330 
1331     return s;
1332 }
1333 
1334 /*
1335  * Function:    usage
1336  * Purpose:     Print a usage message and then exit.
1337  * Return:      Nothing
1338  * Programmer:  Bill Wendling, 31. October 2001
1339  * Modifications:
1340  */
1341 static void
usage(const char * prog)1342 usage(const char *prog)
1343 {
1344 	print_version(prog);
1345         printf("usage: %s [OPTIONS]\n", prog);
1346         printf("  OPTIONS\n");
1347         printf("     -h                Print an usage message and exit\n");
1348         printf("     -A AL             Which APIs to test\n");
1349         printf("                       [default: all of them]\n");
1350         printf("     -c SL             Selects chunked storage and defines chunks dimensions\n");
1351         printf("                       and sizes\n");
1352         printf("                       [default: Off]\n");
1353         printf("     -e SL             Dimensions and sizes of dataset\n");
1354         printf("                       [default: 100,200]\n");
1355         printf("     -i N              Number of iterations to perform\n");
1356         printf("                       [default: 1]\n");
1357         printf("     -r NL             Dimension access order (see below for description)\n");
1358         printf("                       [default: 1,2]\n");
1359         printf("     -t                Selects extendable dimensions for HDF5 dataset\n");
1360         printf("                       [default: Off]\n");
1361         printf("     -v VFD            Selects file driver for HDF5 access\n");
1362         printf("                       [default: sec2]\n");
1363         printf("     -w                Perform write tests, not the read tests\n");
1364         printf("                       [default: Off]\n");
1365         printf("     -x SL             Dimensions and sizes of the transfer buffer\n");
1366         printf("                       [default: 10,20]\n");
1367         printf("\n");
1368         printf("  N  - is an integer > 0.\n");
1369         printf("\n");
1370         printf("  S  - is a size specifier, an integer > 0 followed by a size indicator:\n");
1371         printf("          K - Kilobyte (%d)\n", ONE_KB);
1372         printf("          M - Megabyte (%d)\n", ONE_MB);
1373         printf("          G - Gigabyte (%d)\n", ONE_GB);
1374         printf("\n");
1375         printf("      Example: '37M' is 37 megabytes or %d bytes\n", 37*ONE_MB);
1376         printf("\n");
1377         printf("  AL - is an API list. Valid values are:\n");
1378         printf("          hdf5 - HDF5\n");
1379         printf("          posix - POSIX\n");
1380         printf("\n");
1381         printf("      Example: -A posix,hdf5\n");
1382         printf("\n");
1383         printf("  NL - is list of integers (N) separated by commas.\n");
1384         printf("\n");
1385         printf("      Example: 1,2,3\n");
1386         printf("\n");
1387         printf("  SL - is list of size specifiers (S) separated by commas.\n");
1388         printf("\n");
1389         printf("      Example: 2K,2K,3K\n");
1390         printf("\n");
1391         printf("      The example defines an object (dataset, tranfer buffer) with three\n");
1392         printf("      dimensions. Be aware that as the number of dimensions increases, the\n");
1393         printf("      the total size of the object increases exponentially.\n");
1394         printf("\n");
1395         printf("  VFD  - is an HDF5 file driver specifier. Valid values are:\n");
1396         printf("          sec2, stdio, core, split, multi, family, direct\n");
1397         printf("\n");
1398         printf("  Dimension access order:\n");
1399         printf("      Data access starts at the cardinal origin of the dataset using the\n");
1400         printf("      transfer buffer. The next access occurs on a dataset region next to\n");
1401         printf("      the previous one. For a multidimensional dataset, there are several\n");
1402         printf("      directions as to where to proceed. This can be specified in the dimension\n");
1403         printf("      access order. For example, -r 1,2 states that the tool should traverse\n");
1404         printf("      dimension 1 first, and then dimension 2.\n");
1405         printf("\n");
1406         printf("  Environment variables:\n");
1407         printf("      HDF5_NOCLEANUP   Do not remove data files if set [default remove]\n");
1408         printf("      HDF5_PREFIX      Data file prefix\n");
1409         printf("\n");
1410         fflush(stdout);
1411 }
1412 
debug_start_stop_time(io_time_t * pt,timer_type t,int start_stop)1413 void debug_start_stop_time(io_time_t *pt, timer_type t, int start_stop)
1414 {
1415         if (sio_debug_level >= 4) {
1416             const char *msg;
1417 
1418             switch (t) {
1419             case HDF5_FILE_OPENCLOSE:
1420                 msg = "File Open/Close";
1421                 break;
1422             case HDF5_DATASET_CREATE:
1423                 msg = "Dataset Create";
1424                 break;
1425             case HDF5_MPI_WRITE:
1426                 msg = "MPI Write";
1427                 break;
1428             case HDF5_MPI_READ:
1429                 msg = "MPI Read";
1430                 break;
1431             case HDF5_FINE_WRITE_FIXED_DIMS:
1432                 msg = "Fine Write";
1433                 break;
1434             case HDF5_FINE_READ_FIXED_DIMS:
1435                 msg = "Fine Read";
1436                 break;
1437             case HDF5_GROSS_WRITE_FIXED_DIMS:
1438                 msg = "Gross Write";
1439                 break;
1440             case HDF5_GROSS_READ_FIXED_DIMS:
1441                 msg = "Gross Read";
1442                 break;
1443             case HDF5_RAW_WRITE_FIXED_DIMS:
1444                 msg = "Raw Write";
1445                 break;
1446             case HDF5_RAW_READ_FIXED_DIMS:
1447                 msg = "Raw Read";
1448                 break;
1449             default:
1450                 msg = "Unknown Timer";
1451                 break;
1452             }
1453 
1454             fprintf(output, "    %s %s: %.2f\n", msg,
1455                     (start_stop == TSTART ? "Start" : "Stop"),
1456                     pt->total_time[t]);
1457         }
1458 } /* debug_start_stop_time */
1459 
1460