Advanced Computing Platform for Theoretical Physics

dslash_test.c 8.89 KB
Newer Older
mikeaclark's avatar
mikeaclark committed
1
2
3
4
#include <stdio.h>
#include <stdlib.h>

#include <quda.h>
5
#include <dslash_reference.h>
mikeaclark's avatar
mikeaclark committed
6
#include <util_quda.h>
7
8
#include <spinor_quda.h>
#include <gauge_quda.h>
mikeaclark's avatar
mikeaclark committed
9

10
// What test are we doing (0 = dslash, 1 = MatPC, 2 = Mat)
mikeaclark's avatar
mikeaclark committed
11
int test_type = 1;
rbabich's avatar
rbabich committed
12
// clover-improved? (0 = plain Wilson, 1 = clover)
13
int clover_yes = 1;
mikeaclark's avatar
mikeaclark committed
14

15
QudaGaugeParam gaugeParam;
mikeaclark's avatar
mikeaclark committed
16
QudaInvertParam inv_param;
17
18

FullGauge gauge;
rbabich's avatar
rbabich committed
19
FullClover clover, cloverInv;
mikeaclark's avatar
mikeaclark committed
20
FullSpinor cudaSpinor;
21
FullSpinor cudaSpinorOut;
mikeaclark's avatar
mikeaclark committed
22
23
ParitySpinor tmp;

rbabich's avatar
rbabich committed
24
void *hostGauge[4], *hostClover, *hostCloverInv;
25
26
27
void *spinor, *spinorEven, *spinorOdd;
void *spinorRef, *spinorRefEven, *spinorRefOdd;
void *spinorGPU, *spinorGPUEven, *spinorGPUOdd;
rbabich's avatar
rbabich committed
28

29
double kappa = 1.0;
30
int ODD_BIT = 1;
31
int DAGGER_BIT = 0;
mikeaclark's avatar
mikeaclark committed
32
int TRANSFER = 0; // include transfer time in the benchmark?
33

mikeaclark's avatar
mikeaclark committed
34
35
void init() {

mikeaclark's avatar
mikeaclark committed
36
  gaugeParam.X[0] = 24;
37
  gaugeParam.X[1] = 24;
mikeaclark's avatar
mikeaclark committed
38
39
  gaugeParam.X[2] = 24;
  gaugeParam.X[3] = 32;
40
41
  setDims(gaugeParam.X);

rbabich's avatar
rbabich committed
42
43
44
45
  gaugeParam.anisotropy = 2.3;

  gaugeParam.gauge_order = QUDA_QDP_GAUGE_ORDER;
  gaugeParam.t_boundary = QUDA_ANTI_PERIODIC_T;
46

47
  gaugeParam.cpu_prec = QUDA_DOUBLE_PRECISION;
mikeaclark's avatar
mikeaclark committed
48
  gaugeParam.cuda_prec = QUDA_SINGLE_PRECISION;
49
50
51
  gaugeParam.reconstruct = QUDA_RECONSTRUCT_12;
  gaugeParam.reconstruct_sloppy = gaugeParam.reconstruct;
  gaugeParam.cuda_prec_sloppy = gaugeParam.cuda_prec;
52
  gaugeParam.gauge_fix = QUDA_GAUGE_FIXED_NO;
mikeaclark's avatar
mikeaclark committed
53

rbabich's avatar
rbabich committed
54
55
56
57
58
59
60
61
62
63
  gaugeParam.blockDim = 64;

  if (clover_yes) {
    inv_param.dslash_type = QUDA_CLOVER_WILSON_DSLASH;
  } else {
    inv_param.dslash_type = QUDA_WILSON_DSLASH;
  }

  inv_param.kappa = kappa;

64
  inv_param.cpu_prec = QUDA_DOUBLE_PRECISION;
mikeaclark's avatar
mikeaclark committed
65
  inv_param.cuda_prec = QUDA_SINGLE_PRECISION;
rbabich's avatar
rbabich committed
66

67
68
  if (test_type == 2) inv_param.dirac_order = QUDA_DIRAC_ORDER;
  else inv_param.dirac_order = QUDA_DIRAC_ORDER;
rbabich's avatar
rbabich committed
69

rbabich's avatar
rbabich committed
70
71
  if (clover_yes) {
    inv_param.clover_cpu_prec = QUDA_DOUBLE_PRECISION;
rbabich's avatar
rbabich committed
72
    inv_param.clover_cuda_prec = QUDA_SINGLE_PRECISION;
rbabich's avatar
rbabich committed
73
    inv_param.clover_order = QUDA_PACKED_CLOVER_ORDER;
rbabich's avatar
rbabich committed
74
  }
rbabich's avatar
rbabich committed
75
  inv_param.verbosity = QUDA_VERBOSE;
rbabich's avatar
rbabich committed
76
77

  gauge_param = &gaugeParam;
mikeaclark's avatar
mikeaclark committed
78
79
  invert_param = &inv_param;

80
81
82
  size_t gSize = (gaugeParam.cpu_prec == QUDA_DOUBLE_PRECISION) ? sizeof(double) : sizeof(float);
  size_t sSize = (inv_param.cpu_prec == QUDA_DOUBLE_PRECISION) ? sizeof(double) : sizeof(float);

mikeaclark's avatar
mikeaclark committed
83
  // construct input fields
84
  for (int dir = 0; dir < 4; dir++) hostGauge[dir] = malloc(V*gaugeSiteSize*gSize);
mikeaclark's avatar
mikeaclark committed
85

rbabich's avatar
rbabich committed
86
87
88
89
90
91
92
93
94
95
96
  if (clover_yes) {
    size_t cSize = (inv_param.clover_cpu_prec == QUDA_DOUBLE_PRECISION) ? sizeof(double) : sizeof(float);
    if (test_type == 2) {
      hostClover = malloc(V*cloverSiteSize*cSize);
      hostCloverInv = hostClover; // fake it
    } else {
      hostClover = NULL;
      hostCloverInv = malloc(V*cloverSiteSize*cSize);
    }
  }

97
98
99
  spinor = malloc(V*spinorSiteSize*sSize);
  spinorRef = malloc(V*spinorSiteSize*sSize);
  spinorGPU = malloc(V*spinorSiteSize*sSize);
mikeaclark's avatar
mikeaclark committed
100
  spinorEven = spinor;
101
102
103
104
105
106
107
108
109
110
111
112
  spinorRefEven = spinorRef;
  spinorGPUEven = spinorGPU;
  if (inv_param.cpu_prec == QUDA_DOUBLE_PRECISION) {
    spinorOdd = (void*)((double*)spinor + Vh*spinorSiteSize);
    spinorRefOdd = (void*)((double*)spinorRef + Vh*spinorSiteSize);
    spinorGPUOdd = (void*)((double*)spinorGPU + Vh*spinorSiteSize);
  } else {
    spinorOdd = (void*)((float*)spinor + Vh*spinorSiteSize);
    spinorRefOdd = (void*)((float*)spinorRef + Vh*spinorSiteSize);
    spinorGPUOdd = (void*)((float*)spinorGPU + Vh*spinorSiteSize);
  }

rbabich's avatar
rbabich committed
113
  printf("Randomizing fields... ");
114

115
116
  construct_gauge_field(hostGauge, 1, gaugeParam.cpu_prec);
  construct_spinor_field(spinor, 1, 0, 0, 0, inv_param.cpu_prec);
mikeaclark's avatar
mikeaclark committed
117

rbabich's avatar
rbabich committed
118
  if (clover_yes) {
119
    double norm = 0; // clover components are random numbers in the range (-norm, norm)
rbabich's avatar
rbabich committed
120
121
122
123
124
125
126
127
    double diag = 1.0; // constant added to the diagonal

    if (test_type == 2) {
      construct_clover_field(hostClover, norm, diag, inv_param.clover_cpu_prec);
    } else {
      construct_clover_field(hostCloverInv, norm, diag, inv_param.clover_cpu_prec);
    }
  }
mikeaclark's avatar
mikeaclark committed
128
129
  printf("done.\n"); fflush(stdout);
  
130
131
132
  int dev = 0;
  initQuda(dev);

rbabich's avatar
rbabich committed
133
  loadGaugeQuda(hostGauge, &gaugeParam);
134
  gauge = cudaGaugePrecise;
mikeaclark's avatar
mikeaclark committed
135

rbabich's avatar
rbabich committed
136
137
138
139
140
141
142
  if (clover_yes) {
    loadCloverQuda(hostClover, hostCloverInv, &inv_param);
    clover = cudaCloverPrecise;
    cloverInv = cudaCloverInvPrecise;
  }

  printf("Sending fields to GPU... "); fflush(stdout);
mikeaclark's avatar
mikeaclark committed
143

144
  if (!TRANSFER) {
145

146
147
148
149
150
    gaugeParam.X[0] /= 2;
    tmp = allocateParitySpinor(gaugeParam.X, inv_param.cuda_prec);
    cudaSpinor = allocateSpinorField(gaugeParam.X, inv_param.cuda_prec);
    cudaSpinorOut = allocateSpinorField(gaugeParam.X, inv_param.cuda_prec);
    gaugeParam.X[0] *= 2;
151
152
153

    if (test_type < 2) {
      loadParitySpinor(cudaSpinor.even, spinorEven, inv_param.cpu_prec, 
154
		       inv_param.dirac_order);
155
156
    } else {
      loadSpinorField(cudaSpinor, spinor, inv_param.cpu_prec, 
157
		      inv_param.dirac_order);
158
    }
159

160
  }
161

mikeaclark's avatar
mikeaclark committed
162
163
164
165
166
}

void end() {
  // release memory
  for (int dir = 0; dir < 4; dir++) free(hostGauge[dir]);
rbabich's avatar
rbabich committed
167
168
169
170
  if (clover_yes) {
    if (test_type == 2) free(hostClover);
    else free(hostCloverInv);
  }
171
  free(spinorGPU);
mikeaclark's avatar
mikeaclark committed
172
173
  free(spinor);
  free(spinorRef);
174
  if (!TRANSFER) {
175
    freeSpinorField(cudaSpinorOut);
176
177
178
179
    freeSpinorField(cudaSpinor);
    freeParitySpinor(tmp);
  }
  endQuda();
mikeaclark's avatar
mikeaclark committed
180
181
182
183
184
}

double dslashCUDA() {

  // execute kernel
185
  const int LOOPS = 100;
mikeaclark's avatar
mikeaclark committed
186
187
188
189
  printf("Executing %d kernel loops...", LOOPS);
  fflush(stdout);
  stopwatchStart();
  for (int i = 0; i < LOOPS; i++) {
190
191
    switch (test_type) {
    case 0:
rbabich's avatar
rbabich committed
192
193
194
195
196
197
198
      if (TRANSFER) {
	dslashQuda(spinorOdd, spinorEven, &inv_param, ODD_BIT, DAGGER_BIT);
      } else if (!clover_yes) {
	dslashCuda(cudaSpinor.odd, gauge, cudaSpinor.even, ODD_BIT, DAGGER_BIT);
      } else {
	cloverDslashCuda(cudaSpinor.odd, gauge, cloverInv, cudaSpinor.even, ODD_BIT, DAGGER_BIT);    
      }
199
200
      break;
    case 1:
rbabich's avatar
rbabich committed
201
202
203
204
205
206
207
208
      if (TRANSFER) {
	MatPCQuda(spinorOdd, spinorEven, &inv_param, DAGGER_BIT);
      } else if (!clover_yes) {
	MatPCCuda(cudaSpinor.odd, gauge, cudaSpinor.even, kappa, tmp, QUDA_MATPC_EVEN_EVEN, DAGGER_BIT);
      } else {
	cloverMatPCCuda(cudaSpinor.odd, gauge, clover, cloverInv, cudaSpinor.even, kappa, tmp,
			QUDA_MATPC_EVEN_EVEN, DAGGER_BIT);
      }
209
210
      break;
    case 2:
rbabich's avatar
rbabich committed
211
212
213
214
215
216
217
      if (TRANSFER) {
	MatQuda(spinorGPU, spinor, &inv_param, DAGGER_BIT);
      } else if (!clover_yes) {
	MatCuda(cudaSpinorOut, gauge, cudaSpinor, kappa, DAGGER_BIT);
      } else {
	cloverMatCuda(cudaSpinorOut, gauge, clover, cudaSpinor, kappa, tmp, DAGGER_BIT);
      }
218
    }
mikeaclark's avatar
mikeaclark committed
219
220
221
222
223
224
225
226
227
228
229
230
  }
    
  // check for errors
  cudaError_t stat = cudaGetLastError();
  if (stat != cudaSuccess)
    printf("with ERROR: %s\n", cudaGetErrorString(stat));

  cudaThreadSynchronize();
  double secs = stopwatchReadSeconds() / LOOPS;
  printf("done.\n\n");

  return secs;
231
}
mikeaclark's avatar
mikeaclark committed
232

233
234
235
236
237
238
239
void dslashRef() {
  
  // compare to dslash reference implementation
  printf("Calculating reference implementation...");
  fflush(stdout);
  switch (test_type) {
  case 0:
240
241
    dslash(spinorRef, hostGauge, spinorEven, ODD_BIT, DAGGER_BIT, 
	   inv_param.cpu_prec, gaugeParam.cpu_prec);
242
243
244
245
246
247
248
249
250
251
252
253
    break;
  case 1:    
    matpc(spinorRef, hostGauge, spinorEven, kappa, QUDA_MATPC_EVEN_EVEN, DAGGER_BIT, 
	  inv_param.cpu_prec, gaugeParam.cpu_prec);
    break;
  case 2:
    mat(spinorRef, hostGauge, spinor, kappa, DAGGER_BIT, 
	inv_param.cpu_prec, gaugeParam.cpu_prec);
    break;
  default:
    printf("Test type not defined\n");
    exit(-1);
254
  }
mikeaclark's avatar
mikeaclark committed
255

256
  printf("done.\n");
257
    
mikeaclark's avatar
mikeaclark committed
258
259
}

mikeaclark's avatar
mikeaclark committed
260
261
262
void dslashTest() {

  init();
263
  
264
  float spinorGiB = (float)Vh*spinorSiteSize*sizeof(inv_param.cpu_prec) / (1 << 30);
265
  float sharedKB = (float)dslashCudaSharedBytes(inv_param.cuda_prec, gaugeParam.blockDim) / (1 << 10);
mikeaclark's avatar
mikeaclark committed
266
  printf("\nSpinor mem: %.3f GiB\n", spinorGiB);
267
  printf("Gauge mem: %.3f GiB\n", gaugeParam.gaugeGiB);
mikeaclark's avatar
mikeaclark committed
268
  printf("Shared mem: %.3f KB\n", sharedKB);
269
270
  
  int attempts = 1;
mikeaclark's avatar
mikeaclark committed
271
272
273
274
  dslashRef();
  for (int i=0; i<attempts; i++) {
    
    double secs = dslashCUDA();
275
    
276
    if (!TRANSFER) {
277
278
279
280
      if (test_type < 2) 
	retrieveParitySpinor(spinorOdd, cudaSpinor.odd, inv_param.cpu_prec, inv_param.dirac_order);
      else 
	retrieveSpinorField(spinorGPU, cudaSpinorOut, inv_param.cpu_prec, inv_param.dirac_order);
281
    }
282
    
mikeaclark's avatar
mikeaclark committed
283
284
    // print timing information
    printf("%fms per loop\n", 1000*secs);
285
    
286
287
    int flops = test_type ? 1320*2 + 48 : 1320;
    int floats = test_type ? 2*(7*24+8*gaugeParam.packed_size+24)+24 : 7*24+8*gaugeParam.packed_size+24;
rbabich's avatar
rbabich committed
288
    if (clover_yes) {
rbabich's avatar
rbabich committed
289
290
291
      flops += test_type ? 504*2 : 504;
      floats += test_type ? 72*2 : 72;
    }
292
293
    printf("GFLOPS = %f\n", 1.0e-9*flops*Vh/secs);
    printf("GiB/s = %f\n\n", Vh*floats*sizeof(float)/(secs*(1<<30)));
mikeaclark's avatar
mikeaclark committed
294
    
295
    int res;
296
297
    if (test_type < 2) res = compare_floats(spinorOdd, spinorRef, Vh*4*3*2, 1e-4, inv_param.cpu_prec);
    else res = compare_floats(spinorGPU, spinorRef, V*4*3*2, 1e-4, inv_param.cpu_prec);
298
299
300
301
      
      printf("%d Test %s\n", i, (1 == res) ? "PASSED" : "FAILED");
      
      if (test_type < 2) strong_check(spinorRef, spinorOdd, Vh, inv_param.cpu_prec);
rbabich's avatar
rbabich committed
302
303
      else strong_check(spinorRef, spinorGPU, V, inv_param.cpu_prec);    
  }    
mikeaclark's avatar
mikeaclark committed
304
305
306
307
308
309
  end();
}

int main(int argc, char **argv) {
  dslashTest();
}