From d2be194c4b4a833d3683ac3d89ef901269bee7df Mon Sep 17 00:00:00 2001 From: "L. Riha" <lubomir.riha@vsb.cz> Date: Thu, 4 Apr 2019 10:38:39 +0200 Subject: [PATCH] update --- CSparse/Demo/Makefile | 13 +-- CSparse/Demo/cs_demo.c | 52 ++++++------ CSparse/Include/cs.h | 5 ++ CSparse/Lib/Makefile | 6 +- CSparse/Lib/a.out | Bin 48520 -> 0 bytes CSparse/Source/cs_cholsol.c | 20 +++-- CSparse/Source/cs_lsolve.c | 157 +++++++++++++++++++----------------- 7 files changed, 129 insertions(+), 124 deletions(-) delete mode 100755 CSparse/Lib/a.out diff --git a/CSparse/Demo/Makefile b/CSparse/Demo/Makefile index ecb9bec..5062cec 100644 --- a/CSparse/Demo/Makefile +++ b/CSparse/Demo/Makefile @@ -1,21 +1,12 @@ CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O I = -I../Include +CC = /usr/local/cuda/bin/nvcc -g -G -O0 LDLIBS += -lm -CS = $(LDFLAGS) ../Lib/libcsparse.dylib $(LDLIBS) +CS = $(LDFLAGS) ../Lib/libcsparse.a $(LDLIBS) all: lib cs_demo1 cs_demo2 cs_demo3 - - ./cs_demo1 < ../Matrix/t1 - ./cs_demo2 < ../Matrix/t1 - - ./cs_demo2 < ../Matrix/ash219 - - ./cs_demo2 < ../Matrix/bcsstk01 - - ./cs_demo2 < ../Matrix/fs_183_1 - - ./cs_demo2 < ../Matrix/mbeacxc - - ./cs_demo2 < ../Matrix/west0067 - - ./cs_demo2 < ../Matrix/lp_afiro - - ./cs_demo2 < ../Matrix/bcsstk16 - - ./cs_demo3 < ../Matrix/bcsstk01 - - ./cs_demo3 < ../Matrix/bcsstk16 lib: ( cd ../Lib ; $(MAKE) ) diff --git a/CSparse/Demo/cs_demo.c b/CSparse/Demo/cs_demo.c index f2937eb..2d52000 100644 --- a/CSparse/Demo/cs_demo.c +++ b/CSparse/Demo/cs_demo.c @@ -142,35 +142,35 @@ csi demo2 (problem *Prob) printf ("blocks: %g singletons: %g structural rank: %g\n", (double) nb, (double) ns, (double) sprank) ; cs_dfree (D) ; - for (order = 0 ; order <= 3 ; order += 3) /* natural and amd(A'*A) */ - { - if (!order && m > 1000) continue ; - printf ("QR ") ; - print_order (order) ; - rhs (x, b, m) ; /* compute right-hand side */ - t = tic () ; - ok = cs_qrsol (order, C, x) ; /* min norm(Ax-b) with QR */ - printf ("time: %8.2f ", toc (t)) ; - print_resid (ok, C, x, b, resid) ; /* print residual */ - } - if (m != n || sprank < n) return (1) ; /* return if rect. or singular*/ - for (order = 0 ; order <= 3 ; order++) /* try all orderings */ - { - if (!order && m > 1000) continue ; - printf ("LU ") ; - print_order (order) ; - rhs (x, b, m) ; /* compute right-hand side */ - t = tic () ; - ok = cs_lusol (order, C, x, tol) ; /* solve Ax=b with LU */ - printf ("time: %8.2f ", toc (t)) ; - print_resid (ok, C, x, b, resid) ; /* print residual */ - } - if (!Prob->sym) return (1) ; + // for (order = 0 ; order <= 3 ; order += 3) /* natural and amd(A'*A) */ + // { + // if (!order && m > 1000) continue ; + // printf ("QR ") ; + // print_order (order) ; + // rhs (x, b, m) ; /* compute right-hand side */ + // t = tic () ; + // ok = cs_qrsol (order, C, x) ; /* min norm(Ax-b) with QR */ + // printf ("time: %8.2f ", toc (t)) ; + // print_resid (ok, C, x, b, resid) ; /* print residual */ + // } + // if (m != n || sprank < n) return (1) ; /* return if rect. or singular*/ + // for (order = 0 ; order <= 3 ; order++) /* try all orderings */ + // { + // if (!order && m > 1000) continue ; + // printf ("LU ") ; + // print_order (order) ; + // rhs (x, b, m) ; /* compute right-hand side */ + // t = tic () ; + // ok = cs_lusol (order, C, x, tol) ; /* solve Ax=b with LU */ + // printf ("time: %8.2f ", toc (t)) ; + // print_resid (ok, C, x, b, resid) ; /* print residual */ + // } + // if (!Prob->sym) return (1) ; for (order = 0 ; order <= 1 ; order++) /* natural and amd(A+A') */ { if (!order && m > 1000) continue ; - printf ("Chol ") ; - print_order (order) ; + printf ("Chol \n") ; + //print_order (order) ; rhs (x, b, m) ; /* compute right-hand side */ t = tic () ; ok = cs_cholsol (order, C, x) ; /* solve Ax=b with Cholesky */ diff --git a/CSparse/Include/cs.h b/CSparse/Include/cs.h index adbe032..82d70b0 100644 --- a/CSparse/Include/cs.h +++ b/CSparse/Include/cs.h @@ -36,6 +36,7 @@ typedef struct cs_sparse /* matrix in compressed-column or triplet form */ cs *cs_add (const cs *A, const cs *B, double alpha, double beta) ; csi cs_cholsol (csi order, const cs *A, double *b) ; +csi cs_cholsol_gpu (csi order, const cs *A, double *b) ; cs *cs_compress (const cs *T) ; csi cs_dupl (cs *A) ; csi cs_entry (cs *T, csi i, csi j, double x) ; @@ -56,6 +57,10 @@ cs *cs_spfree (cs *A) ; csi cs_sprealloc (cs *A, csi nzmax) ; void *cs_malloc (csi n, size_t size) ; +//void cs_lsolve_gpu (int n, const int *Lp, const int *Li, const double *Lx, double *x); +//void cs_lsolve_acc (int n, const int *Lp, const int *Li, const double *Lx, double *x); + + /* --- secondary CSparse routines and data structures ----------------------- */ typedef struct cs_symbolic /* symbolic Cholesky, LU, or QR analysis */ { diff --git a/CSparse/Lib/Makefile b/CSparse/Lib/Makefile index e3f32ce..9306418 100644 --- a/CSparse/Lib/Makefile +++ b/CSparse/Lib/Makefile @@ -16,7 +16,7 @@ LIBRARY = libcsparse CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O - +CC = /usr/local/cuda/bin/nvcc -dc -g -G -O0 I = -I../Include RANLIB = ranlib ARCHIVE = $(AR) $(ARFLAGS) @@ -29,7 +29,7 @@ all: install CS = cs_add.o cs_amd.o cs_chol.o cs_cholsol.o cs_counts.o cs_cumsum.o \ cs_droptol.o cs_dropzeros.o cs_dupl.o cs_entry.o \ cs_etree.o cs_fkeep.o cs_gaxpy.o cs_happly.o cs_house.o cs_ipvec.o \ - cs_lsolve.o cs_ltsolve.o cs_lu.o cs_lusol.o cs_util.o cs_multiply.o \ + cs_lsolve.o cs_lsolve_gpu.o cs_ltsolve.o cs_lu.o cs_lusol.o cs_util.o cs_multiply.o \ cs_permute.o cs_pinv.o cs_post.o cs_pvec.o cs_qr.o cs_qrsol.o \ cs_scatter.o cs_schol.o cs_sqr.o cs_symperm.o cs_tdfs.o cs_malloc.o \ cs_transpose.o cs_compress.o cs_usolve.o cs_utsolve.o cs_scc.o \ @@ -38,7 +38,7 @@ CS = cs_add.o cs_amd.o cs_chol.o cs_cholsol.o cs_counts.o cs_cumsum.o \ $(CS): ../Include/cs.h Makefile -%.o: ../Source/%.c ../Include/cs.h +%.o: ../Source/%.c* ../Include/cs.h $(CC) $(CF) $(I) -c $< static: $(AR_TARGET) diff --git a/CSparse/Lib/a.out b/CSparse/Lib/a.out deleted file mode 100755 index 595e3901c555c3f1c5faad27f8a92cb29d7b4e0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48520 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 N6%`bf=A}Y17XZi9xHA9% diff --git a/CSparse/Source/cs_cholsol.c b/CSparse/Source/cs_cholsol.c index 6cff32d..70c80f9 100644 --- a/CSparse/Source/cs_cholsol.c +++ b/CSparse/Source/cs_cholsol.c @@ -1,6 +1,9 @@ #include "cs.h" +#include "cuda_runtime.h" + + /* x=A\b where A is symmetric positive definite; b overwritten with solution */ -csi cs_cholsol (csi order, const cs *A, double *b) +csi cs_cholsol_xxx (csi order, const cs *A, double *b) { double *x ; css *S ; @@ -26,7 +29,7 @@ csi cs_cholsol (csi order, const cs *A, double *b) } -csi cs_cholsol_gpu (csi order, const cs *A, double *b) +csi cs_cholsol (csi order, const cs *A, double *b) { double *x ; css *S ; @@ -59,10 +62,10 @@ csi cs_cholsol_gpu (csi order, const cs *A, double *b) double *d_Lx; double *d_x; - cudaMalloc(&d_Lp, ((N->L->n)+1) * sizeof(int) ; - cudaMalloc(&d_Li, (N->L->nzmax) * sizeof(int) ; - cudaMalloc(&d_Lx, (N->L->nzmax) * sizeof(double) ; - cudaMalloc(&d_x , n * sizeof(double) ; + cudaMalloc(&d_Lp, ((N->L->n)+1) * sizeof(int) ); + cudaMalloc(&d_Li, (N->L->nzmax) * sizeof(int) ); + cudaMalloc(&d_Lx, (N->L->nzmax) * sizeof(double) ); + cudaMalloc(&d_x , n * sizeof(double) ); cudaMemcpy( d_Lp, N->L->p , ((N->L->n)+1) * sizeof(int) , cudaMemcpyHostToDevice) ; cudaMemcpy( d_Li, N->L->i , (N->L->nzmax) * sizeof(int) , cudaMemcpyHostToDevice) ; @@ -72,7 +75,7 @@ csi cs_cholsol_gpu (csi order, const cs *A, double *b) // csi cs_lsolve_gpu (int n, const int *Lp, const int *Li, const double *Lx, double *x) // cs_lsolve_gpu <<<gridSize, blockSize>>> (n, d_Lp, d_Li, d_Lx, d_x); - cs_lsolve_gpu <<<1, 1>>> (n, d_Lp, d_Li, d_Lx, d_x); + cs_lsolve_acc (n, d_Lp, d_Li, d_Lx, d_x); double *x_gpu; x_gpu = cs_malloc (n, sizeof (double)) ; @@ -85,6 +88,7 @@ csi cs_cholsol_gpu (csi order, const cs *A, double *b) for (i=0; i<n; i++) { printf("cpu: %f - gpu: %f\n",x[i], x_gpu[i] ); } + printf("\n"); cs_ltsolve (N->L, x) ; /* x = L'\x */ cs_pvec (S->pinv, x, b, n) ; /* b = P'*x */ @@ -93,4 +97,4 @@ csi cs_cholsol_gpu (csi order, const cs *A, double *b) cs_sfree (S) ; cs_nfree (N) ; return (ok) ; -} \ No newline at end of file +} diff --git a/CSparse/Source/cs_lsolve.c b/CSparse/Source/cs_lsolve.c index 394f283..442ab38 100644 --- a/CSparse/Source/cs_lsolve.c +++ b/CSparse/Source/cs_lsolve.c @@ -12,107 +12,112 @@ csi cs_lsolve (const cs *L, double *x) for (p = Lp [j]+1 ; p < Lp [j+1] ; p++) { x [Li [p]] -= Lx [p] * x [j] ; + printf("XPU: %f", x [Li [p]]); + } } return (1) ; } -/* solve Lx=b where x and b are dense. x=b on input, solution on output. */ +// /* solve Lx=b where x and b are dense. x=b on input, solution on output. */ -//csi cs_lsolve_gpu (const cs *L, double *x) -// typedef struct cs_sparse /* matrix in compressed-column or triplet form */ -// { -// csi nzmax ; /* maximum number of entries */ -// csi m ; /* number of rows */ -// csi n ; /* number of columns */ -// csi *p ; /* column pointers (size n+1) or col indices (size nzmax) */ -// csi *i ; /* row indices, size nzmax */ -// double *x ; /* numerical values, size nzmax */ -// csi nz ; /* # of entries in triplet matrix, -1 for compressed-col */ -// } cs ; - -__global__ -void cs_lsolve_gpu (int n, const int *Lp, const int *Li, const double *Lx, double *x) -{ - int p, j; +// //csi cs_lsolve_gpu (const cs *L, double *x) +// // typedef struct cs_sparse /* matrix in compressed-column or triplet form */ +// // { +// // csi nzmax ; /* maximum number of entries */ +// // csi m ; /* number of rows */ +// // csi n ; /* number of columns */ +// // csi *p ; /* column pointers (size n+1) or col indices (size nzmax) */ +// // csi *i ; /* row indices, size nzmax */ +// // double *x ; /* numerical values, size nzmax */ +// // csi nz ; /* # of entries in triplet matrix, -1 for compressed-col */ +// // } cs ; + +// // __global__ +// // void cs_lsolve_gpu (int n, const int *Lp, const int *Li, const double *Lx, double *x) +// // { +// // int p, j; - // double *Lx ; - // n = L->n ; - // Lp = L->p ; - // Li = L->i ; - // Lx = L->x ; +// // // double *Lx ; +// // // n = L->n ; +// // // Lp = L->p ; +// // // Li = L->i ; +// // // Lx = L->x ; - for (j = 0 ; j < n ; j++) - { - x [j] /= Lx [Lp [j]] ; - for (p = Lp [j]+1 ; p < Lp [j+1] ; p++) - { - x [Li [p]] -= Lx [p] * x [j] ; - } - } +// // for (j = 0 ; j < n ; j++) +// // { +// // x [j] /= Lx [Lp [j]] ; +// // for (p = Lp [j]+1 ; p < Lp [j+1] ; p++) +// // { +// // x [Li [p]] -= Lx [p] * x [j] ; +// // } +// // } - return (1) ; -} +// // //return (1); +// // } -#include <iostream> -#include <math.h> +// #include <iostream> +// #include <math.h> -// CUDA kernel to add elements of two arrays -__global__ -void add(int n, float *x, float *y) -{ - int index = blockIdx.x * blockDim.x + threadIdx.x; - int stride = blockDim.x * gridDim.x; - for (int i = index; i < n; i += stride) - y[i] = x[i] + y[i]; -} +// // CUDA kernel to add elements of two arrays +// __global__ +// void add(int n, float *x, float *y) +// { +// int index = blockIdx.x * blockDim.x + threadIdx.x; +// int stride = blockDim.x * gridDim.x; +// for (int i = index; i < n; i += stride) +// y[i] = x[i] + y[i]; +// } -int main(void) -{ - int N = 1<<20; - float *x, *y; +// int main(void) +// { +// int N = 1<<20; +// float *x, *y; - // Allocate Unified Memory -- accessible from CPU or GPU - cudaMallocManaged(&x, N*sizeof(float)); - cudaMallocManaged(&y, N*sizeof(float)); +// // Allocate Unified Memory -- accessible from CPU or GPU +// cudaMallocManaged(&x, N*sizeof(float)); +// cudaMallocManaged(&y, N*sizeof(float)); - // initialize x and y arrays on the host - for (int i = 0; i < N; i++) { - x[i] = 1.0f; - y[i] = 2.0f; - } +// // initialize x and y arrays on the host +// for (int i = 0; i < N; i++) { +// x[i] = 1.0f; +// y[i] = 2.0f; +// } - // Prefetch the data to the GPU - int device = -1; - cudaGetDevice(&device); - cudaMemPrefetchAsync(x, N*sizeof(float), device, NULL); - cudaMemPrefetchAsync(y, N*sizeof(float), device, NULL); +// // Prefetch the data to the GPU +// int device = -1; +// cudaGetDevice(&device); +// cudaMemPrefetchAsync(x, N*sizeof(float), device, NULL); +// cudaMemPrefetchAsync(y, N*sizeof(float), device, NULL); - // Launch kernel on 1M elements on the GPU - int blockSize = 256; - int numBlocks = (N + blockSize - 1) / blockSize; - add<<<numBlocks, blockSize>>>(N, x, y); +// // Launch kernel on 1M elements on the GPU +// int blockSize = 256; +// int numBlocks = (N + blockSize - 1) / blockSize; +// add<<<numBlocks, blockSize>>>(N, x, y); - // Wait for GPU to finish before accessing on host - cudaDeviceSynchronize(); +// // Wait for GPU to finish before accessing on host +// cudaDeviceSynchronize(); - // Check for errors (all values should be 3.0f) - float maxError = 0.0f; - for (int i = 0; i < N; i++) - maxError = fmax(maxError, fabs(y[i]-3.0f)); - std::cout << "Max error: " << maxError << std::endl; +// // Check for errors (all values should be 3.0f) +// float maxError = 0.0f; +// for (int i = 0; i < N; i++) +// maxError = fmax(maxError, fabs(y[i]-3.0f)); +// std::cout << "Max error: " << maxError << std::endl; - // Free memory - cudaFree(x); - cudaFree(y); +// // Free memory +// cudaFree(x); +// cudaFree(y); - return 0; -} \ No newline at end of file +// return 0; +// } + + + -- GitLab