diff --git a/doc/netcdf4_vs_pnetcdf.md b/doc/netcdf4_vs_pnetcdf.md index 7fe088a65..36d8fb1b9 100644 --- a/doc/netcdf4_vs_pnetcdf.md +++ b/doc/netcdf4_vs_pnetcdf.md @@ -1,5 +1,46 @@ -## Programming difference between NetCDF4 and PnetCDF +# Comparison of PnetCDF and NetCDF4 +* [Supported File Formats](#supported-file-formats) +* [Programming Differences](#programming-differences) +* [Define Mode and Data Mode](#define-mode-and-data-mode) +* [Collective and Independent I/O Mode](#collective-and-independent-io-mode) +* [Blocking vs. Nonblocking APIs](#blocking-vs-nonblocking-apis) + +--- + +## Supported File Formats +* NetCDF4 supports both classic and HDF5-based file formats. + + Classic file format (CDF-1) -- The ESDS Community Standard defined the file format + to be used in the NetCDF user community in 1989. The file header bears a + signature of character string 'CDF-1' and now is commonly referred to as + [CDF-1](https://parallel-netcdf.github.io/doc/c-reference/pnetcdf-c/CDF_002d1-file-format-specification.html) + file format. + * 'CDF-2' format -- The CDF-1 format was later extended to support large + file size (i.e. larger than 2GB) in 2004. See its specification in + [ESDS-RFC-011v2.0](https://cdn.earthdata.nasa.gov/conduit/upload/496/ESDS-RFC-011v2.00.pdf). + Because its file header bears a signature of 'CDF-2' and the format is + also commonly referred to as + [CDF-2](https://parallel-netcdf.github.io/doc/c-reference/pnetcdf-c/CDF_002d2-file-format-specification.html) + format. + * [CDF-5](https://parallel-netcdf.github.io/doc/c-reference/pnetcdf-c/CDF_002d5-file-format-specification.html) + format -- The CDF-2 format was extended by PnetCDF developer team + in 2009 to support large variables and additional large data types, such + as 64-bit integer. + + HDF5-based file format -- Starting from its version 4.0.0, NetCDF includes + the format that is based on HDF5, which is referred to as NetCDF-4 format. + This offer new features such as groups, compound types, variable length + arrays, new unsigned integer types, etc. +* PnetCDF supports only the classic file formats. + + The classic files created by applications using NetCDF4 library can be read + by the PnetCDF library and vice versa. + + PnetCDF provides parallel I/O for accessing files in the classic format. + NetCDF4's parallel I/O for classic files makes use of PnetCDF library + underneath. Such feature can be enabled when building NetCDF4 library. + + +--- + +## Programming Differences * The API names are different between NetCDF4 and PnetCDF. + For C programming, NetCDF4 uses prefix `nc_` while PnetCDF uses `ncmpi_`. + For Fortran 77 programming, NetCDF4 uses prefix `nf_` while PnetCDF uses `nfmpi_`. @@ -35,3 +76,297 @@ | ${\textsf{\color{green}nc\\_put\\_vara\\_float}}$(ncid, varid, start, count, buf); | ${\textsf{\color{blue}ncmpi\\_put\\_vara\\_float\\_all}}$(ncid, varid, start, count, buf); | | /* close file */ | | | ${\textsf{\color{green}nc\\_close}}$(ncid); | ${\textsf{\color{blue}ncmpi\\_close}}$(ncid); | + + +--- + +## Define Mode and Data Mode + +In PnetCDF, an opened file is in either define mode or data mode. Switching +between the modes is done by explicitly calling `"ncmpi_enddef()"` and +`"ncmpi_redef()"`. NetCDF4 when operating on an HDF5-based file has no such +mode switching requirement. The reason of PnetCDF enforcing such a requirement +is to ensure the metadata consistency across all the MPI processes and keep the +overhead of metadata synchronization small. + +* Define mode + + When calling `"ncmpi_create()"` to create a new file, the file is + automatically put in the define mode. While in the define mode, the user + program can create new dimensions, new variables, and netCDF attributes. + Modification of these data objects' metadata can only be done when the file + is in the define mode. + + When opening an existing file, the opened file is automatically put in the + data mode. To add or modify the metadata, the user program must call + `"ncmpi_redef()"`. + +* Data mode + + Once the creation or modification of metadata is complete, the user program + must call `"ncmpi_enddef()"` to leave the define mode and enter the data + mode. + + While an open file is in data mode, the user program can make read and + write requests to that variables that have been created. + + + + +--- +## Collective and Independent I/O Mode + +The terminology of collective and independent I/O comes from MPI standard. A +collective I/O function call requires all the MPI processes opening the same +file to participate. On the other hand, an independent I/O function can be +called by an MPI process independently from others. + +For metadata I/O, both PnetCDF and NetCDF4 require the function calls to be +collective. + +* Mode Switch Mechanism + + PnetCDF -- when a file is in the data mode, it can be put into either + collective or independent I/O mode. The default mode is collective I/O + mode. Switching to and exiting from the independent I/O mode is done by + explicitly calling `"ncmpi_begin_indep_data()"` and + `"ncmpi_end_indep_data()"`. + + + NetCDF4 -- collective and independent mode switching is done per variable + basis. Switching mode is done by explicitly calling `"nc_var_par_access()"` + before accessing the variable. For more information, see + [Parallel I/O with NetCDF-4](https://docs.unidata.ucar.edu/netcdf-c/current/parallel_io.html). + + + + + +--- + +## Blocking vs Nonblocking APIs +* Blocking APIs -- All NetCDF4 APIs are blocking APIs. A blocking API means the + call to the API will not return until the operation is completed. For + example, a call to `nc_put_var_float()` will return only when the write data + has been stored at the system space, e.g. file systems. Similarly, a call to + `nc_get_var_float()` will only return when the user read buffer containing + the data retrieved from the file. Therefore, when a series of `put/get` + blocking APIs are called, these calls will be committed by the NetCDF4 + library one at a time, following the same order of the calls. +* Nonblocking APIs -- In addition to blocking APIs, PnetCDF provides the + nonblocking version of the APIs. A nonblocking API means the call to the API + will return as soon as the `put/get` request has been registered in the + PnetCDF library. The commitment of the request may happen later, when a call + to `ncmpi_wait_all/ncmpi_wait` is made. The nonblocking APIs are listed below. + + `ncmpi_iput_var_xxx()` - posts a nonblocking request to write to a variable. + + `ncmpi_iget_var_xxx()` - posts a nonblocking request to from from a variable. + + `ncmpi_bput_var_xxx()` - posts a nonblocking, buffered request to write to a variable. + + `ncmpi_iput_varn_xxx()` - posts a nonblocking request to write multiple subarrays to a variable. + + `ncmpi_iget_varn_xxx()` - posts a nonblocking request to read multiple subarrays from a variable. + + `ncmpi_bput_varn_xxx()` - posts a nonblocking, buffered request to write multiple subarrays to a variable. + + `ncmpi_wait_all()` - waits for nonblocking requests to complete, using collective MPI-IO. + + `ncmpi_wait()` - waits for nonblocking requests to complete, using independent MPI-IO. + + `ncmpi_attach_buff()` - Let PnetCDF to allocate an internal buffer to cache bput write requests. + + `File.detach_buff()` - Free the attached buffer. +* The advantage of using nonblocking APIs is when there are many small + `put/get` requests and each of them has a small amount. PnetCDF tries to + aggregate and coalesce multiple registered nonblocking requests into a large + one, because I/O usually performs better when the request amounts are large + and contiguous. See example programs + [nonblocking_write.c](../examples/C/nonblocking_write.c) and + [bput_varn_int64.c](../examples/C/bput_varn_int64.c). +* Table below shows the difference in C programming between using blocking + and nonblocking APIs. + +| PnetCDF Blocking APIs | PnetCDF Nonblocking APIs | +|:-------|:--------| +| ...
/* define 3 variables of NC_FLOAT type */ || +| ncmpi_def_var(ncid, "PSFC", NC_FLOAT, 2, dimid, &psfc);
ncmpi_def_var(ncid, "PRCP", NC_FLOAT, 2, dimid, &prcp);
ncmpi_def_var(ncid, "SNOW", NC_FLOAT, 2, dimid, &snow); | ditto | +| ... || +| /* exit define mode and enter data mode */
ncmpi_enddef(ncid); | ditto | +| ...
/* Call blocking APIs to write 3 variables to the file */ |
/* Call nonblocking APIs to post 3 write requests */ | +| ncmpi_put_vara_float_all(ncid, psfc, start, count, buf_psfc);
ncmpi_put_vara_float_all(ncid, prcp, start, count, buf_prcp);
ncmpi_put_vara_float_all(ncid, snow, start, count, buf_snow);| ncmpi_iput_vara_float(ncid, psfc, start, count, buf_psfc, &req[0]);
ncmpi_iput_vara_float(ncid, prcp, start, count, buf_prcp, &req[1]);
ncmpi_iput_vara_float(ncid, snow, start, count, buf_snow, &req[2]);| +| | /* Wait for nonblocking requests to complete */
ncmpi_wait_all(3, reqs, errs)| + +