From 50b8a69d7b7442ac1f169c054b03814ae2edac87 Mon Sep 17 00:00:00 2001 From: YichaoW Date: Tue, 21 Sep 2021 17:24:10 +0800 Subject: [PATCH 1/2] part1-part3 --- src/main.cpp | 2 +- stream_compaction/common.cu | 21 ++++++- stream_compaction/cpu.cu | 51 +++++++++++++++-- stream_compaction/efficient.cu | 101 ++++++++++++++++++++++++++++++++- stream_compaction/naive.cu | 36 ++++++++++++ 5 files changed, 200 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 896ac2b..eb7adb1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,7 @@ int main(int argc, char* argv[]) { printDesc("naive scan, power-of-two"); StreamCompaction::Naive::scan(SIZE, c, a); printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(SIZE, c, true); + printArray(SIZE, c, true); printCmpResult(SIZE, b, c); /* For bug-finding only: Array of 1s to help find bugs in stream compaction or scan diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 2ed6d63..b2d99e9 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -23,7 +23,17 @@ namespace StreamCompaction { * which map to 0 will be removed, and elements which map to 1 will be kept. */ __global__ void kernMapToBoolean(int n, int *bools, const int *idata) { - // TODO + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= n) { + return; + } + + if (idata[idx] != 0) { + bools[idx] = 1; + } + else { + bools[idx] = 0; + } } /** @@ -32,7 +42,14 @@ namespace StreamCompaction { */ __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools, const int *indices) { - // TODO + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= n) { + return; + } + + if (bools[idx] == 1) { + odata[indices[idx]] = idata[idx]; + } } } diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 719fa11..e64af5a 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -2,6 +2,8 @@ #include "cpu.h" #include "common.h" +#include + namespace StreamCompaction { namespace CPU { @@ -12,6 +14,14 @@ namespace StreamCompaction { return timer; } + void scanNoTimer(int n, int* odata, const int* idata) { + // exclusive + odata[0] = 0; + for (int k = 1; k < n; k++) { + odata[k] = odata[k - 1] + idata[k - 1]; + } + } + /** * CPU scan (prefix sum). * For performance analysis, this is supposed to be a simple for loop. @@ -19,10 +29,12 @@ namespace StreamCompaction { */ void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); - // TODO + scanNoTimer(n, odata, idata); timer().endCpuTimer(); } + + /** * CPU stream compaction without using the scan function. * @@ -30,9 +42,15 @@ namespace StreamCompaction { */ int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); - // TODO + int index = 0; + for (int i = 0; i < n; i++) { + if (idata[i] != 0) { + odata[index] = idata[i]; + index++; + } + } timer().endCpuTimer(); - return -1; + return index; } /** @@ -42,9 +60,32 @@ namespace StreamCompaction { */ int compactWithScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); - // TODO + + // compute temp array + int* tempArr = new int[n]; + for (int i = 0; i < n; i++) { + if (idata[i] != 0) { + tempArr[i] = 1; + } + else { + tempArr[i] = 0; + } + } + + // exclusive scan + scanNoTimer(n, odata, tempArr); + + // scatter + int count = 0; + for (int i = 0; i < n; i++) { + if (tempArr[i] != 0) { + odata[odata[i]] = idata[i]; + count++; + } + } + timer().endCpuTimer(); - return -1; + return count; } } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 2db346e..c5e0151 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,6 +3,8 @@ #include "common.h" #include "efficient.h" +#define blockSize 256 + namespace StreamCompaction { namespace Efficient { using StreamCompaction::Common::PerformanceTimer; @@ -12,13 +14,63 @@ namespace StreamCompaction { return timer; } + + // only run for 1 thread at a time + __global__ void kernUpdateArr(int idx, int val, int *arr) { + arr[idx] = val; + } + + __global__ void kernScanUpSweep(int n, int *data, int pow2) { + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= n) { + return; + } + + if (idx % (2 * pow2) == 0) { + data[idx + 2 * pow2 - 1] += data[idx + pow2 - 1]; + } + } + + __global__ void kernScanDownSweep(int n, int *data, int pow2) { + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= n) { + return; + } + + if (idx % (2 * pow2) == 0) { + int temp = data[idx + pow2 - 1]; + data[idx + pow2 - 1] = data[idx + 2 * pow2 - 1]; + data[idx + 2 * pow2 - 1] += temp; + } + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + int* dev_arr; + int maxDepth = ilog2ceil(n); + int size = pow(2, maxDepth); + + cudaMalloc((void**)&dev_arr, size * sizeof(int)); + cudaMemcpy(dev_arr, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + dim3 blockNumPow((size + blockSize - 1) / blockSize); + + timer().startGpuTimer(); - // TODO + for (int d = 0; d < maxDepth; d++) { + kernScanUpSweep << > > (size, dev_arr, pow(2, d)); + } + + kernUpdateArr << <1, 1 >> > (size - 1, 0, dev_arr); + + for (int d = maxDepth - 1; d >= 0; d--) { + kernScanDownSweep << > > (size, dev_arr, pow(2, d)); + } timer().endGpuTimer(); + cudaMemcpy(odata, dev_arr, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(dev_arr); } /** @@ -31,10 +83,53 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { + int* dev_idata, *dev_odata, *dev_bools, *dev_indices; + int maxDepth = ilog2ceil(n); + int size = pow(2, maxDepth); + + cudaMalloc((void**)&dev_idata, size * sizeof(int)); + cudaMalloc((void**)&dev_odata, n * sizeof(int)); + cudaMalloc((void**)&dev_bools, size * sizeof(int)); + cudaMalloc((void**)&dev_indices, size * sizeof(int)); + cudaMemcpy(dev_idata, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + dim3 blockNum((n + blockSize - 1) / blockSize); + dim3 blockNumPow((size + blockSize - 1) / blockSize); + timer().startGpuTimer(); - // TODO + Common::kernMapToBoolean << > > (size, dev_bools, dev_idata); + cudaMemcpy(dev_indices, dev_bools, size * sizeof(int), cudaMemcpyHostToDevice); + + // scan + for (int d = 0; d < maxDepth; d++) { + kernScanUpSweep << > > (size, dev_indices, pow(2, d)); + } + + kernUpdateArr << <1, 1 >> > (size - 1, 0, dev_indices); + + for (int d = maxDepth - 1; d >= 0; d--) { + kernScanDownSweep << > > (size, dev_indices, pow(2, d)); + } + + // scatter + Common::kernScatter << > > (n, dev_odata, dev_idata, dev_bools, dev_indices); timer().endGpuTimer(); - return -1; + + cudaMemcpy(odata, dev_odata, n * sizeof(int), cudaMemcpyDeviceToHost); + int* bools = new int[n]; + cudaMemcpy(bools, dev_bools, n * sizeof(int), cudaMemcpyDeviceToHost); + int count = 0; + for (int i = 0; i < n; i++) { + if (bools[i]) { + count++; + } + } + + cudaFree(dev_idata); + cudaFree(dev_odata); + cudaFree(dev_bools); + cudaFree(dev_indices); + return count; } } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 4308876..d8daa08 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -3,6 +3,9 @@ #include "common.h" #include "naive.h" + +#define blockSize 256 + namespace StreamCompaction { namespace Naive { using StreamCompaction::Common::PerformanceTimer; @@ -13,13 +16,46 @@ namespace StreamCompaction { } // TODO: __global__ + __global__ void kernNaiveScan(int n, int *odata, int *idata, int offset) { + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= n) { + return; + } + if (idx >= offset) { + odata[idx] = idata[idx - offset] + idata[idx]; + } + else { + odata[idx] = idata[idx]; + } + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + int* dev_arr1,* dev_arr2; + + cudaMalloc((void**)&dev_arr1, n * sizeof(int)); + cudaMalloc((void**)&dev_arr2, n * sizeof(int)); + cudaMemcpy(dev_arr1, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + dim3 blockNum((n + blockSize - 1) / blockSize); + + int maxDepth = ilog2ceil(n); timer().startGpuTimer(); // TODO + for (int d = 1; d <= maxDepth; d++) { + kernNaiveScan << > > (n, dev_arr2, dev_arr1, pow(2, d - 1)); + dev_arr1 = dev_arr2; + } + + cudaMemcpy(odata + 1, dev_arr2, (n - 1) * sizeof(int), cudaMemcpyDeviceToHost); + odata[0] = 0; timer().endGpuTimer(); + + cudaFree(dev_arr1); + cudaFree(dev_arr2); + } } } From bd2964c85a9772d840d4858f817ff01499abe29a Mon Sep 17 00:00:00 2001 From: YichaoW Date: Wed, 22 Sep 2021 00:15:29 +0800 Subject: [PATCH 2/2] finish --- README.md | 109 +++++++++++++++++++++++++++++++-- img/blockSize.png | Bin 0 -> 38332 bytes img/compact.png | Bin 0 -> 35324 bytes img/scan.png | Bin 0 -> 35489 bytes src/main.cpp | 2 +- stream_compaction/common.h | 1 + stream_compaction/efficient.cu | 29 +++++++-- stream_compaction/naive.cu | 15 +++-- stream_compaction/thrust.cu | 4 ++ 9 files changed, 144 insertions(+), 16 deletions(-) create mode 100644 img/blockSize.png create mode 100644 img/compact.png create mode 100644 img/scan.png diff --git a/README.md b/README.md index 0e38ddb..513938d 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,109 @@ 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) +* Yichao Wang + * [LinkedIn](https://www.linkedin.com/in/wangyic/) +* Tested on: Windows 10 Home 64-bit (10.0, Build 18363) + * Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 CPUs) + * GeForce GTX 1060 6.1 -### (TODO: Your README) +## Description -Include analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) +This project implements Scan and Stream Compaction in various ways: +* Scan (all implementations support Non-Power-Of-Two input) + * cpu + * naive (gpu) + * work-efficient (gpu, optimized indexing) + * thrust (gpu) +* Stream Compaction + * cpu without scan + * cpu with scan + * gpu with work-efficient scan + +For more information, see [INSTRUCTION.md](INSTRUCTION.md). + +## Performance Analysis + +### Block Size Optimize + +![](img/blockSize.png) + +Note: ```NPOT stands for Non-Power-of-Two``` + +From above plot, we can see that there is no much difference between block sizes. So we choose block size of 512 for the following analysis. + +### Implmentations Comparation + +![](img/scan.png) + +![](img/compact.png) + +From above plots, we can see that the elapsed time increases as input size increases. However, there is no much difference for elapsed time when input size is non-power-of-two. Not surprising, thrust implmentation is the fastest one. + +For stream compaction, we can see cpu without scan runs faster than cpu with scan. This is because cpu with scan requires three for loop while cpu without scan only requires one. + +### Work Efficient Scan Optimization + +Before the optimization, work efficient scan even runs slower than naive and cpu implementation. This is because not all threads are actually working. For example, if the input size is 1024, we only need 512 threads at most instead of 1024 for the first depth. This is because the additions is half of the size. Thus, to optimize the work efficient scan, I have adjusted the box amount according to the depth level and have changed index calculation in up-sweep and down-sweep method. + + +### Output for Scan and Stream Compaction Test (512 block size, 2^24 input size) + +``` + +**************** +** SCAN TESTS ** +**************** + [ 47 5 43 43 27 45 0 29 1 26 3 8 27 ... 2 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 29.0025ms (std::chrono Measured) + [ 0 47 52 95 138 165 210 210 239 240 266 269 277 ... 410953421 410953423 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 29.5704ms (std::chrono Measured) + [ 0 47 52 95 138 165 210 210 239 240 266 269 277 ... 410953326 410953375 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 24.2698ms (CUDA Measured) + [ 0 47 52 95 138 165 210 210 239 240 266 269 277 ... 410953421 410953423 ] + passed +==== naive scan, non-power-of-two ==== + elapsed time: 23.7513ms (CUDA Measured) + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 9.78432ms (CUDA Measured) + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 9.76662ms (CUDA Measured) + passed +==== thrust scan, power-of-two ==== + elapsed time: 1.13667ms (CUDA Measured) + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 1.34381ms (CUDA Measured) + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** + [ 2 0 0 0 1 3 3 0 2 3 3 2 2 ... 3 0 ] +==== cpu compact without scan, power-of-two ==== + elapsed time: 50.8381ms (std::chrono Measured) + [ 2 1 3 3 2 3 3 2 2 3 1 3 3 ... 3 3 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 44.1896ms (std::chrono Measured) + [ 2 1 3 3 2 3 3 2 2 3 1 3 3 ... 1 3 ] + passed +==== cpu compact with scan ==== + elapsed time: 73.4177ms (std::chrono Measured) + [ 2 1 3 3 2 3 3 2 2 3 1 3 3 ... 3 3 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 13.1512ms (CUDA Measured) + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 13.1215ms (CUDA Measured) + passed +Press any key to continue . . . +``` diff --git a/img/blockSize.png b/img/blockSize.png new file mode 100644 index 0000000000000000000000000000000000000000..c531be8aed098dfd5f06790d7b22c39b538456db GIT binary patch literal 38332 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 literal 0 HcmV?d00001 diff --git a/img/compact.png b/img/compact.png new file mode 100644 index 0000000000000000000000000000000000000000..d3343d3232fbfc3cfd573e382d4ee0f3eedb0626 GIT binary patch literal 35324 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 CaUFyJ literal 0 HcmV?d00001 diff --git a/img/scan.png b/img/scan.png new file mode 100644 index 0000000000000000000000000000000000000000..5cb280ee4d6fed986c6fe585a4aab0a91806d67b GIT binary patch literal 35489 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 XRK`8jM@3;xB#izvJ)3*_`d|MGYr=Lj literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index eb7adb1..48337b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,7 @@ #include #include "testing_helpers.hpp" -const int SIZE = 1 << 8; // feel free to change the size of array +const int SIZE = 1 << 24; // 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]; diff --git a/stream_compaction/common.h b/stream_compaction/common.h index d2c1fed..6ad4383 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -12,6 +12,7 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) +#define blockSize 512 /** * Check for CUDA errors; print and exit if there was a problem. diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index c5e0151..579e5bb 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,7 +3,6 @@ #include "common.h" #include "efficient.h" -#define blockSize 256 namespace StreamCompaction { namespace Efficient { @@ -21,18 +20,27 @@ namespace StreamCompaction { } __global__ void kernScanUpSweep(int n, int *data, int pow2) { - int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + /*int idx = (blockIdx.x * blockDim.x) + threadIdx.x; if (idx >= n) { return; } if (idx % (2 * pow2) == 0) { data[idx + 2 * pow2 - 1] += data[idx + pow2 - 1]; + }*/ + + // optimized solution + size_t idx = (blockIdx.x * blockDim.x) + threadIdx.x; + idx = 2 * pow2 * (idx + 1) - 1; + if (idx >= n) { + return; } + data[idx] += data[idx - pow2]; + } __global__ void kernScanDownSweep(int n, int *data, int pow2) { - int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + /*int idx = (blockIdx.x * blockDim.x) + threadIdx.x; if (idx >= n) { return; } @@ -41,7 +49,16 @@ namespace StreamCompaction { int temp = data[idx + pow2 - 1]; data[idx + pow2 - 1] = data[idx + 2 * pow2 - 1]; data[idx + 2 * pow2 - 1] += temp; + }*/ + // optimized solution + size_t idx = (blockIdx.x * blockDim.x) + threadIdx.x; + idx = 2 * pow2 * (idx + 1) - 1; + if (idx >= n) { + return; } + int temp = data[idx - pow2]; + data[idx - pow2] = data[idx]; + data[idx] += temp; } /** @@ -60,12 +77,14 @@ namespace StreamCompaction { timer().startGpuTimer(); for (int d = 0; d < maxDepth; d++) { + blockNumPow = (size / pow(2, d + 1) + blockSize - 1) / blockSize; kernScanUpSweep << > > (size, dev_arr, pow(2, d)); } kernUpdateArr << <1, 1 >> > (size - 1, 0, dev_arr); for (int d = maxDepth - 1; d >= 0; d--) { + blockNumPow = (size / pow(2, d + 1) + blockSize - 1) / blockSize; kernScanDownSweep << > > (size, dev_arr, pow(2, d)); } timer().endGpuTimer(); @@ -86,7 +105,7 @@ namespace StreamCompaction { int* dev_idata, *dev_odata, *dev_bools, *dev_indices; int maxDepth = ilog2ceil(n); int size = pow(2, maxDepth); - + cudaMalloc((void**)&dev_idata, size * sizeof(int)); cudaMalloc((void**)&dev_odata, n * sizeof(int)); cudaMalloc((void**)&dev_bools, size * sizeof(int)); @@ -102,12 +121,14 @@ namespace StreamCompaction { // scan for (int d = 0; d < maxDepth; d++) { + blockNumPow = (size / pow(2, d + 1) + blockSize - 1) / blockSize; kernScanUpSweep << > > (size, dev_indices, pow(2, d)); } kernUpdateArr << <1, 1 >> > (size - 1, 0, dev_indices); for (int d = maxDepth - 1; d >= 0; d--) { + blockNumPow = (size / pow(2, d + 1) + blockSize - 1) / blockSize; kernScanDownSweep << > > (size, dev_indices, pow(2, d)); } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index d8daa08..d8d34ed 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -4,7 +4,7 @@ #include "naive.h" -#define blockSize 256 + namespace StreamCompaction { namespace Naive { @@ -43,15 +43,20 @@ namespace StreamCompaction { int maxDepth = ilog2ceil(n); timer().startGpuTimer(); - // TODO for (int d = 1; d <= maxDepth; d++) { - kernNaiveScan << > > (n, dev_arr2, dev_arr1, pow(2, d - 1)); - dev_arr1 = dev_arr2; + kernNaiveScan << > > (n, dev_arr2, dev_arr1, pow(2.0,d-1)); + + // ping pong + if (d < maxDepth) { + int* temp = dev_arr1; + dev_arr1 = dev_arr2; + dev_arr2 = temp; + } } + timer().endGpuTimer(); cudaMemcpy(odata + 1, dev_arr2, (n - 1) * sizeof(int), cudaMemcpyDeviceToHost); odata[0] = 0; - timer().endGpuTimer(); cudaFree(dev_arr1); cudaFree(dev_arr2); diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 1def45e..7cb6311 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -18,11 +18,15 @@ 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 dv_in(idata, idata + n); + thrust::device_vector dv_out(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(dv_in.begin(), dv_in.end(), dv_out.begin()); timer().endGpuTimer(); + thrust::copy(dv_out.begin(), dv_out.end(), odata); } } }