From 8136faf2f04f8f9ffee6ceb15dedcc59ff304056 Mon Sep 17 00:00:00 2001 From: WanruZhao Date: Thu, 13 Sep 2018 00:56:45 -0400 Subject: [PATCH 1/7] part 1 partial --- stream_compaction/cpu.cu | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 05ce667..7ad7909 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -1,15 +1,15 @@ #include #include "cpu.h" -#include "common.h" +#include "common.h" namespace StreamCompaction { namespace CPU { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } /** @@ -18,8 +18,17 @@ namespace StreamCompaction { * (Optional) For better understanding before starting moving to GPU, you can simulate your GPU scan in this function first. */ void scan(int n, int *odata, const int *idata) { + + if(n == 0) return; + timer().startCpuTimer(); // TODO + + odata[0] = 0; + for(int i = 0; i < n; i++) { + odata[i] = idata[i] + odata[i-1]; + } + timer().endCpuTimer(); } @@ -31,8 +40,16 @@ namespace StreamCompaction { int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + + int count = 0; + for(int i = 0; i < n; i++) { + if(idata[i] != 0) { + odata[count++] = idata[i]; + } + } + timer().endCpuTimer(); - return -1; + return count; } /** @@ -42,7 +59,8 @@ namespace StreamCompaction { */ int compactWithScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); - // TODO + // TODO + timer().endCpuTimer(); return -1; } From 861d5546feb772e75449efbd31442c333191a2db Mon Sep 17 00:00:00 2001 From: WanruZhao Date: Sun, 16 Sep 2018 14:26:43 -0400 Subject: [PATCH 2/7] part 1 --- stream_compaction/cpu.cu | 31 ++++++++++++++++++++++++++++--- stream_compaction/naive.cu | 16 +++++++++++----- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 7ad7909..7d2320e 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -25,8 +25,8 @@ namespace StreamCompaction { // TODO odata[0] = 0; - for(int i = 0; i < n; i++) { - odata[i] = idata[i] + odata[i-1]; + for(int i = 1; i < n; i++) { + odata[i] = idata[i - 1] + odata[i - 1]; } timer().endCpuTimer(); @@ -58,11 +58,36 @@ namespace StreamCompaction { * @returns the number of elements remaining after compaction. */ int compactWithScan(int n, int *odata, const int *idata) { + if(n == 0) return 0; timer().startCpuTimer(); // TODO + int count = 0; + + int *tmp = (int*)malloc(n * sizeof(int)); + for(int i = 0; i < n; i++) { + if(idata[i] == 0) { + tmp[i] = 0; + } else { + tmp[i] = 1; + } + } + + int *scan = (int*)malloc(n * sizeof(int)); + scan[0] = 0; + for(int i = 1; i < n; i++) { + scan[i] = tmp[i - 1] + scan[i - 1]; + } + + for(int i = 0; i < n; i++) { + if(tmp[i]) { + odata[scan[i]] = idata[i]; + count++; + } + } + timer().endCpuTimer(); - return -1; + return count; } } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 9218f8e..d4cbe23 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -5,13 +5,19 @@ namespace StreamCompaction { namespace Naive { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } // TODO: __global__ + __global__ void scan(float *g_odata, float *g_idata, int n) { + extern __shared__ float temp[]; + int thid = threadIdx.x; + int pout = 0, pin = 1; + + } /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. From e45d02a9120ae2f3e2c25b80824e4519b645a11c Mon Sep 17 00:00:00 2001 From: WanruZhao Date: Sun, 16 Sep 2018 21:28:36 -0400 Subject: [PATCH 3/7] part 1- 4 --- src/main.cpp | 4 +- stream_compaction/CMakeLists.txt | 2 +- stream_compaction/common.cu | 12 ++++ stream_compaction/common.h | 2 + stream_compaction/cpu.cu | 2 + stream_compaction/efficient.cu | 104 ++++++++++++++++++++++++++++++- stream_compaction/naive.cu | 41 ++++++++++-- stream_compaction/thrust.cu | 7 +++ 8 files changed, 165 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1850161..496c178 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,14 +71,14 @@ int main(int argc, char* argv[]) { printDesc("work-efficient scan, power-of-two"); StreamCompaction::Efficient::scan(SIZE, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(SIZE, c, true); + printArray(SIZE, c, true); printCmpResult(SIZE, b, c); zeroArray(SIZE, c); printDesc("work-efficient scan, non-power-of-two"); StreamCompaction::Efficient::scan(NPOT, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(NPOT, c, true); + printArray(NPOT, c, true); printCmpResult(NPOT, b, c); zeroArray(SIZE, c); diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index cdbef77..4bb0dc2 100644 --- a/stream_compaction/CMakeLists.txt +++ b/stream_compaction/CMakeLists.txt @@ -13,5 +13,5 @@ set(SOURCE_FILES cuda_add_library(stream_compaction ${SOURCE_FILES} - OPTIONS -arch=sm_20 + OPTIONS -arch=sm_61 ) diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 8fc0211..94237dd 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -24,6 +24,12 @@ namespace StreamCompaction { */ __global__ void kernMapToBoolean(int n, int *bools, const int *idata) { // TODO + + int index = blockDim.x * blockIdx.x + threadIdx.x; + if (index >= n) return; + + bools[index] = idata[index] ? 1 : 0; + } /** @@ -33,6 +39,12 @@ namespace StreamCompaction { __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools, const int *indices) { // TODO + int index = blockDim.x * blockIdx.x + threadIdx.x; + if (index >= n) return; + + if (bools[index]) { + odata[indices[index]] = idata[index]; + } } } diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 99a1b04..d3555f5 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -13,6 +13,8 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) +#define blockSize 1024 + /** * Check for CUDA errors; print and exit if there was a problem. */ diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 7d2320e..0c57085 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -87,6 +87,8 @@ namespace StreamCompaction { } timer().endCpuTimer(); + free(tmp); + free(scan); return count; } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 36c5ef2..33b2e2b 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -12,13 +12,71 @@ namespace StreamCompaction { return timer; } + __global__ void kernReduction(int n, int d, int *idata) { + int index = blockDim.x * blockIdx.x + threadIdx.x; + if (index >= n) return; + + int offset1 = 1 << d; + int offset2 = 1 << (d + 1); + + idata[index * offset2 + offset2 - 1] += idata[index * offset2 + offset1 - 1]; + } + + __global__ void kernScan(int n, int d, int *idata) { + int index = blockDim.x * blockIdx.x + threadIdx.x; + if (index >= n) return; + + int offset1 = 1 << d; + int offset2 = 1 << (d + 1); + + int leftIdx = index * offset2 + offset1 - 1; + int rightIdx = index * offset2 + offset2 - 1; + + int originLeft = idata[leftIdx]; + idata[leftIdx] = idata[rightIdx]; + idata[rightIdx] += originLeft; + } + + + void scanCore(int nPow, int d, int *dev_idata) { + dim3 gridDim; + for (int i = 0; i < d; i++) { + int scale = 1 << (i + 1); + gridDim = ((nPow / scale + blockSize - 1) / blockSize); + kernReduction << > > (nPow / scale, i, dev_idata); + } + cudaMemset(dev_idata + nPow - 1, 0, sizeof(int)); + for (int i = d - 1; i >= 0; i--) { + int scale = 1 << (i + 1); + gridDim = ((nPow / scale + blockSize - 1) / blockSize); + kernScan << > > (nPow / scale, i, dev_idata); + } + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + + int d = ilog2ceil(n); + int nPow = 1 << d; + int *dev_idata; + cudaMalloc((void**)&dev_idata, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_idata failed!"); + cudaMemcpy(dev_idata, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_idata failed!"); + cudaMemset(dev_idata + n, 0, (nPow - n) * sizeof(int)); + checkCUDAError("cudaMemset dev_idata failed!"); + timer().startGpuTimer(); // TODO + + scanCore(nPow, d, dev_idata); + timer().endGpuTimer(); + + cudaMemcpy(odata , dev_idata, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(dev_idata); } /** @@ -31,10 +89,54 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { + + int *dev_idata, *dev_bools, *dev_odata, *dev_indices; + + int d = ilog2ceil(n); + int nPow = 1 << d; + + cudaMalloc((void**)&dev_idata, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_idata failed!"); + cudaMemcpy(dev_idata, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_idata failed!"); + cudaMemset(dev_idata + n, 0, (nPow - n) * sizeof(int)); + checkCUDAError("cudaMemset dev_idata failed!"); + + cudaMalloc((void**)&dev_bools, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_bools failed!"); + cudaMalloc((void**)&dev_odata, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_odata failed!"); + cudaMalloc((void**)&dev_indices, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_indices failed!"); + timer().startGpuTimer(); // TODO + + dim3 gridDim((nPow + blockSize - 1) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (nPow, dev_bools, dev_idata); + cudaMemcpy(dev_indices, dev_bools, nPow * sizeof(int), cudaMemcpyDeviceToDevice); + scanCore(nPow, d, dev_indices); + StreamCompaction::Common::kernScatter << > > (nPow, dev_odata, dev_idata, dev_bools, dev_indices); + timer().endGpuTimer(); - return -1; + + cudaMemcpy(odata, dev_odata, nPow * sizeof(int), cudaMemcpyDeviceToHost); + + cudaFree(dev_idata); + cudaFree(dev_odata); + cudaFree(dev_bools); + cudaFree(dev_indices); + + int count = 0; + for (int i = 0; i < n; i++) { + if (odata[i]) { + count++; + } + else { + break; + } + } + return count; } } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index d4cbe23..16050cf 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -12,20 +12,51 @@ namespace StreamCompaction { return timer; } // TODO: __global__ - __global__ void scan(float *g_odata, float *g_idata, int n) { - extern __shared__ float temp[]; - int thid = threadIdx.x; - int pout = 0, pin = 1; - + __global__ void kernNaiveScan(int n, int d, int *idata, int *odata) { + int index = blockIdx.x * blockDim.x + threadIdx.x; + if (index >= n) { + return; + } + int offset = 1 << (d - 1); + if (index >= offset) { + odata[index] = idata[index - offset] + idata[index]; + } + else { + odata[index] = idata[index]; + } } /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + + int *dev_idata, *dev_odata; + cudaMalloc((void**)&dev_idata, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_idata failed!"); + cudaMalloc((void**)&dev_odata, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_odata failed!"); + cudaMemcpy(dev_idata, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_idata failed!"); + + int d = ilog2ceil(n); + timer().startGpuTimer(); // TODO + dim3 gridDim((n + blockSize - 1) / blockSize); + for (int i = 1; i <= d; i++) { + kernNaiveScan << > > (n, i, dev_idata, dev_odata); + std::swap(dev_idata, dev_odata); + } + std::swap(dev_idata, dev_odata); + timer().endGpuTimer(); + + odata[0] = 0; + cudaMemcpy(odata + 1, dev_odata, (n - 1)* sizeof(int), cudaMemcpyDeviceToHost); + + cudaFree(dev_idata); + cudaFree(dev_odata); } } } diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 36b732d..717dc39 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -18,11 +18,18 @@ namespace StreamCompaction { * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + thrust::device_vector dev_idata(idata, idata + n), dev_odata(odata, odata + n); + timer().startGpuTimer(); // TODO use `thrust::exclusive_scan` // example: for device_vectors dv_in and dv_out: // thrust::exclusive_scan(dv_in.begin(), dv_in.end(), dv_out.begin()); + + thrust::exclusive_scan(dev_idata.begin(), dev_idata.end(), dev_odata.begin()); + timer().endGpuTimer(); + + thrust::copy(dev_odata.begin(), dev_odata.end(), odata); } } } From 19d4b6eee14e8e9c322aaa8dbbf1d58f189bf782 Mon Sep 17 00:00:00 2001 From: WanruZhao Date: Sun, 16 Sep 2018 23:44:42 -0400 Subject: [PATCH 4/7] img --- img/compact_as.JPG | Bin 0 -> 39636 bytes img/scan_as.JPG | Bin 0 -> 52773 bytes img/scan_bs.JPG | Bin 0 -> 51794 bytes src/main.cpp | 4 ++-- stream_compaction/common.h | 2 +- stream_compaction/naive.cu | 2 +- stream_compaction/thrust.cu | 2 +- 7 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 img/compact_as.JPG create mode 100644 img/scan_as.JPG create mode 100644 img/scan_bs.JPG diff --git a/img/compact_as.JPG b/img/compact_as.JPG new file mode 100644 index 0000000000000000000000000000000000000000..6a7549343b75b16b97fdffbb142d2b6b451089e4 GIT binary patch literal 39636 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

ksC7G|Bi&&Oe;FI-<%Avz$2x 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 FKLGnVjr#xq literal 0 HcmV?d00001 diff --git a/img/scan_as.JPG b/img/scan_as.JPG new file mode 100644 index 0000000000000000000000000000000000000000..730be506808f73fb2af7852f25b7e374fd77e859 GIT binary patch literal 52773 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 literal 0 HcmV?d00001 diff --git a/img/scan_bs.JPG b/img/scan_bs.JPG new file mode 100644 index 0000000000000000000000000000000000000000..8b1551bf7e03756303c85ccb52d71c5e0ecceec3 GIT binary patch literal 51794 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 literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index 496c178..1850161 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,14 +71,14 @@ int main(int argc, char* argv[]) { printDesc("work-efficient scan, power-of-two"); StreamCompaction::Efficient::scan(SIZE, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, c, true); + //printArray(SIZE, c, true); printCmpResult(SIZE, b, c); zeroArray(SIZE, c); printDesc("work-efficient scan, non-power-of-two"); StreamCompaction::Efficient::scan(NPOT, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, c, true); + //printArray(NPOT, c, true); printCmpResult(NPOT, b, c); zeroArray(SIZE, c); diff --git a/stream_compaction/common.h b/stream_compaction/common.h index d3555f5..0007d14 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -13,7 +13,7 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) -#define blockSize 1024 +#define blockSize 16 /** * Check for CUDA errors; print and exit if there was a problem. diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 16050cf..8d3df39 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -53,7 +53,7 @@ namespace StreamCompaction { timer().endGpuTimer(); odata[0] = 0; - cudaMemcpy(odata + 1, dev_odata, (n - 1)* sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata + 1, dev_odata, (n - 1) * sizeof(int), cudaMemcpyDeviceToHost); cudaFree(dev_idata); cudaFree(dev_odata); diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 717dc39..4e76a8e 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -18,7 +18,7 @@ namespace StreamCompaction { * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { - thrust::device_vector dev_idata(idata, idata + n), dev_odata(odata, odata + n); + thrust::device_vector dev_idata(idata, idata + n), dev_odata(n); timer().startGpuTimer(); // TODO use `thrust::exclusive_scan` From b58b2a8d4af69f6cd38f0fe45baf47054b2ec853 Mon Sep 17 00:00:00 2001 From: WanruZhao Date: Tue, 18 Sep 2018 12:53:40 -0400 Subject: [PATCH 5/7] extra --- .vscode/settings.json | 6 +++ src/main.cpp | 29 ++++++++++ stream_compaction/efficient.cu | 11 ++-- stream_compaction/efficient.h | 2 + stream_compaction/naive.cu | 93 +++++++++++++++++++++++++++++++- stream_compaction/naive.h | 2 + stream_compaction/radix.cu | 96 ++++++++++++++++++++++++++++++++++ stream_compaction/radix.h | 11 ++++ stream_compaction/thrust.cu | 17 +++--- 9 files changed, 252 insertions(+), 15 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 stream_compaction/radix.cu create mode 100644 stream_compaction/radix.h diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9c2ba4a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "algorithm": "cpp", + "cstdio": "cpp" + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1850161..28f1165 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,18 +7,24 @@ */ #include +#include #include #include #include #include +#include #include "testing_helpers.hpp" +//#define RADIX + const int SIZE = 1 << 8; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int *a = new int[SIZE]; int *b = new int[SIZE]; int *c = new int[SIZE]; +int *d = new int[SIZE]; + int main(int argc, char* argv[]) { // Scan tests @@ -95,6 +101,28 @@ int main(int argc, char* argv[]) { //printArray(NPOT, c, true); printCmpResult(NPOT, b, c); +#ifdef RADIX + zeroArray(SIZE, d); + + std::vector aVec(SIZE); + for(int i = 0; i < SIZE; i++) { + aVec[i] = a[i]; + } + std::sort(aVec.begin(), aVec.end()); + for(int i = 0; i < SIZE; i++) { + d[i] = aVec[i]; + } + printArray(SIZE, d, true); + + zeroArray(SIZE, c); + printDesc("radix sort, power-of-two"); + StreamCompaction::Raidx::sort(SIZE, c, a); + printElapsedTime(StreamCompaction::Raidx::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, c, true); + printCmpResult(SIZE, d, c); + +#endif + printf("\n"); printf("*****************************\n"); printf("** STREAM COMPACTION TESTS **\n"); @@ -151,4 +179,5 @@ int main(int argc, char* argv[]) { delete[] a; delete[] b; delete[] c; + delete[] d; } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 33b2e2b..cfe6ddb 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -5,11 +5,11 @@ namespace StreamCompaction { namespace Efficient { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } __global__ void kernReduction(int n, int d, int *idata) { @@ -70,7 +70,6 @@ namespace StreamCompaction { timer().startGpuTimer(); // TODO - scanCore(nPow, d, dev_idata); timer().endGpuTimer(); diff --git a/stream_compaction/efficient.h b/stream_compaction/efficient.h index 803cb4f..5fc4adc 100644 --- a/stream_compaction/efficient.h +++ b/stream_compaction/efficient.h @@ -6,6 +6,8 @@ namespace StreamCompaction { namespace Efficient { StreamCompaction::Common::PerformanceTimer& timer(); + void scanCore(int n, int d, int *idata); + void scan(int n, int *odata, const int *idata); int compact(int n, int *odata, const int *idata); diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 8d3df39..b90a02b 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -57,6 +57,97 @@ namespace StreamCompaction { cudaFree(dev_idata); cudaFree(dev_odata); - } + } + + + __global__ void kernSharedNaiveScan(int n, int *odata, int *auxidata, const int *idata, int isMulti) { + extern __shared__ int temp[]; + + int index = threadIdx.x; + int boffset = blockIdx.x * blockDim.x * 2; + + int pout = 1, pin = 0; + temp[pout * n + index + boffset] = idata[pout * n + index - 1 + boffset]; + + _syncthreads(); + for(int i = 1; i < n; i *= 2) { + pout = 1 - pout; + pin = 1 - pout; + + if(index >= i) { + temp[pout * n + index + boffset] += temp[pin * n + index + boffset - i]; + } else { + temp[pout * n + index + boffset] = temp[pin * n + index + boffset]; + } + + __syncthreads(); + } + + if(index == n - 1 && isMulti) { + if(blockIdx.x) + auxidata[blockIdx.x] = temp[pout * n + index + boffset]; + else + auxidata[blockIdx.x] = 0; + } + + odata[index + boffset] = temp[pout * n + index + boffset]; + } + + __global__ void kernAddAuxi(int n, int *odata, const int *auxi) { + extern __shared__ int temp[]; + + int index = blockDim.x * blockIdx.x + threadIdx.x; + if(index >= n) return; + + temp[blockIdx.x] = auxi[blockIdx.x]; + + __syncthreads(); + + odata[index] += temp[blockIdx.x]; + } + + + + void shared_scan(int n, int *odata, const int *idata) + { + int blockCount = (n + blockSize - 1) / blockSize; + int lastBlockN = n - (blockCount - 1) * blockSize; + int d = ilog2ceil(blockSize); + int lastD = ilog2ceil(lastBlockN); + + int *dev_idata, *dev_odata, *dev_auxi, *dev_tauxi; + + cudaMalloc((void**)&dev_idata, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_idata failed!"); + cudaMemcpy(dev_idata, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + cudaMalloc((void**)&dev_odata, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_odata failed!"); + + cudaMalloc((void**)&dev_auxi, blockCount * sizeof(int)); + checkCUDAError("cudaMalloc dev_auxi failed!"); + + cudaMalloc((void**)&dev_tauxi, blockCount * sizeof(int)); + checkCUDAError("cudaMalloc dev_tauxi failed!"); + + int blocknum = blockSize; + int sharedMemory = 2 * blockSize * sizeof(int); + kernSharedNaiveScan<<>>(blocknum, dev_odata, dev_auxi, dev_idata, 1); + + // assump blockSize <= blockSize + kernSharedNaiveScan<<<1, blocknum, sharedMemory>>>(blocknum, dev_tauxi, NULL, dev_auxi, 0); + + sharedMemory = blockSize * sizeof(int); + kernAddAuxi<<>> (blocknum, dev_odata, dev_tauxi); + + odata[0] = 0; + cudaMemcpy(odata + 1, dev_odata, (n - 1) * sizeof(int), cudaMemcpyDeviceToHost); + + cudaFree(dev_idata); + cudaFree(dev_odata); + cudaFree(dev_auxi); + + free(temp); + } } } diff --git a/stream_compaction/naive.h b/stream_compaction/naive.h index 37dcb06..bc49781 100644 --- a/stream_compaction/naive.h +++ b/stream_compaction/naive.h @@ -7,5 +7,7 @@ namespace StreamCompaction { StreamCompaction::Common::PerformanceTimer& timer(); void scan(int n, int *odata, const int *idata); + + void shared_scan(int n, int *odata, const int *idata); } } diff --git a/stream_compaction/radix.cu b/stream_compaction/radix.cu new file mode 100644 index 0000000..e3eca36 --- /dev/null +++ b/stream_compaction/radix.cu @@ -0,0 +1,96 @@ +#include +#include +#include "common.h" +#include "radix.h" +#include "efficient.h" + +namespace StreamCompaction { + namespace radix { + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; + } + + __global__ void kernRadixEArray(int n, int p, int *bdata, int *edata, const int *idata) { + int index = blockDim.x * blockIdx.x + threadIdx.x; + if(index >= n) return; + + int digit = idata[index] & p; + + edata[index] = digit ? 0 : 1; + bdata[index] = digit ? 1 : 0; + } + + __global__ void kernRadixDArray(int n, int p, int totalFalse, int *ddata, const int *fdata, const int *bdata) { + int index = blockDim.x * blockIdx.x + threadIdx.x; + if(index >= n) return; + + int f = fdata[index]; + int t = index - f + totalFalse; + ddata[index] = bdata[index] ? t : f; + } + + void sort(int n, int *odata, const int *idata){ + + int d = ilog2ceil(n); + int nPow = 1 << d; + + int *dev_idataPow, *dev_bdataPow, *dev_edataPow, *dev_fdataPow, *dev_ddataPow, *dev_odataPow; + int en = 0, fn = 0; + + cudaMalloc((void**)&dev_idataPow, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_idataPow failed!"); + cudaMemcpy(dev_idataPow, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_idataPow failed!"); + cudaMemset(dev_idataPow + n, 0, (nPow - n) * sizeof(int)); + checkCUDAError("cudaMemset dev_idataPow failed!"); + + cudaMalloc((void**)&dev_edataPow, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_edataPow failed!"); + cudaMemset(dev_edataPow, 0, nPow * sizeof(int)); + cudaMalloc((void**)&dev_bdataPow, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_bdataPow failed!"); + cudaMemset(dev_bdataPow, 0, nPow * sizeof(int)); + cudaMalloc((void**)&dev_fdataPow, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_fdataPow failed!"); + cudaMemset(dev_fdataPow, 0, nPow * sizeof(int)); + cudaMalloc((void**)&dev_ddata, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_idata failed!"); + cudaMemset(dev_ddataPow, 0, nPow * sizeof(int)); + cudaMalloc((void**)&dev_odataPow, nPow * sizeof(int)); + checkCUDAError("cudaMalloc dev_odata failed!"); + cudaMemset(dev_odataPow, 0, nPow * sizeof(int)); + + timer().startGpuTimer(); + + dim3 gridDim((n + blockSize - 1) / blockSize); + + for(int p = 1; p <= 6; p++) { + kernRadixEArray<<>>(n, p, dev_edataPow, dev_idataPow); + cudaMemcpy(dev_fdataPow, dev_edataPow, nPow * sizeof(int), cudaMemcpyDeviceToDevice); + StreamCompaction::Efficient::scanCore(nPow, d, dev_fdataPow); + cudaMemcpy(en, dev_edataPow + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(fn, dev_fdataPow + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + kernRadixDArray<<>>(n, p, en + fn, dev_ddataPow, dev_fdataPow, dev_bdataPow); + StreamCompaction::Common::kernScatter<<>>(n, dev_odataPow, dev_idataPow, dev_bdataPow, dev_ddataPow); + std::swap(dev_idataPow, dev_odataPow); + } + std::swap(dev_idataPow, dev_odataPow); + + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_odataPow, n * sizeof(int), cudaMemcpyDeviceToHost); + + cudaFree(dev_idataPow); + cudaFree(dev_bdataPow); + cudaFree(dev_edataPow); + cudaFree(dev_fdataPow); + cudaFree(dev_ddataPow); + cudaFree(dev_odataPow); + + } + + } +} \ No newline at end of file diff --git a/stream_compaction/radix.h b/stream_compaction/radix.h new file mode 100644 index 0000000..aa489d9 --- /dev/null +++ b/stream_compaction/radix.h @@ -0,0 +1,11 @@ +#pragma once + +#include "common.h" + +namespace StreamCompaction { + namespace Radix { + StreamCompaction::Common::PerformanceTimer& timer(); + + void sort(int n, int *odata, const int *idata); + } +} diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 4e76a8e..3b3764d 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -8,28 +8,29 @@ namespace StreamCompaction { namespace Thrust { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { - thrust::device_vector dev_idata(idata, idata + n), dev_odata(n); + //thrust::device_vector dev_idata(idata, idata + n), dev_odata(n); timer().startGpuTimer(); // TODO use `thrust::exclusive_scan` // example: for device_vectors dv_in and dv_out: // thrust::exclusive_scan(dv_in.begin(), dv_in.end(), dv_out.begin()); - thrust::exclusive_scan(dev_idata.begin(), dev_idata.end(), dev_odata.begin()); + //thrust::exclusive_scan(dev_idata.begin(), dev_idata.end(), dev_odata.begin()); + thrust::exclusive_scan(idata, idata + n, odata); timer().endGpuTimer(); - thrust::copy(dev_odata.begin(), dev_odata.end(), odata); + //thrust::copy(dev_odata.begin(), dev_odata.end(), odata); } } } From d502c178c80b13cd1430d921d557ebf9079edf19 Mon Sep 17 00:00:00 2001 From: WanruZhao Date: Tue, 18 Sep 2018 14:54:32 -0400 Subject: [PATCH 6/7] extra fixed radix sort --- img/scan_as.JPG | Bin 52773 -> 52131 bytes result.txt | 62 +++++++++++++++++++++++++++++++ src/main.cpp | 62 +++++++++++++++++++++++++------ stream_compaction/CMakeLists.txt | 2 + stream_compaction/common.h | 2 +- stream_compaction/naive.cu | 24 ++++++------ stream_compaction/radix.cu | 22 +++++++---- stream_compaction/radix.h | 2 +- 8 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 result.txt diff --git a/img/scan_as.JPG b/img/scan_as.JPG index 730be506808f73fb2af7852f25b7e374fd77e859..1f6a4b8f4604a4dfcf2737e14a83de461b813c25 100644 GIT binary patch literal 52131 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 diff --git a/result.txt b/result.txt new file mode 100644 index 0000000..89d4664 --- /dev/null +++ b/result.txt @@ -0,0 +1,62 @@ + +**************** +** SCAN TESTS ** +**************** + [ 18 22 20 42 10 18 23 8 38 0 30 27 2 ... 27 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 0.0011ms (std::chrono Measured) + [ 0 18 40 60 102 112 130 153 161 199 199 229 256 ... 6238 6265 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 0.0008ms (std::chrono Measured) + [ 0 18 40 60 102 112 130 153 161 199 199 229 256 ... 6157 6161 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 0.036864ms (CUDA Measured) + passed +==== naive scan, non-power-of-two ==== + elapsed time: 0.036864ms (CUDA Measured) + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 0.070656ms (CUDA Measured) + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 0.068608ms (CUDA Measured) + passed +==== thrust scan, power-of-two ==== + elapsed time: 0.001024ms (CUDA Measured) + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 0.001024ms (CUDA Measured) + passed + [ 18 22 20 42 10 18 23 8 38 0 30 27 2 ... 27 35 ] +==== radix sort, power-of-two ==== + elapsed time: 1.52883ms (CUDA Measured) + [ 0 0 0 1 1 1 1 2 2 2 2 2 2 ... 49 49 ] + passed +==== radix sort, non-power-of-two ==== + elapsed time: 1.52576ms (CUDA Measured) + [ 0 0 0 1 1 1 1 2 2 2 2 2 2 ... 49 49 ] + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** + [ 0 2 2 0 0 0 3 0 2 2 2 1 0 ... 1 0 ] +==== cpu compact without scan, power-of-two ==== + elapsed time: 0.0015ms (std::chrono Measured) + [ 2 2 3 2 2 2 1 1 3 1 3 1 1 ... 1 1 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 0.0015ms (std::chrono Measured) + [ 2 2 3 2 2 2 1 1 3 1 3 1 1 ... 3 1 ] + passed +==== cpu compact with scan ==== + elapsed time: 0.0062ms (std::chrono Measured) + [ 2 2 3 2 2 2 1 1 3 1 3 1 1 ... 1 1 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 0.09216ms (CUDA Measured) + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 0.090112ms (CUDA Measured) + passed \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 28f1165..94f7dbf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,7 @@ #include #include "testing_helpers.hpp" -//#define RADIX +#define RADIX const int SIZE = 1 << 8; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two @@ -24,6 +24,8 @@ int *b = new int[SIZE]; int *c = new int[SIZE]; int *d = new int[SIZE]; +int *e = new int[NPOT]; +int *f = new int[SIZE]; int main(int argc, char* argv[]) { // Scan tests @@ -73,6 +75,20 @@ int main(int argc, char* argv[]) { //printArray(SIZE, c, true); printCmpResult(NPOT, b, c); + //zeroArray(SIZE, c); + //printDesc("naive scan, power-of-two, shared memory"); + //StreamCompaction::Naive::shared_scan(SIZE, c, a); + //printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(SIZE, c, true); + //printCmpResult(SIZE, b, c); + + //zeroArray(SIZE, c); + //printDesc("naive scan, non-power-of-two, shared memory"); + //StreamCompaction::Naive::shared_scan(NPOT, c, a); + //printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(SIZE, c, true); + //printCmpResult(NPOT, b, c); + zeroArray(SIZE, c); printDesc("work-efficient scan, power-of-two"); StreamCompaction::Efficient::scan(SIZE, c, a); @@ -101,25 +117,45 @@ int main(int argc, char* argv[]) { //printArray(NPOT, c, true); printCmpResult(NPOT, b, c); + + + + #ifdef RADIX zeroArray(SIZE, d); - - std::vector aVec(SIZE); + genArray(SIZE, d, 50); + printArray(SIZE, d, true); + std::vector dVec(SIZE); for(int i = 0; i < SIZE; i++) { - aVec[i] = a[i]; + dVec[i] = d[i]; } - std::sort(aVec.begin(), aVec.end()); + std::sort(dVec.begin(), dVec.end()); for(int i = 0; i < SIZE; i++) { - d[i] = aVec[i]; + f[i] = dVec[i]; } - printArray(SIZE, d, true); - zeroArray(SIZE, c); + zeroArray(SIZE, e); printDesc("radix sort, power-of-two"); - StreamCompaction::Raidx::sort(SIZE, c, a); - printElapsedTime(StreamCompaction::Raidx::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, c, true); - printCmpResult(SIZE, d, c); + StreamCompaction::Radix::sort(SIZE, e, d); + printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, e, true); + printCmpResult(SIZE, f, e); + + std::vector dVecN(NPOT); + for (int i = 0; i < NPOT; i++) { + dVecN[i] = d[i]; + } + std::sort(dVecN.begin(), dVecN.end()); + for (int i = 0; i < NPOT; i++) { + f[i] = dVecN[i]; + } + + zeroArray(NPOT, e); + printDesc("radix sort, non-power-of-two"); + StreamCompaction::Radix::sort(NPOT, e, d); + printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, e, true); + printCmpResult(NPOT, f, e); #endif @@ -180,4 +216,6 @@ int main(int argc, char* argv[]) { delete[] b; delete[] c; delete[] d; + delete[] e; + delete[] f; } diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index 4bb0dc2..fc37515 100644 --- a/stream_compaction/CMakeLists.txt +++ b/stream_compaction/CMakeLists.txt @@ -9,6 +9,8 @@ set(SOURCE_FILES "efficient.cu" "thrust.h" "thrust.cu" + "radix.h" + "radix.cu" ) cuda_add_library(stream_compaction diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 0007d14..d3555f5 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -13,7 +13,7 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) -#define blockSize 16 +#define blockSize 1024 /** * Check for CUDA errors; print and exit if there was a problem. diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index b90a02b..f8e7687 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -60,24 +60,24 @@ namespace StreamCompaction { } - __global__ void kernSharedNaiveScan(int n, int *odata, int *auxidata, const int *idata, int isMulti) { + __global__ void kernSharedNaiveScan(int n, int d, int *odata, int *auxidata, const int *idata, int isMulti) { extern __shared__ int temp[]; int index = threadIdx.x; - int boffset = blockIdx.x * blockDim.x * 2; + int boffset = blockIdx.x * blockDim.x; int pout = 1, pin = 0; - temp[pout * n + index + boffset] = idata[pout * n + index - 1 + boffset]; + temp[pout * n + index + boffset * 2] = idata[pout * n + index + boffset]; - _syncthreads(); - for(int i = 1; i < n; i *= 2) { + __syncthreads(); + for(int i = 1; i < (1 << d); i *= 2) { pout = 1 - pout; pin = 1 - pout; if(index >= i) { - temp[pout * n + index + boffset] += temp[pin * n + index + boffset - i]; + temp[pout * n + index + boffset * 2] += temp[pin * n + index + boffset * 2 - i]; } else { - temp[pout * n + index + boffset] = temp[pin * n + index + boffset]; + temp[pout * n + index + boffset * 2] = temp[pin * n + index + boffset * 2]; } __syncthreads(); @@ -113,7 +113,6 @@ namespace StreamCompaction { int blockCount = (n + blockSize - 1) / blockSize; int lastBlockN = n - (blockCount - 1) * blockSize; int d = ilog2ceil(blockSize); - int lastD = ilog2ceil(lastBlockN); int *dev_idata, *dev_odata, *dev_auxi, *dev_tauxi; @@ -132,12 +131,14 @@ namespace StreamCompaction { int blocknum = blockSize; int sharedMemory = 2 * blockSize * sizeof(int); - kernSharedNaiveScan<<>>(blocknum, dev_odata, dev_auxi, dev_idata, 1); + kernSharedNaiveScan<<>>(blocknum, d, dev_odata, dev_auxi, dev_idata, 1); // assump blockSize <= blockSize - kernSharedNaiveScan<<<1, blocknum, sharedMemory>>>(blocknum, dev_tauxi, NULL, dev_auxi, 0); + sharedMemory = 2 * blockCount * sizeof(int); + d = ilog2ceil(blockCount); + kernSharedNaiveScan<<<1, blockCount, sharedMemory>>>(blocknum, d, dev_tauxi, NULL, dev_auxi, 0); - sharedMemory = blockSize * sizeof(int); + sharedMemory = blockCount * sizeof(int); kernAddAuxi<<>> (blocknum, dev_odata, dev_tauxi); odata[0] = 0; @@ -147,7 +148,6 @@ namespace StreamCompaction { cudaFree(dev_odata); cudaFree(dev_auxi); - free(temp); } } } diff --git a/stream_compaction/radix.cu b/stream_compaction/radix.cu index e3eca36..8a1ec7d 100644 --- a/stream_compaction/radix.cu +++ b/stream_compaction/radix.cu @@ -1,11 +1,10 @@ #include #include -#include "common.h" #include "radix.h" #include "efficient.h" namespace StreamCompaction { - namespace radix { + namespace Radix { using StreamCompaction::Common::PerformanceTimer; PerformanceTimer& timer() { @@ -23,13 +22,14 @@ namespace StreamCompaction { bdata[index] = digit ? 1 : 0; } - __global__ void kernRadixDArray(int n, int p, int totalFalse, int *ddata, const int *fdata, const int *bdata) { + __global__ void kernRadixDArray(int n, int totalFalse, int *ddata, const int *fdata, int *bdata) { int index = blockDim.x * blockIdx.x + threadIdx.x; if(index >= n) return; int f = fdata[index]; int t = index - f + totalFalse; ddata[index] = bdata[index] ? t : f; + bdata[index] = 1; } void sort(int n, int *odata, const int *idata){ @@ -38,7 +38,10 @@ namespace StreamCompaction { int nPow = 1 << d; int *dev_idataPow, *dev_bdataPow, *dev_edataPow, *dev_fdataPow, *dev_ddataPow, *dev_odataPow; - int en = 0, fn = 0; + int *en, *fn; + + en = (int*)std::malloc(sizeof(int)); + fn = (int*)std::malloc(sizeof(int)); cudaMalloc((void**)&dev_idataPow, nPow * sizeof(int)); checkCUDAError("cudaMalloc dev_idataPow failed!"); @@ -56,7 +59,7 @@ namespace StreamCompaction { cudaMalloc((void**)&dev_fdataPow, nPow * sizeof(int)); checkCUDAError("cudaMalloc dev_fdataPow failed!"); cudaMemset(dev_fdataPow, 0, nPow * sizeof(int)); - cudaMalloc((void**)&dev_ddata, nPow * sizeof(int)); + cudaMalloc((void**)&dev_ddataPow, nPow * sizeof(int)); checkCUDAError("cudaMalloc dev_idata failed!"); cudaMemset(dev_ddataPow, 0, nPow * sizeof(int)); cudaMalloc((void**)&dev_odataPow, nPow * sizeof(int)); @@ -67,13 +70,13 @@ namespace StreamCompaction { dim3 gridDim((n + blockSize - 1) / blockSize); - for(int p = 1; p <= 6; p++) { - kernRadixEArray<<>>(n, p, dev_edataPow, dev_idataPow); + for(int p = 1; p <= (1 << 6); p = p << 1) { + kernRadixEArray<<>>(n, p, dev_bdataPow, dev_edataPow, dev_idataPow); cudaMemcpy(dev_fdataPow, dev_edataPow, nPow * sizeof(int), cudaMemcpyDeviceToDevice); StreamCompaction::Efficient::scanCore(nPow, d, dev_fdataPow); cudaMemcpy(en, dev_edataPow + n - 1, sizeof(int), cudaMemcpyDeviceToHost); cudaMemcpy(fn, dev_fdataPow + n - 1, sizeof(int), cudaMemcpyDeviceToHost); - kernRadixDArray<<>>(n, p, en + fn, dev_ddataPow, dev_fdataPow, dev_bdataPow); + kernRadixDArray<<>>(n, en[0] + fn[0], dev_ddataPow, dev_fdataPow, dev_bdataPow); StreamCompaction::Common::kernScatter<<>>(n, dev_odataPow, dev_idataPow, dev_bdataPow, dev_ddataPow); std::swap(dev_idataPow, dev_odataPow); } @@ -90,6 +93,9 @@ namespace StreamCompaction { cudaFree(dev_ddataPow); cudaFree(dev_odataPow); + free(en); + free(fn); + } } diff --git a/stream_compaction/radix.h b/stream_compaction/radix.h index aa489d9..c50fddd 100644 --- a/stream_compaction/radix.h +++ b/stream_compaction/radix.h @@ -6,6 +6,6 @@ namespace StreamCompaction { namespace Radix { StreamCompaction::Common::PerformanceTimer& timer(); - void sort(int n, int *odata, const int *idata); + void sort(int n, int *odata, const int *idata); } } From dc11977803d42c42b281bb7f3ac819da0b9e868a Mon Sep 17 00:00:00 2001 From: WanruZhao <31498168+WanruZhao@users.noreply.github.com> Date: Tue, 18 Sep 2018 15:29:27 -0400 Subject: [PATCH 7/7] Update README.md --- README.md | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0e38ddb..02ceac8 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,107 @@ CUDA Stream Compaction **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 2** -* (TODO) YOUR NAME HERE - * (TODO) [LinkedIn](), [personal website](), [twitter](), etc. -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Wanru Zhao + * [LinkedIn](www.linkedin.com/in/wanru-zhao). +* Tested on: Windows 10, Intel(R) Xeon(R) CPU E5-1630 v4 @ 3.70GHz, GTX 1070 (SIG Lab) -### (TODO: Your README) +### Features -Include analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) + - CPU Scan & Stream Compaction + - Naive GPU Scan Algorithm + - Work-Efficient GPU Scan + - Work-Efficient GPU Stream Compaction + - Thrust Implementation + +### Extra Credits +- Work-Efficient GPU Scan Optimization: by reducing empty or rest threads, dynamically lauch kernal +- Radix Sort + +### Performance Analysis +#### Block size over GPU scan methods (Array size 256) + +![](img/scan_bs.JPG) + +Performed analysis of blocksize impact over Naive Scan(power of two/non-power of two) and work-efficient scan(power of two/non-power of two). It shows that given the same block size, work-efficient GPU scan will be always better than Naive scan. And the size of array, whether is power of two or not, has little impact on one implementation of same block size. And from the graph, the performance has little change over the block size. The rough optimal blocksize is 512 for each implementation. + +#### Array size over scan methods (Block size 1024) + +![](img/scan_as.JPG) + +From this graph, we can find, thrust scan has the best performance over changes of array size, and it keeps the same for 2^6 to 2^20 numbers. And as array size raises, CPU scan's performance decreases dramatically. And Naive is better than CPU, but worse than work-efficient scan. When array size is between 2^6 to 2^14, CPU method is better than two GPU scan methods, and when array size is between 2^14 to 2^16, work-efficient is better than CPU, and when array size is larger than 2^16, Naive becomes better than CPU. +Thrust methods may optimized memory allocation and accessing methods and how it devides the block to make the performance stable and best. + +#### Array size over compaction methods (Block size 1024) + +![](img/compact_as.JPG) +We can see from the graph that, CPU method with scan is the worst, since for compaction, it actually does O(n) for finding booleans, O(n) for doing the scan and O(n) for scattering, since simple compaction just needs O(n) time. And when array size is large enough, work-efficient compaction benefits from its parallism and performs the best. + +#### Radix Sort (Block size 1024, Array size 256) + +Time: 1.52576ms + +### Result +``` +**************** +** SCAN TESTS ** +**************** + [ 18 22 20 42 10 18 23 8 38 0 30 27 2 ... 27 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 0.0011ms (std::chrono Measured) + [ 0 18 40 60 102 112 130 153 161 199 199 229 256 ... 6238 6265 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 0.0008ms (std::chrono Measured) + [ 0 18 40 60 102 112 130 153 161 199 199 229 256 ... 6157 6161 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 0.036864ms (CUDA Measured) + passed +==== naive scan, non-power-of-two ==== + elapsed time: 0.036864ms (CUDA Measured) + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 0.070656ms (CUDA Measured) + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 0.068608ms (CUDA Measured) + passed +==== thrust scan, power-of-two ==== + elapsed time: 0.001024ms (CUDA Measured) + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 0.001024ms (CUDA Measured) + passed + [ 18 22 20 42 10 18 23 8 38 0 30 27 2 ... 27 35 ] +==== radix sort, power-of-two ==== + elapsed time: 1.52883ms (CUDA Measured) + [ 0 0 0 1 1 1 1 2 2 2 2 2 2 ... 49 49 ] + passed +==== radix sort, non-power-of-two ==== + elapsed time: 1.52576ms (CUDA Measured) + [ 0 0 0 1 1 1 1 2 2 2 2 2 2 ... 49 49 ] + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** + [ 0 2 2 0 0 0 3 0 2 2 2 1 0 ... 1 0 ] +==== cpu compact without scan, power-of-two ==== + elapsed time: 0.0015ms (std::chrono Measured) + [ 2 2 3 2 2 2 1 1 3 1 3 1 1 ... 1 1 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 0.0015ms (std::chrono Measured) + [ 2 2 3 2 2 2 1 1 3 1 3 1 1 ... 3 1 ] + passed +==== cpu compact with scan ==== + elapsed time: 0.0062ms (std::chrono Measured) + [ 2 2 3 2 2 2 1 1 3 1 3 1 1 ... 1 1 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 0.09216ms (CUDA Measured) + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 0.090112ms (CUDA Measured) + passed +```