From 20a639dccaab3729d26d022fd6a61117e551c628 Mon Sep 17 00:00:00 2001 From: wkliao Date: Thu, 29 Aug 2024 14:46:43 -0500 Subject: [PATCH] New benchmark programs that write multiple variables * benchmarks/C/pnetcdf_put_vara.c + This program writes a series of 3D variables with 2D block-block partitioning pattern. Each variable is a record variable. The number of variables, variable size, number of time records, and the NetCDF file format can be customized through command-line options. In addition, option '-i', if set, PnetCDF nonblocking APIs will be used to write to the file. * benchmarks/C/netcdf_put_vara.c + This sequential NetCDF-C program writes a series of 3D variables. Each variable is a record variable. The number of variables, variable size, number of time records, and the NetCDF file format can be customized through command-line options. + This program and `C/pnetcdf_put_vara.c` can be used to compare the performance of NetCDF and PnetCDF when running sequentially, i.e. one process. --- benchmarks/C/Makefile.am | 5 +- benchmarks/C/netcdf_put_vara.c | 284 +++++++++++++++++++++++++++++ benchmarks/C/pnetcdf_put_vara.c | 311 ++++++++++++++++++++++++++++++++ benchmarks/README.md | 16 ++ sneak_peek.md | 11 +- 5 files changed, 624 insertions(+), 3 deletions(-) create mode 100644 benchmarks/C/netcdf_put_vara.c create mode 100644 benchmarks/C/pnetcdf_put_vara.c diff --git a/benchmarks/C/Makefile.am b/benchmarks/C/Makefile.am index bb6d114ac..973de62ff 100644 --- a/benchmarks/C/Makefile.am +++ b/benchmarks/C/Makefile.am @@ -13,7 +13,8 @@ LDADD = $(top_builddir)/src/libs/libpnetcdf.la LDADD += @NETCDF4_LDFLAGS@ @ADIOS_LDFLAGS@ @NETCDF4_LIBS@ @ADIOS_LIBS@ check_PROGRAMS = aggregation \ - write_block_read_column + write_block_read_column \ + pnetcdf_put_vara # parallel runs only # TESTS = $(check_PROGRAMS) @@ -35,7 +36,7 @@ NC_FILES = $(check_PROGRAMS:%=$(TESTOUTDIR)/%.nc) \ CLEANFILES = core core.* *.gcda *.gcno *.gcov gmon.out \ $(NC_FILES) -EXTRA_DIST = parallel_run.sh +EXTRA_DIST = parallel_run.sh pnetcdf_put_vara.c ptest ptests ptest4: $(check_PROGRAMS) @echo "===========================================================" diff --git a/benchmarks/C/netcdf_put_vara.c b/benchmarks/C/netcdf_put_vara.c new file mode 100644 index 000000000..9b5c4ebe0 --- /dev/null +++ b/benchmarks/C/netcdf_put_vara.c @@ -0,0 +1,284 @@ +/********************************************************************* + * + * Copyright (C) 2024, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + * + *********************************************************************/ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * This sequential NetCDF-C program writes a series of 3D variables. Each + * variable is a record variable. The number of variables, variable size, + * number of time records, and the NetCDF file format can be customized through + * command-line options. + * + * To compile: + * % gcc netcdf_put_vara.c -o netcdf_put_vara -I $NETCDF_DIR/include -L $NETCDF_DIR/lib -lnetcdf + * + * Example run command and outputs from running ncdump on the output netCDF + * file produced by this example program: + + * % ./netcdf_put_vara -n 4 -t 10 -l 1024 -k 5 + * ----------------------------------------------------------- + * Output NetCDF file name: testfile.nc + * Output NetCDF file kind: CDF-5 + * Total number of variables: 4 + * Data type of variables: NC_FLOAT + * Each 2D variable size: 1024 x 1024 + * Number of time records: 10 + * Total write amount: 167772160 B + * 160.00 MiB + * 0.16 GiB + * variable write time: 0.3411 sec + * Write bandwidth: 469.10 MiB/s + * 0.46 GiB/s + * open-to-close time: 0.9867 sec + * Write bandwidth: 162.15 MiB/s + * 0.16 GiB/s + * ----------------------------------------------------------- + * + * % ncdump -h testfile.nc + * netcdf testfile { + * dimensions: + * time = UNLIMITED ; // (10 currently) + * Y = 1024 ; + * X = 1024 ; + * variables: + * float var_0(time, Y, X) ; + * var_0:str_att = "some text attribute 0 type text." ; + * var_0:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_0:short_att = 1234s ; + * float var_1(time, Y, X) ; + * var_1:str_att = "some text attribute 1 type text." ; + * var_1:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_1:short_att = 1234s ; + * float var_2(time, Y, X) ; + * var_2:str_att = "some text attribute 2 type text." ; + * var_2:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_2:short_att = 1234s ; + * float var_3(time, Y, X) ; + * var_3:str_att = "some text attribute 3 type text." ; + * var_3:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_3:short_att = 1234s ; + * + * // global attributes: + * :history = "Thu Aug 29 14:29:35 2024" ; + * } + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include /* strcpy(), strncpy() */ +#include /* getopt() */ +#include +#include + +static int verbose; + +#define ERR { \ + if (err != NC_NOERR) { \ + printf("Error at %s:%d : %s\n", __FILE__,__LINE__, nc_strerror(err)); \ + nerrs++; \ + } \ +} + +static double wtime(void) +{ + double now_time; + struct timeval etstart; + struct timezone tzp; + + if (gettimeofday(&etstart, &tzp) == -1) + perror("Error: calling gettimeofday() not successful.\n"); + + now_time = ((double)etstart.tv_sec) + /* in seconds */ + ((double)etstart.tv_usec) / 1000000.0; /* in microseconds */ + return now_time; +} + +/*----< pnetcdf_io() >-------------------------------------------------------*/ +static int +netcdf_io(char *filename, + int kind, + int len, + int nvars, + int ntimes) +{ + char name[128], str_att[128], *file_kind; + int i, j, err, nerrs=0; + int cmode, ncid, *varid, dimid[3]; + float **buf; + double bw, timing[2]; + size_t w_size; + size_t start[3], count[3]; + + /* each local array is of size len x len */ + buf = (float**) malloc(sizeof(float*) * nvars); + for (i=0; i 0); +} + diff --git a/benchmarks/C/pnetcdf_put_vara.c b/benchmarks/C/pnetcdf_put_vara.c new file mode 100644 index 000000000..0a49a5446 --- /dev/null +++ b/benchmarks/C/pnetcdf_put_vara.c @@ -0,0 +1,311 @@ +/********************************************************************* + * + * Copyright (C) 2024, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + * + *********************************************************************/ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * This program writes a series of 3D variables with 2D block-block partitioning + * pattern. Each variable is a record variable. The number of variables, + * variable size, number of time records, and the NetCDF file format can be + * customized through command-line options. In addition, option '-i', if set, + * PnetCDF nonblocking APIs will be used to write to the file. + * + * To compile: + * % mpicc -O2 pnetcdf_put_vara.c -o pnetcdf_put_vara -lpnetcdf + * + * Example run command and outputs from running ncmpidump on the output netCDF + * file produced by this example program: + * + * % mpiexec -n 4 ./pnetcdf_put_vara -n 4 -t 10 -l 1024 -k 5 -i + * ----------------------------------------------------------- + * Output NetCDF file name: testfile.nc + * Output NetCDF file kind: CDF-5 + * Number of MPI processes: 4 + * Total number of variables: 4 + * Data type of variables: NC_FLOAT + * Each 2D variable size: 2048 x 2048 + * Number of time records: 10 + * If using nonblocking APIs: Yes + * Total write amount: 671088640 B + * 640.00 MiB + * 0.62 GiB + * Max variable write time: 0.5402 sec + * Write bandwidth: 1184.69 MiB/s + * 1.16 GiB/s + * Max open-to-close time: 0.5521 sec + * Write bandwidth: 1159.13 MiB/s + * 1.13 GiB/s + * ----------------------------------------------------------- + * + * % ncmpidump -h testfile.nc + * netcdf testfile { + * // file format: CDF-5 (big variables) + * dimensions: + * time = UNLIMITED ; // (10 currently) + * Y = 2048 ; + * X = 2048 ; + * variables: + * float var_0(time, Y, X) ; + * var_0:str_att = "some text attribute 0 type text." ; + * var_0:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_0:short_att = 1234s ; + * float var_1(time, Y, X) ; + * var_1:str_att = "some text attribute 1 type text." ; + * var_1:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_1:short_att = 1234s ; + * float var_2(time, Y, X) ; + * var_2:str_att = "some text attribute 2 type text." ; + * var_2:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_2:short_att = 1234s ; + * float var_3(time, Y, X) ; + * var_3:str_att = "some text attribute 3 type text." ; + * var_3:float_att = 0.f, 1.f, 2.f, 3.f ; + * var_3:short_att = 1234s ; + * + * // global attributes: + * :history = "Thu Aug 29 14:29:35 2024" ; + * } + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include /* strcpy(), strncpy() */ +#include /* getopt() */ +#include +#include + +static int verbose; + +#define ERR { \ + if (err != NC_NOERR) { \ + printf("Error at %s:%d : %s\n", __FILE__,__LINE__, ncmpi_strerror(err)); \ + nerrs++; \ + } \ +} + +/*----< pnetcdf_io() >-------------------------------------------------------*/ +static int +pnetcdf_io(char *filename, + int nonblocking, + int kind, + int len, + int nvars, + int ntimes) +{ + char name[128], str_att[128], *file_kind; + int i, j, rank, nprocs, err, nerrs=0; + int psizes[2], cmode, ncid, *varid, dimid[3]; + float **buf; + double bw, timing[2], max_t[2]; + size_t w_size; + MPI_Offset start[3], count[3]; + MPI_Comm comm = MPI_COMM_WORLD; + + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &nprocs); + + psizes[0] = psizes[1] = 0; + MPI_Dims_create(nprocs, 2, psizes); + + /* each local array is of size (psizes[0] * len) x (psizes[1] * len) */ + buf = (float**) malloc(sizeof(float*) * nvars); + for (i=0; i 1) MPI_Barrier(comm); + timing[0] = MPI_Wtime(); + + /* create a new file for writing ----------------------------------------*/ + cmode |= NC_CLOBBER; + err = ncmpi_create(comm, filename, cmode, MPI_INFO_NULL, &ncid); ERR + + /* add a global attribute */ + sprintf(str_att, "Thu Aug 29 14:29:35 2024"); + err = ncmpi_put_att_text(ncid, NC_GLOBAL, "history", strlen(str_att), + str_att); ERR + + /* define dimensions x and y */ + err = ncmpi_def_dim(ncid, "time", NC_UNLIMITED, &dimid[0]); ERR + err = ncmpi_def_dim(ncid, "Y", psizes[0] * len, &dimid[1]); ERR + err = ncmpi_def_dim(ncid, "X", psizes[1] * len, &dimid[2]); ERR + + /* define 2D variables of float type */ + for (i=0; i 0) return nerrs; + + printf("-----------------------------------------------------------\n"); + printf("Output NetCDF file name: %s\n", filename); + printf("%s\n", file_kind); + printf("Number of MPI processes: %d\n", nprocs); + printf("Total number of variables: %d\n", nvars); + printf("Data type of variables: NC_FLOAT\n"); + printf("Each 2D variable size: %d x %d\n",psizes[0]*len,psizes[1]*len); + printf("Number of time records: %d\n",ntimes); + if (nonblocking) + printf("If using nonblocking APIs: Yes\n"); + else + printf("If using nonblocking APIs: NO\n"); + w_size = sizeof(float) * nprocs * len * len * nvars * ntimes; + printf("Total write amount: %zd B\n", w_size); + printf(" %.2f MiB\n", (float)w_size/1048576); + printf(" %.2f GiB\n", (float)w_size/1073741824); + bw = (double)w_size / 1048576; + printf("Max variable write time: %.4f sec\n", max_t[1]); + printf("Write bandwidth: %.2f MiB/s\n", bw/max_t[1]); + printf(" %.2f GiB/s\n", bw/1024.0/max_t[1]); + printf("Max open-to-close time: %.4f sec\n", max_t[0]); + printf("Write bandwidth: %.2f MiB/s\n", bw/max_t[0]); + printf(" %.2f GiB/s\n", bw/1024.0/max_t[0]); + printf("-----------------------------------------------------------\n"); + + return nerrs; +} + +static void +usage(char *argv0) +{ + char *help = + "Usage: %s [-h | -q | -i | -k num |-l num | -n num | -t num] [file_name]\n" + " [-h] Print help\n" + " [-q] Quiet mode (reports when fail)\n" + " [-i] Use PnetCDF nonblocking APIs\n" + " [-k format] file format: 1 for CDF-1,\n" + " 2 for CDF-2,\n" + " 5 for CDF-5 (default)\n" + " [-l] X and Y dimension lengths (default 32)\n" + " [-n] number of variables (default 4)\n" + " [-t] number of time iterations (default 1)\n" + " [filename] output netCDF file name\n"; + fprintf(stderr, help, argv0); +} + +int main(int argc, char** argv) +{ + extern int optind; + extern char *optarg; + char filename[512]; + int i, rank, kind, nerrs=0; + int nonblocking, nvars, len, ntimes; + + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + verbose = 1; + nonblocking = 0; + kind = 5; + nvars = 4; + len = 32; + ntimes = 1; + + /* get command-line arguments */ + while ((i = getopt(argc, argv, "hqik:l:n:t:")) != EOF) + switch(i) { + case 'q': verbose = 0; + break; + case 'i': nonblocking = 1; + break; + case 'k': kind = atoi(optarg); + break; + case 'l': len = atoi(optarg); + break; + case 'n': nvars = atoi(optarg); + break; + case 't': ntimes = atoi(optarg); + break; + case 'h': + default: if (rank==0) usage(argv[0]); + MPI_Finalize(); + return 1; + } + if (argv[optind] == NULL) strcpy(filename, "testfile.nc"); + else snprintf(filename, 512, "%s", argv[optind]); + + MPI_Bcast(filename, 512, MPI_CHAR, 0, MPI_COMM_WORLD); + + nerrs += pnetcdf_io(filename, nonblocking, kind, len, nvars, ntimes); + + MPI_Finalize(); + return (nerrs > 0); +} + diff --git a/benchmarks/README.md b/benchmarks/README.md index 63ca45d53..bcc51b2b1 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -19,6 +19,22 @@ various of APIs as well as access patterns. but in a 2D `*-block` pattern. + Write and read performance are measured and reported separately. +* C/pnetcdf_put_vara.c + + This program writes a series of 3D variables with 2D block-block + partitioning pattern. Each variable is a record variable. The number of + variables, variable size, number of time records, and the NetCDF file + format can be customized through command-line options. In addition, option + '-i', if set, PnetCDF nonblocking APIs will be used to write to the file. + +* C/netcdf_put_vara.c + + This sequential NetCDF-C program writes a series of 3D variables. Each + variable is a record variable. The number of variables, variable size, + number of time records, and the NetCDF file format can be customized + through command-line options. + + This program and `C/pnetcdf_put_vara.c` can be used to compare the + performance of NetCDF and PnetCDF when running sequentially, i.e. one + process. + * FLASH-IO + FLASH is a reacting hydrodynamics code developed at University of Chicago. https://astro.uchicago.edu/research/flash.php diff --git a/sneak_peek.md b/sneak_peek.md index 26af422c9..19a40421a 100644 --- a/sneak_peek.md +++ b/sneak_peek.md @@ -68,7 +68,16 @@ This is essentially a placeholder for the next release note ... when calling the PnetCDF flexible APIs. * New programs for I/O benchmarks - + none + + C/pnetcdf_put_vara.c -- + * This program writes a series of 3D variables with 2D block-block + partitioning pattern. Each variable is a record variable. + + + C/netcdf_put_vara.c -- + * This sequential NetCDF-C program writes a series of 3D variables. Each + variable is a record variable. + * This program and `C/pnetcdf_put_vara.c` can be used to compare the + performance of NetCDF and PnetCDF when running sequentially, i.e. one + process. * New test program + test/testcases/flexible_large_count.c - tests flexible APIs that use MPI