├── README.md ├── run_experiments.sh ├── Makefile ├── inc ├── mvstructs.h └── mmio.h ├── apps └── csrspmv.cpp └── src ├── mmio.cpp └── mvstructs.cpp /README.md: -------------------------------------------------------------------------------- 1 | # cusparse spmv 2 | 3 | A small example program for benchmarking cuSPARSE's csrmv routine with real-world 4 | data, against a randomly initialised vector. 5 | 6 | Calling `make` should be sufficient to build the example program. 7 | The example can then be called as follows: `./bin/csrspmv ` -------------------------------------------------------------------------------- /run_experiments.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | datasetf=$1 4 | echo "Dataset folder: $datasetf" 5 | 6 | spmv=$2 7 | echo "SparseMatrixDenseVector excutable: $spmv" 8 | 9 | table=$3 10 | echo "Table name: $table" 11 | 12 | # Get some unique data for the experiment ID 13 | now=$(date -Iminutes) 14 | hsh=$(git rev-parse HEAD) 15 | exID="$hsh-$now" 16 | host=$(hostname) 17 | 18 | # make a folder for results 19 | mkdir -p "results-$exID" 20 | 21 | for f in $(cat $datasetf/datasets.txt); 22 | do 23 | echo "matrix: $f" 24 | echo "Resultfile: result_$f.txt" 25 | 26 | $spmv $datasetf/$f/$f.mtx $f $host $exID $table &> results-$exID/result_$f.txt 27 | done 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Compiler 2 | CC = g++ 3 | 4 | # (Final) Binary, Source, Include, Object and Apps directories 5 | BIN = bin 6 | SRC = src 7 | INC = inc 8 | OBJ = obj 9 | APP = apps 10 | 11 | # Sources for building object files, and their associated objects 12 | SOURCES = mvstructs.cpp mmio.cpp 13 | OBJECTS = $(patsubst %.cpp,$(OBJ)/%.o,$(SOURCES)) 14 | 15 | # Sources for the applications this makefile builds 16 | APP_SOURCES = csrspmv.cpp 17 | APPS = $(patsubst %.cpp,$(BIN)/%,$(APP_SOURCES)) 18 | 19 | # Universal C flags 20 | CFLAGS = -std=c++11 -O3 21 | 22 | # Get the host and shell, to determine include directories and link options 23 | HOST = $(shell hostname) 24 | UNAME = $(shell uname) 25 | SKELCL_DIR = 26 | 27 | # Add the include directories to a single variable, which we can pass to $(CC) 28 | INCLUDE = -I$(INC) -I/usr/local/cuda-8.0/include/ 29 | 30 | # Define a single general linker string for $(CC) 31 | LINK = -L/usr/local/cuda-8.0/lib64/ -lcuda -lcudart -lcusparse 32 | 33 | # discover where source and header files are located 34 | vpath %.cpp $(SRC) $(APPS) 35 | # vpath %.cpp 36 | vpath %.h $(INC) 37 | vpath %.hpp $(INC) 38 | 39 | # General rule to trigger the others, depend on the makefile so that everything recompiles when the makefile changes 40 | all: $(APPS) $(OBJECTS) Makefile 41 | 42 | # Clean by simply deleting the $(OBJ) and $(BIN) directories 43 | clean: 44 | rm -rf $(OBJ) $(BIN) 45 | 46 | # A rule for building individual apps - make the $(BIN) directory if it doesn't exist 47 | $(BIN)/%: $(APP)/%.cpp $(OBJECTS) 48 | if [ ! -d $(BIN) ]; then mkdir $(BIN); fi 49 | # add -Werror here, as it breaks some of the libraries (e.g. mmio) that we rely on 50 | $(CC) $< $(INCLUDE) $(OBJECTS) $(CFLAGS) $(LINK) -o $@ 51 | 52 | # A rule for building individual object files - make the $(OBJ) directory if it doesn't exist 53 | $(OBJ)/%.o: %.cpp 54 | if [ ! -d $(OBJ) ]; then mkdir $(OBJ); fi 55 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 56 | 57 | -------------------------------------------------------------------------------- /inc/mvstructs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "mmio.h" 11 | #include 12 | #include "cusparse.h" 13 | 14 | 15 | enum MemStatus { 16 | HostOutdated, 17 | DeviceOutdated, 18 | UpToDate 19 | }; 20 | 21 | class denseVector 22 | { 23 | public: 24 | denseVector(int); 25 | ~denseVector(); 26 | denseVector & operator= (const denseVector&); 27 | void push(float); 28 | void fill(float); 29 | void fillRandom(); 30 | void print(); 31 | float* getDevPtr(); 32 | void download(); 33 | private: 34 | float* hostPtr; 35 | float* devPtr; 36 | int n; 37 | int ixPtr; 38 | MemStatus mstatus; 39 | 40 | void updateBuffers(); 41 | void cleanup(); 42 | }; 43 | 44 | class csrMatrix 45 | { 46 | public: 47 | 48 | csrMatrix(int, int, int, int*, int*, float*); 49 | ~csrMatrix(); 50 | std::vector spmv(cusparseHandle_t,denseVector&,denseVector&); 51 | private: 52 | // device pointers 53 | int* rowDevPtr; 54 | int* colIxDevPtr; 55 | float* valDevPtr; 56 | int nnz; 57 | int h; 58 | int w; 59 | // no host pointers - we hopefully won't need them 60 | // buffer status. This should always be "HostOutdated" 61 | // MemStatus status; 62 | // void updateBuffers(); 63 | }; 64 | 65 | class cooMatrix 66 | { 67 | public: 68 | cooMatrix(int, int, int); 69 | cooMatrix(std::string); 70 | ~cooMatrix(); 71 | void push(int, int, float); 72 | // sorting after pushing values 73 | void print(); 74 | csrMatrix asCSR(cusparseHandle_t); 75 | int getWidth() {return w;} 76 | 77 | private: 78 | int nnz; 79 | int h; 80 | int w; 81 | // host pointers 82 | int * rowIndexHostPtr; 83 | int * colIndexHostPtr; 84 | float * valHostPtr; 85 | // device pointers 86 | int * rowIndexDevPtr; 87 | int * colIndexDevPtr; 88 | float* valDevPtr; 89 | int ixPtr; 90 | // transfer status 91 | MemStatus mstatus; 92 | void updateBuffers(); 93 | // cleanup functionality 94 | void cleanup(); 95 | // memory allocation 96 | void alloc(); 97 | }; 98 | 99 | 100 | -------------------------------------------------------------------------------- /inc/mmio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Matrix Market I/O library for ANSI C 3 | * 4 | * See http://math.nist.gov/MatrixMarket for details. 5 | * 6 | * 7 | */ 8 | 9 | #ifndef MM_IO_H 10 | #define MM_IO_H 11 | 12 | #define MM_MAX_LINE_LENGTH 1025 13 | #define MatrixMarketBanner "%%MatrixMarket" 14 | #define MM_MAX_TOKEN_LENGTH 64 15 | 16 | typedef char MM_typecode[4]; 17 | 18 | char *mm_typecode_to_str(MM_typecode matcode); 19 | 20 | int mm_read_banner(FILE *f, MM_typecode *matcode); 21 | int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz); 22 | int mm_read_mtx_array_size(FILE *f, int *M, int *N); 23 | 24 | int mm_write_banner(FILE *f, MM_typecode matcode); 25 | int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz); 26 | int mm_write_mtx_array_size(FILE *f, int M, int N); 27 | 28 | 29 | /********************* MM_typecode query fucntions ***************************/ 30 | 31 | #define mm_is_matrix(typecode) ((typecode)[0]=='M') 32 | 33 | #define mm_is_sparse(typecode) ((typecode)[1]=='C') 34 | #define mm_is_coordinate(typecode)((typecode)[1]=='C') 35 | #define mm_is_dense(typecode) ((typecode)[1]=='A') 36 | #define mm_is_array(typecode) ((typecode)[1]=='A') 37 | 38 | #define mm_is_complex(typecode) ((typecode)[2]=='C') 39 | #define mm_is_real(typecode) ((typecode)[2]=='R') 40 | #define mm_is_pattern(typecode) ((typecode)[2]=='P') 41 | #define mm_is_integer(typecode) ((typecode)[2]=='I') 42 | 43 | #define mm_is_symmetric(typecode)((typecode)[3]=='S') 44 | #define mm_is_general(typecode) ((typecode)[3]=='G') 45 | #define mm_is_skew(typecode) ((typecode)[3]=='K') 46 | #define mm_is_hermitian(typecode)((typecode)[3]=='H') 47 | 48 | int mm_is_valid(MM_typecode matcode); /* too complex for a macro */ 49 | 50 | 51 | /********************* MM_typecode modify fucntions ***************************/ 52 | 53 | #define mm_set_matrix(typecode) ((*typecode)[0]='M') 54 | #define mm_set_coordinate(typecode) ((*typecode)[1]='C') 55 | #define mm_set_array(typecode) ((*typecode)[1]='A') 56 | #define mm_set_dense(typecode) mm_set_array(typecode) 57 | #define mm_set_sparse(typecode) mm_set_coordinate(typecode) 58 | 59 | #define mm_set_complex(typecode)((*typecode)[2]='C') 60 | #define mm_set_real(typecode) ((*typecode)[2]='R') 61 | #define mm_set_pattern(typecode)((*typecode)[2]='P') 62 | #define mm_set_integer(typecode)((*typecode)[2]='I') 63 | 64 | 65 | #define mm_set_symmetric(typecode)((*typecode)[3]='S') 66 | #define mm_set_general(typecode)((*typecode)[3]='G') 67 | #define mm_set_skew(typecode) ((*typecode)[3]='K') 68 | #define mm_set_hermitian(typecode)((*typecode)[3]='H') 69 | 70 | #define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \ 71 | (*typecode)[2]=' ',(*typecode)[3]='G') 72 | 73 | #define mm_initialize_typecode(typecode) mm_clear_typecode(typecode) 74 | 75 | 76 | /********************* Matrix Market error codes ***************************/ 77 | 78 | 79 | #define MM_COULD_NOT_READ_FILE 11 80 | #define MM_PREMATURE_EOF 12 81 | #define MM_NOT_MTX 13 82 | #define MM_NO_HEADER 14 83 | #define MM_UNSUPPORTED_TYPE 15 84 | #define MM_LINE_TOO_LONG 16 85 | #define MM_COULD_NOT_WRITE_FILE 17 86 | 87 | 88 | /******************** Matrix Market internal definitions ******************** 89 | 90 | MM_matrix_typecode: 4-character sequence 91 | 92 | object sparse/ data storage 93 | dense type scheme 94 | 95 | string position: [0] [1] [2] [3] 96 | 97 | Matrix typecode: M(atrix) C(oord) R(eal) G(eneral) 98 | A(array) C(omplex) H(ermitian) 99 | P(attern) S(ymmetric) 100 | I(nteger) K(kew) 101 | 102 | ***********************************************************************/ 103 | 104 | #define MM_MTX_STR "matrix" 105 | #define MM_ARRAY_STR "array" 106 | #define MM_DENSE_STR "array" 107 | #define MM_COORDINATE_STR "coordinate" 108 | #define MM_SPARSE_STR "coordinate" 109 | #define MM_COMPLEX_STR "complex" 110 | #define MM_REAL_STR "real" 111 | #define MM_INT_STR "integer" 112 | #define MM_GENERAL_STR "general" 113 | #define MM_SYMM_STR "symmetric" 114 | #define MM_HERM_STR "hermitian" 115 | #define MM_SKEW_STR "skew-symmetric" 116 | #define MM_PATTERN_STR "pattern" 117 | 118 | 119 | /* high level routines */ 120 | 121 | int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], 122 | double val[], MM_typecode matcode); 123 | int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], 124 | double val[], MM_typecode matcode); 125 | int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, 126 | MM_typecode matcode); 127 | 128 | int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, 129 | double **val_, int **I_, int **J_); 130 | 131 | 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /apps/csrspmv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cusparse.h" 8 | #include "mvstructs.h" 9 | 10 | std::tuple initCUSparse() { 11 | cusparseStatus_t status; 12 | cusparseHandle_t handle = 0; 13 | 14 | // init cusparse 15 | status = cusparseCreate(&handle); 16 | if (status != CUSPARSE_STATUS_SUCCESS) { 17 | std::cerr << "CUSPARSE Library initialisation failed" << std::endl; 18 | cusparseDestroy(handle); 19 | exit(1); 20 | } 21 | 22 | // get ad device, and check it has compute capability 1.3 23 | int devID; 24 | cudaDeviceProp prop; 25 | cudaError_t cudaStat; 26 | cudaStat = cudaGetDevice(&devID); 27 | if (cudaSuccess != cudaStat) { 28 | std::cerr << "Error: cudaGetDevice failed!" << std::endl; 29 | // do some cleanup... 30 | cusparseDestroy(handle); 31 | std::cerr << "Error: cudaStat: " << cudaStat << ", " 32 | << cudaGetErrorString(cudaStat) << std::endl; 33 | exit(1); 34 | } 35 | 36 | cudaStat = cudaGetDeviceProperties(&prop, devID); 37 | if (cudaSuccess != cudaStat) { 38 | std::cerr << "Error: cudaGetDeviceProperties failed!" << std::endl; 39 | // do some cleanup... 40 | cusparseDestroy(handle); 41 | std::cerr << "Error: cudaStat: " << cudaStat << ", " 42 | << cudaGetErrorString(cudaStat) << std::endl; 43 | exit(1); 44 | } 45 | 46 | int cc = 100 * prop.major + 10 * prop.minor; 47 | if (cc <= 130) { 48 | cusparseDestroy(handle); 49 | 50 | std::cerr << "waive the test because only sm13 and above are supported" 51 | << std::endl; 52 | std::cerr << "the device has compute capability" << cc << std::endl; 53 | std::cerr << "example test WAIVED" << std::endl; 54 | exit(2); 55 | } else { 56 | std::cerr << "Compute capability: " << prop.major << "." << prop.minor 57 | << std::endl; 58 | } 59 | 60 | std::string deviceName(prop.name); 61 | return std::make_tuple(handle, deviceName); 62 | } 63 | 64 | void printSqlResult(std::string host, std::string device, std::string matrix, 65 | std::string exID, std::string table, 66 | std::vector runtimes) { 67 | std::cout << "insert into " << table 68 | << " (time, correct, kernel, global, local, host, device, matrix, " 69 | "iteration, trial, statistic, experiment_id) values "; 70 | // std::cout<<"insert into TABLE (time, host, device, matrix) values ("<< 71 | int trial = 0; 72 | std::sort(runtimes.begin(), runtimes.end()); 73 | for (auto time : runtimes) { 74 | 75 | if (trial == 0) { 76 | std::cout << "("; 77 | } else { 78 | std::cout << ",("; 79 | } 80 | std::cout << time << "," << // time 81 | "\'correct\'" 82 | << "," << // correct 83 | "\'cuSPARSE\'" 84 | << "," << // kernel 85 | "-1" 86 | << "," << // global 87 | "-1" 88 | << "," << // local 89 | "\'" << host << "\'" 90 | << "," << // host 91 | "\'" << device << "\'" 92 | << "," << // device 93 | "\'" << matrix << "\'" 94 | << "," << // matrix 95 | "0" 96 | << "," << // iteration 97 | trial << "," << // trial 98 | "\'RAW_RESULT\'" 99 | << "," << // statistic 100 | "\'" << exID << "\'" 101 | << ")"; // experiment ID 102 | trial++; 103 | } 104 | 105 | auto median = runtimes[runtimes.size() / 2]; 106 | std::cout << ",(" << median << ", " << // time 107 | "\'correct\'" 108 | << "," << // correct 109 | "\'cuSPARSE\'" 110 | << "," << // kernel 111 | "-1" 112 | << "," << // global 113 | "-1" 114 | << "," << // local 115 | "\'" << host << "\'" 116 | << "," << // host 117 | "\'" << device << "\'" 118 | << "," << // device 119 | "\'" << matrix << "\'" 120 | << "," << // matrix 121 | "0" 122 | << "," << // iteration 123 | "-1" 124 | << "," << // trial 125 | "\'MEDIAN_RESULT\'" 126 | << "," << // statistic 127 | "\'" << exID << "\'" 128 | << ")"; // experiment ID 129 | std::cout << ";" << std::endl; 130 | } 131 | 132 | int main(int argc, char const *argv[]) { 133 | if (argc < 6) { 134 | std::cerr << "No table name given!" << std::endl; 135 | exit(1); 136 | } 137 | if (argc < 5) { 138 | std::cerr << "No expermient id given!" << std::endl; 139 | exit(1); 140 | } 141 | if (argc < 4) { 142 | std::cerr << "Error: no hostname given!" << std::endl; 143 | exit(1); 144 | } 145 | if (argc < 3) { 146 | std::cerr << "Error: no matrix name given!" << std::endl; 147 | exit(1); 148 | } 149 | if (argc < 2) { 150 | std::cerr << "Error: no matrix file specified!" << std::endl; 151 | exit(1); 152 | } 153 | std::string mfname(argv[1]); 154 | std::string mname(argv[2]); 155 | std::string hostname(argv[3]); 156 | std::string exID(argv[4]); 157 | std::string table(argv[5]); 158 | std::cerr << "Matrix filename: " << mfname << std::endl; 159 | std::cerr << "Matrix name: " << mname << std::endl; 160 | std::cerr << "Hostname: " << hostname << std::endl; 161 | std::cerr << "Experiment ID: " << exID << std::endl; 162 | std::cerr << "SQL table: " << table << std::endl; 163 | 164 | // input matrix 165 | cooMatrix cm(mfname); 166 | 167 | // input vector 168 | denseVector v(cm.getWidth()); 169 | v.fillRandom(); 170 | std::cerr << "v before: " << std::endl; 171 | // v.print(); 172 | 173 | // output vector 174 | denseVector result(cm.getWidth()); 175 | 176 | // cusparse handle 177 | auto hn = initCUSparse(); 178 | auto handle = std::get<0>(hn); 179 | auto devname = std::get<1>(hn); 180 | std::cerr << "Running on device: " << devname << std::endl; 181 | 182 | // csr version of the matrix 183 | csrMatrix csrm = cm.asCSR(handle); 184 | 185 | // compute a sparse matrix vector multiplication 186 | auto times = csrm.spmv(handle, v, result); 187 | // std::sort(times.begin(), times.end()); 188 | // if (times.size() % 2) { 189 | // std::cerr << "Median: " << times[times.size() / 2] << std::endl; 190 | // } else { 191 | // std::cerr << "Median: " << times[(times.size() + 1) / 2] << std::endl; 192 | // } 193 | 194 | printSqlResult(hostname, devname, mname, exID, table, times); 195 | 196 | // the result 197 | // std::cerr<<"result after: "< 11 | #include 12 | #include 13 | #include 14 | 15 | #include "mmio.h" 16 | 17 | int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, 18 | double **val_, int **I_, int **J_) 19 | { 20 | FILE *f; 21 | MM_typecode matcode; 22 | int M, N, nz; 23 | int i; 24 | double *val; 25 | int *I, *J; 26 | 27 | if ((f = fopen(fname, "r")) == NULL) 28 | return -1; 29 | 30 | 31 | if (mm_read_banner(f, &matcode) != 0) 32 | { 33 | fprintf(stderr, "mm_read_unsymetric: Could not process Matrix Market banner "); 34 | fprintf(stderr, " in file [%s]\n", fname); 35 | return -1; 36 | } 37 | 38 | 39 | 40 | if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) && 41 | mm_is_sparse(matcode))) 42 | { 43 | fprintf(stderr, "Sorry, this application does not support "); 44 | fprintf(stderr, "Market Market type: [%s]\n", 45 | mm_typecode_to_str(matcode)); 46 | return -1; 47 | } 48 | 49 | /* find out size of sparse matrix: M, N, nz .... */ 50 | 51 | if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0) 52 | { 53 | fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n"); 54 | return -1; 55 | } 56 | 57 | *M_ = M; 58 | *N_ = N; 59 | *nz_ = nz; 60 | 61 | /* reseve memory for matrices */ 62 | 63 | I = (int *) malloc(nz * sizeof(int)); 64 | J = (int *) malloc(nz * sizeof(int)); 65 | val = (double *) malloc(nz * sizeof(double)); 66 | 67 | *val_ = val; 68 | *I_ = I; 69 | *J_ = J; 70 | 71 | /* NOTE: when reading in doubles, ANSI C requires the use of the "l" */ 72 | /* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */ 73 | /* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */ 74 | 75 | for (i=0; i csrMatrix::spmv(cusparseHandle_t handle, denseVector& _x, denseVector& _r){ 24 | // create a matrix descriptor 25 | cusparseMatDescr_t descr=0; 26 | cusparseStatus_t status = cusparseCreateMatDescr(&descr); 27 | if(status != CUSPARSE_STATUS_SUCCESS) { 28 | std::cerr<<"Matrix desriptor initialisation failed"<(runtimes, runtimes + iterations); 91 | delete[] runtimes; 92 | return rv; 93 | } 94 | 95 | 96 | // ============================================================================= 97 | // =============================== COO Matrix ================================== 98 | // ============================================================================= 99 | 100 | // public 101 | 102 | cooMatrix::cooMatrix(int _nnz, int _h, int _w) { 103 | nnz = _nnz; 104 | h = _h; 105 | w = _w; 106 | alloc(); 107 | // set the indexing pointer for adding nonzero elements 108 | ixPtr = 0; 109 | // assume we start with the device buffers outdated 110 | mstatus = DeviceOutdated; 111 | } 112 | 113 | cooMatrix::cooMatrix(std::string filename) { 114 | // parse the file! 115 | // we have to use crappy C file IO functions, 116 | // as we're using the mmio libraries 117 | int ret_code; 118 | MM_typecode matcode; 119 | FILE* f; 120 | 121 | if((f = fopen(filename.c_str(), "r")) == NULL) { 122 | std::cerr<<"Failed to open matrix file!"< nzelems; 160 | int pat = mm_is_pattern(matcode); 161 | int sym = mm_is_symmetric(matcode); 162 | 163 | // the mmio routines have read up until the first entry, so take advantage of it 164 | for(int i = 0; i < _nnz; i++){ 165 | coord tmp = {-1, -1, -1.0f}; 166 | if(pat) { 167 | fscanf(f, "%d %d\n", &(tmp.row), &(tmp.col)); 168 | tmp.val = 1.0; 169 | }else{ 170 | fscanf(f, "%d %d %f\n", &(tmp.row), &(tmp.col), &(tmp.val)); 171 | } 172 | // std::cerr<<"row: " << tmp.row << " col: " << tmp.col << " val: " << tmp.val << std::endl; 173 | tmp.row -= 1; 174 | tmp.col -= 1; 175 | nzelems.push_back(tmp); 176 | // add an element if symmetric - but not repeating the diagonal 177 | if(sym && (tmp.row != tmp.col)){ 178 | int t = tmp.row; 179 | tmp.row = tmp.col; tmp.col=t; 180 | nzelems.push_back(tmp); 181 | } 182 | 183 | } 184 | // sort the nonzero elements 185 | auto comparator = [](coord a, coord b){ 186 | if(a.row < b.row){ 187 | return true; 188 | } else if(a.row > b.row){ 189 | return false; 190 | } else { 191 | if(a.col < b.col){ 192 | return true; 193 | }else{ 194 | return false; 195 | } 196 | } 197 | }; 198 | std::sort(nzelems.begin(), nzelems.end(), comparator); 199 | 200 | // allocate space in the matrix class 201 | nnz = nzelems.size(); 202 | h = _h; 203 | w = _w; 204 | alloc(); 205 | 206 | // add the nonzero elements 207 | for(int i = 0;i= nnz){ 230 | std::cerr<<"Error: allocating too many elements!"<= "<< nnz << " (nnz) "<< std::endl; 232 | } 233 | // todo: add check that element is within bounds 234 | rowIndexHostPtr[ixPtr] = row; 235 | colIndexHostPtr[ixPtr] = col; 236 | valHostPtr[ixPtr] = val; 237 | ixPtr++; 238 | } 239 | 240 | void cooMatrix::print() { 241 | for (int i=0; i= n){ 414 | std::cerr<<"Error: allocating too many elements!"< distribution(0.0, 1000.0); 440 | auto rgen = std::bind(distribution, generator); 441 | 442 | // build the vector 443 | for(int i = 0;i