Compressed Sparse Blocks  1.2
 All Classes Files Functions Variables Typedefs Friends Macros Pages
spmm_test.cpp
Go to the documentation of this file.
1 #define NOMINMAX
2 #include <iostream>
3 #include <algorithm>
4 #include <numeric>
5 #include <functional>
6 #include <fstream>
7 #include <ctime>
8 #include <cmath>
9 #include <string>
10 #include <array>
11 
12 #include "timer.gettimeofday.c"
13 #include "cilk_util.h"
14 #include "aligned.h"
15 
16 #define INDEXTYPE uint32_t
17 #ifdef SINGLEPRECISION
18  #define VALUETYPE float
19 #else
20  #define VALUETYPE double
21 #endif
22 
23 #ifndef RHSDIM
24  #define RHSDIM 16
25 #endif
26 #define ALIGN 32
27 
28 #include "utility.h"
29 #include "triple.h"
30 #include "csc.h"
31 #include "bicsb.h"
32 #include "bmcsb.h"
33 #include "spvec.h"
34 #include "Semirings.h"
35 
36 using namespace std;
37 
38 
39 template <typename NT, typename ALLOC, int DIM>
40 void fillzero (vector< array<NT,DIM>, ALLOC > & vecofarr)
41 {
42  for(auto itr = vecofarr.begin(); itr != vecofarr.end(); ++itr)
43  {
44  itr->fill(static_cast<NT> (0));
45  }
46 }
47 
48 template <typename NT, typename ALLOC, int DIM>
49 void fillrandom (vector< array<NT,DIM>, ALLOC > & vecofarr)
50 {
51  for(auto itr = vecofarr.begin(); itr != vecofarr.end(); ++itr)
52  {
53  #if (__GNUC__ == 4 && (__GNUC_MINOR__ < 7) )
54  RandGen G;
55  for(auto refarr = itr->begin(); refarr != itr->end(); ++refarr)
56  {
57  *refarr = G.RandReal();
58  }
59  #else
60  std::uniform_real_distribution<NT> distribution(0.0f, 1.0f); //Values between 0 and 1
61  std::mt19937 engine; // Mersenne twister MT19937
62  auto generator = std::bind(distribution, engine);
63  std::generate_n(itr->begin(), DIM, generator);
64  #endif
65  }
66 }
67 
68 template <typename NT, typename ALLOC, int DIM>
69 void VerifyMM (vector< array<NT,DIM>, ALLOC > & control, vector< array<NT,DIM>, ALLOC > & test)
70 {
71  vector< array<NT,DIM> > error;
72  pair<size_t, size_t> maxerrloc;
73  NT prevmax = 0.0;
74 
75  for(auto itr1 = control.begin(), itr2 = test.begin(); itr1 != control.end(); ++itr1, ++itr2)
76  {
77  array<NT,DIM> entry;
78  transform(itr1->begin(), itr1->end(), itr2->begin(), entry.begin(), absdiff<NT>());
79  auto maxelement = max_element(entry.begin(), entry.end());
80  size_t maxcol = maxelement-entry.begin();
81  if(*maxelement > prevmax)
82  {
83  maxerrloc = make_pair(itr1- control.begin(), maxcol);
84  prevmax = *maxelement;
85  }
86  error.emplace_back(entry);
87  }
88 
89  cout << "Max error is: " << prevmax << " on y[" << maxerrloc.first <<"][" << maxerrloc.second << "]=";
90  cout << test[maxerrloc.first][maxerrloc.second] << endl;
91 
92  NT machEps = machineEpsilon<NT>();
93  cout << "Absolute machine epsilon is: " << machEps <<" and y[" << maxerrloc.first <<"][" << maxerrloc.second;
94  cout << "]*EPSILON becomes " << machEps * test[maxerrloc.first][maxerrloc.second] << endl;
95 
96  NT sqrtm = sqrt(static_cast<NT>(control.size()));
97  cout << "sqrt(n) * relative error is: " << abs(machEps * test[maxerrloc.first][maxerrloc.second]) * sqrtm << endl;
98  if ( (abs(machEps * test[maxerrloc.first][maxerrloc.second]) * sqrtm) < abs(prevmax))
99  {
100  cout << "*** ATTENTION ***: error is more than sqrt(n) times the relative machine epsilon" << endl;
101  }
102 }
103 
104 
105 
106 int main(int argc, char* argv[])
107 {
108 #ifndef CILK_STUB
109  int gl_nworkers = __cilkrts_get_nworkers();
110 #else
111  int gl_nworkers = 0;
112 #endif
113  bool syminput = false;
114  bool binary = false;
115  bool iscsc = false;
116  INDEXTYPE m = 0, n = 0, nnz = 0, forcelogbeta = 0;
117  string inputname;
118  if(argc < 2)
119  {
120  cout << "Normal usage: ./a.out inputmatrix.mtx sym/nosym binary/text triples/csc" << endl;
121  cout << "Assuming matrix.txt is the input, matrix is unsymmetric, and stored in text(ascii) file" << endl;
122  inputname = "matrix.txt";
123  }
124  else if(argc < 3)
125  {
126  cout << "Normal usage: ./a.out inputmatrix.mtx sym/nosym binary/text triples/csc" << endl;
127  cout << "Assuming that the matrix is unsymmetric, and stored in text(ascii) file" << endl;
128  inputname = argv[1];
129  }
130  else if(argc < 4)
131  {
132  cout << "Normal usage: ./a.out inputmatrix.mtx sym/nosym binary/text triples/csc" << endl;
133  cout << "Assuming matrix is stored in text(ascii) file" << endl;
134  inputname = argv[1];
135  string issym(argv[2]);
136  if(issym == "sym")
137  syminput = true;
138  else if(issym == "nosym")
139  syminput = false;
140  else
141  cout << "unrecognized option, assuming nosym" << endl;
142  }
143  else
144  {
145  inputname = argv[1];
146  string issym(argv[2]);
147  if(issym == "sym")
148  syminput = true;
149  else if(issym == "nosym")
150  syminput = false;
151  else
152  cout << "unrecognized option, assuming unsymmetric" << endl;
153 
154  string isbinary(argv[3]);
155  if(isbinary == "text")
156  binary = false;
157  else if(isbinary == "binary")
158  binary = true;
159  else
160  cout << "unrecognized option, assuming text file" << endl;
161 
162  if(argc > 4)
163  {
164  string type(argv[4]);
165  if(type == "csc")
166  {
167  iscsc = true;
168  cout << "Processing CSC binary" << endl;
169  }
170  }
171 
172  if(argc == 6)
173  forcelogbeta = atoi(argv[5]);
174  }
175 
177  if(binary)
178  {
179  FILE * f = fopen(inputname.c_str(), "r");
180  if(!f)
181  {
182  cerr << "Problem reading binary input file\n";
183  return 1;
184  }
185  if(iscsc)
186  {
187  fread(&n, sizeof(INDEXTYPE), 1, f);
188  fread(&m, sizeof(INDEXTYPE), 1, f);
189  fread(&nnz, sizeof(INDEXTYPE), 1, f);
190  }
191  else
192  {
193  fread(&m, sizeof(INDEXTYPE), 1, f);
194  fread(&n, sizeof(INDEXTYPE), 1, f);
195  fread(&nnz, sizeof(INDEXTYPE), 1, f);
196  }
197  if (m <= 0 || n <= 0 || nnz <= 0)
198  {
199  cerr << "Problem with matrix size in binary input file\n";
200  return 1;
201  }
202  long tstart = cilk_get_time(); // start timer
203  cout << "Reading matrix with dimensions: "<< m << "-by-" << n <<" having "<< nnz << " nonzeros" << endl;
204  INDEXTYPE * rowindices = new INDEXTYPE[nnz];
205  VALUETYPE * vals = new VALUETYPE[nnz];
206  INDEXTYPE * colindices;
207  INDEXTYPE * colpointers;
208  if(iscsc)
209  {
210  colpointers = new INDEXTYPE[n+1];
211  size_t cols = fread(colpointers, sizeof(INDEXTYPE), n+1, f);
212  if(cols != n+1)
213  {
214  cerr << "Problem with FREAD, aborting... " << endl;
215  return -1;
216  }
217  }
218  else
219  {
220  colindices = new INDEXTYPE[nnz];
221  size_t cols = fread(colindices, sizeof(INDEXTYPE), nnz, f);
222  if(cols != nnz)
223  {
224  cerr << "Problem with FREAD, aborting... " << endl;
225  return -1;
226  }
227  }
228  size_t rows = fread(rowindices, sizeof(INDEXTYPE), nnz, f);
229  size_t nums = fread(vals, sizeof(VALUETYPE), nnz, f);
230 
231  if(rows != nnz || nums != nnz)
232  {
233  cerr << "Problem with FREAD, aborting... " << endl;
234  return -1;
235  }
236  long tend = cilk_get_time(); // end timer
237  cout<< "Reading matrix in binary took " << ((VALUETYPE) (tend-tstart)) /1000 << " seconds" <<endl;
238  fclose(f);
239  if(iscsc)
240  {
241  csc = new Csc<VALUETYPE, INDEXTYPE>();
242  csc->SetPointers(colpointers, rowindices, vals , nnz, m, n, true); // do the fortran thing
243  // csc itself will manage the data in this case (shallow copy)
244  }
245  else
246  {
247  csc = new Csc<VALUETYPE, INDEXTYPE>(rowindices, colindices, vals , nnz, m, n);
248  delete [] colindices;
249  delete [] rowindices;
250  delete [] vals;
251  }
252  }
253  else
254  {
255  cout << "reading input matrix in text(ascii)... " << endl;
256  ifstream infile(inputname.c_str());
257  char line[256];
258  char c = infile.get();
259  while(c == '%')
260  {
261  infile.getline(line,256);
262  c = infile.get();
263  }
264  infile.unget();
265  infile >> m >> n >> nnz; // #{rows}-#{cols}-#{nonzeros}
266 
267  long tstart = cilk_get_time(); // start timer
269 
270  if (infile.is_open())
271  {
272  INDEXTYPE cnz = 0; // current number of nonzeros
273  while (! infile.eof() && cnz < nnz)
274  {
275  infile >> triples[cnz].row >> triples[cnz].col >> triples[cnz].val; // row-col-value
276  triples[cnz].row--;
277  triples[cnz].col--;
278  ++cnz;
279  }
280  assert(cnz == nnz);
281  }
282  long tend = cilk_get_time(); // end timer
283  cout<< "Reading matrix in ascii took " << ((double) (tend-tstart)) /1000 << " seconds" <<endl;
284 
285  cout << "converting to csc ... " << endl;
286  csc= new Csc<VALUETYPE,INDEXTYPE>(triples, nnz, m, n);
287  delete [] triples;
288  }
289 
290  cout << "# workers: "<< gl_nworkers << endl;
291  BiCsb<VALUETYPE, INDEXTYPE> bicsb(*csc, gl_nworkers, forcelogbeta);
292 
293  double mflops = (2.0 * static_cast<double>(nnz) * RHSDIM) / 1000000.0;
294  cout << "generating " << RHSDIM << " multi vectors... " << endl;
295  typedef array<VALUETYPE, RHSDIM> PACKED;
296  vector< PACKED, aligned_allocator<PACKED, ALIGN> > x(n);
297  vector< PACKED, aligned_allocator<PACKED, ALIGN> > y_bicsb(m);
298  vector< PACKED, aligned_allocator<PACKED, ALIGN> > y_csc(m);
299 
300  fillzero<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(y_csc);
301  fillzero<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(y_bicsb);
302  fillrandom<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(x);
303 
305  cout << "starting SpMV ... " << endl;
306  cout << "Row imbalance is: " << RowImbalance(bicsb) << endl;
307  cout << "Col imbalance is: " << ColImbalance(bicsb) << endl;
308  timer_init();
309 
310 
311  bicsb_gespmv<PTARR>(bicsb, &(x[0]), &(y_bicsb[0]));
312  double t0 = timer_seconds_since_init();
313 
314  for(int i=0; i < REPEAT; ++i)
315  {
316  bicsb_gespmv<PTARR>(bicsb, &(x[0]), &(y_bicsb[0]));
317  }
318  double t1 = timer_seconds_since_init();
319 
320  double time = (t1-t0)/REPEAT;
321  cout<< "BiCSB" << " time: " << time << " seconds" <<endl;
322  cout<< "BiCSB" << " mflop/sec: " << mflops / time <<endl;
323 
324 
325  cout << "starting SpMV_T" << endl;
326  vector< PACKED, aligned_allocator<PACKED, ALIGN> > xt(m);
327  vector< PACKED, aligned_allocator<PACKED, ALIGN> > yt_bicsb(n);
328  vector< PACKED, aligned_allocator<PACKED, ALIGN> > yt_csc(n);
329 
330  fillzero<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(yt_csc);
331  fillzero<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(yt_bicsb);
332  fillrandom<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(xt);
333 
334  bicsb_gespmvt<PTARR>(bicsb, &(xt[0]), &(yt_bicsb[0])); // warm-up computation
335  t0 = timer_seconds_since_init();
336  for(int i=0; i < REPEAT; ++i)
337  {
338  bicsb_gespmvt<PTARR>(bicsb, &(xt[0]), &(yt_bicsb[0]));
339  }
340  t1 = timer_seconds_since_init();
341 
342  double totaltime = time + (t1-t0)/REPEAT;
343  time = (t1-t0)/REPEAT;
344  cout<< "BiCSB Trans" << " time: " << time << " seconds" <<endl;
345  cout<< "BiCSB Trans" << " mflop/sec: " << mflops / time <<endl;
346 
347 
348  cout<< "BiCSB Total" << " time: " << totaltime << " seconds" <<endl;
349  cout<< "BiCSB Total" << " mflop/sec: " << 2*mflops / totaltime <<endl;
350 
351  // Verify with CSC (serial)
352  csc_gaxpy_mm<RHSDIM>(*csc, &(x[0]), &(y_csc[0]));
353  t0 = timer_seconds_since_init();
354  for(int i=0; i < REPEAT; ++i)
355  {
356  csc_gaxpy_mm<RHSDIM>(*csc, &(x[0]), &(y_csc[0]));
357  }
358  t1 = timer_seconds_since_init();
359  double csctime = (t1-t0)/REPEAT;
360  cout<< "CSC" << " time: " << csctime << " seconds" <<endl;
361  cout<< "CSC" << " mflop/sec: " << mflops / csctime <<endl;
362 
363  VerifyMM<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(y_csc, y_bicsb);
364 
365 
366  csc_gaxpy_mm_trans<RHSDIM> ( *csc, &(xt[0]), &(yt_csc[0]));
367  t0 = timer_seconds_since_init();
368  for(int i=0; i < REPEAT; ++i)
369  {
370  csc_gaxpy_mm_trans<RHSDIM> ( *csc, &(xt[0]), &(yt_csc[0]));
371  }
372  t1 = timer_seconds_since_init();
373  time = (t1-t0)/REPEAT;
374  cout <<"Transposed CSC time: " << time << " seconds" << endl;
375  cout <<"Transposed CSC mflop/sec: " << mflops/ time << endl;
376 
377  VerifyMM<VALUETYPE, aligned_allocator<PACKED, ALIGN>, RHSDIM>(yt_csc, yt_bicsb);
378 
379  delete csc;
380 
381 }
382 
int main(int argc, char *argv[])
Definition: spmm_test.cpp:106
#define REPEAT
Definition: utility.h:144
ITYPE col
Definition: triple.h:14
void fillzero(vector< array< NT, DIM >, ALLOC > &vecofarr)
Definition: spmm_test.cpp:40
double RandReal()
Definition: randgen.h:85
float ColImbalance(const BiCsb< NT, IT > &A)
Definition: friends.h:414
void fillrandom(vector< array< NT, DIM >, ALLOC > &vecofarr)
Definition: spmm_test.cpp:49
#define RHSDIM
Definition: spmm_test.cpp:24
int cilk_get_time()
Definition: cilk_util.h:23
void VerifyMM(vector< array< NT, DIM >, ALLOC > &control, vector< array< NT, DIM >, ALLOC > &test)
Definition: spmm_test.cpp:69
ITYPE row
Definition: triple.h:13
#define INDEXTYPE
Definition: spmm_test.cpp:16
Definition: csc.h:12
Definition: csc.h:15
#define VALUETYPE
Definition: spmm_test.cpp:20
float RowImbalance(const CSB &A)
Definition: friends.h:400
void SetPointers(ITYPE *colpointers, ITYPE *rowindices, T *vals, ITYPE size, ITYPE rows, ITYPE cols, bool fortran)
Definition: csc.h:27
Definition: bicsb.h:19
T val
Definition: triple.h:15