diff --git a/nc_perf/bm_file.c b/nc_perf/bm_file.c index b26387041b..b758d6d6c2 100644 --- a/nc_perf/bm_file.c +++ b/nc_perf/bm_file.c @@ -28,38 +28,39 @@ #define MILLION 1000000 #define BAD -99 #define NOMEM -98 -#define MAX_VO 50 /* Max number of var options on command line. */ +#define MAX_VO 255 /* Max number of var options on command line. */ +#define MAX_VO_PRINTED 3 #define MAX_DIMS 7 /* Max dim for variables in input file. */ /* This struct holds data about what options we want to apply to * variable in the created file. (Chunking, compression, etc.) */ typedef struct { - int varid; - int ndims; - int deflate_num; - int shuffle; - size_t chunksize[MAX_DIMS]; - int endian; - size_t start[MAX_DIMS], count[MAX_DIMS], inc[MAX_DIMS]; + int varid; + int ndims; + int deflate_num; + int shuffle; + size_t chunksize[MAX_DIMS]; + int endian; + size_t start[MAX_DIMS], count[MAX_DIMS], inc[MAX_DIMS]; } VAR_OPTS_T; /* This macro prints an error message with line number and name of * test program. */ -#define ERR1(n) do { \ -fflush(stdout); /* Make sure our stdout is synced with stderr. */ \ -fprintf(stderr, "Sorry! Unexpected result, %s, line: %d - %s\n", \ - __FILE__, __LINE__, nc_strerror(n)); \ -return n; \ -} while (0) +#define ERR1(n) do { \ + fflush(stdout); /* Make sure our stdout is synced with stderr. */ \ + fprintf(stderr, "Sorry! Unexpected result, %s, line: %d - %s\n", \ + __FILE__, __LINE__, nc_strerror(n)); \ + return n; \ + } while (0) #ifdef USE_PARALLEL /* Error handling code for MPI calls. */ -#define MPIERR(e) do { \ -MPI_Error_string(e, err_buffer, &resultlen); \ -printf("MPI error, line %d, file %s: %s\n", __LINE__, __FILE__, err_buffer); \ -MPI_Finalize(); \ -return 2; \ -} while (0) +#define MPIERR(e) do { \ + MPI_Error_string(e, err_buffer, &resultlen); \ + printf("MPI error, line %d, file %s: %s\n", __LINE__, __FILE__, err_buffer); \ + MPI_Finalize(); \ + return 2; \ + } while (0) #endif /* Prototype from tst_utils.c. */ @@ -74,120 +75,120 @@ get_starts_counts(int ndims, size_t *dimlen, int p, int my_rank, int *num_steps, int *start_inc, int *slice_len, size_t *last_count, size_t *start, size_t *count) { - int extra_step = 0; - int total[NC_MAX_VAR_DIMS]; - int total_len; - int s, d; - - /* User has specified start/count/inc for this var. Parallel runs - * not allowed yet. */ - if (use_scs) - { - /* Set the starts and counts for each dim, the len of the slice, - * the total len of the data, and the total extent of the - * dataset in each dimension. */ - for (d = 0, *slice_len = 1, total_len = 1; d < vo->ndims; d++) - { - start[d] = vo->start[d]; - count[d] = vo->count[d]; - (*slice_len) *= count[d]; - total_len *= dimlen[d]; - } - - /* The start increment is provided by the user. */ - *start_inc = vo->inc[0]; - - /* How many steps to write/read these data? */ - *num_steps = total_len / (*slice_len); - - /* Init this for the total extent in each dim. */ - for (d = 0; d < vo->ndims; d++) - total[d] = 0; - - /* Check our numbers if we apply increments to start, and read - * count, for this many steps. */ - for (s = 0; s < *num_steps; s++) - { - for (d = 0; d < vo->ndims; d++) - { - total[d] += count[d]; - if (total[d] >= dimlen[d]) - break; - } - if (d != vo->ndims) - break; - } - - /* If the numbers didn't come out clean, then figure out the - * last set of counts needed to completely read the data. */ - if (s == (*num_steps) - 1) - *last_count = count[0]; - else - { - (*num_steps)++; - *last_count = dimlen[0] - total[0]; - } - } - else - { - *start_inc = dimlen[0]/slow_count; - while (*start_inc * slow_count < dimlen[0]) - (*start_inc)++; - *slice_len = *start_inc; - start[0] = *start_inc * my_rank; - if (start[0] > dimlen[0]) - { - fprintf(stderr, "slow_count too large for this many processors, " - "start_inc=%d, slow_count=%d, p=%d, my_rank=%d start[0]=%ld\n", - *start_inc, slow_count, p, my_rank, start[0]); - return 2; - } - count[0] = *start_inc; - for (d = 1; d < ndims; d++) - { - start[d] = 0; - count[d] = dimlen[d]; - *slice_len *= dimlen[d]; - } - *num_steps = (float)dimlen[0] / (*start_inc * p); - if ((float)dimlen[0] / (*start_inc * p) != dimlen[0] / (*start_inc * p)) - { - extra_step++; - (*num_steps)++; - } - - if (p > 1) - { - if (!extra_step) - *last_count = 0; - else - { - int left; - left = dimlen[0] - (*num_steps - 1) * *start_inc * p; - if (left > (my_rank + 1) * *start_inc) - *last_count = *start_inc; - else - { - if (left - my_rank * *start_inc < 0) - *last_count = 0; - else - *last_count = left - my_rank * *start_inc; - } - } - } - else - *last_count = dimlen[0] - (*num_steps - 1) * *start_inc; - } - return 0; + int extra_step = 0; + int total[NC_MAX_VAR_DIMS]; + int total_len; + int s, d; + + /* User has specified start/count/inc for this var. Parallel runs + * not allowed yet. */ + if (use_scs) + { + /* Set the starts and counts for each dim, the len of the slice, + * the total len of the data, and the total extent of the + * dataset in each dimension. */ + for (d = 0, *slice_len = 1, total_len = 1; d < vo->ndims; d++) + { + start[d] = vo->start[d]; + count[d] = vo->count[d]; + (*slice_len) *= count[d]; + total_len *= dimlen[d]; + } + + /* The start increment is provided by the user. */ + *start_inc = vo->inc[0]; + + /* How many steps to write/read these data? */ + *num_steps = total_len / (*slice_len); + + /* Init this for the total extent in each dim. */ + for (d = 0; d < vo->ndims; d++) + total[d] = 0; + + /* Check our numbers if we apply increments to start, and read + * count, for this many steps. */ + for (s = 0; s < *num_steps; s++) + { + for (d = 0; d < vo->ndims; d++) + { + total[d] += count[d]; + if (total[d] >= dimlen[d]) + break; + } + if (d != vo->ndims) + break; + } + + /* If the numbers didn't come out clean, then figure out the + * last set of counts needed to completely read the data. */ + if (s == (*num_steps) - 1) + *last_count = count[0]; + else + { + (*num_steps)++; + *last_count = dimlen[0] - total[0]; + } + } + else + { + *start_inc = dimlen[0]/slow_count; + while (*start_inc * slow_count < dimlen[0]) + (*start_inc)++; + *slice_len = *start_inc; + start[0] = *start_inc * my_rank; + if (start[0] > dimlen[0]) + { + fprintf(stderr, "slow_count too large for this many processors, " + "start_inc=%d, slow_count=%d, p=%d, my_rank=%d start[0]=%ld\n", + *start_inc, slow_count, p, my_rank, start[0]); + return 2; + } + count[0] = *start_inc; + for (d = 1; d < ndims; d++) + { + start[d] = 0; + count[d] = dimlen[d]; + *slice_len *= dimlen[d]; + } + *num_steps = (float)dimlen[0] / (*start_inc * p); + if ((float)dimlen[0] / (*start_inc * p) != dimlen[0] / (*start_inc * p)) + { + extra_step++; + (*num_steps)++; + } + + if (p > 1) + { + if (!extra_step) + *last_count = 0; + else + { + int left; + left = dimlen[0] - (*num_steps - 1) * *start_inc * p; + if (left > (my_rank + 1) * *start_inc) + *last_count = *start_inc; + else + { + if (left - my_rank * *start_inc < 0) + *last_count = 0; + else + *last_count = left - my_rank * *start_inc; + } + } + } + else + *last_count = dimlen[0] - (*num_steps - 1) * *start_inc; + } + return 0; } /* This function finds the size of a file. */ static size_t file_size(char* name) { - struct stat stbuf; - stat(name, &stbuf); - return stbuf.st_size; + struct stat stbuf; + stat(name, &stbuf); + return stbuf.st_size; } @@ -196,261 +197,261 @@ file_size(char* name) static int check_att(int ncid1, int ncid2, int varid, int a) { - int typeid, typeid2; - size_t len, len2, typelen; - char name[NC_MAX_NAME + 1]; - void *d = NULL, *d2 = NULL; - int ret = 0; - - /* Check the metadata about the metadata - name, type, length. */ - if ((ret = nc_inq_attname(ncid1, varid, a, name))) - return ret; - if ((ret = nc_inq_att(ncid1, varid, name, &typeid, &len))) - return ret; - if ((ret = nc_inq_att(ncid2, varid, name, &typeid2, &len2))) - return ret; - if (len != len2 || typeid != typeid2) - return BAD; - if ((ret = nc_inq_type(ncid1, typeid, NULL, &typelen))) - return ret; - - /* Get the two attributes, if they are non-zero. */ - if (len) - { - if(!(d = malloc(typelen * len))) - return NOMEM; - if(!(d2 = malloc(typelen * len))) - { - ret = NOMEM; - goto exit; - } - if ((ret = nc_get_att(ncid1, varid, name, d))) - goto exit; - if ((ret = nc_get_att(ncid2, varid, name, d2))) - goto exit; - - /* Are they the same? */ - if (memcmp(d, d2, typelen * len)) - ret = BAD; - } - - exit: - /* Free up our resources. */ - if (d) - free(d); - if (d2) - free(d2); - - return ret; + int typeid, typeid2; + size_t len, len2, typelen; + char name[NC_MAX_NAME + 1]; + void *d = NULL, *d2 = NULL; + int ret = 0; + + /* Check the metadata about the metadata - name, type, length. */ + if ((ret = nc_inq_attname(ncid1, varid, a, name))) + return ret; + if ((ret = nc_inq_att(ncid1, varid, name, &typeid, &len))) + return ret; + if ((ret = nc_inq_att(ncid2, varid, name, &typeid2, &len2))) + return ret; + if (len != len2 || typeid != typeid2) + return BAD; + if ((ret = nc_inq_type(ncid1, typeid, NULL, &typelen))) + return ret; + + /* Get the two attributes, if they are non-zero. */ + if (len) + { + if(!(d = malloc(typelen * len))) + return NOMEM; + if(!(d2 = malloc(typelen * len))) + { + ret = NOMEM; + goto exit; + } + if ((ret = nc_get_att(ncid1, varid, name, d))) + goto exit; + if ((ret = nc_get_att(ncid2, varid, name, d2))) + goto exit; + + /* Are they the same? */ + if (memcmp(d, d2, typelen * len)) + ret = BAD; + } + +exit: + /* Free up our resources. */ + if (d) + free(d); + if (d2) + free(d2); + + return ret; } /* Do two files contain the same data and metadata? */ static int -cmp_file(char *file1, char *file2, int *meta_read_us, int *data_read_us, +cmp_file(char *file1, char *file2, int *meta_read_us, size_t *data_read_us, int use_par, int par_access, int do_cmp, int p, int my_rank, int slow_count, int verbose, int num_vo, VAR_OPTS_T *vo, int use_scs) { - int ncid1, ncid2; - int unlimdimid, unlimdimid2; - char name[NC_MAX_NAME + 1], name2[NC_MAX_NAME + 1]; - size_t len, len2; + int ncid1, ncid2; + int unlimdimid, unlimdimid2; + char name[NC_MAX_NAME + 1], name2[NC_MAX_NAME + 1]; + size_t len, len2; #ifdef USE_PARALLEL - double ftime; + double ftime; #endif - struct timeval start_time, end_time, diff_time; - void *data = NULL, *data2 = NULL; - int a, v, d; - nc_type xtype, xtype2; - int nvars, ndims, dimids[NC_MAX_VAR_DIMS], natts, real_ndims; - int nvars2, ndims2, dimids2[NC_MAX_VAR_DIMS], natts2; - size_t *count = NULL, *start = NULL; - int slice_len = 1; - size_t *dimlen = NULL, type_size = 0; - size_t last_count; - int start_inc; - int num_steps, step; - int ret = NC_NOERR; - - /* Note in the code below I only want to time stuff for file2. */ - - /* Read the metadata for both files. */ - if (use_par) - { + struct timeval start_time, end_time, diff_time; + void *data = NULL, *data2 = NULL; + int a, v, d; + nc_type xtype, xtype2; + int nvars, ndims, dimids[NC_MAX_VAR_DIMS], natts, real_ndims; + int nvars2, ndims2, dimids2[NC_MAX_VAR_DIMS], natts2; + size_t *count = NULL, *start = NULL; + int slice_len = 1; + size_t *dimlen = NULL, type_size = 0; + size_t last_count; + int start_inc; + int num_steps, step; + int ret = NC_NOERR; + + /* Note in the code below I only want to time stuff for file2. */ + + /* Read the metadata for both files. */ + if (use_par) + { #ifdef USE_PARALLEL - if ((ret = nc_open_par(file1, 0, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid1))) - ERR1(ret); - MPI_Barrier(MPI_COMM_WORLD); - ftime = MPI_Wtime(); - if ((ret = nc_open_par(file2, 0, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid2))) - ERR1(ret); - *meta_read_us += (MPI_Wtime() - ftime) * MILLION; + if ((ret = nc_open_par(file1, 0, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid1))) + ERR1(ret); + MPI_Barrier(MPI_COMM_WORLD); + ftime = MPI_Wtime(); + if ((ret = nc_open_par(file2, 0, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid2))) + ERR1(ret); + *meta_read_us += (MPI_Wtime() - ftime) * MILLION; #else - return NC_EPARINIT; + return NC_EPARINIT; #endif - } - else - { - if ((ret = nc_open(file1, 0, &ncid1))) - ERR1(ret); - if (gettimeofday(&start_time, NULL)) ERR; - if ((ret = nc_open(file2, 0, &ncid2))) - ERR1(ret); - if (gettimeofday(&end_time, NULL)) ERR; - if (nc4_timeval_subtract(&diff_time, &end_time, &start_time)) ERR; - *meta_read_us += (int)diff_time.tv_sec * MILLION + (int)diff_time.tv_usec; - } - if (verbose) - printf("%d: reading metadata took %d micro-seconds\n", - my_rank, *meta_read_us); - - /* Check the counts of dims, vars, and atts. */ - if ((ret = nc_inq(ncid1, &ndims, &nvars, &natts, &unlimdimid))) - ERR1(ret); - if ((ret = nc_inq(ncid1, &ndims2, &nvars2, &natts2, &unlimdimid2))) - ERR1(ret); - if (ndims != ndims2 || nvars != nvars2 || natts != natts2 || - unlimdimid != unlimdimid2) - ERR1(BAD); - - /* Check dims. */ - for (d = 0; d < ndims; d++) - { - if ((ret = nc_inq_dim(ncid1, d, name, &len))) - ERR1(ret); - if ((ret = nc_inq_dim(ncid2, d, name2, &len2))) - ERR1(ret); - if (len != len2 || strcmp(name, name2)) - ERR1(BAD); - } - - /* Check global atts. */ - for (a = 0; a < natts; a++) - if ((ret = check_att(ncid1, ncid2, NC_GLOBAL, a))) - ERR1(ret); - - /* Check the variables. */ - for (v = 0; v < nvars; v++) - { - /* Learn about this var in both files. */ - if ((ret = nc_inq_var(ncid1, v, name, &xtype, &ndims, dimids, &natts))) - return ret; - if ((ret = nc_inq_var(ncid2, v, name2, &xtype2, &ndims2, dimids2, &natts2))) - return ret; - - /* Check var metadata. */ - if (strcmp(name, name2) || xtype != xtype2 || ndims != ndims2 || natts != natts2) - return BAD; - for (d = 0; d < ndims; d++) - if (dimids[d] != dimids2[d]) - return BAD; - - /* Check the attributes. */ - for (a = 0; a < natts; a++) - if ((ret = check_att(ncid1, ncid2, v, a))) - ERR1(ret); - - /* Check the data, one slice at a time. (slicing along slowest - * varying dimension.) */ - - /* Allocate memory for our start and count arrays. If ndims = 0 - this is a scalar, which I will treat as a 1-D array with one - element. */ - real_ndims = ndims ? ndims : 1; - if (!(start = malloc(real_ndims * sizeof(size_t)))) - ERR1(NC_ENOMEM); - if (!(count = malloc(real_ndims * sizeof(size_t)))) - ERR1(NC_ENOMEM); - - /* The start array will be all zeros, except the first element, - which will be the slice number. Count will be the dimension - size, except for the first element, which will be one, because - we will copy one slice at a time. For this we need the var - shape. */ - if (!(dimlen = malloc(real_ndims * sizeof(size_t)))) - ERR1(NC_ENOMEM); - for (d=0; d MAX_VO) - return 1; - if (!(token = strtok_r(str1, COMMA, &saveptr1))) - break; - for (ndims = 0, str2 = token; ; str2 = NULL) - { - int tmp_int; - if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) - break; - if (str2) - sscanf(subtoken, "%d", &(vo[num_vo].varid)); - else if (!got_z++) - sscanf(subtoken, "%d", &(vo[num_vo].deflate_num)); - else if (!got_s++) - sscanf(subtoken, "%d", &(vo[num_vo].shuffle)); - else - { - sscanf(subtoken, "%d", &tmp_int); - vo[num_vo].chunksize[ndims++] = tmp_int; - } - } - vo[num_vo].ndims = ndims; + int got_z = 0, got_s = 0; + if (num_vo > MAX_VO) + return 1; + if (!(token = strtok_r(str1, COMMA, &saveptr1))) + break; + for (ndims = 0, str2 = token; ; str2 = NULL) + { + int tmp_int; + if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) + break; + if (str2) + sscanf(subtoken, "%d", &(vo[num_vo].varid)); + else if (!got_z++) + sscanf(subtoken, "%d", &(vo[num_vo].deflate_num)); + else if (!got_s++) + sscanf(subtoken, "%d", &(vo[num_vo].shuffle)); + else + { + sscanf(subtoken, "%d", &tmp_int); + vo[num_vo].chunksize[ndims++] = tmp_int; + } + } + vo[num_vo].ndims = ndims; } break; - case 't': + case 't': for (num_vo = 0, str1 = optarg; ; num_vo++, str1 = NULL) { - if (num_vo > MAX_VO) - return 1; - if (!(token = strtok_r(str1, COMMA, &saveptr1))) - break; - for (ndims = 0, str2 = token; ; str2 = NULL) - { - if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) - break; - if (str2) - sscanf(subtoken, "%d", &(vo[num_vo].varid)); - else - sscanf(subtoken, "%ld", &(vo[num_vo].start[ndims++])); - } - vo[num_vo].ndims = ndims; + if (num_vo > MAX_VO) + return 1; + if (!(token = strtok_r(str1, COMMA, &saveptr1))) + break; + for (ndims = 0, str2 = token; ; str2 = NULL) + { + if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) + break; + if (str2) + sscanf(subtoken, "%d", &(vo[num_vo].varid)); + else + sscanf(subtoken, "%ld", &(vo[num_vo].start[ndims++])); + } + vo[num_vo].ndims = ndims; } use_scs++; break; - case 'u': + case 'u': for (num_vo = 0, str1 = optarg; ; num_vo++, str1 = NULL) { - if (num_vo > MAX_VO) - return 1; - if (!(token = strtok_r(str1, COMMA, &saveptr1))) - break; - for (ndims = 0, str2 = token; ; str2 = NULL) - { - if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) - break; - if (str2) - sscanf(subtoken, "%d", &(vo[num_vo].varid)); - else - sscanf(subtoken, "%ld", &(vo[num_vo].count[ndims++])); - } - vo[num_vo].ndims = ndims; + if (num_vo > MAX_VO) + return 1; + if (!(token = strtok_r(str1, COMMA, &saveptr1))) + break; + for (ndims = 0, str2 = token; ; str2 = NULL) + { + if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) + break; + if (str2) + sscanf(subtoken, "%d", &(vo[num_vo].varid)); + else + sscanf(subtoken, "%ld", &(vo[num_vo].count[ndims++])); + } + vo[num_vo].ndims = ndims; } break; - case 'r': + case 'r': for (num_vo = 0, str1 = optarg; ; num_vo++, str1 = NULL) { - if (num_vo > MAX_VO) - return 1; - if (!(token = strtok_r(str1, COMMA, &saveptr1))) - break; - for (ndims = 0, str2 = token; ; str2 = NULL) - { - if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) - break; - if (str2) - sscanf(subtoken, "%d", &(vo[num_vo].varid)); - else - sscanf(subtoken, "%ld", &(vo[num_vo].inc[ndims++])); - } - vo[num_vo].ndims = ndims; + if (num_vo > MAX_VO) + return 1; + if (!(token = strtok_r(str1, COMMA, &saveptr1))) + break; + for (ndims = 0, str2 = token; ; str2 = NULL) + { + if (!(subtoken = strtok_r(str2, COLON, &saveptr2))) + break; + if (str2) + sscanf(subtoken, "%d", &(vo[num_vo].varid)); + else + sscanf(subtoken, "%ld", &(vo[num_vo].inc[ndims++])); + } + vo[num_vo].ndims = ndims; } break; - case 'd': + case 'd': doublecheck++; break; - case 'm': + case 'm': do_cmp++; doublecheck++; break; - case 'p': + case 'p': use_par++; break; - case 'i': + case 'i': mpiio++; break; - case 's': + case 's': sscanf(optarg, "%d", &slow_count); break; - case 'e': + case 'e': sscanf(optarg, "%d", &endianness); break; - case 'l': + case 'l': convert_unlim++; break; - case '?': + case '?': usage(); return 1; - } - - if (use_scs) - { - if (use_par) - { - printf("Can't use start/count/slice for parallel runs yet!\n"); - return 2; - } - } - else - { - if (slow_count < p) - slow_count = p; - if (slow_count % p) - { - printf("slow_count must be even multiple of p\n"); - return 2; - } - } - - argc -= optind; - argv += optind; - - /* If no file arguments left, report and exit */ - if (argc < 1) - { - printf("no file specified\n"); - return 0; - } - - /* Get the name of the file to copy. */ - strcpy(file_in, argv[0]); - - /* Verbose mode seems a bit stupid, but it's really useful when you - * are running in batch mode on a supercomputer, and can't use - * anything else to figure out what the heck is going on. */ - if (verbose && !my_rank) - { - printf("copying %s to %s on %d processors with endianness %d and...\n", - file_in, file_out, p, endianness); - if (use_scs) - for (v = 0; v < num_vo; v++) - { - printf("options for var %d:\n", vo[v].varid); - for (d = 0; d < vo[v].ndims; d++) - printf("start[%d]=%ld, count[%d]=%ld, inc[%d]=%ld\n", - d, vo[v].start[d], d, vo[v].count[d], d, vo[v].inc[d]); - } - else - printf("slow_count=%d, doublecheck=%d\n", slow_count, doublecheck); - } - - /* Copy the file, keeping track of the read and write times for metadata and data. */ - if ((ret = copy_file(file_in, file_out, cmode, num_vo, vo, &meta_read_us, &meta_write_us, - &data_read_us, &data_write_us, &in_format, use_par, par_access, - &num_bytes, p, my_rank, slow_count, verbose, use_scs, endianness, - convert_unlim))) - return ret; - - /* If the user wants a double check, make sure the data in the new - * file is exactly the same. */ - if (doublecheck) - { + } + + if (use_scs) + { + if (use_par) + { + printf("Can't use start/count/slice for parallel runs yet!\n"); + return 2; + } + } + else + { + if (slow_count < p) + slow_count = p; + if (slow_count % p) + { + printf("slow_count must be even multiple of p\n"); + return 2; + } + } + + argc -= optind; + argv += optind; + + /* If no file arguments left, report and exit */ + if (argc < 1) + { + printf("no file specified\n"); + return 0; + } + + /* Get the name of the file to copy. */ + strcpy(file_in, argv[0]); + + /* Verbose mode seems a bit stupid, but it's really useful when you + * are running in batch mode on a supercomputer, and can't use + * anything else to figure out what the heck is going on. */ + if (verbose && !my_rank) + { + printf("copying %s to %s on %d processors with endianness %d and...\n", + file_in, file_out, p, endianness); + if (use_scs) + for (v = 0; v < num_vo; v++) + { + printf("options for var %d:\n", vo[v].varid); + for (d = 0; d < vo[v].ndims; d++) + printf("start[%d]=%ld, count[%d]=%ld, inc[%d]=%ld\n", + d, vo[v].start[d], d, vo[v].count[d], d, vo[v].inc[d]); + } + else + printf("slow_count=%d, doublecheck=%d\n", slow_count, doublecheck); + } + + /* Copy the file, keeping track of the read and write times for metadata and data. */ + if ((ret = copy_file(file_in, file_out, cmode, num_vo, vo, &meta_read_us, &meta_write_us, + &data_read_us, &data_write_us, &in_format, use_par, par_access, + &num_bytes, p, my_rank, slow_count, verbose, use_scs, endianness, + convert_unlim))) + return ret; + + /* If the user wants a double check, make sure the data in the new + * file is exactly the same. */ + if (doublecheck) + { + /* We need a string long enough for the copy command. */ + char cmd[NC_MAX_NAME * 2 + 5]; + #ifdef USE_PARALLEL - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); #endif - if ((ret = cmp_file(file_in, file_out, &meta_read2_us, &data_read2_us, - use_par, par_access, do_cmp, p, my_rank, slow_count, - verbose, num_vo, vo, use_scs))) - return ret; - } - - if (use_par) - { + /* Create a copy of file_out. This will defeat any buffering + * that may exist from the fact that we just wrote file_out. */ + sprintf(file_out_2, "tst_copy_%s", file_out); + sprintf(cmd, "cp %s %s\n", file_out, file_out_2); + system(cmd); + + if ((ret = cmp_file(file_in, file_out_2, &meta_read2_us, &data_read2_us, + use_par, par_access, do_cmp, p, my_rank, slow_count, + verbose, num_vo, vo, use_scs))) + return ret; + } + + if (use_par) + { #ifdef USE_PARALLEL - MPI_Reduce(&meta_read_us, &tmeta_read_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&meta_write_us, &tmeta_write_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&data_read_us, &tdata_read_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&data_write_us, &tdata_write_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&data_read2_us, &tdata_read2_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(&meta_read_us, &tmeta_read_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(&meta_write_us, &tmeta_write_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(&data_read_us, &tdata_read_us, 1, MPI_OFFSET, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(&data_write_us, &tdata_write_us, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(&data_read2_us, &tdata_read2_us, 1, MPI_OFFSET, MPI_MAX, 0, MPI_COMM_WORLD); #else - return NC_EPARINIT; + return NC_EPARINIT; #endif - } - else - { - tmeta_read_us = meta_read_us; - tmeta_write_us = meta_write_us; - tdata_read_us = data_read_us; - tdata_write_us = data_write_us; - tmeta_read2_us = meta_read2_us; - tdata_read2_us = data_read2_us; - } - - if (verbose) - printf("num_bytes=%lld tdata_read_us=%d\n", num_bytes, tdata_read_us); - - read_rate = (float)num_bytes/((float)tdata_read_us/p); - write_rate = (float)num_bytes/((float)tdata_write_us/p); - reread_rate = (float)num_bytes/((float)tdata_read2_us/p); - if (verbose) - printf("%d: read rate %g, write rate %g, reread_rate %g\n", my_rank, read_rate, - write_rate, reread_rate); - - /* Print some output. */ - if (!my_rank) - { - /* Does the user want a text header for the data? */ - if (header) - { - printf("input format, output_format, input size, output size, meta read time, " - "meta write time, data read time, data write time, enddianness, "); - if (doublecheck) - printf("metadata reread time, data reread time, read rate, " - "write rate, reread rate, "); - else - printf("read rate, write rate, "); - if (use_par) - printf("num_proc, "); - printf("deflate, shuffle, chunksize[0], chunksize[1], chunksize[2], " - "chunksize[3]\n"); - } - - printf("%d, %d, %ld, %ld, %d, %d, %d, %d, %d, ", in_format, out_format, file_size(file_in), - file_size(file_out), tmeta_read_us, tmeta_write_us, tdata_read_us, tdata_write_us, - endianness); - if (doublecheck) - printf("%d, %d, %g, %g, %g, ", tmeta_read2_us, tdata_read2_us, read_rate, write_rate, - reread_rate); - else - printf("%g, %g, ", read_rate, write_rate); - if (use_par) - printf("%d, ", p); - for (o1 = 0; o1 < num_vo; o1++) - { - printf("%d, %d, %d, %d, %d, %d ", vo[o1].deflate_num, vo[o1].shuffle, - (int)vo[o1].chunksize[0], (int)vo[o1].chunksize[1], (int)vo[o1].chunksize[2], (int)vo[o1].chunksize[3]); - if (o1 != num_vo - 1) - printf(", "); - } - printf("\n"); - } + } + else + { + tmeta_read_us = meta_read_us; + tmeta_write_us = meta_write_us; + tdata_read_us = data_read_us; + tdata_write_us = data_write_us; + tmeta_read2_us = meta_read2_us; + tdata_read2_us = data_read2_us; + } + + if (verbose) + printf("num_bytes=%g tdata_read_us=%ld\n", num_bytes, tdata_read_us); + + read_rate = num_bytes/((float)tdata_read_us/p); + write_rate = num_bytes/((float)tdata_write_us/p); + reread_rate = num_bytes/((float)tdata_read2_us/p); + if (verbose) + printf("%d: read rate %g, write rate %g, reread_rate %g\n", my_rank, read_rate, + write_rate, reread_rate); + + /* Print some output. */ + if (!my_rank) + { + /* Does the user want a text header for the data? */ + if (header) + { + printf("input format, output_format, input size, output size, meta read time, " + "meta write time, data read time, data write time, enddianness, "); + if (doublecheck) + printf("metadata reread time, data reread time, read rate, " + "write rate, reread rate, "); + else + printf("read rate, write rate, "); + if (use_par) + printf("num_proc, "); + printf("deflate, shuffle, chunksize[0], chunksize[1], chunksize[2], " + "chunksize[3]\n"); + } + + printf("%d, %d, %ld, %ld, %d, %d, %ld, %d, %d, ", in_format, out_format, file_size(file_in), + file_size(file_out), tmeta_read_us, tmeta_write_us, tdata_read_us, tdata_write_us, + endianness); + if (doublecheck) + printf("%d, %ld, %g, %g, %g, ", tmeta_read2_us, tdata_read2_us, read_rate, write_rate, + reread_rate); + else + printf("%g, %g, ", read_rate, write_rate); + if (use_par) + printf("%d, ", p); + for (o1 = 0; o1 < num_vo; o1++) + { + printf("%d, %d, %d, %d, %d, %d ", vo[o1].deflate_num, vo[o1].shuffle, + (int)vo[o1].chunksize[0], (int)vo[o1].chunksize[1], (int)vo[o1].chunksize[2], (int)vo[o1].chunksize[3]); + if (o1 >= MAX_VO_PRINTED) + break; + if (o1 != num_vo - 1) + printf(", "); + } + printf("\n"); + } #ifdef USE_PARALLEL - MPI_Finalize(); + MPI_Finalize(); #endif - FINAL_RESULTS_QUIET; + FINAL_RESULTS_QUIET; }