QUDA  v1.1.0
A library for QCD on GPUs
contract_test.cpp
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <time.h>
4 #include <math.h>
5 #include <string.h>
6 
7 #include <util_quda.h>
8 #include <host_utils.h>
9 #include <command_line_params.h>
10 #include <dslash_reference.h>
11 #include <contract_reference.h>
12 #include "misc.h"
13 
14 // google test
15 #include <gtest/gtest.h>
16 
17 // In a typical application, quda.h is the only QUDA header required.
18 #include <quda.h>
19 #include <color_spinor_field.h>
20 
21 // If you add a new contraction type, this must be updated++
22 constexpr int NcontractType = 2;
23 // For googletest, names must be non-empty, unique, and may only contain ASCII
24 // alphanumeric characters or underscore.
25 const char *names[] = {"OpenSpin", "DegrandRossi"};
26 const char *prec_str[] = {"single", "double"};
27 
28 namespace quda
29 {
30  extern void setTransferGPU(bool);
31 }
32 
34 {
35  printfQuda("running the following test:\n");
36 
37  printfQuda("prec sloppy_prec S_dimension T_dimension Ls_dimension\n");
38  printfQuda("%s %s %d/%d/%d %d %d\n", get_prec_str(prec), get_prec_str(prec_sloppy),
39  xdim, ydim, zdim, tdim, Lsdim);
40 
41  printfQuda("Contraction test");
42  printfQuda("Grid partition info: X Y Z T\n");
43  printfQuda(" %d %d %d %d\n", dimPartitioned(0), dimPartitioned(1), dimPartitioned(2),
44  dimPartitioned(3));
45  return;
46 }
47 
48 int main(int argc, char **argv)
49 {
50  // Start Google Test Suite
51  //-----------------------------------------------------------------------------
52  ::testing::InitGoogleTest(&argc, argv);
53 
54  // QUDA initialise
55  //-----------------------------------------------------------------------------
56  // command line options
57  auto app = make_app();
58  try {
59  app->parse(argc, argv);
60  } catch (const CLI::ParseError &e) {
61  return app->exit(e);
62  }
63 
64  // initialize QMP/MPI, QUDA comms grid and RNG (host_utils.cpp)
65  initComms(argc, argv, gridsize_from_cmdline);
66 
67  // Ensure gtest prints only from rank 0
69  if (comm_rank() != 0) { delete listeners.Release(listeners.default_result_printer()); }
70 
71  // call srand() with a rank-dependent seed
72  initRand();
74 
75  // initialize the QUDA library
77  int X[4] = {xdim, ydim, zdim, tdim};
78  setDims(X);
79  //-----------------------------------------------------------------------------
80 
82 
83  // Check for correctness
84  int result = 0;
85  if (verify_results) {
87  if (comm_rank() != 0) { delete listeners.Release(listeners.default_result_printer()); }
88  result = RUN_ALL_TESTS();
89  if (result) warningQuda("Google tests for QUDA contraction failed!");
90  }
91  //-----------------------------------------------------------------------------
92 
93  // finalize the QUDA library
94  endQuda();
95 
96  // finalize the communications layer
97  finalizeComms();
98 
99  return result;
100 }
101 
102 // Functions used for Google testing
103 //-----------------------------------------------------------------------------
104 
105 // Performs the CPU GPU comparison with the given parameters
106 int test(int contractionType, int Prec)
107 {
109  switch (Prec) {
110  case 0: test_prec = QUDA_SINGLE_PRECISION; break;
111  case 1: test_prec = QUDA_DOUBLE_PRECISION; break;
112  default: errorQuda("Undefined QUDA precision type %d\n", Prec);
113  }
114 
115  int X[4] = {xdim, ydim, zdim, tdim};
116 
119  inv_param.cpu_prec = test_prec;
120  inv_param.cuda_prec = test_prec;
121  inv_param.cuda_prec_sloppy = test_prec;
122  inv_param.cuda_prec_precondition = test_prec;
123 
124  size_t data_size = (test_prec == QUDA_DOUBLE_PRECISION) ? sizeof(double) : sizeof(float);
125  void *spinorX = malloc(V * spinor_site_size * data_size);
126  void *spinorY = malloc(V * spinor_site_size * data_size);
127  void *d_result = malloc(2 * V * 16 * data_size);
128 
129  if (test_prec == QUDA_SINGLE_PRECISION) {
130  for (int i = 0; i < V * spinor_site_size; i++) {
131  ((float *)spinorX)[i] = rand() / (float)RAND_MAX;
132  ((float *)spinorY)[i] = rand() / (float)RAND_MAX;
133  }
134  } else {
135  for (int i = 0; i < V * spinor_site_size; i++) {
136  ((double *)spinorX)[i] = rand() / (double)RAND_MAX;
137  ((double *)spinorY)[i] = rand() / (double)RAND_MAX;
138  }
139  }
140 
141  // Host side spinor data and result passed to QUDA.
142  // QUDA will allocate GPU memory, transfer the data,
143  // perform the requested contraction, and return the
144  // result in the array 'result'
145  // We then compare the GPU result with a CPU refernce code
146 
148  switch (contractionType) {
149  case 0: cType = QUDA_CONTRACT_TYPE_OPEN; break;
150  case 1: cType = QUDA_CONTRACT_TYPE_DR; break;
151  default: errorQuda("Undefined contraction type %d\n", contractionType);
152  }
153 
154  // Perform GPU contraction.
155  contractQuda(spinorX, spinorY, d_result, cType, &inv_param, X);
156 
157  // Compare each site contraction from the host and device.
158  // It returns the number of faults it detects.
159  int faults = 0;
160  if (test_prec == QUDA_DOUBLE_PRECISION) {
161  faults = contraction_reference((double *)spinorX, (double *)spinorY, (double *)d_result, cType, X);
162  } else {
163  faults = contraction_reference((float *)spinorX, (float *)spinorY, (float *)d_result, cType, X);
164  }
165 
166  printfQuda("Contraction comparison for contraction type %s complete with %d/%d faults\n", get_contract_str(cType),
167  faults, V * 16 * 2);
168 
169  free(spinorX);
170  free(spinorY);
171  free(d_result);
172 
173  return faults;
174 }
175 
176 // The following tests gets each contraction type and precision using google testing framework
180 using ::testing::TestWithParam;
182 
183 class ContractionTest : public ::testing::TestWithParam<::testing::tuple<int, int>>
184 {
185  protected:
186  ::testing::tuple<int, int> param;
187 
188  public:
189  virtual ~ContractionTest() {}
190  virtual void SetUp() { param = GetParam(); }
191 };
192 
193 // Sets up the Google test
195 {
196  int prec = ::testing::get<0>(GetParam());
197  int contractionType = ::testing::get<1>(GetParam());
198  auto faults = test(contractionType, prec);
199  EXPECT_EQ(faults, 0) << "CPU and GPU implementations do not agree";
200 }
201 
202 // Helper function to construct the test name
204 {
205  int prec = ::testing::get<0>(param.param);
206  int contractType = ::testing::get<1>(param.param);
207  std::string str(names[contractType]);
208  str += std::string("_");
209  str += std::string(prec_str[prec]);
210  return str; // names[contractType] + "_" + prec_str[prec];
211 }
212 
213 // Instantiate all test cases
virtual void SetUp()
::testing::tuple< int, int > param
virtual ~ContractionTest()
TestEventListener * Release(TestEventListener *listener)
TestEventListener * default_result_printer() const
Definition: gtest.h:1186
TestEventListeners & listeners()
static UnitTest * GetInstance()
static const ParamType & GetParam()
Definition: gtest.h:1851
int comm_rank(void)
std::shared_ptr< QUDAApp > make_app(std::string app_description, std::string app_name)
int device_ordinal
int & ydim
bool verify_results
int & zdim
QudaPrecision prec
int Lsdim
int & tdim
int & xdim
std::array< int, 4 > gridsize_from_cmdline
QudaPrecision prec_sloppy
int contraction_reference(Float *spinorX, Float *spinorY, Float *d_result, QudaContractType cType, int X[])
int V
Definition: host_utils.cpp:37
const char * names[]
int test(int contractionType, int Prec)
int main(int argc, char **argv)
TEST_P(ContractionTest, verify)
constexpr int NcontractType
std::string getContractName(testing::TestParamInfo<::testing::tuple< int, int >> param)
const char * prec_str[]
INSTANTIATE_TEST_SUITE_P(QUDA, ContractionTest, Combine(Range(0, 2), Range(0, NcontractType)), getContractName)
void display_test_info()
void setDims(int *)
Definition: host_utils.cpp:315
QudaInvertParam inv_param
Definition: covdev_test.cpp:27
enum QudaPrecision_s QudaPrecision
@ QUDA_DOUBLE_PRECISION
Definition: enum_quda.h:65
@ QUDA_SINGLE_PRECISION
Definition: enum_quda.h:64
@ QUDA_INVALID_PRECISION
Definition: enum_quda.h:66
enum QudaContractType_s QudaContractType
@ QUDA_CONTRACT_TYPE_OPEN
Definition: enum_quda.h:523
@ QUDA_CONTRACT_TYPE_INVALID
Definition: enum_quda.h:525
@ QUDA_CONTRACT_TYPE_DR
Definition: enum_quda.h:524
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:2017
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: gtest.h:2468
int dimPartitioned(int dim)
Definition: host_utils.cpp:376
void initComms(int argc, char **argv, std::array< int, 4 > &commDims)
Definition: host_utils.cpp:255
void finalizeComms()
Definition: host_utils.cpp:292
void initRand()
Definition: host_utils.cpp:302
#define spinor_site_size
Definition: host_utils.h:9
void setContractInvertParam(QudaInvertParam &inv_param)
Definition: set_params.cpp:768
const char * get_prec_str(QudaPrecision prec)
Definition: misc.cpp:26
const char * get_contract_str(QudaContractType type)
Definition: misc.cpp:141
void setTransferGPU(bool)
void contractQuda(const ColorSpinorField &x, const ColorSpinorField &y, void *result, QudaContractType cType)
::std::string string
Definition: gtest-port.h:891
internal::ParamGenerator< T > Range(T start, T end, IncrementT step)
internal::CartesianProductHolder< Generator... > Combine(const Generator &... g)
internal::ValueArray< T... > Values(T... v)
internal::ParamGenerator< bool > Bool()
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
QudaGaugeParam param
Definition: pack_test.cpp:18
Main header file for the QUDA library.
void initQuda(int device)
QudaInvertParam newQudaInvertParam(void)
void endQuda(void)
QudaPrecision cuda_prec
Definition: quda.h:238
QudaPrecision cpu_prec
Definition: quda.h:237
QudaPrecision cuda_prec_sloppy
Definition: quda.h:239
QudaPrecision cuda_prec_precondition
Definition: quda.h:241
#define printfQuda(...)
Definition: util_quda.h:114
#define warningQuda(...)
Definition: util_quda.h:132
#define errorQuda(...)
Definition: util_quda.h:120