summaryrefslogtreecommitdiffstats
path: root/raslib/test/test_miter.cc
blob: 55b2930b360692df6e1b22cf4adccaf0cdfeae3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see <http://www.rasdaman.org>
* or contact Peter Baumann via <baumann@rasdaman.com>.
*/
/*************************************************************
 *
 * SOURCE: test_miter.cc
 *
 * MODULE: raslib
 *
 ************************************************************/

#include <iostream>
#include <math.h>
#include <stdlib.h>

#include "raslib/miter.hh"
#include "raslib/minterval.hh"
#include "raslib/rminit.hh"
#include "raslib/rmdebug.hh"
RMINITGLOBALS('C')

// structure storing information on iteration for each dimension
// (perhaps add dimension for reordering later)
typedef struct {
  int repeat; // total number of repeats
  int inc;    // increment per repeat
  int curr;   // current repeat
} incArrElem;

// for repeating inside the test functions
const int numRepeat = 100;

r_Minterval
createCube(int size, int dim)
{
  int i;
  long c = pow((double)size, 1.0/(double)dim);

  r_Minterval res(dim);

  for(i=0; i<dim; i++)
    res << r_Sinterval(0l, c-1);

  i = 0;
  while(res.cell_count() < size) {
    res[i].set_high(res[i].high() + 1);
    i++;
  }
  if(res.cell_count() > size)
    res[i-1].set_high(res[i-1].high() - 1);
    
  return res;
}

void
test_Miter( r_Minterval& m1, r_Minterval& m2, char* data ) 
{
  char* currCell;

  // just to do something inside the loop
  unsigned long sum = 0;

  cout <<"Iteration r_Miter: ";

  // for performance measurement
  RMTimer mIterTimer("Iterator","r_Miter" );
  mIterTimer.start( );

  r_Miter iter(&m2, &m1, 4, (char*)data);
  for(int i=0; i<numRepeat; i++) {
    iter.reset();
    while(!iter.isDone()) {
      currCell = iter.nextCell();
      sum += *(long*)currCell;
    }
  }

  mIterTimer.stop( );
  cout << sum << endl;
}

void
test_DirectIter( r_Minterval& m1, r_Minterval& m2, char* data )
{
  int opSize = 4;
  int dim = m1.dimension();
  int i;
  char* currCell;

  // just to do something inside the loop
  unsigned long sum = 0;

  incArrElem* incArrIter;

  cout <<"Iteration direct: ";

  // for performance measurement
  RMTimer iterTimer("Iterator","directIter" );
  iterTimer.start( );

  for(int r=0; r<numRepeat; r++) {

    // stores the increments
    incArrIter = new incArrElem[dim];

    currCell = (char*)data;

    // the following initializes incArrIter and calculates the first offset
    int tIncIter = 1;     // total increment for current dimension
    int prevTIncIter = 1; // total increment for previous dimension
    int incIter = 4;      // current increment, corresponds to cell size
    int firstOff = 0;

    for( i=0; i<dim; i++ ) {
      // in RasDaMan the order of dimensions is the other way round!
      int r = dim - i - 1;
      // used for counting in iteration, initialize with 0
      incArrIter[i].curr = 0;
      // how often is the increment added?
      incArrIter[i].repeat = m2[r].high() - m2[r].low() + 1;
      // the increment for the result tile (higher dimensions calculated 
      // further down)
      incArrIter[i].inc = incIter;

      // calculate starting offset and increments for higher dimensions
      // firstOff is the offset in chars of the first cell
      firstOff += (m2[r].low()-m1[r].low()) * prevTIncIter * 4;
      // tInc is the increment if the dimension would be skipped
      tIncIter = (m1[r].high() - m1[r].low()+1) * prevTIncIter;
      // inc is the real increment, after some cells in the dimensions
      // have been iterated through.
      incIter = (tIncIter - incArrIter[i].repeat*prevTIncIter) * 4;
      // remember total increment of last dimension
      prevTIncIter = tIncIter;
    }
    
    currCell += firstOff;

    int done = 0;
    // get first adresses

    while(!done) {
      // iterate through lowest dimension
      for(i=0; i<incArrIter[0].repeat; i++) {
	// execute operation
	sum += *(long*)currCell;
	// increment adresses
	currCell += incArrIter[0].inc;
      }
      // increment other dimensions
      for(i=1; i<dim; i++) {
	incArrIter[i].curr++;
	currCell += incArrIter[i].inc;
	if(incArrIter[i].curr < incArrIter[i].repeat) {
	  // no overflow in this dimension
	  break;
	} else {
	  // overflow in this dimension
	  incArrIter[i].curr = 0;
	}
      }
      if( i == dim ) {
	// overflow in last dimension
	done = 1;
      }
    }
    delete [] incArrIter;
  }
  iterTimer.stop();
  cout << sum << endl;
}

void
test_OldIter( r_Minterval& m1, r_Minterval& m2, char* data )
{
  // just to do something inside the loop
  unsigned long sum = 0;

  cout <<"Iteration oldIter: ";
  // for performance measurement
  RMTimer oldIterTimer("Iterator","oldIter" );
  oldIterTimer.start( );

  r_Point pOp(m2.dimension());
  int done;
  int recalc;
  int i, j;
  const int opSize = 4;
  int dim = m2.dimension();
  int innerExtent = (m2.get_extent())[dim-1];
  char* cellOp;

  // initialize points
  for(i = 0; i < dim; i++)
  {
    pOp << 0;
  }

  for(int r=0; r<numRepeat; r++) {
    done = 0;
    recalc = 0;
    
    // initialize points
    for(i = 0; i < dim; i++)
    {
      pOp[i] = m2[i].low();
    }

    cellOp = (char*)data + m1.cell_offset(pOp)*4;

    // iterate over all cells
    while(!done)
    {
      if( recalc )
      {
	cellOp = (char*)data + m1.cell_offset(pOp)*4;
	recalc = 0;
      }

      // iterate through innermost dimension
      for(j = 0; j < innerExtent; j++ ) {
	// execute operation on cell
	sum += *(long*)cellOp;
	cellOp += opSize;
      }

      // increment coordinates
      i = dim - 2;
      // special case! 1-D operands!
      if( i < 0 ) 
	break;
      ++pOp[i];
      recalc = 1;
      while( pOp[i] > m2[i].high() )
      {
	pOp[i] = m2[i].low();
	i--;
	if(i < 0)
	{
	  done = 1;
	  break;
	}
	++pOp[i];
      }
   }
  }

  oldIterTimer.stop();
  cout << sum << endl;
}

void
test_CppIter( unsigned long cells, char* data )
{
  unsigned long sum = 0;
  RMTimer cppIterTimer("Iterator", "cppIter");
  cppIterTimer.start();

  for(int r=0; r<numRepeat; r++) {
    for(int i = 0; i<1048576; i++) {
      sum += data[i];
    }
  }

  cppIterTimer.stop();
  cout <<"Iteration C++: " << sum << endl;
}

int main()
{   
  const unsigned long noCells = 1048576;
  unsigned long* data;

  for(int dim=1; dim<=7; dim++) {
    r_Minterval m2;
    r_Minterval m1(dim);
    
    m2 =  createCube(noCells, dim);

    for(int i=0; i<dim; i++) {
      m1 << r_Sinterval(m2[i].low()-1, m2[i].high()+1);
    }

    // as basis for the operations
    data = new unsigned long[m1.cell_count()];
    for(int i=0; i < m1.cell_count(); i++) {
      data[i] = i;
    }

    cout <<"Iterate through " << m2 << " in "<< m1 << endl; 

    RMInit::bmOut << "Dimensionality: " << dim << ", cells: " 
		  << m2.cell_count() << endl;

    for(int i=0; i<5; i++) {
      test_Miter( m1, m2, (char*)data );
      test_OldIter( m1, m2, (char*)data );
      test_DirectIter( m1, m2, (char*)data );
    }
    delete [] data;
  }

  RMInit::bmOut << "1-D Iteration in C++:" << endl;

  data = new unsigned long[noCells];

  for(int i=0; i < noCells; i++) {
    data[i] = i;
  }

  for(int i=0; i<5; i++) {
    test_CppIter( noCells, (char*)data );
  }
  delete [] data;
}