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