Advanced Computing Platform for Theoretical Physics

dslash_test.c 9.22 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
  gaugeParam.X[2] = 24;
39
  gaugeParam.X[3] = 48;
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.matpc_type = QUDA_MATPC_ODD_ODD_ASYMMETRIC;
65

66
  inv_param.cpu_prec = QUDA_DOUBLE_PRECISION;
mikeaclark's avatar
mikeaclark committed
67
  inv_param.cuda_prec = QUDA_SINGLE_PRECISION;
rbabich's avatar
rbabich committed
68

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

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

  gauge_param = &gaugeParam;
mikeaclark's avatar
mikeaclark committed
80
81
  invert_param = &inv_param;

82
83
84
  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
85
  // construct input fields
86
  for (int dir = 0; dir < 4; dir++) hostGauge[dir] = malloc(V*gaugeSiteSize*gSize);
mikeaclark's avatar
mikeaclark committed
87

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

99
100
101
  spinor = malloc(V*spinorSiteSize*sSize);
  spinorRef = malloc(V*spinorSiteSize*sSize);
  spinorGPU = malloc(V*spinorSiteSize*sSize);
mikeaclark's avatar
mikeaclark committed
102
  spinorEven = spinor;
103
104
105
106
107
108
109
110
111
112
113
114
  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
115
  printf("Randomizing fields... ");
116

117
118
  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
119

rbabich's avatar
rbabich committed
120
  if (clover_yes) {
121
    double norm = 0; // clover components are random numbers in the range (-norm, norm)
rbabich's avatar
rbabich committed
122
123
124
125
126
127
128
129
    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
130
131
  printf("done.\n"); fflush(stdout);
  
132
133
134
  int dev = 0;
  initQuda(dev);

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

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

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

146
  if (!TRANSFER) {
147

148
149
150
151
152
    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;
153
154
155

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

162
  }
163

mikeaclark's avatar
mikeaclark committed
164
165
166
167
168
}

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

double dslashCUDA() {

  // execute kernel
187
  const int LOOPS = 100;
mikeaclark's avatar
mikeaclark committed
188
189
190
191
  printf("Executing %d kernel loops...", LOOPS);
  fflush(stdout);
  stopwatchStart();
  for (int i = 0; i < LOOPS; i++) {
192
193
    switch (test_type) {
    case 0:
rbabich's avatar
rbabich committed
194
195
196
197
198
199
200
      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);    
      }
201
202
      break;
    case 1:
rbabich's avatar
rbabich committed
203
204
205
      if (TRANSFER) {
	MatPCQuda(spinorOdd, spinorEven, &inv_param, DAGGER_BIT);
      } else if (!clover_yes) {
206
	MatPCCuda(cudaSpinor.odd, gauge, cudaSpinor.even, kappa, tmp, inv_param.matpc_type, DAGGER_BIT);
rbabich's avatar
rbabich committed
207
208
      } else {
	cloverMatPCCuda(cudaSpinor.odd, gauge, clover, cloverInv, cudaSpinor.even, kappa, tmp,
209
			inv_param.matpc_type, DAGGER_BIT);
rbabich's avatar
rbabich committed
210
      }
211
212
      break;
    case 2:
rbabich's avatar
rbabich committed
213
214
215
216
217
218
219
      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);
      }
220
    }
mikeaclark's avatar
mikeaclark committed
221
222
223
224
225
226
227
228
229
230
231
232
  }
    
  // 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;
233
}
mikeaclark's avatar
mikeaclark committed
234

235
void dslashRef() {
236

237
  // FIXME: remove once reference clover is finished
238
239
240
241
242
243
  if (inv_param.matpc_type == QUDA_MATPC_EVEN_EVEN_ASYMMETRIC) {
    inv_param.matpc_type = QUDA_MATPC_EVEN_EVEN;
  } else if (inv_param.matpc_type == QUDA_MATPC_ODD_ODD_ASYMMETRIC) {
    inv_param.matpc_type = QUDA_MATPC_ODD_ODD;
  }

244
245
246
247
248
  // compare to dslash reference implementation
  printf("Calculating reference implementation...");
  fflush(stdout);
  switch (test_type) {
  case 0:
249
250
    dslash(spinorRef, hostGauge, spinorEven, ODD_BIT, DAGGER_BIT, 
	   inv_param.cpu_prec, gaugeParam.cpu_prec);
251
252
    break;
  case 1:    
253
    matpc(spinorRef, hostGauge, spinorEven, kappa, inv_param.matpc_type, DAGGER_BIT, 
254
255
256
257
258
259
260
261
262
	  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);
263
  }
mikeaclark's avatar
mikeaclark committed
264

265
  printf("done.\n");
266
    
mikeaclark's avatar
mikeaclark committed
267
268
}

mikeaclark's avatar
mikeaclark committed
269
270
271
void dslashTest() {

  init();
272
  
273
  float spinorGiB = (float)Vh*spinorSiteSize*sizeof(inv_param.cpu_prec) / (1 << 30);
274
  float sharedKB = (float)dslashCudaSharedBytes(inv_param.cuda_prec, gaugeParam.blockDim) / (1 << 10);
mikeaclark's avatar
mikeaclark committed
275
  printf("\nSpinor mem: %.3f GiB\n", spinorGiB);
276
  printf("Gauge mem: %.3f GiB\n", gaugeParam.gaugeGiB);
mikeaclark's avatar
mikeaclark committed
277
  printf("Shared mem: %.3f KB\n", sharedKB);
278
279
  
  int attempts = 1;
mikeaclark's avatar
mikeaclark committed
280
281
282
283
  dslashRef();
  for (int i=0; i<attempts; i++) {
    
    double secs = dslashCUDA();
284
    
285
    if (!TRANSFER) {
286
287
288
289
      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);
290
    }
291
    
mikeaclark's avatar
mikeaclark committed
292
293
    // print timing information
    printf("%fms per loop\n", 1000*secs);
294
    
295
296
    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
297
    if (clover_yes) {
rbabich's avatar
rbabich committed
298
299
300
      flops += test_type ? 504*2 : 504;
      floats += test_type ? 72*2 : 72;
    }
301
302
    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
303
    
304
    int res;
305
306
    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);
307
308
309
310
      
      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
311
312
      else strong_check(spinorRef, spinorGPU, V, inv_param.cpu_prec);    
  }    
mikeaclark's avatar
mikeaclark committed
313
314
315
316
317
318
  end();
}

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