QUDA  v0.5.0
A library for QCD on GPUs
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gauge_force_test.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include <quda.h>
6 #include <test_util.h>
7 #include <gauge_field.h>
8 #include "misc.h"
10 #include "gauge_force_quda.h"
11 #include <sys/time.h>
12 #include "fat_force_quda.h"
13 #include <dslash_quda.h>
14 
15 #ifdef MULTI_GPU
16 #include <face_quda.h>
17 #endif
18 
19 extern int device;
20 
21 static QudaGaugeParam qudaGaugeParam;
23 static int verify_results = 0;
24 extern int tdim;
25 extern QudaPrecision prec;
26 extern int xdim;
27 extern int ydim;
28 extern int zdim;
29 extern int tdim;
30 extern void usage(char** argv);
31 extern bool tune;
32 
33 int attempts = 1;
34 
37 
38 extern int gridsize_from_cmdline[];
39 
40 
41 int length[]={
42  3,
43  3,
44  3,
45  3,
46  3,
47  3,
48  5,
49  5,
50  5,
51  5,
52  5,
53  5,
54  5,
55  5,
56  5,
57  5,
58  5,
59  5,
60  5,
61  5,
62  5,
63  5,
64  5,
65  5,
66  5,
67  5,
68  5,
69  5,
70  5,
71  5,
72  5,
73  5,
74  5,
75  5,
76  5,
77  5,
78  5,
79  5,
80  5,
81  5,
82  5,
83  5,
84  5,
85  5,
86  5,
87  5,
88  5,
89  5,
90 };
91 
92 
93 float loop_coeff_f[]={
94  1.1,
95  1.2,
96  1.3,
97  1.4,
98  1.5,
99  1.6,
100  2.5,
101  2.6,
102  2.7,
103  2.8,
104  2.9,
105  3.0,
106  3.1,
107  3.2,
108  3.3,
109  3.4,
110  3.5,
111  3.6,
112  3.7,
113  3.8,
114  3.9,
115  4.0,
116  4.1,
117  4.2,
118  4.3,
119  4.4,
120  4.5,
121  4.6,
122  4.7,
123  4.8,
124  4.9,
125  5.0,
126  5.1,
127  5.2,
128  5.3,
129  5.4,
130  5.5,
131  5.6,
132  5.7,
133  5.8,
134  5.9,
135  5.0,
136  6.1,
137  6.2,
138  6.3,
139  6.4,
140  6.5,
141  6.6,
142 };
143 
144 int path_dir_x[][5] = {
145  {1, 7, 6 },
146  {6, 7, 1 },
147  {2, 7, 5 },
148  {5, 7, 2 },
149  {3, 7, 4 },
150  {4, 7, 3 },
151  {0, 1, 7, 7, 6 },
152  {1, 7, 7, 6, 0 },
153  {6, 7, 7, 1, 0 },
154  {0, 6, 7, 7, 1 },
155  {0, 2, 7, 7, 5 },
156  {2, 7, 7, 5, 0 },
157  {5, 7, 7, 2, 0 },
158  {0, 5, 7, 7, 2 },
159  {0, 3, 7, 7, 4 },
160  {3, 7, 7, 4, 0 },
161  {4, 7, 7, 3, 0 },
162  {0, 4, 7, 7, 3 },
163  {6, 6, 7, 1, 1 },
164  {1, 1, 7, 6, 6 },
165  {5, 5, 7, 2, 2 },
166  {2, 2, 7, 5, 5 },
167  {4, 4, 7, 3, 3 },
168  {3, 3, 7, 4, 4 },
169  {1, 2, 7, 6, 5 },
170  {5, 6, 7, 2, 1 },
171  {1, 5, 7, 6, 2 },
172  {2, 6, 7, 5, 1 },
173  {6, 2, 7, 1, 5 },
174  {5, 1, 7, 2, 6 },
175  {6, 5, 7, 1, 2 },
176  {2, 1, 7, 5, 6 },
177  {1, 3, 7, 6, 4 },
178  {4, 6, 7, 3, 1 },
179  {1, 4, 7, 6, 3 },
180  {3, 6, 7, 4, 1 },
181  {6, 3, 7, 1, 4 },
182  {4, 1, 7, 3, 6 },
183  {6, 4, 7, 1, 3 },
184  {3, 1, 7, 4, 6 },
185  {2, 3, 7, 5, 4 },
186  {4, 5, 7, 3, 2 },
187  {2, 4, 7, 5, 3 },
188  {3, 5, 7, 4, 2 },
189  {5, 3, 7, 2, 4 },
190  {4, 2, 7, 3, 5 },
191  {5, 4, 7, 2, 3 },
192  {3, 2, 7, 4, 5 },
193 };
194 
195 
196 int path_dir_y[][5] = {
197  { 2 ,6 ,5 },
198  { 5 ,6 ,2 },
199  { 3 ,6 ,4 },
200  { 4 ,6 ,3 },
201  { 0 ,6 ,7 },
202  { 7 ,6 ,0 },
203  { 1 ,2 ,6 ,6 ,5 },
204  { 2 ,6 ,6 ,5 ,1 },
205  { 5 ,6 ,6 ,2 ,1 },
206  { 1 ,5 ,6 ,6 ,2 },
207  { 1 ,3 ,6 ,6 ,4 },
208  { 3 ,6 ,6 ,4 ,1 },
209  { 4 ,6 ,6 ,3 ,1 },
210  { 1 ,4 ,6 ,6 ,3 },
211  { 1 ,0 ,6 ,6 ,7 },
212  { 0 ,6 ,6 ,7 ,1 },
213  { 7 ,6 ,6 ,0 ,1 },
214  { 1 ,7 ,6 ,6 ,0 },
215  { 5 ,5 ,6 ,2 ,2 },
216  { 2 ,2 ,6 ,5 ,5 },
217  { 4 ,4 ,6 ,3 ,3 },
218  { 3 ,3 ,6 ,4 ,4 },
219  { 7 ,7 ,6 ,0 ,0 },
220  { 0 ,0 ,6 ,7 ,7 },
221  { 2 ,3 ,6 ,5 ,4 },
222  { 4 ,5 ,6 ,3 ,2 },
223  { 2 ,4 ,6 ,5 ,3 },
224  { 3 ,5 ,6 ,4 ,2 },
225  { 5 ,3 ,6 ,2 ,4 },
226  { 4 ,2 ,6 ,3 ,5 },
227  { 5 ,4 ,6 ,2 ,3 },
228  { 3 ,2 ,6 ,4 ,5 },
229  { 2 ,0 ,6 ,5 ,7 },
230  { 7 ,5 ,6 ,0 ,2 },
231  { 2 ,7 ,6 ,5 ,0 },
232  { 0 ,5 ,6 ,7 ,2 },
233  { 5 ,0 ,6 ,2 ,7 },
234  { 7 ,2 ,6 ,0 ,5 },
235  { 5 ,7 ,6 ,2 ,0 },
236  { 0 ,2 ,6 ,7 ,5 },
237  { 3 ,0 ,6 ,4 ,7 },
238  { 7 ,4 ,6 ,0 ,3 },
239  { 3 ,7 ,6 ,4 ,0 },
240  { 0 ,4 ,6 ,7 ,3 },
241  { 4 ,0 ,6 ,3 ,7 },
242  { 7 ,3 ,6 ,0 ,4 },
243  { 4 ,7 ,6 ,3 ,0 },
244  { 0 ,3 ,6 ,7 ,4 }
245 };
246 
247 int path_dir_z[][5] = {
248  { 3 ,5 ,4 },
249  { 4 ,5 ,3 },
250  { 0 ,5 ,7 },
251  { 7 ,5 ,0 },
252  { 1 ,5 ,6 },
253  { 6 ,5 ,1 },
254  { 2 ,3 ,5 ,5 ,4 },
255  { 3 ,5 ,5 ,4 ,2 },
256  { 4 ,5 ,5 ,3 ,2 },
257  { 2 ,4 ,5 ,5 ,3 },
258  { 2 ,0 ,5 ,5 ,7 },
259  { 0 ,5 ,5 ,7 ,2 },
260  { 7 ,5 ,5 ,0 ,2 },
261  { 2 ,7 ,5 ,5 ,0 },
262  { 2 ,1 ,5 ,5 ,6 },
263  { 1 ,5 ,5 ,6 ,2 },
264  { 6 ,5 ,5 ,1 ,2 },
265  { 2 ,6 ,5 ,5 ,1 },
266  { 4 ,4 ,5 ,3 ,3 },
267  { 3 ,3 ,5 ,4 ,4 },
268  { 7 ,7 ,5 ,0 ,0 },
269  { 0 ,0 ,5 ,7 ,7 },
270  { 6 ,6 ,5 ,1 ,1 },
271  { 1 ,1 ,5 ,6 ,6 },
272  { 3 ,0 ,5 ,4 ,7 },
273  { 7 ,4 ,5 ,0 ,3 },
274  { 3 ,7 ,5 ,4 ,0 },
275  { 0 ,4 ,5 ,7 ,3 },
276  { 4 ,0 ,5 ,3 ,7 },
277  { 7 ,3 ,5 ,0 ,4 },
278  { 4 ,7 ,5 ,3 ,0 },
279  { 0 ,3 ,5 ,7 ,4 },
280  { 3 ,1 ,5 ,4 ,6 },
281  { 6 ,4 ,5 ,1 ,3 },
282  { 3 ,6 ,5 ,4 ,1 },
283  { 1 ,4 ,5 ,6 ,3 },
284  { 4 ,1 ,5 ,3 ,6 },
285  { 6 ,3 ,5 ,1 ,4 },
286  { 4 ,6 ,5 ,3 ,1 },
287  { 1 ,3 ,5 ,6 ,4 },
288  { 0 ,1 ,5 ,7 ,6 },
289  { 6 ,7 ,5 ,1 ,0 },
290  { 0 ,6 ,5 ,7 ,1 },
291  { 1 ,7 ,5 ,6 ,0 },
292  { 7 ,1 ,5 ,0 ,6 },
293  { 6 ,0 ,5 ,1 ,7 },
294  { 7 ,6 ,5 ,0 ,1 },
295  { 1 ,0 ,5 ,6 ,7 }
296 };
297 
298 int path_dir_t[][5] = {
299  { 0 ,4 ,7 },
300  { 7 ,4 ,0 },
301  { 1 ,4 ,6 },
302  { 6 ,4 ,1 },
303  { 2 ,4 ,5 },
304  { 5 ,4 ,2 },
305  { 3 ,0 ,4 ,4 ,7 },
306  { 0 ,4 ,4 ,7 ,3 },
307  { 7 ,4 ,4 ,0 ,3 },
308  { 3 ,7 ,4 ,4 ,0 },
309  { 3 ,1 ,4 ,4 ,6 },
310  { 1 ,4 ,4 ,6 ,3 },
311  { 6 ,4 ,4 ,1 ,3 },
312  { 3 ,6 ,4 ,4 ,1 },
313  { 3 ,2 ,4 ,4 ,5 },
314  { 2 ,4 ,4 ,5 ,3 },
315  { 5 ,4 ,4 ,2 ,3 },
316  { 3 ,5 ,4 ,4 ,2 },
317  { 7 ,7 ,4 ,0 ,0 },
318  { 0 ,0 ,4 ,7 ,7 },
319  { 6 ,6 ,4 ,1 ,1 },
320  { 1 ,1 ,4 ,6 ,6 },
321  { 5 ,5 ,4 ,2 ,2 },
322  { 2 ,2 ,4 ,5 ,5 },
323  { 0 ,1 ,4 ,7 ,6 },
324  { 6 ,7 ,4 ,1 ,0 },
325  { 0 ,6 ,4 ,7 ,1 },
326  { 1 ,7 ,4 ,6 ,0 },
327  { 7 ,1 ,4 ,0 ,6 },
328  { 6 ,0 ,4 ,1 ,7 },
329  { 7 ,6 ,4 ,0 ,1 },
330  { 1 ,0 ,4 ,6 ,7 },
331  { 0 ,2 ,4 ,7 ,5 },
332  { 5 ,7 ,4 ,2 ,0 },
333  { 0 ,5 ,4 ,7 ,2 },
334  { 2 ,7 ,4 ,5 ,0 },
335  { 7 ,2 ,4 ,0 ,5 },
336  { 5 ,0 ,4 ,2 ,7 },
337  { 7 ,5 ,4 ,0 ,2 },
338  { 2 ,0 ,4 ,5 ,7 },
339  { 1 ,2 ,4 ,6 ,5 },
340  { 5 ,6 ,4 ,2 ,1 },
341  { 1 ,5 ,4 ,6 ,2 },
342  { 2 ,6 ,4 ,5 ,1 },
343  { 6 ,2 ,4 ,1 ,5 },
344  { 5 ,1 ,4 ,2 ,6 },
345  { 6 ,5 ,4 ,1 ,2 },
346  { 2 ,1 ,4 ,5 ,6 }
347 };
348 
349 
350 
351 static int
352 gauge_force_test(void)
353 {
354  int max_length = 6;
355 
356  initQuda(device);
357 
358  qudaGaugeParam = newQudaGaugeParam();
359 
360  qudaGaugeParam.X[0] = xdim;
361  qudaGaugeParam.X[1] = ydim;
362  qudaGaugeParam.X[2] = zdim;
363  qudaGaugeParam.X[3] = tdim;
364 
365  setDims(qudaGaugeParam.X);
366 
367  qudaGaugeParam.anisotropy = 1.0;
368  qudaGaugeParam.cpu_prec = link_prec;
369  qudaGaugeParam.cuda_prec = link_prec;
370  qudaGaugeParam.reconstruct = link_recon;
371  qudaGaugeParam.type = QUDA_WILSON_LINKS; // in this context, just means these are site links
372 
373  qudaGaugeParam.gauge_order = gauge_order;
374 
375  int gSize = qudaGaugeParam.cpu_prec;
376 
377  void* sitelink;
378  void* sitelink_1d;
379 
380 #ifdef GPU_DIRECT
381  if (cudaMallocHost(&sitelink_1d, 4*V*gaugeSiteSize*gSize) == cudaErrorMemoryAllocation) {
382  errorQuda("ERROR: cudaMallocHost failed for sitelink_1d\n");
383  }
384 #else
385  sitelink_1d= malloc(4*V*gaugeSiteSize*gSize);
386 #endif
387  if(sitelink_1d == NULL){
388  printf("ERROR: malloc failed for sitelink_1d\n");
389  exit(1);
390  }
391 
392  // this is a hack to have site link generated in 2d
393  // then copied to 1d array in "MILC" format
394  void* sitelink_2d[4];
395  for(int i=0;i < 4;i++){
396 #ifdef GPU_DIRECT
397  if(cudaMallocHost(&sitelink_2d[i], V*gaugeSiteSize*qudaGaugeParam.cpu_prec) == cudaErrorMemoryAllocation) {
398  errorQuda("ERROR: cudaMallocHost failed for sitelink_2d\n");
399  }
400 #else
401  sitelink_2d[i] = malloc(V*gaugeSiteSize*qudaGaugeParam.cpu_prec);
402 #endif
403  }
404 
405  // fills the gauge field with random numbers
406  createSiteLinkCPU(sitelink_2d, qudaGaugeParam.cpu_prec, 0);
407 
408  //copy the 2d sitelink to 1d milc format
409 
410  for(int dir = 0; dir < 4; dir++){
411  for(int i=0; i < V; i++){
412  char* src = ((char*)sitelink_2d[dir]) + i * gaugeSiteSize* qudaGaugeParam.cpu_prec;
413  char* dst = ((char*)sitelink_1d) + (4*i+dir)*gaugeSiteSize*qudaGaugeParam.cpu_prec ;
414  memcpy(dst, src, gaugeSiteSize*qudaGaugeParam.cpu_prec);
415  }
416  }
417  if (qudaGaugeParam.gauge_order == QUDA_MILC_GAUGE_ORDER){
418  sitelink = sitelink_1d;
419  }else{ //QUDA_QDP_GAUGE_ORDER
420  sitelink = (void**)sitelink_2d;
421  }
422 
423 #ifdef MULTI_GPU
424  void* sitelink_ex;
425  void* sitelink_ex_2d[4];
426  void* sitelink_ex_1d;
427 
428  if (cudaMallocHost((void**)&sitelink_ex_1d, 4*V_ex*gaugeSiteSize*gSize) == cudaErrorMemoryAllocation) {
429  errorQuda("ERROR: cudaMallocHost failed for sitelink_ex_1d\n");
430  }
431  for(int i=0;i < 4;i++){
432  if (cudaMallocHost((void**)&sitelink_ex_2d[i], V_ex*gaugeSiteSize*gSize) == cudaErrorMemoryAllocation) {
433  errorQuda("ERROR: cudaMallocHost failed for sitelink_ex_2d\n");
434  }
435  if(sitelink_ex_2d[i] == NULL){
436  errorQuda("ERROR; allocate sitelink_ex[%d] failed\n", i);
437  }
438  }
439 
440  int X1= Z[0];
441  int X2= Z[1];
442  int X3= Z[2];
443  int X4= Z[3];
444 
445  for(int i=0; i < V_ex; i++){
446  int sid = i;
447  int oddBit=0;
448  if(i >= Vh_ex){
449  sid = i - Vh_ex;
450  oddBit = 1;
451  }
452 
453  int za = sid/E1h;
454  int x1h = sid - za*E1h;
455  int zb = za/E2;
456  int x2 = za - zb*E2;
457  int x4 = zb/E3;
458  int x3 = zb - x4*E3;
459  int x1odd = (x2 + x3 + x4 + oddBit) & 1;
460  int x1 = 2*x1h + x1odd;
461 
462  if( x1< 2 || x1 >= X1 +2
463  || x2< 2 || x2 >= X2 +2
464  || x3< 2 || x3 >= X3 +2
465  || x4< 2 || x4 >= X4 +2){
466  continue;
467  }
468 
469  x1 = (x1 - 2 + X1) % X1;
470  x2 = (x2 - 2 + X2) % X2;
471  x3 = (x3 - 2 + X3) % X3;
472  x4 = (x4 - 2 + X4) % X4;
473 
474  int idx = (x4*X3*X2*X1+x3*X2*X1+x2*X1+x1)>>1;
475  if(oddBit){
476  idx += Vh;
477  }
478  for(int dir= 0; dir < 4; dir++){
479  char* src = (char*)sitelink_2d[dir];
480  char* dst = (char*)sitelink_ex_2d[dir];
481  memcpy(dst+i*gaugeSiteSize*gSize, src+idx*gaugeSiteSize*gSize, gaugeSiteSize*gSize);
482  }//dir
483  }//i
484 
485 
486  for(int dir = 0; dir < 4; dir++){
487  for(int i=0; i < V_ex; i++){
488  char* src = ((char*)sitelink_ex_2d[dir]) + i * gaugeSiteSize* qudaGaugeParam.cpu_prec;
489  char* dst = ((char*)sitelink_ex_1d) + (4*i+dir)*gaugeSiteSize*qudaGaugeParam.cpu_prec ;
490  memcpy(dst, src, gaugeSiteSize*qudaGaugeParam.cpu_prec);
491  }
492  }
493 
494  if(qudaGaugeParam.gauge_order == QUDA_QDP_GAUGE_ORDER){
495  sitelink_ex = sitelink_ex_2d;
496  }else{
497  sitelink_ex = sitelink_ex_1d;
498  }
499 
500 #endif
501 
502 
503 
504  void* mom = malloc(4*V*momSiteSize*gSize);
505  void* refmom = malloc(4*V*momSiteSize*gSize);
506  if(mom == NULL || refmom == NULL){
507  printf("ERROR: malloc failed for mom/refmom\n");
508  exit(1);
509  }
510  memset(mom, 0, 4*V*momSiteSize*gSize);
511  //initiaze some data in cpuMom
512  createMomCPU(mom, qudaGaugeParam.cpu_prec);
513  memcpy(refmom, mom, 4*V*momSiteSize*qudaGaugeParam.cpu_prec);
514 
515 
516  double loop_coeff_d[sizeof(loop_coeff_f)/sizeof(float)];
517  for(unsigned int i=0;i < sizeof(loop_coeff_f)/sizeof(float); i++){
518  loop_coeff_d[i] = loop_coeff_f[i];
519  }
520 
521  void* loop_coeff;
522  if(qudaGaugeParam.cuda_prec == QUDA_SINGLE_PRECISION){
523  loop_coeff = (void*)&loop_coeff_f[0];
524  }else{
525  loop_coeff = loop_coeff_d;
526  }
527  double eb3 = 0.3;
528  int num_paths = sizeof(path_dir_x)/sizeof(path_dir_x[0]);
529 
530  int** input_path_buf[4];
531  for(int dir =0; dir < 4; dir++){
532  input_path_buf[dir] = (int**)malloc(num_paths*sizeof(int*));
533  if (input_path_buf[dir] == NULL){
534  printf("ERORR: malloc failed for input path\n");
535  exit(1);
536  }
537 
538  for(int i=0;i < num_paths;i++){
539  input_path_buf[dir][i] = (int*)malloc(length[i]*sizeof(int));
540  if (input_path_buf[dir][i] == NULL){
541  printf("ERROR: malloc failed for input_path_buf[dir][%d]\n", i);
542  exit(1);
543  }
544  if(dir == 0) memcpy(input_path_buf[dir][i], path_dir_x[i], length[i]*sizeof(int));
545  else if(dir ==1) memcpy(input_path_buf[dir][i], path_dir_y[i], length[i]*sizeof(int));
546  else if(dir ==2) memcpy(input_path_buf[dir][i], path_dir_z[i], length[i]*sizeof(int));
547  else if(dir ==3) memcpy(input_path_buf[dir][i], path_dir_t[i], length[i]*sizeof(int));
548  }
549  }
550 
551  if (tune) {
552  printfQuda("Tuning...\n");
554  }
555 
556  struct timeval t0, t1;
557  double timeinfo[3];
558  /* Multiple execution to exclude warmup time in the first run*/
559  for (int i =0;i < attempts; i++){
560  gettimeofday(&t0, NULL);
561 #ifdef MULTI_GPU
562  computeGaugeForceQuda(mom, sitelink_ex, input_path_buf, length,
563  loop_coeff, num_paths, max_length, eb3,
564  &qudaGaugeParam, timeinfo);
565 
566 #else
567  computeGaugeForceQuda(mom, sitelink, input_path_buf, length,
568  loop_coeff, num_paths, max_length, eb3,
569  &qudaGaugeParam, timeinfo);
570 #endif
571  gettimeofday(&t1, NULL);
572  }
573 
574  double total_time = t1.tv_sec - t0.tv_sec + 0.000001*(t1.tv_usec - t0.tv_usec);
575  //The number comes from CPU implementation in MILC, gauge_force_imp.c
576  int flops=153004;
577 
578  if (verify_results){
579  for(int i = 0;i < attempts;i++){
580 #ifdef MULTI_GPU
581  //last arg=0 means no optimization for communication, i.e. exchange data in all directions
582  //even they are not partitioned
583  int R[4] = {2, 2, 2, 2};
584  exchange_cpu_sitelink_ex(qudaGaugeParam.X, R, (void**)sitelink_ex_2d,
585  QUDA_QDP_GAUGE_ORDER, qudaGaugeParam.cpu_prec, 0);
586  gauge_force_reference(refmom, eb3, sitelink_2d, sitelink_ex_2d, qudaGaugeParam.cpu_prec,
587  input_path_buf, length, loop_coeff, num_paths);
588 #else
589  gauge_force_reference(refmom, eb3, sitelink_2d, NULL, qudaGaugeParam.cpu_prec,
590  input_path_buf, length, loop_coeff, num_paths);
591 #endif
592  }
593  }
594 
595  int res;
596  res = compare_floats(mom, refmom, 4*V*momSiteSize, 1e-3, qudaGaugeParam.cpu_prec);
597 
598  int accuracy_level;
599  accuracy_level = strong_check_mom(mom, refmom, 4*V, qudaGaugeParam.cpu_prec);
600 
601  printf("Test %s\n",(1 == res) ? "PASSED" : "FAILED");
602 
603  double perf = 1.0* flops*V/(total_time*1e+9);
604  double kernel_perf = 1.0*flops*V/(timeinfo[1]*1e+9);
605  printf("init and cpu->gpu time: %.2f ms, kernel time: %.2f ms, gpu->cpu and cleanup time: %.2f total time =%.2f ms\n",
606  timeinfo[0]*1e+3, timeinfo[1]*1e+3, timeinfo[2]*1e+3, total_time*1e+3);
607  printf("kernel performance: %.2f GFLOPS, overall performance : %.2f GFOPS\n", kernel_perf, perf);
608 
609  for(int dir = 0; dir < 4; dir++){
610  for(int i=0;i < num_paths; i++){
611  free(input_path_buf[dir][i]);
612  }
613  free(input_path_buf[dir]);
614  }
615 
616 #ifdef GPU_DIRECT
617  cudaFreeHost(sitelink_1d);
618 #else
619  free(sitelink_1d);
620 #endif
621  for(int dir=0;dir < 4;dir++){
622 #ifdef GPU_DIRECT
623  cudaFreeHost(sitelink_2d[dir]);
624 #else
625  free(sitelink_2d[dir]);
626 #endif
627  }
628 
629 #ifdef MULTI_GPU
630  cudaFreeHost(sitelink_ex_1d);
631  for(int dir=0; dir < 4; dir++){
632  cudaFreeHost(sitelink_ex_2d[dir]);
633  }
634 #endif
635 
636 
637  free(mom);
638  free(refmom);
639  endQuda();
640 
641  if (res == 0){//failed
642  printf("\n");
643  printf("Warning: you test failed. \n");
644  printf(" Did you use --verify?\n");
645  printf(" Did you check the GPU health by running cuda memtest?\n");
646  }
647 
648  return accuracy_level;
649 }
650 
651 
652 static void
654 {
655  printf("running the following test:\n");
656 
657  printf("link_precision link_reconstruct space_dim(x/y/z) T_dimension Gauge_order Attempts\n");
658  printf("%s %s %d/%d/%d %d %s %d\n",
661  xdim,ydim,zdim, tdim,
663  attempts);
664  return ;
665 
666 }
667 
668 void
669 usage_extra(char** argv )
670 {
671  printf("Extra options:\n");
672  printf(" --gauge-order <qdp/milc> # Gauge storing order in CPU\n");
673  printf(" --attempts <n> # Number of tests\n");
674  printf(" --verify # Verify the GPU results using CPU results\n");
675  return ;
676 }
677 
678 int
679 main(int argc, char **argv)
680 {
681  int i;
682  for (i =1;i < argc; i++){
683 
684  if(process_command_line_option(argc, argv, &i) == 0){
685  continue;
686  }
687 
688  if( strcmp(argv[i], "--gauge-order") == 0){
689  if(i+1 >= argc){
690  usage(argv);
691  }
692 
693  if(strcmp(argv[i+1], "milc") == 0){
695  }else if(strcmp(argv[i+1], "qdp") == 0){
697  }else{
698  fprintf(stderr, "Error: unsupported gauge-field order\n");
699  exit(1);
700  }
701  i++;
702  continue;
703  }
704  if( strcmp(argv[i], "--attempts") == 0){
705  if(i+1 >= argc){
706  usage(argv);
707  }
708 
709  attempts = atoi(argv[i+1]);
710  if(attempts <= 0){
711  printf("ERROR: invalid number of attempts(%d)\n", attempts);
712  }
713  i++;
714  continue;
715  }
716 
717  if( strcmp(argv[i], "--verify") == 0){
718  verify_results=1;
719  continue;
720  }
721 
722  fprintf(stderr, "ERROR: Invalid option:%s\n", argv[i]);
723  usage(argv);
724  }
725 
726 
727  link_prec = prec;
728 
729  initComms(argc, argv, gridsize_from_cmdline);
730 
732 
733  int accuracy_level = gauge_force_test();
734  printfQuda("accuracy_level=%d\n", accuracy_level);
735 
736  finalizeComms();
737 
738  int ret;
739  if(accuracy_level >=3 ){
740  ret = 0;
741  }else{
742  ret = 1; //we delclare the test failed
743  }
744 
745  return ret;
746 }