From 4824ed3a5dda61966a55eaca324cb79c4c5c398c Mon Sep 17 00:00:00 2001 From: Uchanka Date: Mon, 17 Sep 2018 19:30:39 -0400 Subject: [PATCH 01/19] CPU naive implementation --- stream_compaction/CMakeLists.txt | 2 +- stream_compaction/cpu.cu | 72 ++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index cdbef77..48e2f35 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_60 ) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 05ce667..2eb7670 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; } /** @@ -20,6 +20,14 @@ namespace StreamCompaction { void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + // Insert I + odata[0] = 0; + // Compute + for (int i = 1; i != n; ++i) + { + odata[i] = idata[i - 1] + odata[i - 1]; + } + timer().endCpuTimer(); } @@ -31,8 +39,18 @@ namespace StreamCompaction { int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + int remaining = 0; + for (int i = 0; i != n; ++i) + { + if (idata[i] != 0) + { + odata[remaining] = idata[i]; + ++remaining; + } + } + timer().endCpuTimer(); - return -1; + return remaining; } /** @@ -41,10 +59,46 @@ namespace StreamCompaction { * @returns the number of elements remaining after compaction. */ int compactWithScan(int n, int *odata, const int *idata) { - timer().startCpuTimer(); + + bool* hasChanged = new bool[n]; + int* sum = new int[n]; + + timer().startCpuTimer(); // TODO + + for (int i = 0; i != n; ++i) + { + if (idata[i] == 0) + { + hasChanged[i] = false; + } + else + { + hasChanged[i] = true; + } + } + + odata[0] = 0; + for (int i = 1; i != n; ++i) + { + odata[i] = idata[i - 1] + odata[i - 1]; + } + int remaining = 0; + for (int i = 0; i < n; ++i) + { + if (hasChanged[i]) + { + odata[sum[i]] = idata[i]; + ++remaining; + } + } + timer().endCpuTimer(); - return -1; + + delete[] hasChanged; + delete[] sum; + + return remaining; } } } From f19487c62e80cf3b9bdd9d4767f0393c85a08645 Mon Sep 17 00:00:00 2001 From: Uchanka Date: Mon, 17 Sep 2018 19:40:19 -0400 Subject: [PATCH 02/19] CPU implementation passed --- stream_compaction/cpu.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 2eb7670..cd5e839 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -22,7 +22,7 @@ namespace StreamCompaction { // TODO // Insert I odata[0] = 0; - // Compute + // Compute the sums for (int i = 1; i != n; ++i) { odata[i] = idata[i - 1] + odata[i - 1]; From fc5614932e7a251f72af3017322cdb4a0d2fe473 Mon Sep 17 00:00:00 2001 From: Uchanka Date: Mon, 17 Sep 2018 19:48:38 -0400 Subject: [PATCH 03/19] Line feed problems... --- stream_compaction/naive.cu | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 9218f8e..dde09d0 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -5,11 +5,11 @@ 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__ From 2458870561cb5be4eff794becde36cfdb473cb9f Mon Sep 17 00:00:00 2001 From: Uchanka Date: Mon, 17 Sep 2018 23:20:06 -0400 Subject: [PATCH 04/19] Added some macros and common kernels --- stream_compaction/common.cu | 32 +++++++++++++++++++++++++++++++- stream_compaction/common.h | 4 ++++ stream_compaction/cpu.cu | 8 ++++---- stream_compaction/naive.cu | 5 +++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 8fc0211..c7b3ae9 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -1,5 +1,7 @@ #include "common.h" +# define MEETCRITERION 0 + void checkCUDAErrorFn(const char *msg, const char *file, int line) { cudaError_t err = cudaGetLastError(); if (cudaSuccess == err) { @@ -24,6 +26,21 @@ namespace StreamCompaction { */ __global__ void kernMapToBoolean(int n, int *bools, const int *idata) { // TODO + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx >= n) + { + return; + } + + int &flag = bools[idx]; + if (idata[idx] == MEETCRITERION) + { + flag = HAS_MET; + } + else + { + flag = NOT_MET; + } } /** @@ -33,7 +50,20 @@ namespace StreamCompaction { __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools, const int *indices) { // TODO - } + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx >= n) + { + return; + } + if (idx == n - 1) + { + odata[indices[idx]] = idata[idx]; + } + else if (indices[idx] != indices[idx + 1]) + { + odata[indices[idx]] = idata[idx]; + } + } } } diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 99a1b04..af1436f 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -130,3 +130,7 @@ namespace StreamCompaction { }; } } + +// Used as a boolean function for elaborating if a certain element meets criterion +// 0 for not met, 1 for met +enum ElementAttribute { NOT_MET, HAS_MET }; \ No newline at end of file diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index cd5e839..129ba2a 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -60,7 +60,7 @@ namespace StreamCompaction { */ int compactWithScan(int n, int *odata, const int *idata) { - bool* hasChanged = new bool[n]; + int* hasChanged = new int[n]; int* sum = new int[n]; timer().startCpuTimer(); @@ -70,11 +70,11 @@ namespace StreamCompaction { { if (idata[i] == 0) { - hasChanged[i] = false; + hasChanged[i] = NOT_MET; } else { - hasChanged[i] = true; + hasChanged[i] = HAS_MET; } } @@ -86,7 +86,7 @@ namespace StreamCompaction { int remaining = 0; for (int i = 0; i < n; ++i) { - if (hasChanged[i]) + if (hasChanged[i] == HAS_MET) { odata[sum[i]] = idata[i]; ++remaining; diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index dde09d0..e38162e 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -13,6 +13,11 @@ namespace StreamCompaction { } // TODO: __global__ + __global__ void streamCompactionNaive() + { + + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ From 89982dc3e13e19e718ef22e0ea73f74ede33ce2f Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 00:17:09 -0400 Subject: [PATCH 05/19] Weird bugs appered --- stream_compaction/common.h | 4 ++- stream_compaction/naive.cu | 57 ++++++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/stream_compaction/common.h b/stream_compaction/common.h index af1436f..b317adc 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -133,4 +133,6 @@ namespace StreamCompaction { // Used as a boolean function for elaborating if a certain element meets criterion // 0 for not met, 1 for met -enum ElementAttribute { NOT_MET, HAS_MET }; \ No newline at end of file +enum ElementAttribute { NOT_MET, HAS_MET }; + +# define BLOCKSIZE 1024 \ No newline at end of file diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index e38162e..080129b 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -12,19 +12,66 @@ namespace StreamCompaction { return timer; } // TODO: __global__ - - __global__ void streamCompactionNaive() + // Stride: 2^n, the stride of the elements + __global__ void streamCompactionNaive(int n, int stride, const int* idata, int* odata) { - + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx >= n) + { + return; + } + + // Add element + if (idx >= stride) + { + odata[idx] = idata[idx - stride] + idata[idx]; + + } + // Got no element to add + 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) { - timer().startGpuTimer(); - // TODO + int* idataDev = nullptr; + int* odataDev = nullptr; + size_t heapSize = sizeof(int) * n; + cudaMalloc(reinterpret_cast(&idataDev), heapSize); + checkCUDAError("Malloc for input data failed"); + cudaMalloc(reinterpret_cast(&odataDev), heapSize); + checkCUDAError("Malloc for output data failed"); + + cudaMemcpy(reinterpret_cast(idataDev), idata, heapSize, cudaMemcpyHostToDevice); + checkCUDAError("Memcpy input data host 2 device failed"); + cudaMemcpy(reinterpret_cast(odataDev), odata, heapSize, cudaMemcpyHostToDevice); + checkCUDAError("Memcpy input data host 2 device failed"); + + dim3 gridLayout((n - 1 + BLOCKSIZE) / BLOCKSIZE); + dim3 blockLayout(BLOCKSIZE); + + //Layers of the problem + int layer = ilog2ceil(n); + + timer().startGpuTimer(); + // TODO + for (int layerI = 0; layerI < layer; ++layerI) + { + int strideWidth = 1 << layerI; + streamCompactionNaive<<>>(n, strideWidth, idataDev, odataDev); + + int* temp = idataDev; + idataDev = odataDev; + odataDev = temp; + } timer().endGpuTimer(); + + cudaMemcpy(odata, reinterpret_cast(odataDev), heapSize, cudaMemcpyDeviceToHost); + checkCUDAError("Memcpy output data device 2 host failed"); } } } From bc55773511eadc889e9c978f35b7aae22bdda3d6 Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 00:26:02 -0400 Subject: [PATCH 06/19] Naive bug defused --- stream_compaction/naive.cu | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 080129b..3e64c31 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -34,6 +34,13 @@ namespace StreamCompaction { } } + void swapBuffer(int*& ptr1, int*& ptr2) + { + int* temp = ptr1; + ptr1 = ptr2; + ptr2 = temp; + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ @@ -64,14 +71,17 @@ namespace StreamCompaction { int strideWidth = 1 << layerI; streamCompactionNaive<<>>(n, strideWidth, idataDev, odataDev); - int* temp = idataDev; - idataDev = odataDev; - odataDev = temp; + swapBuffer(idataDev, odataDev); } + swapBuffer(idataDev, odataDev); timer().endGpuTimer(); - cudaMemcpy(odata, reinterpret_cast(odataDev), heapSize, cudaMemcpyDeviceToHost); + cudaMemcpy(odata + 1, reinterpret_cast(odataDev), heapSize - sizeof(int), cudaMemcpyDeviceToHost); + odata[0] = 0; checkCUDAError("Memcpy output data device 2 host failed"); + + cudaFree(idataDev); + cudaFree(odataDev); } } } From 271a6485cd0016017265ce75735e947ac740d031 Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 00:34:09 -0400 Subject: [PATCH 07/19] Turns out using thrust is so simple --- stream_compaction/efficient.cu | 10 +++++----- stream_compaction/thrust.cu | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 36c5ef2..fd1d622 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; } /** diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 36b732d..225841e 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -8,20 +8,22 @@ 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) { timer().startGpuTimer(); + thrust::device_vector dv_in(idata, idata + n); + thrust::device_vector dv_out(odata, odata + n); // 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(); } } From 2ed5496b7f862c27be5da61cecb605b1f1afc5fa Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 00:41:28 -0400 Subject: [PATCH 08/19] Forgot to copy stuff back --- stream_compaction/thrust.cu | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 225841e..dc34bd5 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -18,13 +18,16 @@ namespace StreamCompaction { * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { - timer().startGpuTimer(); thrust::device_vector dv_in(idata, idata + n); thrust::device_vector dv_out(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()); timer().endGpuTimer(); + + thrust::copy(dv_out.begin(), dv_out.end(), odata); } } } From 0a3ea992fb947d571480f7bb9e8661194f69a58a Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 01:06:42 -0400 Subject: [PATCH 09/19] Efficient implementation in progress --- stream_compaction/efficient.cu | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index fd1d622..c09c3f1 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -12,10 +12,46 @@ namespace StreamCompaction { return timer; } + //No-longer const int* idata, this time we do it in-place + __global__ void upSweeping(int n, int stride, int *idata) + { + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx >= n) + { + return; + } + + int stride2times = stride * 2; + if (idx % stride2times == 0) + { + idata[idx + stride2times - 1] += idata[idx + stride - 1]; + } + } + __global__ void downSweeping(int n, int stride, int *idata) + { + int idx = threadIdx.x + blockIdx.x * blockDim.x; + if (idx >= n) + { + return; + } + + int stride2times = stride * 2; + if (idx % stride2times == 0) + { + int indexCorresponding = idx + stride - 1; + int indexCorresponding2times = idx + stride2times - 1; + int delta = idata[indexCorresponding]; + idata[indexCorresponding] += idata[indexCorresponding2times]; + idata[indexCorresponding2times] += delta; + } + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + int layer = ilog2ceil(n); + timer().startGpuTimer(); // TODO timer().endGpuTimer(); From b633422f2ac2cf8a816d1a875d0e4937a7bf534f Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 02:27:33 -0400 Subject: [PATCH 10/19] Non-power of 2 still fails --- stream_compaction/efficient.cu | 146 ++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 4 deletions(-) diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index c09c3f1..f5f968b 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -41,20 +41,84 @@ namespace StreamCompaction { int indexCorresponding = idx + stride - 1; int indexCorresponding2times = idx + stride2times - 1; int delta = idata[indexCorresponding]; - idata[indexCorresponding] += idata[indexCorresponding2times]; + idata[indexCorresponding] = idata[indexCorresponding2times]; idata[indexCorresponding2times] += delta; } } + //Tell if a number is power of 2 + bool isPowerOfTwo(int n) + { + if (n == 0) + { + return false; + } + else + { + return (n & (n - 1)) == 0; + } + } /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { int layer = ilog2ceil(n); + int elementNumber = 0; + + if (!isPowerOfTwo(n)) + { + elementNumber = 1 << layer; + } + else + { + elementNumber = n; + } + int *paddedInput = new int[elementNumber]; + //Copy and pad the redundant elements with 0, if any + for (int i = 0; i < elementNumber; ++i) + { + if (i >= n) + { + paddedInput[i] = 0; + } + else + { + paddedInput[i] = idata[i]; + } + } + + int bufferSize = elementNumber * sizeof(int); + int* paddedIDataDev = nullptr; + + cudaMalloc(reinterpret_cast(&paddedIDataDev), bufferSize); + checkCUDAError("Malloc for padded input failed"); + cudaMemcpy(reinterpret_cast(paddedIDataDev), paddedInput, bufferSize, cudaMemcpyHostToDevice); + checkCUDAError("Memcpy for padded input failed from host to device"); timer().startGpuTimer(); // TODO + dim3 gridLayout((n - 1 + BLOCKSIZE) / BLOCKSIZE); + dim3 blockLayout(BLOCKSIZE); + + for (int layerI = 0; layerI < layer; ++layerI) + { + int stride = 1 << layerI; + upSweeping<<>>(n, stride, paddedIDataDev); + } + int initialZero = 0; + cudaMemcpy(reinterpret_cast(paddedIDataDev + n - 1), &initialZero, sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("Memcpy for the initial 0 failed from host to device"); + for (int layerI = layer - 1; layerI >= 0; --layerI) + { + int stride = 1 << layerI; + downSweeping<<>>(n, stride, paddedIDataDev); + } + timer().endGpuTimer(); + + cudaMemcpy(odata, reinterpret_cast(paddedIDataDev), bufferSize, cudaMemcpyDeviceToHost); + checkCUDAError("Memcpy for padded input failed from device to host"); + cudaFree(paddedIDataDev); } /** @@ -68,9 +132,83 @@ namespace StreamCompaction { */ int compact(int n, int *odata, const int *idata) { timer().startGpuTimer(); - // TODO - timer().endGpuTimer(); - return -1; + int layer = ilog2ceil(n); + int elementNumber = 0; + + if (!isPowerOfTwo(n)) + { + elementNumber = 1 << layer; + } + else + { + elementNumber = n; + } + int *paddedInput = new int[elementNumber]; + //Copy and pad the redundant elements with 0, if any + for (int i = 0; i < elementNumber; ++i) + { + if (i >= n) + { + paddedInput[i] = 0; + } + else + { + paddedInput[i] = idata[i]; + } + } + + int bufferSize = elementNumber * sizeof(int); + + int* paddedIDataDev; + int* oDataDev; + int* mDataDev; + cudaMalloc(reinterpret_cast(&paddedIDataDev), bufferSize); + checkCUDAError("Malloc for padded input failed"); + cudaMalloc(reinterpret_cast(&oDataDev), bufferSize); + checkCUDAError("Malloc for output failed"); + cudaMalloc(reinterpret_cast(&mDataDev), bufferSize); + checkCUDAError("Malloc for intermediate failed"); + cudaMemcpy(paddedIDataDev, paddedInput, bufferSize, cudaMemcpyHostToDevice); + checkCUDAError("Memcpy for padded input failed"); + + timer().startGpuTimer(); + // TODO + dim3 gridLayout((n - 1 + BLOCKSIZE) / BLOCKSIZE); + dim3 blockLayout(BLOCKSIZE); + + StreamCompaction::Common::kernMapToBoolean<<>>(elementNumber, mDataDev, paddedIDataDev); + int endingElement = 0; + cudaMemcpy(&endingElement, reinterpret_cast(mDataDev + elementNumber - 1), sizeof(int), cudaMemcpyDeviceToHost); + + for (int layerI = 0; layerI < layer; ++layerI) + { + int stride = 1 << layerI; + upSweeping<<>>(elementNumber, stride, mDataDev); + } + int initialZero = 0; + cudaMemcpy(reinterpret_cast(mDataDev + elementNumber - 1), &initialZero, sizeof(int), cudaMemcpyHostToDevice); + for (int layerI = layer - 1; layerI >= 0; --layerI) + { + int stride = 1 << layerI; + downSweeping<<>>(n, stride, mDataDev); + } + int elements = 0; + cudaMemcpy(&elements, reinterpret_cast(mDataDev + elementNumber - 1), sizeof(int), cudaMemcpyHostToDevice); + StreamCompaction::Common::kernScatter<<>>(elementNumber, oDataDev, paddedIDataDev, mDataDev, mDataDev); + + + timer().endGpuTimer(); + + cudaMemcpy(odata, reinterpret_cast(oDataDev), bufferSize, cudaMemcpyDeviceToHost); + if (endingElement == 1) + { + ++elements; + } + cudaFree(paddedIDataDev); + cudaFree(oDataDev); + cudaFree(mDataDev); + + return elements; } } } From 0a46907861d039be93b072b7128b33f33fde1e0c Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 03:05:17 -0400 Subject: [PATCH 11/19] Debugged the CPU implementation --- stream_compaction/cpu.cu | 4 ++-- stream_compaction/efficient.cu | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 129ba2a..c6c1e2d 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -78,10 +78,10 @@ namespace StreamCompaction { } } - odata[0] = 0; + sum[0] = 0; for (int i = 1; i != n; ++i) { - odata[i] = idata[i - 1] + odata[i - 1]; + sum[i] = hasChanged[i - 1] + sum[i - 1]; } int remaining = 0; for (int i = 0; i < n; ++i) diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index f5f968b..2105d54 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -65,13 +65,13 @@ namespace StreamCompaction { int layer = ilog2ceil(n); int elementNumber = 0; - if (!isPowerOfTwo(n)) + if (isPowerOfTwo(n)) { - elementNumber = 1 << layer; + elementNumber = n; } else { - elementNumber = n; + elementNumber = 1 << layer; } int *paddedInput = new int[elementNumber]; //Copy and pad the redundant elements with 0, if any @@ -100,18 +100,18 @@ namespace StreamCompaction { dim3 gridLayout((n - 1 + BLOCKSIZE) / BLOCKSIZE); dim3 blockLayout(BLOCKSIZE); - for (int layerI = 0; layerI < layer; ++layerI) + for (int layerI = 0; layerI < layer - 1; ++layerI) { int stride = 1 << layerI; - upSweeping<<>>(n, stride, paddedIDataDev); + upSweeping<<>>(elementNumber, stride, paddedIDataDev); } int initialZero = 0; - cudaMemcpy(reinterpret_cast(paddedIDataDev + n - 1), &initialZero, sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(reinterpret_cast(paddedIDataDev + elementNumber - 1), &initialZero, sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("Memcpy for the initial 0 failed from host to device"); for (int layerI = layer - 1; layerI >= 0; --layerI) { int stride = 1 << layerI; - downSweeping<<>>(n, stride, paddedIDataDev); + downSweeping<<>>(elementNumber, stride, paddedIDataDev); } timer().endGpuTimer(); @@ -131,7 +131,6 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { - timer().startGpuTimer(); int layer = ilog2ceil(n); int elementNumber = 0; From 882b4397d9d0e56f4afd20c7ad40d9bc09738bfe Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 03:19:57 -0400 Subject: [PATCH 12/19] CPU implementation weird bug --- stream_compaction/common.cu | 5 ++--- stream_compaction/common.h | 4 ++-- stream_compaction/efficient.cu | 14 ++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index c7b3ae9..5a89ba5 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -32,14 +32,13 @@ namespace StreamCompaction { return; } - int &flag = bools[idx]; if (idata[idx] == MEETCRITERION) { - flag = HAS_MET; + bools[idx] = HAS_MET; } else { - flag = NOT_MET; + bools[idx] = NOT_MET; } } diff --git a/stream_compaction/common.h b/stream_compaction/common.h index b317adc..ef3579a 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -132,7 +132,7 @@ namespace StreamCompaction { } // Used as a boolean function for elaborating if a certain element meets criterion -// 0 for not met, 1 for met -enum ElementAttribute { NOT_MET, HAS_MET }; +// 1 for not met, 0 for met +enum ElementAttribute { HAS_MET, NOT_MET }; # define BLOCKSIZE 1024 \ No newline at end of file diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 2105d54..73276c8 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -134,13 +134,13 @@ namespace StreamCompaction { int layer = ilog2ceil(n); int elementNumber = 0; - if (!isPowerOfTwo(n)) + if (isPowerOfTwo(n)) { - elementNumber = 1 << layer; + elementNumber = n; } else { - elementNumber = n; + elementNumber = 1 << layer; } int *paddedInput = new int[elementNumber]; //Copy and pad the redundant elements with 0, if any @@ -179,20 +179,22 @@ namespace StreamCompaction { int endingElement = 0; cudaMemcpy(&endingElement, reinterpret_cast(mDataDev + elementNumber - 1), sizeof(int), cudaMemcpyDeviceToHost); - for (int layerI = 0; layerI < layer; ++layerI) + for (int layerI = 0; layerI < layer - 1; ++layerI) { int stride = 1 << layerI; upSweeping<<>>(elementNumber, stride, mDataDev); } int initialZero = 0; cudaMemcpy(reinterpret_cast(mDataDev + elementNumber - 1), &initialZero, sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("Memcpy for the initial 0 failed from host to device"); for (int layerI = layer - 1; layerI >= 0; --layerI) { int stride = 1 << layerI; - downSweeping<<>>(n, stride, mDataDev); + downSweeping<<>>(elementNumber, stride, mDataDev); } int elements = 0; - cudaMemcpy(&elements, reinterpret_cast(mDataDev + elementNumber - 1), sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(&elements, reinterpret_cast(mDataDev + elementNumber - 1), sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("Memcpy for element count failed from device to host"); StreamCompaction::Common::kernScatter<<>>(elementNumber, oDataDev, paddedIDataDev, mDataDev, mDataDev); From c984218fe71856c44331e22bf9eea9c198067210 Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 03:23:53 -0400 Subject: [PATCH 13/19] Fixed some really messed up macro definitions --- stream_compaction/common.cu | 2 -- stream_compaction/common.h | 2 +- stream_compaction/cpu.cu | 8 ++++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 5a89ba5..7328d28 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -1,7 +1,5 @@ #include "common.h" -# define MEETCRITERION 0 - void checkCUDAErrorFn(const char *msg, const char *file, int line) { cudaError_t err = cudaGetLastError(); if (cudaSuccess == err) { diff --git a/stream_compaction/common.h b/stream_compaction/common.h index ef3579a..35403e8 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -134,5 +134,5 @@ namespace StreamCompaction { // Used as a boolean function for elaborating if a certain element meets criterion // 1 for not met, 0 for met enum ElementAttribute { HAS_MET, NOT_MET }; - +# define MEETCRITERION 0 # define BLOCKSIZE 1024 \ No newline at end of file diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index c6c1e2d..ecc4e13 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -68,13 +68,13 @@ namespace StreamCompaction { for (int i = 0; i != n; ++i) { - if (idata[i] == 0) + if (idata[i] == MEETCRITERION) { - hasChanged[i] = NOT_MET; + hasChanged[i] = HAS_MET; } else { - hasChanged[i] = HAS_MET; + hasChanged[i] = NOT_MET; } } @@ -86,7 +86,7 @@ namespace StreamCompaction { int remaining = 0; for (int i = 0; i < n; ++i) { - if (hasChanged[i] == HAS_MET) + if (hasChanged[i] == NOT_MET) { odata[sum[i]] = idata[i]; ++remaining; From 7fbf4783ebc5e166418c5a997e49acf07e79c93f Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 03:24:57 -0400 Subject: [PATCH 14/19] Cleaning up --- stream_compaction/naive.cu | 1 - 1 file changed, 1 deletion(-) diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 3e64c31..a014ae5 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -25,7 +25,6 @@ namespace StreamCompaction { if (idx >= stride) { odata[idx] = idata[idx - stride] + idata[idx]; - } // Got no element to add else From 4a2166f989c095dfe71bcae57d2e980359cbaa66 Mon Sep 17 00:00:00 2001 From: Uchanka Date: Tue, 18 Sep 2018 23:11:54 -0400 Subject: [PATCH 15/19] Added all the images --- img/2Power.png | Bin 0 -> 22686 bytes img/compact2Power.png | Bin 0 -> 21566 bytes img/compactn2power.png | Bin 0 -> 20124 bytes img/n2power.png | Bin 0 -> 22686 bytes img/thrust2power.png | Bin 0 -> 19059 bytes img/thrustn2power.png | Bin 0 -> 17322 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/2Power.png create mode 100644 img/compact2Power.png create mode 100644 img/compactn2power.png create mode 100644 img/n2power.png create mode 100644 img/thrust2power.png create mode 100644 img/thrustn2power.png diff --git a/img/2Power.png b/img/2Power.png new file mode 100644 index 0000000000000000000000000000000000000000..ba8c513722c408f991fe5dd6f89ef1781b92c56b GIT binary patch literal 22686 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 Z?kq+AF~OlTK$OeH1vf>QR2ZL4{4WG(rvCr{ literal 0 HcmV?d00001 diff --git a/img/compact2Power.png b/img/compact2Power.png new file mode 100644 index 0000000000000000000000000000000000000000..cfba4bbeda4d1666a99df034146a96ec708648fe GIT binary patch literal 21566 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 literal 0 HcmV?d00001 diff --git a/img/compactn2power.png b/img/compactn2power.png new file mode 100644 index 0000000000000000000000000000000000000000..f774ddb8751617e8763c3d4592f302a71c703acd GIT binary patch literal 20124 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 Z?kq+AF~OlTK$OeH1vf>QR2ZL4{4WG(rvCr{ literal 0 HcmV?d00001 diff --git a/img/thrust2power.png b/img/thrust2power.png new file mode 100644 index 0000000000000000000000000000000000000000..6c03e6f8d8cd1f1a040e5f6468f1ca3b391d6a0f GIT binary patch literal 19059 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 F{$D3e)B*qi literal 0 HcmV?d00001 diff --git a/img/thrustn2power.png b/img/thrustn2power.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce3e6414f4402714ddb949e7e3247defdd429b3 GIT binary patch literal 17322 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 literal 0 HcmV?d00001 From ec4654229a3eb62c80102f6d2bea2e0cf4ba16c5 Mon Sep 17 00:00:00 2001 From: AIPC Date: Tue, 18 Sep 2018 23:13:22 -0400 Subject: [PATCH 16/19] Update README --- README.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0e38ddb..55d1e21 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,72 @@ 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) +* Name: Bowen Yang + * [LinkedIn](https://www.linkedin.com/in/%E5%8D%9A%E6%96%87-%E6%9D%A8-83bba6148) + * [GitHub](https://github.com/Grillnov) + * [Facebook](https://www.facebook.com/yang.bowen.7399) + * [Steam](https://steamcommunity.com/id/grillnov) +* Tested on: Windows 10 x64, i7-6800K @ 3.40GHz 32GB, GTX 1080 8GB (Personal computer at home) -### (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.) +Stream compaction from scratch. In our case, we're to filter out all the elements that equals to 0. Analogly it's the dead paths in the list of all the rays. +**Performance Test + +**The results + +``` +**************** +** SCAN TESTS ** +**************** + [ 34 23 45 34 24 43 35 44 26 22 13 28 37 ... 47 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 0.001204ms (std::chrono Measured) + [ 0 34 57 102 136 160 203 238 282 308 330 343 371 ... 6116 6163 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 0.001205ms (std::chrono Measured) + [ 0 34 57 102 136 160 203 238 282 308 330 343 371 ... 6064 6085 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 0.033792ms (CUDA Measured) + passed +==== naive scan, non-power-of-two ==== + elapsed time: 0.032896ms (CUDA Measured) + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 0.123904ms (CUDA Measured) + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 0.126976ms (CUDA Measured) + passed +==== thrust scan, power-of-two ==== + elapsed time: 13.1891ms (CUDA Measured) + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 0.96256ms (CUDA Measured) + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** + [ 0 3 3 0 1 2 0 2 2 2 1 2 2 ... 3 0 ] +==== cpu compact without scan, power-of-two ==== + elapsed time: 0.001506ms (std::chrono Measured) + [ 3 3 1 2 2 2 2 1 2 2 3 2 1 ... 3 3 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 0.002108ms (std::chrono Measured) + [ 3 3 1 2 2 2 2 1 2 2 3 2 1 ... 2 3 ] + passed +==== cpu compact with scan ==== + elapsed time: 0.003313ms (std::chrono Measured) + [ 3 3 1 2 2 2 2 1 2 2 3 2 1 ... 3 3 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 0.23984ms (CUDA Measured) + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 0.238592ms (CUDA Measured) + passed +``` From 69efb3c4984fba3fe25ba066cfa5894745f723b5 Mon Sep 17 00:00:00 2001 From: AIPC Date: Tue, 18 Sep 2018 23:18:19 -0400 Subject: [PATCH 17/19] Update README.md --- README.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 55d1e21..7afa00f 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,40 @@ CUDA Stream Compaction * [Steam](https://steamcommunity.com/id/grillnov) * Tested on: Windows 10 x64, i7-6800K @ 3.40GHz 32GB, GTX 1080 8GB (Personal computer at home) -**Description +**Description** Stream compaction from scratch. In our case, we're to filter out all the elements that equals to 0. Analogly it's the dead paths in the list of all the rays. -**Performance Test +*Part 1: CPU implementation* +*Part 2: Brute force naive reduction on GPU* +*Part 3: Efficient implementation that's actually not so efficient* +*Part 4: Thrust* + +**Performance Test** + +**Scan** + +*When element number is exactly 2-power* +![](img/2Power.png) + +*When element number is not exactly 2-powered* +![](images/n2power.png) + +**Compaction** + +*When element number is exactly 2-powered* +![](images/compact2Power.png) + +*When element number is not exactly 2-powered* +![](images/compactn2power.png) + +**Thrust implementation** + +*When element number is exactly 2-powered* +![](images/thrust2power.png) + +*When element number is not exactly 2-powered* +![](images/thrustn2power.png **The results From 9a0fb2d2f20768a94051ed8ca21f4ad4e854ed87 Mon Sep 17 00:00:00 2001 From: AIPC Date: Tue, 18 Sep 2018 23:19:45 -0400 Subject: [PATCH 18/19] Fixed the pic issues in readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7afa00f..838e351 100644 --- a/README.md +++ b/README.md @@ -27,23 +27,23 @@ Stream compaction from scratch. In our case, we're to filter out all the element ![](img/2Power.png) *When element number is not exactly 2-powered* -![](images/n2power.png) +![](img/n2power.png) **Compaction** *When element number is exactly 2-powered* -![](images/compact2Power.png) +![](img/compact2Power.png) *When element number is not exactly 2-powered* -![](images/compactn2power.png) +![](img/compactn2power.png) **Thrust implementation** *When element number is exactly 2-powered* -![](images/thrust2power.png) +![](img/thrust2power.png) *When element number is not exactly 2-powered* -![](images/thrustn2power.png +![](img/thrustn2power.png **The results From c40523da410bfb63b884dbb256431a9aa882d712 Mon Sep 17 00:00:00 2001 From: AIPC Date: Tue, 18 Sep 2018 23:31:55 -0400 Subject: [PATCH 19/19] Update README.md --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 838e351..e8bd4f0 100644 --- a/README.md +++ b/README.md @@ -19,31 +19,41 @@ Stream compaction from scratch. In our case, we're to filter out all the element *Part 3: Efficient implementation that's actually not so efficient* *Part 4: Thrust* +**Issues** + +Just as always, I modified the `sm_20` option to `sm_60` to make it compile on nvcc 9.2. + **Performance Test** **Scan** *When element number is exactly 2-power* + ![](img/2Power.png) *When element number is not exactly 2-powered* + ![](img/n2power.png) **Compaction** *When element number is exactly 2-powered* + ![](img/compact2Power.png) *When element number is not exactly 2-powered* + ![](img/compactn2power.png) **Thrust implementation** *When element number is exactly 2-powered* + ![](img/thrust2power.png) *When element number is not exactly 2-powered* -![](img/thrustn2power.png + +![](img/thrustn2power.png) **The results @@ -101,3 +111,17 @@ Stream compaction from scratch. In our case, we're to filter out all the element elapsed time: 0.238592ms (CUDA Measured) passed ``` + +**The explanation for the efficiency of the efficient implementation** + +From the charts we find the surprising fact that, *efficient* implementation is actually not that efficient. +2 main reasons for this to happen: + +**I/O intensive** +In our efficient implementation, we have to write the initial element to the GPU buffer or read the last element of the buffer back. This causes lots of system interrupts and therefore is harmful to performance. + +**The reduce algorithm itself** +With the layer going even deeper, stride becomes larger and larger, which, is a behavior that all caches hate. The spatial locality is horrible when the layer goes deep. + +**Something wrong with the thread scheduling** +With the layer going deeper, more and more threads become idle and does nothing useful, and even worse, with the stride growing larger, branch divergence inside warps is getting unacceptable.