Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libnczarr/zwalk.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
Additonal optimizations:
3
1. slice covers all of exactly one chunk: we can just tranfer whole chunk to/from memory
4
5
*/
6
/*********************************************************************
7
 *   Copyright 2018, UCAR/Unidata
8
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
9
 *********************************************************************/
10
#include "zincludes.h"
11
12
#define WDEBUG
13
#undef DFALTOPTIMIZE
14
15
static int initialized = 0;
16
17
static unsigned int optimize = 0;
18
19
extern int NCZ_buildchunkkey(size_t R, const size64_t* chunkindices, char** keyp);
20
21
/* 0 => no debug */
22
static unsigned int wdebug = 1;
23
24
/* Forward */
25
static int NCZ_walk(NCZProjection** projv, NCZOdometer* chunkodom, NCZOdometer* slpodom, NCZOdometer* memodom, const struct Common* common, void* chunkdata);
26
static int rangecount(NCZChunkRange range);
27
static int readfromcache(void* source, size64_t* chunkindices, void** chunkdata);
28
static int iswholechunk(struct Common* common,NCZSlice*);
29
static int wholechunk_indices(struct Common* common, NCZSlice* slices, size64_t* chunkindices);
30
31
const char*
32
astype(int typesize, void* ptr)
33
0
{
34
0
    switch(typesize) {
35
0
    case 4: {
36
0
  static char is[8];
37
0
  snprintf(is,sizeof(is),"%u",*((unsigned int*)ptr));
38
0
  return is;
39
0
        } break;
40
0
    default: break;
41
0
    }
42
0
    return "?";
43
0
}
44
45
/**************************************************/
46
int
47
ncz_chunking_init(void)
48
0
{
49
0
    const char* val = NULL;
50
#ifdef DFALTOPTIMIZE
51
    val = getenv("NCZ_NOOPTIMIZATION");
52
    optimize = (val == NULL ? 1 : 0);
53
#else
54
0
    optimize = 0;
55
0
#endif
56
0
    val = getenv("NCZ_WDEBUG");
57
0
    wdebug = (val == NULL ? 0 : atoi(val));
58
0
#ifdef WDEBUG
59
0
    if(wdebug > 0) fprintf(stderr,"wdebug=%u\n",wdebug);
60
0
#endif
61
0
    initialized = 1;
62
0
    return NC_NOERR;
63
0
}
64
65
/**************************************************/
66
67
/**
68
Goal: Given the slices being applied to the variable, create
69
and walk all possible combinations of projection vectors that
70
can be evaluated to provide the output data.
71
Note that we do not actually pass NCZSlice but rather
72
(start,count,stride) vectors.
73
74
@param var Controlling variable
75
@param usreading reading vs writing
76
@param start start vector
77
@param stop stop vector
78
@param stride stride vector
79
@param memory target or source of data
80
@param typecode nc_type of type being written
81
@param walkfcn fcn parameter to actually transfer data
82
*/
83
84
int
85
NCZ_transferslice(NC_VAR_INFO_T* var, int reading,
86
      size64_t* start, size64_t* count, size64_t* stride,
87
      void* memory, nc_type typecode)
88
0
{
89
0
    int r,stat = NC_NOERR;
90
0
    size64_t dimlens[NC_MAX_VAR_DIMS];
91
0
    size64_t chunklens[NC_MAX_VAR_DIMS];
92
0
    size64_t memshape[NC_MAX_VAR_DIMS];
93
0
    NCZSlice slices[NC_MAX_VAR_DIMS];
94
0
    struct Common common;
95
0
    NCZ_FILE_INFO_T* zfile = NULL;
96
0
    NCZ_VAR_INFO_T* zvar = NULL;
97
0
    size_t typesize;
98
99
0
    if(!initialized) ncz_chunking_init();
100
101
0
    if((stat = NC4_inq_atomic_type(typecode, NULL, &typesize))) goto done;
102
103
0
    if(wdebug >= 1) {
104
0
        size64_t stopvec[NC_MAX_VAR_DIMS];
105
0
  for(r=0;r<var->ndims;r++) stopvec[r] = start[r]+(count[r]*stride[r]);
106
0
        fprintf(stderr,"var: name=%s",var->hdr.name);
107
0
        fprintf(stderr," start=%s",nczprint_vector(var->ndims,start));
108
0
        fprintf(stderr," count=%s",nczprint_vector(var->ndims,count));
109
0
        fprintf(stderr," stop=%s",nczprint_vector(var->ndims,stopvec));
110
0
        fprintf(stderr," stride=%s\n",nczprint_vector(var->ndims,stride));
111
0
    }
112
113
    /* Fill in common */
114
0
    memset(&common,0,sizeof(common));
115
0
    common.var = var;
116
0
    common.file = (var->container)->nc4_info;
117
0
    zfile = common.file->format_file_info;
118
0
    zvar = common.var->format_var_info;
119
120
0
    common.reading = reading;
121
0
    common.memory = memory;
122
0
    common.typesize = typesize;
123
0
    common.cache = zvar->cache;
124
125
    /* We need to talk scalar into account */
126
0
    common.rank = var->ndims;
127
0
    common.scalar = zvar->scalar;
128
0
    common.swap = (zfile->native_endianness == var->endianness ? 0 : 1);
129
130
0
    common.chunkcount = 1;
131
0
    if(common.scalar) {
132
0
  dimlens[0] = 1;
133
0
  chunklens[0] = 1;
134
0
  slices[0].start = 0;
135
0
  slices[0].stride = 1;
136
0
  slices[0].stop = 0;
137
0
  slices[0].len = 1;
138
0
  common.chunkcount = 1;
139
0
  memshape[0] = 1;
140
0
    } else for(r=0;r<common.rank;r++) {
141
0
      dimlens[r] = var->dim[r]->len;
142
0
  chunklens[r] = var->chunksizes[r];
143
0
  slices[r].start = start[r];
144
0
  slices[r].stride = stride[r];
145
0
  slices[r].stop = minimum(start[r]+(count[r]*stride[r]),dimlens[r]);
146
0
  slices[r].len = dimlens[r];
147
0
  common.chunkcount *= chunklens[r];
148
0
  memshape[r] = count[r];
149
0
    }
150
151
0
    if(wdebug >= 1) {
152
0
        fprintf(stderr,"\trank=%d",common.rank);
153
0
        if(!common.scalar) {
154
0
            fprintf(stderr," dimlens=%s",nczprint_vector(common.rank,dimlens));
155
0
            fprintf(stderr," chunklens=%s",nczprint_vector(common.rank,chunklens));
156
0
            fprintf(stderr," memshape=%s",nczprint_vector(common.rank,memshape));
157
0
        }
158
0
  fprintf(stderr,"\n");
159
0
    }
160
0
    common.dimlens = dimlens; /* BAD: storing stack vector in a pointer; do not free */
161
0
    common.chunklens = chunklens; /* ditto */
162
0
    common.memshape = memshape; /* ditto */
163
0
    common.reader.source = ((NCZ_VAR_INFO_T*)(var->format_var_info))->cache;
164
0
    common.reader.read = readfromcache;
165
166
0
    if(common.scalar) {
167
0
        if((stat = NCZ_transferscalar(&common))) goto done;
168
0
    }
169
0
    else {
170
0
        if((stat = NCZ_transfer(&common, slices))) goto done;
171
0
    }
172
0
done:
173
0
    NCZ_clearcommon(&common);
174
0
    return stat;
175
0
}
176
177
/*
178
Walk the possible projections.
179
Broken out so we can use it for unit testing
180
@param common common parameters
181
@param slices
182
*/
183
int
184
NCZ_transfer(struct Common* common, NCZSlice* slices)
185
0
{
186
0
    int stat = NC_NOERR;
187
0
    NCZOdometer* chunkodom =  NULL;
188
0
    NCZOdometer* slpodom = NULL;
189
0
    NCZOdometer* memodom = NULL;
190
0
    void* chunkdata = NULL;
191
0
    int wholechunk = 0;
192
193
    /*
194
     We will need three sets of odometers.
195
     1. Chunk odometer to walk the chunk ranges to get all possible
196
        combinations of chunkranges over all dimensions.
197
     2. For each chunk odometer set of indices, we need a projection
198
        odometer that walks the set of projection slices for a given
199
        set of chunk ranges over all dimensions.
200
     3. A memory odometer that walks the memory data to specify
201
        the locations in memory for read/write
202
    */     
203
204
0
    if(wdebug >= 2) {
205
0
  fprintf(stderr,"slices=%s\n",nczprint_slices(common->rank,slices));
206
0
    }
207
208
0
    if((stat = NCZ_projectslices(common->dimlens, common->chunklens, slices,
209
0
      common, &chunkodom)))
210
0
  goto done;
211
212
0
    if(wdebug >= 4) {
213
0
  fprintf(stderr,"allprojections:\n%s",nczprint_allsliceprojections(common->rank,common->allprojections)); fflush(stderr);
214
0
    }
215
216
0
    wholechunk = iswholechunk(common,slices);
217
218
0
    if(wholechunk) {
219
        /* Implement a whole chunk read optimization; this is a rare occurrence
220
           where the the slices cover all of a single chunk.
221
        */
222
0
  size64_t chunkindices[NC_MAX_VAR_DIMS];
223
0
  unsigned char* memptr;
224
0
        unsigned char* slpptr;
225
226
  /* Which chunk are we getting? */
227
0
  if((stat=wholechunk_indices(common,slices,chunkindices))) goto done;
228
0
  if(wdebug >= 1)
229
0
      fprintf(stderr,"case: wholechunk: chunkindices: %s\n",nczprint_vector(common->rank,chunkindices));
230
  /* Read the chunk; handles fixed vs char* strings*/
231
0
        switch ((stat = common->reader.read(common->reader.source, chunkindices, &chunkdata))) {
232
0
        case NC_EEMPTY: /* cache created the chunk */
233
0
      break;
234
0
        case NC_NOERR: break;
235
0
        default: goto done;
236
0
        }
237
        /* Figure out memory address */
238
0
  memptr = ((unsigned char*)common->memory);
239
0
  slpptr = ((unsigned char*)chunkdata);
240
0
  if(common->reading) {
241
0
      if((stat=NCZ_copy_data(common->file,common->var->type_info,slpptr,common->chunkcount,!ZCLEAR,memptr))) goto done;
242
0
  } else {
243
0
      if((stat=NCZ_copy_data(common->file,common->var->type_info,memptr,common->chunkcount,ZCLEAR,slpptr))) goto done;
244
0
  }
245
//        transfern(common,slpptr,memptr,common->chunkcount,1,chunkdata);
246
0
        if(zutest && zutest->tests & UTEST_WHOLECHUNK)
247
0
      zutest->print(UTEST_WHOLECHUNK, common, chunkindices);
248
0
  goto done;
249
0
    }
250
251
    /* iterate over the odometer: all combination of chunk
252
       indices in the projections */
253
0
    for(;nczodom_more(chunkodom);) {
254
0
  int r;
255
0
  size64_t* chunkindices = NULL;
256
0
        NCZSlice slpslices[NC_MAX_VAR_DIMS];
257
0
        NCZSlice memslices[NC_MAX_VAR_DIMS];
258
0
        NCZProjection* proj[NC_MAX_VAR_DIMS];
259
0
  size64_t shape[NC_MAX_VAR_DIMS];
260
261
0
  chunkindices = nczodom_indices(chunkodom);
262
0
  if(wdebug >= 1) {
263
0
      fprintf(stderr,"chunkindices: %s\n",nczprint_vector(common->rank,chunkindices));
264
0
  }
265
266
0
  for(r=0;r<common->rank;r++) {
267
0
      NCZSliceProjections* slp = &common->allprojections[r];
268
0
      NCZProjection* projlist = slp->projections;
269
0
      size64_t indexr = chunkindices[r];
270
        /* use chunkindices[r] to find the corresponding projection slice */
271
      /* We must take into account that the chunkindex of projlist[r]
272
               may be greater than zero */
273
      /* note the 2 level indexing */
274
0
      indexr -= slp->range.start;
275
0
      NCZProjection* pr = &projlist[indexr];
276
0
      proj[r] = pr;
277
0
  }
278
279
0
  if(wdebug > 0) {
280
0
        fprintf(stderr,"Selected projections:\n");
281
0
      for(r=0;r<common->rank;r++) {
282
0
            fprintf(stderr,"\t[%d] %s\n",r,nczprint_projection(*proj[r]));
283
0
    shape[r] = proj[r]->iocount;
284
0
      }
285
0
      fprintf(stderr,"\tshape=%s\n",nczprint_vector(common->rank,shape));
286
0
  }
287
288
  /* See if any of the projections is a skip; if so, then move to the next chunk indices */
289
0
  for(r=0;r<common->rank;r++) {
290
0
      if(proj[r]->skip) goto next;
291
0
  }
292
293
0
  for(r=0;r<common->rank;r++) {
294
0
      slpslices[r] = proj[r]->chunkslice;
295
0
      memslices[r] = proj[r]->memslice;
296
0
  }
297
0
  if(zutest && zutest->tests & UTEST_TRANSFER)
298
0
      zutest->print(UTEST_TRANSFER, common, chunkodom, slpslices, memslices);
299
300
        /* Read from cache */
301
0
        stat = common->reader.read(common->reader.source, chunkindices, &chunkdata);
302
0
  switch (stat) {
303
0
        case NC_EEMPTY: /* cache created the chunk */
304
0
      break;
305
0
        case NC_NOERR: break;
306
0
        default: goto done;
307
0
        }
308
309
0
  slpodom = nczodom_fromslices(common->rank,slpslices);
310
0
  memodom = nczodom_fromslices(common->rank,memslices);
311
312
0
  { /* walk with odometer */
313
0
      if(wdebug >= 1)
314
0
      fprintf(stderr,"case: odometer:\n");
315
        /* This is the key action: walk this set of slices and transfer data */
316
0
        if((stat = NCZ_walk(proj,chunkodom,slpodom,memodom,common,chunkdata))) goto done;
317
0
  }
318
0
next:
319
0
        nczodom_free(slpodom); slpodom = NULL;
320
0
        nczodom_free(memodom); memodom = NULL;
321
0
        nczodom_next(chunkodom);
322
0
    }
323
0
done:
324
0
    nczodom_free(slpodom);
325
0
    nczodom_free(memodom);
326
0
    nczodom_free(chunkodom);
327
0
    return stat;
328
0
}
329
330
331
#ifdef WDEBUG
332
static void
333
wdebug2(const struct Common* common, unsigned char* slpptr, unsigned char* memptr, size_t avail, size_t stride, void* chunkdata)
334
0
{
335
0
    unsigned char* slpbase = chunkdata;
336
0
    unsigned char* membase = common->memory;
337
0
    unsigned slpoff = (unsigned)(slpptr - slpbase);
338
0
    unsigned memoff = (unsigned)(memptr - membase);
339
0
    unsigned slpidx = slpoff / common->typesize;
340
0
    unsigned memidx = memoff / common->typesize;
341
0
    unsigned value;
342
343
0
    fprintf(stderr,"wdebug2: %s: [%u/%d] %u->%u",
344
0
      common->reading?"read":"write",
345
0
      (unsigned)avail,
346
0
          (unsigned)stride,
347
0
      (unsigned)(common->reading?slpidx:memidx),
348
0
      (unsigned)(common->reading?memidx:slpidx)
349
0
      );
350
0
    if(common->reading)
351
0
        value = ((unsigned*)slpptr)[0];
352
0
    else
353
0
        value = ((unsigned*)memptr)[0];
354
0
    fprintf(stderr,"; [%u]=%u",(unsigned)(common->reading?slpidx:memidx),value);
355
356
0
    fprintf(stderr,"\n");
357
0
}
358
#else
359
#define wdebug2(common,slpptr,memptr,avail,stride,chunkdata)
360
#endif
361
362
/*
363
@param projv
364
@param chunkodom
365
@param slpodom
366
@param memodom
367
@param common
368
@param chunkdata
369
@return NC_NOERR
370
*/
371
static int
372
NCZ_walk(NCZProjection** projv, NCZOdometer* chunkodom, NCZOdometer* slpodom, NCZOdometer* memodom, const struct Common* common, void* chunkdata)
373
0
{
374
0
    int stat = NC_NOERR;
375
376
0
    for(;;) {
377
0
  size64_t slpoffset = 0;
378
0
  size64_t memoffset = 0;
379
0
  size64_t slpavail = 0;
380
0
  size64_t memavail = 0;
381
0
  size64_t laststride = 0;
382
0
  unsigned char* memptr0 = NULL;
383
0
  unsigned char* slpptr0 = NULL;
384
  
385
386
0
        if(!nczodom_more(slpodom)) break;
387
  
388
0
            if(wdebug >= 3) {
389
0
    fprintf(stderr,"xx.slp: odom: %s\n",nczprint_odom(slpodom));
390
0
    fprintf(stderr,"xx.mem: odom: %s\n",nczprint_odom(memodom));
391
0
      }
392
393
            /* Convert the indices to a linear offset WRT to chunk indices */
394
0
            slpoffset = nczodom_offset(slpodom);
395
0
            memoffset = nczodom_offset(memodom);
396
397
            /* transfer data between these addresses */
398
0
            memptr0 = ((unsigned char*)common->memory)+(memoffset * common->typesize);
399
0
            slpptr0 = ((unsigned char*)chunkdata)+(slpoffset * common->typesize);
400
401
0
      LOG((1,"%s: slpptr0=%p memptr0=%p slpoffset=%llu memoffset=%lld",__func__,slpptr0,memptr0,slpoffset,memoffset));
402
0
      if(zutest && zutest->tests & UTEST_WALK)
403
0
    zutest->print(UTEST_WALK, common, chunkodom, slpodom, memodom);
404
      /* See if we can transfer multiple values at one shot */
405
0
      laststride = slpodom->stride[common->rank-1];
406
0
      if(laststride == 1) {
407
0
          slpavail = nczodom_avail(slpodom); /* How much can we read? */
408
0
          memavail = nczodom_avail(memodom);
409
0
    assert(memavail == slpavail);
410
0
    nczodom_skipavail(slpodom);
411
0
          nczodom_skipavail(memodom);
412
0
      } else {
413
0
          slpavail = 1;
414
0
      }
415
0
        if(slpavail > 0) {
416
0
if(wdebug > 0) wdebug2(common,slpptr0,memptr0,slpavail,laststride,chunkdata);
417
0
      if(common->reading) {
418
0
        if((stat=NCZ_copy_data(common->file,common->var->type_info,slpptr0,slpavail,!ZCLEAR,memptr0))) goto done;
419
0
    } else {
420
0
        if((stat=NCZ_copy_data(common->file,common->var->type_info,memptr0,slpavail,ZCLEAR,slpptr0))) goto done;
421
0
    }
422
0
      }
423
//      if((stat = transfern(common,slpptr0,memptr0,avail,nczodom_laststride(slpodom),chunkdata)))goto done;
424
0
            nczodom_next(memodom);
425
0
            nczodom_next(slpodom);
426
0
    }
427
0
done:
428
0
    return stat;    
429
0
}
430
431
#if 0
432
static void
433
wdebug1(const struct Common* common, unsigned char* srcptr, unsigned char* dstptr, size_t count, size_t stride, void* chunkdata, const char* tag)
434
{
435
    unsigned char* dstbase = (common->reading?common->memory:chunkdata);
436
    unsigned char* srcbase = (common->reading?chunkdata:common->memory);
437
    unsigned dstoff = (unsigned)(dstptr - dstbase);
438
    unsigned srcoff = (unsigned)(srcptr - srcbase);
439
    unsigned srcidx = srcoff / sizeof(unsigned);
440
441
    fprintf(stderr,"%s: %s: [%u/%d] %u->%u",
442
      tag,
443
      common->reading?"read":"write",
444
      (unsigned)count,
445
          (unsigned)stride,
446
      (unsigned)(srcoff/common->typesize),
447
      (unsigned)(dstoff/common->typesize)
448
      );
449
#if 0
450
    fprintf(stderr,"\t%s[%u]=%u\n",(common->reading?"chunkdata":"memdata"),
451
//      0,((unsigned*)srcptr)[0]
452
        srcidx,((unsigned*)srcbase)[srcidx]
453
  );
454
#endif
455
#if 0
456
    { size_t len = common->typesize*count;
457
    fprintf(stderr," | [%u] %u->%u\n",(unsigned)len,(unsigned)srcoff,(unsigned)dstoff);
458
    }
459
#endif
460
    fprintf(stderr,"\n");
461
}
462
#else
463
#define wdebug1(common,srcptr,dstptr,count,srcstride,dststride,chunkdata,tag)
464
#endif
465
466
#if 0
467
static int
468
transfern(const struct Common* common, unsigned char* slpptr, unsigned char* memptr, size_t avail, size_t slpstride, void* chunkdata)
469
{
470
    int stat = NC_NOERR;
471
    size_t typesize = common->typesize;
472
    size_t len = typesize*avail;
473
    size_t m,s;
474
475
    if(common->reading) {
476
  if(slpstride == 1)
477
            memcpy(memptr,slpptr,len); /* straight copy */
478
  else {
479
      for(m=0,s=0;s<avail;s+=slpstride,m++) {
480
    size_t soffset = s*typesize;
481
    size_t moffset = m*typesize;
482
          memcpy(memptr+moffset,slpptr+soffset,typesize);
483
      }
484
  }
485
        if(common->swap)
486
            NCZ_swapatomicdata(len,memptr,common->typesize);
487
    } else { /*writing*/
488
unsigned char* srcbase = (common->reading?chunkdata:common->memory);
489
unsigned srcoff = (unsigned)(memptr - srcbase);
490
unsigned srcidx = srcoff / sizeof(unsigned); (void)srcidx;
491
  if(slpstride == 1)
492
            memcpy(slpptr,memptr,len); /* straight copy */
493
  else {
494
      for(m=0,s=0;s<avail;s+=slpstride,m++) {
495
    size_t soffset = s*typesize;
496
    size_t moffset = m*typesize;
497
          memcpy(slpptr+soffset,memptr+moffset,typesize);
498
      }
499
  }
500
        if(common->swap)
501
            NCZ_swapatomicdata(len,slpptr,common->typesize);
502
    }
503
    return THROW(stat);
504
}
505
#endif
506
507
#if 0
508
/* This function may not be necessary if code in zvar does it instead */
509
static int
510
NCZ_fillchunk(void* chunkdata, struct Common* common)
511
{
512
    int stat = NC_NOERR;    
513
514
    if(common->fillvalue == NULL) {
515
        memset(chunkdata,0,common->chunkcount*common->typesize);
516
  goto done;
517
    } 
518
519
    if(common->cache->fillchunk == NULL) {
520
        /* Get fill chunk*/
521
        if((stat = NCZ_create_fill_chunk(common->cache->chunksize, common->typesize, common->fillvalue, &common->cache->fillchunk)))
522
      goto done;
523
    }
524
    memcpy(chunkdata,common->cache->fillchunk,common->cache->chunksize);
525
done:
526
    return stat;
527
}
528
#endif
529
530
/* Break out this piece so we can use it for unit testing */
531
int
532
NCZ_projectslices(size64_t* dimlens,
533
                  size64_t* chunklens,
534
                  NCZSlice* slices,
535
                  struct Common* common, 
536
                  NCZOdometer** odomp)
537
0
{
538
0
    int stat = NC_NOERR;
539
0
    int r;
540
0
    NCZOdometer* odom = NULL;
541
0
    NCZSliceProjections* allprojections = NULL;
542
0
    NCZChunkRange ranges[NC_MAX_VAR_DIMS];
543
0
    size64_t start[NC_MAX_VAR_DIMS];
544
0
    size64_t stop[NC_MAX_VAR_DIMS];
545
0
    size64_t stride[NC_MAX_VAR_DIMS];
546
0
    size64_t len[NC_MAX_VAR_DIMS];
547
548
0
    if((allprojections = calloc(common->rank,sizeof(NCZSliceProjections))) == NULL)
549
0
        {stat = NC_ENOMEM; goto done;}
550
0
    memset(ranges,0,sizeof(ranges));
551
552
    /* Package common arguments */
553
0
    common->dimlens = dimlens;
554
0
    common->chunklens = chunklens;
555
    /* Compute the chunk ranges for each slice in a given dim */
556
0
    if((stat = NCZ_compute_chunk_ranges(common->rank,slices,common->chunklens,ranges)))
557
0
        goto done;
558
559
    /* Compute the slice index vector */
560
0
    if((stat=NCZ_compute_all_slice_projections(common,slices,ranges,allprojections)))
561
0
        goto done;
562
563
    /* Verify */
564
0
    for(r=0;r<common->rank;r++) {
565
0
        assert(rangecount(ranges[r]) == allprojections[r].count);
566
0
    }
567
568
    /* Compute the shape vector */
569
0
    for(r=0;r<common->rank;r++) {
570
0
        int j;
571
0
        size64_t iocount = 0;
572
0
        NCZProjection* projections = allprojections[r].projections;
573
0
        for(j=0;j<allprojections[r].count;j++) {
574
0
            NCZProjection* proj = &projections[j];
575
0
            iocount += proj->iocount;
576
0
        }
577
0
        common->shape[r] = iocount;
578
0
    }
579
0
    common->allprojections = allprojections;
580
0
    allprojections = NULL;
581
582
    /* Create an odometer to walk all the range combinations */
583
0
    for(r=0;r<common->rank;r++) {
584
0
        start[r] = ranges[r].start; 
585
0
        stop[r] = ranges[r].stop;
586
0
        stride[r] = 1;
587
0
        len[r] = ceildiv(common->dimlens[r],common->chunklens[r]);
588
0
    }   
589
590
0
    if((odom = nczodom_new(common->rank,start,stop,stride,len)) == NULL)
591
0
        {stat = NC_ENOMEM; goto done;}
592
0
    if(odomp) *odomp = odom;
593
594
0
done:
595
    /* reclaim allprojections if !NULL */
596
0
    if(allprojections != NULL) {
597
0
        NCZ_clearsliceprojections(common->rank,allprojections);
598
0
  nullfree(allprojections);
599
0
    }
600
0
    return stat;
601
0
}
602
603
/***************************************************/
604
/* Utilities */
605
606
static int
607
rangecount(NCZChunkRange range)
608
0
{
609
0
    return (range.stop - range.start);
610
0
}
611
612
/* Goal: Given a set of per-dimension indices,
613
     compute the corresponding linear position.
614
*/
615
size64_t
616
NCZ_computelinearoffset(size_t R, const size64_t* indices, const size64_t* dimlens)
617
0
{
618
0
      size64_t offset;
619
0
      int i;
620
621
0
      offset = 0;
622
0
      for(i=0;i<R;i++) {
623
0
          offset *= dimlens[i];
624
0
          offset += indices[i];
625
0
      } 
626
0
      return offset;
627
0
}
628
629
#if 0
630
/* Goal: Given a linear position
631
     compute the corresponding set of R indices
632
*/
633
void
634
NCZ_offset2indices(size_t R, size64_t offset, const size64_t* dimlens, size64_t* indices)
635
{
636
      int i;
637
638
      for(i=0;i<R;i++) {
639
          indices[i] = offset % dimlens[i];
640
          offset = offset / dimlens[i];
641
      } 
642
}
643
#endif
644
645
/**************************************************/
646
/* Unit test entry points */
647
648
int
649
NCZ_chunkindexodom(int rank, const NCZChunkRange* ranges, size64_t* chunkcounts, NCZOdometer** odomp)
650
0
{
651
0
    int stat = NC_NOERR;
652
0
    int r;
653
0
    NCZOdometer* odom = NULL;
654
0
    size64_t start[NC_MAX_VAR_DIMS];
655
0
    size64_t stop[NC_MAX_VAR_DIMS];
656
0
    size64_t stride[NC_MAX_VAR_DIMS];
657
0
    size64_t len[NC_MAX_VAR_DIMS];
658
659
0
    for(r=0;r<rank;r++) {
660
0
        start[r] = ranges[r].start; 
661
0
        stop[r] = ranges[r].stop;
662
0
        stride[r] = 1;
663
0
        len[r] = chunkcounts[r];
664
0
    }   
665
666
0
    if((odom = nczodom_new(rank, start, stop, stride, len))==NULL)
667
0
        {stat = NC_ENOMEM; goto done;}
668
669
0
    if(odomp) {*odomp = odom; odom = NULL;}
670
671
0
done:
672
0
    nczodom_free(odom);
673
0
    return stat;
674
0
}
675
676
static int
677
readfromcache(void* source, size64_t* chunkindices, void** chunkdatap)
678
0
{
679
0
    return NCZ_read_cache_chunk((struct NCZChunkCache*)source, chunkindices, chunkdatap);
680
0
}
681
682
void
683
NCZ_clearcommon(struct Common* common)
684
0
{
685
0
    NCZ_clearsliceprojections(common->rank,common->allprojections);
686
0
    nullfree(common->allprojections);
687
0
}
688
689
/* Does the User want all of one and only chunk? */
690
static int
691
iswholechunk(struct Common* common, NCZSlice* slices)
692
0
{
693
0
    int i;
694
    
695
    /* Check that slices cover a whole chunk */
696
0
    for(i=0;i<common->rank;i++) {
697
0
  if(!(slices[i].stride == 1                            /* no point skipping              */
698
0
     && (slices[i].start % common->chunklens[i]) == 0 /* starting at beginning of chunk */
699
0
     && (slices[i].stop - slices[i].start)            /* stop-start = edge length       */
700
0
        == common->chunklens[i]                       /* edge length == chunk length    */
701
0
     )) 
702
0
      return 0; /* slices do not cover a whole chunk */
703
0
    }
704
0
    return 1;
705
0
}
706
707
static int
708
wholechunk_indices(struct Common* common, NCZSlice* slices, size64_t* chunkindices)
709
0
{
710
0
    int i;
711
0
    for(i=0;i<common->rank;i++)
712
0
  chunkindices[i] = (slices[i].start / common->chunklens[i]);
713
0
    return NC_NOERR;
714
0
}
715
716
/**************************************************/
717
/* Scalar variable support */
718
719
/*
720
@param common common parameters
721
*/
722
723
int
724
NCZ_transferscalar(struct Common* common)
725
0
{
726
0
    int stat = NC_NOERR;
727
0
    void* chunkdata = NULL;
728
0
    size64_t chunkindices[NC_MAX_VAR_DIMS];
729
0
    unsigned char* memptr, *slpptr;
730
731
    /* Read from single chunk from cache */
732
0
    chunkindices[0] = 0;
733
0
    switch ((stat = common->reader.read(common->reader.source, chunkindices, &chunkdata))) {
734
0
    case NC_EEMPTY: /* cache created the chunk */
735
0
  break;
736
0
    case NC_NOERR: break;
737
0
    default: goto done;
738
0
    }
739
740
    /* Figure out memory address */
741
0
    memptr = ((unsigned char*)common->memory);
742
0
    slpptr = ((unsigned char*)chunkdata);
743
0
    if(common->reading) {
744
0
        if((stat=NCZ_copy_data(common->file,common->var->type_info,slpptr,common->chunkcount,!ZCLEAR,memptr))) goto done;
745
0
    } else {
746
0
        if((stat=NCZ_copy_data(common->file,common->var->type_info,memptr,common->chunkcount,ZCLEAR,slpptr))) goto done;
747
0
    }
748
749
0
done:
750
0
    return stat;
751
0
}
752
753
/* Debugging Interface: return the contents of a specified chunk */
754
EXTERNL int
755
NCZ_read_chunk(int ncid, int varid, size64_t* zindices, void* chunkdata)
756
0
{
757
0
    int stat = NC_NOERR;
758
0
    NC_VAR_INFO_T* var = NULL;
759
0
    NCZ_VAR_INFO_T* zvar = NULL;
760
0
    struct NCZChunkCache* cache = NULL;
761
0
    void* cachedata = NULL;
762
763
0
    if ((stat = nc4_find_grp_h5_var(ncid, varid, NULL, NULL, &var)))
764
0
  return THROW(stat);
765
0
    zvar = (NCZ_VAR_INFO_T*)var->format_var_info;
766
0
    cache = zvar->cache;
767
768
0
    if((stat = NCZ_read_cache_chunk(cache,zindices,&cachedata))) goto done;
769
0
    if(chunkdata) {
770
0
  if((stat = nc_copy_data(ncid,var->type_info->hdr.id,cachedata,cache->chunkcount,chunkdata))) goto done;
771
0
    } 
772
    
773
0
done:
774
0
    return stat;
775
0
}