Skip to content

Commit 98443b7

Browse files
committed
add example of using chunking and compression
1 parent 2eec8aa commit 98443b7

File tree

2 files changed

+234
-1
lines changed

2 files changed

+234
-1
lines changed

examples/C/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ check_PROGRAMS = collective_write \
3737
ghost_cell \
3838
req_all \
3939
vard_mvars \
40-
time_var
40+
time_var \
41+
chunk_compress
4142

4243
if INSTALL_EXAMPLES
4344
example_execbin_PROGRAMS = $(check_PROGRAMS)

examples/C/chunk_compress.c

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*********************************************************************
2+
*
3+
* Copyright (C) 2013, Northwestern University and Argonne National Laboratory
4+
* See COPYRIGHT notice in top-level directory.
5+
*
6+
*********************************************************************/
7+
8+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9+
* This example shows how to use the chunking and compression features of
10+
* PnetCDF to write a 3D record variable of integer data type in parallel. It
11+
* first defines a netCDF variable of size time * global_ny * global_nx where
12+
* global_ny == NY and
13+
* global_nx == (NX * number of MPI processes).
14+
* The data partitioning pattern is a column-wise partitioning across all
15+
* processes. Each process writes a subarray of size ny * nx per record.
16+
*
17+
* To compile:
18+
* mpicc -O2 chunk_compress.c -o chunk_compress -lpnetcdf
19+
*
20+
* Example commands for MPI run and outputs from running ncmpidump on the
21+
* output netCDF file produced by this example program:
22+
*
23+
* % mpiexec -n 4 ./chunk_compress /pvfs2/wkliao/testfile.nc
24+
*
25+
* % ncmpidump /pvfs2/wkliao/testfile.nc
26+
* netcdf testfile {
27+
* // file format: CDF-5 (big variables)
28+
* dimensions:
29+
* time = UNLIMITED ; // (0 currently) <-- Not used anymore
30+
* Y = 10 ;
31+
* X = 16 ;
32+
* _datablock_dim_0 = 65593 ;
33+
* _datablock_dim_1 = 57 ;
34+
* variables:
35+
* int var ;
36+
* var:_ndim = 3 ; <-- true ndims
37+
* var:_dimids = 0, 1, 2 ; <-- dim IDs
38+
* var:_datatype = 4 ; <-- true data type
39+
* var:_varkind = 1 ; <-- compressed or not
40+
* var:_chunkdim = 1, 10, 4 ; <-- chunk sizes
41+
* var:_filter = 2 ; <-- filter ID
42+
* var:_metaoffset = 4LL ; <-- offset to metadata block
43+
* byte _datablock_0(_datablock_dim_0) ;
44+
* _datablock_0:_varkind = 2 ;
45+
* byte _datablock_1(_datablock_dim_1) ;
46+
* _datablock_1:_varkind = 2 ;
47+
*
48+
* // global attributes:
49+
* :_comressed = 1 ; <-- file contains compressed variables or not
50+
* :_nwrite = 2 ;
51+
* :_recsize = 2LL ; <-- true number of records
52+
* }
53+
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
54+
55+
#include <stdio.h>
56+
#include <stdlib.h>
57+
#include <string.h> /* strcpy(), strncpy() */
58+
#include <unistd.h> /* getopt() */
59+
#include <time.h> /* time() localtime(), asctime() */
60+
#include <mpi.h>
61+
#include <pnetcdf.h>
62+
63+
#define NY 10
64+
#define NX 4
65+
66+
static int verbose;
67+
68+
#define ERR {if(err!=NC_NOERR){printf("Error at %s:%d : %s\n", __FILE__,__LINE__, ncmpi_strerror(err));nerrs++;}}
69+
70+
static void
71+
usage(char *argv0)
72+
{
73+
char *help =
74+
"Usage: %s [-h] | [-q] [-k format] [file_name]\n"
75+
" [-h] Print help\n"
76+
" [-q] Quiet mode (reports when fail)\n"
77+
" [-k format] file format: 1 for CDF-1, 2 for CDF-2, 5 for CDF-5\n"
78+
" [filename] output netCDF file name\n";
79+
fprintf(stderr, help, argv0);
80+
}
81+
82+
/*----< pnetcdf_check_mem_usage() >------------------------------------------*/
83+
/* check PnetCDF library internal memory usage */
84+
static int
85+
pnetcdf_check_mem_usage(MPI_Comm comm)
86+
{
87+
int err, nerrs=0, rank;
88+
MPI_Offset malloc_size, sum_size;
89+
90+
MPI_Comm_rank(comm, &rank);
91+
92+
/* print info about PnetCDF internal malloc usage */
93+
err = ncmpi_inq_malloc_max_size(&malloc_size);
94+
if (err == NC_NOERR) {
95+
MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
96+
if (rank == 0 && verbose)
97+
printf("maximum heap memory allocated by PnetCDF internally is %lld bytes\n",
98+
sum_size);
99+
100+
/* check if there is any PnetCDF internal malloc residue */
101+
err = ncmpi_inq_malloc_size(&malloc_size);
102+
MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
103+
if (rank == 0 && sum_size > 0)
104+
printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
105+
sum_size);
106+
}
107+
else if (err != NC_ENOTENABLED) {
108+
printf("Error at %s:%d: %s\n", __FILE__,__LINE__,ncmpi_strerror(err));
109+
nerrs++;
110+
}
111+
return nerrs;
112+
}
113+
114+
/*----< pnetcdf_io() >-------------------------------------------------------*/
115+
static int
116+
pnetcdf_io(MPI_Comm comm, char *filename, int cmode)
117+
{
118+
int i, j, rank, nprocs, err, nerrs=0;
119+
int ncid, varid, dimid[3], buf[NY][NX];
120+
MPI_Offset global_ny, global_nx;
121+
MPI_Offset start[3], count[3];
122+
MPI_Info info;
123+
124+
MPI_Comm_rank(comm, &rank);
125+
MPI_Comm_size(comm, &nprocs);
126+
127+
MPI_Info_create(&info);
128+
MPI_Info_set(info, "nc_chunking", "enable");
129+
MPI_Info_set(info, "nc_chunk_default_filter", "zlib");
130+
131+
/* create a new file for writing ----------------------------------------*/
132+
cmode |= NC_CLOBBER;
133+
err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
134+
MPI_Info_free(&info);
135+
136+
/* the global array is NY * (NX * nprocs) */
137+
global_ny = NY;
138+
global_nx = NX * nprocs;
139+
140+
for (i=0; i<NY; i++)
141+
for (j=0; j<NX; j++)
142+
buf[i][j] = rank;
143+
144+
/* define dimensions x and y */
145+
err = ncmpi_def_dim(ncid, "time", NC_UNLIMITED, &dimid[0]); ERR
146+
err = ncmpi_def_dim(ncid, "Y", global_ny, &dimid[1]); ERR
147+
err = ncmpi_def_dim(ncid, "X", global_nx, &dimid[2]); ERR
148+
149+
/* define a 2D variable of integer type */
150+
err = ncmpi_def_var(ncid, "var", NC_INT, 3, dimid, &varid); ERR
151+
152+
/* set chunking (1st dimension should always be 1 for record variable) */
153+
int chunk_dim[3] = {1, NY, NX};
154+
err = ncmpi_var_set_chunk(ncid, varid, chunk_dim);; ERR
155+
156+
/* use default filter */
157+
err = ncmpi_var_set_filter(ncid, varid, NC_FILTER_DEFLATE); ERR
158+
159+
/* exit define mode */
160+
err = ncmpi_enddef(ncid); ERR
161+
162+
/* set subarray start and count */
163+
start[0] = 0;
164+
start[1] = 0;
165+
start[2] = NX * rank;
166+
count[0] = 1;
167+
count[1] = NY;
168+
count[2] = NX;
169+
170+
/* write to the 1st record */
171+
err = ncmpi_put_vara_int_all(ncid, varid, start, count, &buf[0][0]); ERR
172+
173+
/* write to the 2nd record */
174+
start[0] = 1;
175+
err = ncmpi_put_vara_int_all(ncid, varid, start, count, &buf[0][0]); ERR
176+
177+
/* check the current record dimension size */
178+
MPI_Offset dim_len;
179+
err = ncmpi_inq_dimlen(ncid, 0, &dim_len); ERR
180+
if (rank == 0)
181+
printf("Time dimension length = %lld\n", dim_len);
182+
183+
err = ncmpi_close(ncid); ERR
184+
185+
return nerrs;
186+
}
187+
188+
int main(int argc, char** argv)
189+
{
190+
extern int optind;
191+
extern char *optarg;
192+
char filename[256];
193+
int i, rank, kind=0, cmode=0, nerrs=0;
194+
195+
MPI_Init(&argc, &argv);
196+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
197+
198+
verbose = 1;
199+
200+
/* get command-line arguments */
201+
while ((i = getopt(argc, argv, "hqk:")) != EOF)
202+
switch(i) {
203+
case 'q': verbose = 0;
204+
break;
205+
case 'k': kind = atoi(optarg);
206+
break;
207+
case 'h':
208+
default: if (rank==0) usage(argv[0]);
209+
MPI_Finalize();
210+
return 1;
211+
}
212+
if (argv[optind] == NULL) strcpy(filename, "testfile.nc");
213+
else snprintf(filename, 256, "%s", argv[optind]);
214+
215+
MPI_Bcast(filename, 256, MPI_CHAR, 0, MPI_COMM_WORLD);
216+
217+
if (verbose && rank == 0) printf("%s: example of using put_vara APIs\n",__FILE__);
218+
219+
switch (kind) {
220+
case(2): cmode = NC_64BIT_OFFSET; break;
221+
case(5): cmode = NC_64BIT_DATA; break;
222+
default: cmode = 0;
223+
}
224+
225+
nerrs += pnetcdf_io(MPI_COMM_WORLD, filename, cmode);
226+
227+
nerrs += pnetcdf_check_mem_usage(MPI_COMM_WORLD);
228+
229+
MPI_Finalize();
230+
return (nerrs > 0);
231+
}
232+

0 commit comments

Comments
 (0)