1/*********************************************************************
2 *   Copyright 1989, University Corporation for Atmospheric Research
3 *   See netcdf/README file for copying and redistribution conditions.
4 *   $Header: /upc/share/CVS/netcdf-3/nctest/nctime.c,v 1.12 1996/04/30 17:56:58 davis Exp $
5 *********************************************************************/
6
7/*
8 * This is a standalone benchmark program for timing netCDF hyperslab accesses.
9 * Once it is built, the benchmarks are run by invoking it with the shape of a
10 * four-dimensional netCDF variable, e.g.
11 *
12 *  nctime 10 20 30 40
13 *
14 * which will run timing benchmarks accessing 1-, 2-, 3-, and 4-dimensional
15 * slabs from 10 by 20 by 30 by 40 variables of each type.  The first dimension
16 * varies most slowly and is an unlimited (record) dimension.
17 *
18 * This program is especially useful for testing the effect of various compiler
19 * optimization levels or platform-specific optimizations on the performance of
20 * netCDF I/O.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <sys/param.h> /* for HZ */
27#include <sys/times.h>
28#include <assert.h>
29#include <time.h>
30
31#ifndef HZ
32#ifdef CLK_TCK
33#define HZ CLK_TCK
34#else
35#define HZ 60
36#endif
37#endif
38
39#include "netcdf.h"
40
41struct ncdim { /* dimension */
42    char *name;
43    long size;
44};
45
46struct ncvar { /* variable */
47    char *name;
48    nc_type type;
49    int ndims;
50    int *dims;
51    int natts;
52};
53
54
55#define LEN_OF(array) ((sizeof array) / (sizeof array[0]))
56
57/* Number of dimensions.  Changing this requires other changes as well. */
58#define NDIMS   4
59
60#define NVARS   6 /* number of variables, one for each type */
61
62/* Any function that maps dimension values 1-1 to values is OK here */
63#define VF(w)  1000*w[0]+100*w[1]+10*w[2]+w[3]
64
65static int DEFAULTDIMS[NDIMS] = {10, 20, 30, 40};
66
67/*
68 * Fill typed array element with specified value, that is
69 * 
70 *  v[ii] = val;
71 */
72static void
73val_stuff(typeviival) /* v[ii] = val */
74     nc_type type; /* netcdf type of v, NC_BYTE, ..., NC_DOUBLE */
75     void *v; /* array of specified type */
76     int ii; /* it's v[ii] we want to store into */
77     long val; /* value to store */
78{
79    union gp {
80 char cp[1];
81 short sp[1];
82 nclong lp[1];
83 float fp[1];
84 double dp[1];
85    } *gp;
86
87    gp = (union gp *) v;
88    switch (type) {
89      case NC_BYTE:
90      case NC_CHAR:
91 gp->cp[ii] = (char) val;
92 break;
93      case NC_SHORT:
94 gp->sp[ii] = (short) val;
95 break;
96      case NC_LONG:
97 gp->lp[ii] = (nclongval;
98 break;
99      case NC_FLOAT:
100 gp->fp[ii] = (float) val;
101 break;
102      case NC_DOUBLE:
103 gp->dp[ii] = (double) val;
104 break;
105    }
106}
107
108
109/*
110 * Compare typed array element with specified value, that is return
111 *
112 *  (v[ii] != val)
113 *
114 * returns 0 if equal, 1 if not equal
115 */
116
117static int
118val_diff(typeviival) /* v[ii] != val */
119     nc_type type; /* netcdf type of v, NC_BYTE, ..., NC_DOUBLE */
120     void *v; /* array of specified type */
121     int ii; /* it's v[ii] we want to compare */
122     long val; /* value to compare with */
123{
124    union gp {
125 char cp[1];
126 short sp[1];
127 nclong lp[1];
128 float fp[1];
129 double dp[1];
130    } *gp;
131
132    gp = (union gp *) v;
133    switch (type) {
134      case NC_BYTE:
135      case NC_CHAR:
136 return (gp->cp[ii] != (char) val);
137      case NC_SHORT:
138 return (gp->sp[ii] != (short) val);
139      case NC_LONG:
140 return (gp->lp[ii] != (nclongval);
141      case NC_FLOAT:
142 return (gp->fp[ii] != (float) val);
143      case NC_DOUBLE:
144 return (gp->dp[ii] != (double) val);
145    }
146    /* NOTREACHED */
147    return 0;
148}
149
150/*
151 * The following timing macros can be used by including the necessary
152 * declarations with
153 *
154 *     TIMING_DECLS ;
155 *
156 * and surrounding sections of code to be timed with the "statements"
157 *
158 *     TIMING_START ;
159 *     [code to be timed goes here]
160 *     TIMING_END ;
161 *
162 * (The terminating semicolon is required for TIMING_DECLS and TIMING_END.)
163 * The macros assume the user has stored a description of what is being timed
164 * in the user-declared string time_mess, and has included <sys/times.h>
165 */
166
167#define TIMING_DECLS \
168 long TMreps; /* counts repetitions of timed code */ \
169 long TMrepeats; /* repetitions needed to exceed a second */ \
170 clock_t TMusTMsy; /* user and system time in clock ticks */ \
171 float TMelapsed; /* elapsed time in seconds */ \
172 struct tms TMru;
173
174#define TIMING_START \
175 TMrepeats = 1; \
176 do {  /* loop enough times for at least 0.1 second elapsed time */ \
177     TMrepeats *= 2; \
178     times(&TMru); \
179     TMus = TMru.tms_utime; \
180     TMsy = TMru.tms_stime; \
181     for(TMreps=0;TMreps < TMrepeats;TMreps++) {
182
183#define TIMING_END \
184            } \
185     times(&TMru); \
186     TMus = TMru.tms_utime - TMus; \
187     TMsy = TMru.tms_stime - TMsy; \
188     TMelapsed= (float) (TMus+TMsy) / (float) HZ; \
189     if (TMreps < TMrepeats) break; \
190 } while (TMelapsed < 0.1 ); \
191 printf("time for %-20.20s %10.3f msec\n", \
192        time_messTMelapsed*1000./(TMreps+1))
193
194
195
196/*
197 * For each type of variable, put a four-dimensional hypercube of values
198 * with a single call to ncvarput.  Then use ncvarget to retrieve a single
199 * value, a vector of values along each of the four dimensions, a plane of
200 * values along each of the six pairs of dimensions, a cube of values along
201 * each of the four triples of dimensions, and all the values.
202 */
203void
204test_slabs(ncidsizes)
205     int ncid; /* handle of netcdf open and in data mode */
206     int *sizes; /* dimension sizes */
207{
208    char time_mess[100];
209
210    struct ncdim dims[NDIMS];
211    int dimids[NDIMS]; /* dimension ids */
212    long corner[NDIMS], edge[NDIMS], point[NDIMS];
213
214    static struct ncvar va[NVARS] = { /* variables of all types */
215 {"byte_var", NC_BYTENDIMS, 0, 0},
216 {"char_var", NC_CHARNDIMS, 0, 0},
217 {"short_var", NC_SHORTNDIMS, 0, 0},
218 {"long_var", NC_LONGNDIMS, 0, 0},
219 {"float_var", NC_FLOATNDIMS, 0, 0},
220 {"double_var", NC_DOUBLENDIMS, 0, 0},
221    };
222    void *v;
223
224    int varid[NVARS], iv; /* variable id */
225    int idimjdimkdimldim;
226    int iwixiyiziijjkk;
227    static char* dnames[] = {"w", "x", "y", "z", "u", "v", "a", "b", "c", "d"};
228
229    assert(NDIMS <= LEN_OF(dnames));
230    for (idim = 0; idim < NDIMSidim++) {
231 dims[idim].size = sizes[idim];
232 dims[idim].name = dnames[idim];
233    }
234
235    /* back in define mode OK, now add dimensions */
236
237    dimids[0] = ncdimdef(nciddims[0].nameNC_UNLIMITED);
238    if (dimids[0] == -1) {
239 ncclose(ncid);
240 return;
241    }
242    for (idim = 1; idim < NDIMSidim++) {
243 dimids[idim] = ncdimdef(nciddims[idim].namedims[idim].size);
244 if (dimids[idim] == -1) {
245     ncclose(ncid);
246     return;
247 }
248    }
249
250    /* define a multi-dimensional variable of each type */
251
252    for (iv = 0; iv < NVARSiv++) {
253 va[iv].dims = (int *) malloc(sizeof(int) * (unsigned)va[iv].ndims);
254 for (idim = 0; idim < va[iv].ndimsidim++)
255   va[iv].dims[idim] = dimids[idim];
256 varid[iv] = ncvardef(ncidva[iv].nameva[iv].typeva[iv].ndims,
257      va[iv].dims);
258 if (varid[iv] == -1) {
259     ncclose(ncid); return;
260 }
261    }
262
263    if (ncendef (ncid) == -1) {
264 ncclose(ncid); return;
265    }
266
267    printf("Note: first ncvarput writes fill values for all variables.\n");
268
269    for (iv = 0; iv < NVARSiv++) { /* test each type of variable */
270 TIMING_DECLS ;
271 printf("\n----- %s(%d,%d,%d,%d)\n",
272        va[iv].namesizes[0], sizes[1], sizes[2], sizes[3]);
273
274 v = (void *) malloc((unsigned)sizes[0]*sizes[1]*sizes[2]*sizes[3]
275     * nctypelen(va[iv].type));
276
277 /* fill it with values using a function of dimension indices */
278 ii = 0;
279 for (iw=0; iw < sizes[0]; iw++) {
280     corner[0] = iw;
281     for (ix=0; ix < sizes[1]; ix++) {
282 corner[1] = ix;
283 for (iy=0; iy < sizes[2]; iy++) {
284     corner[2] = iy;
285     for (iz=0; iz < sizes[3]; iz++) {
286 corner[3] = iz;
287 /* v[ii++] = VF(corner); */
288 val_stuff(va[iv].typeviiVF(corner));
289 ii++;
290     }
291 }
292     }
293 }
294
295 for (idim = 0; idim < NDIMSidim++) {
296     corner[idim] = 0;
297     edge[idim] = dims[idim].size;
298 }
299
300 sprintf(time_mess,"ncvarput %ldx%ldx%ldx%ld",
301 edge[0], edge[1], edge[2], edge[3]);
302
303 TIMING_START ;
304 /* ncvarput the whole variable */
305 if (ncvarput(ncidvarid[iv], corneredge, (void *) v) == -1) {
306     ncclose(ncid);
307     return;
308 }
309 TIMING_END ;
310
311 /*
312  * For several combinations of fixed dimensions, get a slab and compare
313  * values to function values.
314  */
315
316 /* get an interior point */
317 for (idim=0; idim < NDIMSidim++) {
318     corner[idim] = dims[idim].size/2;
319     edge[idim] = 1;
320     point[idim] = corner[idim];
321 }
322
323 sprintf(time_mess,"ncvarget %ldx%ldx%ldx%ld"
324 ,edge[0],edge[1],edge[2],edge[3]);
325
326 TIMING_START ;
327 if (ncvarget(ncidvarid[iv], corneredge, (void *) v) == -1)
328     return;
329 TIMING_END ;
330
331 /* if (v[0] != VF(point)) */
332 if (val_diff(va[iv].typev, 0, VF(point)))
333   fprintf(stderr,"ncvarget got wrong value for point");
334
335 /* get a vector in each direction */
336 for (idim=0; idim < NDIMSidim++) {
337     for (jdim=0; jdim < NDIMSjdim++) {
338 corner[jdim] = 0;
339 edge[jdim] = 1;
340 point[jdim] = corner[jdim];
341     }
342     corner[idim] = 0; /* get vector along dimension idim */
343     edge[idim] = dims[idim].size;
344
345     sprintf(time_mess,"ncvarget %ldx%ldx%ldx%ld"
346     ,edge[0],edge[1],edge[2],edge[3]);
347
348     TIMING_START ;
349     if (ncvarget(ncidvarid[iv], corneredge, (void *) v) == -1)
350       return;
351     TIMING_END ;
352
353     for (ii=corner[idim]; ii < edge[idim]; ii++) {
354 point[idim] = ii;
355 /* if (v[ii] != VF(point)) */
356 if (val_diff(va[iv].typeviiVF(point)))
357   fprintf(stderr,"ncvarget got wrong value for vector");
358     }
359 }
360
361 /* get a plane in each direction */
362 for (idim=0; idim < NDIMSidim++) {
363     for (jdim=idim+1; jdim < NDIMSjdim++) {
364 for (kdim=0; kdim < NDIMSkdim++) { /* reset corners and edges */
365     corner[kdim] = 0;
366     edge[kdim] = 1;
367     point[kdim] = corner[kdim];
368 }
369 corner[idim] = 0; /* plane along dimensions idim jdim */
370 corner[jdim] = 0;
371 edge[idim] = dims[idim].size;
372 edge[jdim] = dims[jdim].size;
373
374 sprintf(time_mess,"ncvarget %ldx%ldx%ldx%ld"
375 ,edge[0],edge[1],edge[2],edge[3]);
376
377 TIMING_START ;
378 if (ncvarget(ncidvarid[iv], corneredge, (void *) v) == -1)
379   return;
380 TIMING_END ;
381
382 for (ii=corner[idim]; ii < edge[idim]; ii++) {
383     for (jj=corner[jdim]; jj < edge[jdim]; jj++) {
384 point[idim] = ii;
385 point[jdim] = jj;
386 /* if (v[(ii)*edge[jdim]+jj] != VF(point)) { */
387 if (val_diff(va[iv].typev,
388      (ii)*(int)edge[jdim]+jjVF(point))) {
389     fprintf(stderr,
390     "ncvarget got wrong value in plane");
391 }
392     }
393 }
394     }
395 }
396
397 /* get a cube in each direction */
398 for (idim=0; idim < NDIMSidim++) {
399     for (jdim=idim+1; jdim < NDIMSjdim++) {
400 for (kdim=jdim+1; kdim < NDIMSkdim++) {
401     for (ldim=0; ldim < NDIMSldim++) { /* reset corners, edges */
402 corner[ldim] = 0;
403 edge[ldim] = 1;
404 point[ldim] = corner[ldim];
405     }
406     corner[idim] = 0; /* intr. cube along idim jdim kdim */
407     corner[jdim] = 0;
408     corner[kdim] = 0;
409     edge[idim] = dims[idim].size;
410     edge[jdim] = dims[jdim].size;
411     edge[kdim] = dims[kdim].size;
412
413     sprintf(time_mess,"ncvarget %ldx%ldx%ldx%ld"
414     ,edge[0],edge[1],edge[2],edge[3]);
415
416     TIMING_START ;
417     if (ncvarget(ncidvarid[iv], corneredge,
418  (void *) v) == -1)
419       return;
420     TIMING_END ;
421
422     for (ii=corner[idim]; ii < edge[idim]; ii++) {
423 for (jj=corner[jdim]; jj < edge[jdim]; jj++) {
424     for (kk=corner[kdim]; kk < edge[kdim]; kk++) {
425 point[idim] = ii;
426 point[jdim] = jj;
427 point[kdim] = kk;
428 /* if (v[((ii)*edge[jdim]+jj)*
429    edge[kdim]+kk] != VF(point)) { */
430 if (val_diff(va[iv].type,v,
431      ((ii)*(int)edge[jdim]+jj)*
432      (int)edge[kdim]+kk,VF(point))) {
433     fprintf(stderr,
434     "ncvarget - bad value in cube");
435 }
436     }
437 }
438     }
439 }
440     }
441 }
442
443 /* get one 4-D slab of data */
444 for(idim = 0; idim < NDIMSidim++) {
445     corner[idim] = 0;
446     edge[idim] = dims[idim].size;
447 }
448
449 sprintf(time_mess,"ncvarget %ldx%ldx%ldx%ld"
450 ,edge[0],edge[1],edge[2],edge[3]);
451
452 TIMING_START ;
453 if (ncvarget(ncidvarid[iv], corneredge, (void *) v) == -1)
454   return;
455 TIMING_END ;
456
457 free(v);
458    }
459}
460
461void
462usage(argv)
463     char **argv;
464{
465    int i;
466    fprintf(stderr, "usage: %s ", argv[0]);
467    for (i=0; i < NDIMSi++)
468      fprintf(stderr, "dim%d ", i);
469    fprintf(stderr, "\n");
470}
471
472
473int
474main(argcargv)
475     int argc;
476     char **argv;
477{
478    int ncid;
479    int i;
480    int w[NDIMS];
481
482    if (argc != NDIMS+1) {
483        for (i = 0; i < NDIMSi++)
484          w[i] = DEFAULTDIMS[i];
485    } else {
486        for (i = 0; i < NDIMSi++)
487          w[i] = atoi(argv[i+1]);
488    }
489
490    ncid = nccreate("benchmark.nc",NC_CLOBBER);
491
492    test_slabs(ncidw);
493
494    ncclose(ncid);
495    return 0;
496}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed