From 2d1313b6cd6f3f3707c77c7ef65343792c9a8020 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Wed, 13 Sep 2017 14:40:53 -0400 Subject: [PATCH 01/27] CPU functions --- stream_compaction/cpu.cu | 57 ++++++++++++++++++++++++++++++++------ stream_compaction/naive.cu | 29 +++++++++++++++---- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 05ce667..c47c2ef 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; } /** @@ -19,7 +19,14 @@ namespace StreamCompaction { */ void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); + // TODO + int sum = 0; + for (int i = 0; i < n; ++i ) { + odata[i] = sum; + sum += idata[i]; + } + timer().endCpuTimer(); } @@ -30,9 +37,19 @@ namespace StreamCompaction { */ int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); + // TODO + int num = 0; + for (int i = 0; i < n; ++i) { + int val = idata[i]; + if (val != 0) { + odata[num] = val; + num++; + } + } + timer().endCpuTimer(); - return -1; + return num; } /** @@ -43,8 +60,32 @@ namespace StreamCompaction { int compactWithScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + + int* temp = new int[n]; + int num = 0; + // compute temporary array + for (int i = 0; i < n; ++i) { + temp[i] = (idata[i] == 0) ? 0 : 1; + } + // run exclusive scan on temporary array + int sum = 0; + for (int i = 0; i < n; ++i) { + int val = temp[i]; + temp[i] = sum; + sum += val; + } + + // scatter + for (int i = 1; i < n; ++i) { + if (temp[i] != temp[i-1]) { + odata[num] = idata[i - 1]; + num++; + } + } + + delete[] temp; timer().endCpuTimer(); - return -1; + return num; } } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 9218f8e..698170e 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -5,20 +5,37 @@ 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__ + // TODO + __global__ void kernNaiveScan(int n, int d, int *odata, const int *idata) + { + int index = threadIdx.x; + if (index >= n) return; + + int val = 1 << (d - 1); + for (int k = val; k < n; ++k) { + odata[k] = odata[k] + odata[k - val]; + } + } /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { timer().startGpuTimer(); + // TODO + for (int i = 0; i < n; ++i) odata[i] = idata[i]; + for (int d = 1; d < ilog2ceil(n); ++d) { + kernNaiveScan << <1, n >> > (n, d, odata, idata); + } + checkCUDAError("kernComputeIndices failed!"); + timer().endGpuTimer(); } } From 916ed397c6b3dbcda9c5e7d92c4d14a039a7ba16 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Wed, 13 Sep 2017 15:52:02 -0400 Subject: [PATCH 02/27] kernel compiles but wrong --- src/main.cpp | 6 +++--- stream_compaction/naive.cu | 40 +++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7305641..37df638 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) { printDesc("cpu scan, power-of-two"); StreamCompaction::CPU::scan(SIZE, b, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(SIZE, b, true); + printArray(SIZE, b, false); zeroArray(SIZE, c); printDesc("cpu scan, non-power-of-two"); @@ -49,7 +49,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, false); printCmpResult(SIZE, b, c); zeroArray(SIZE, c); @@ -129,7 +129,7 @@ int main(int argc, char* argv[]) { printDesc("work-efficient compact, power-of-two"); count = StreamCompaction::Efficient::compact(SIZE, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(count, c, true); + printArray(count, c, true); printCmpLenResult(count, expectedCount, b, c); zeroArray(SIZE, c); diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 698170e..44a16a6 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -3,6 +3,8 @@ #include "common.h" #include "naive.h" +#define blockSize 128 + namespace StreamCompaction { namespace Naive { using StreamCompaction::Common::PerformanceTimer; @@ -12,15 +14,12 @@ namespace StreamCompaction { return timer; } // TODO - __global__ void kernNaiveScan(int n, int d, int *odata, const int *idata) + __global__ void kernNaiveScan(int n, int val, int *odata, int *idata) { - int index = threadIdx.x; + int index = (blockIdx.x * blockDim.x) + threadIdx.x; if (index >= n) return; - int val = 1 << (d - 1); - for (int k = val; k < n; ++k) { - odata[k] = odata[k] + odata[k - val]; - } + odata[index] = (n >= val) ? idata[index] + idata[index - val] : idata[index]; } /** @@ -30,11 +29,34 @@ namespace StreamCompaction { timer().startGpuTimer(); // TODO - for (int i = 0; i < n; ++i) odata[i] = idata[i]; + int *dev_in; + int *dev_out; + + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + + cudaMalloc((void**)&dev_in, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_in failed!"); + + cudaMalloc((void**)&dev_out, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_in failed!"); + + cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_in failed!"); + cudaMemcpy(dev_out, odata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_out failed!"); + for (int d = 1; d < ilog2ceil(n); ++d) { - kernNaiveScan << <1, n >> > (n, d, odata, idata); + int val = 1 << (d - 1); + kernNaiveScan << > > (n, val, dev_out, dev_in); + std::swap(dev_in, dev_out); + checkCUDAError("kernNaiveScan failed!"); } - checkCUDAError("kernComputeIndices failed!"); + + cudaMemcpy(odata, dev_in, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + cudaFree(dev_in); + cudaFree(dev_out); timer().endGpuTimer(); } From 1630006d91155a9a1d490ff101503b4400aaea51 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Thu, 14 Sep 2017 15:45:12 -0400 Subject: [PATCH 03/27] work efficient scan --- CMakeLists.txt | 1 + src/main.cpp | 24 +++++---- stream_compaction/CMakeLists.txt | 4 +- stream_compaction/cpu.cu | 7 +-- stream_compaction/efficient.cu | 84 ++++++++++++++++++++++++++++---- stream_compaction/naive.cu | 15 +++--- 6 files changed, 103 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16abe08..a51d998 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_CXX_STANDARD 11) list(APPEND CUDA_NVCC_FLAGS_DEBUG -G -g) list(APPEND CUDA_NVCC_FLAGS_RELWITHDEBUGINFO -lineinfo) +list(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_60,code=sm_60) # Crucial magic for CUDA linking find_package(Threads REQUIRED) diff --git a/src/main.cpp b/src/main.cpp index 37df638..f51985c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,8 @@ #include #include "testing_helpers.hpp" -const int SIZE = 1 << 8; // feel free to change the size of array +//const int SIZE = 1 << 8; // feel free to change the size of array +const int SIZE = 1 << 3; const int NPOT = SIZE - 3; // Non-Power-Of-Two int a[SIZE], b[SIZE], c[SIZE]; @@ -25,8 +26,11 @@ int main(int argc, char* argv[]) { printf("** SCAN TESTS **\n"); printf("****************\n"); - genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case - a[SIZE - 1] = 0; + //genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case + //a[SIZE - 1] = 0; + + for (int i = 0; i < SIZE; ++i) a[i] = i; + printArray(SIZE, a, true); // initialize b using StreamCompaction::CPU::scan you implement @@ -36,7 +40,7 @@ int main(int argc, char* argv[]) { printDesc("cpu scan, power-of-two"); StreamCompaction::CPU::scan(SIZE, b, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(SIZE, b, false); + printArray(SIZE, b, true); zeroArray(SIZE, c); printDesc("cpu scan, non-power-of-two"); @@ -49,42 +53,42 @@ 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, false); + printArray(SIZE, c, true); printCmpResult(SIZE, b, c); zeroArray(SIZE, c); printDesc("naive scan, non-power-of-two"); StreamCompaction::Naive::scan(NPOT, c, a); printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(SIZE, c, true); + printArray(NPOT, c, true); printCmpResult(NPOT, b, c); zeroArray(SIZE, c); 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); printDesc("thrust scan, power-of-two"); StreamCompaction::Thrust::scan(SIZE, c, a); printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(SIZE, c, true); + printArray(SIZE, c, true); printCmpResult(SIZE, b, c); zeroArray(SIZE, c); printDesc("thrust scan, non-power-of-two"); StreamCompaction::Thrust::scan(NPOT, c, a); printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(NPOT, c, true); + printArray(NPOT, c, true); printCmpResult(NPOT, b, c); printf("\n"); diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index cdbef77..595d731 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 + ) \ No newline at end of file diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index c47c2ef..c107c81 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -61,7 +61,8 @@ namespace StreamCompaction { timer().startCpuTimer(); // TODO - int* temp = new int[n]; + int* temp = new int[n + 1]; + temp[n] = 0; int num = 0; // compute temporary array for (int i = 0; i < n; ++i) { @@ -69,14 +70,14 @@ namespace StreamCompaction { } // run exclusive scan on temporary array int sum = 0; - for (int i = 0; i < n; ++i) { + for (int i = 0; i <= n; ++i) { int val = temp[i]; temp[i] = sum; sum += val; } // scatter - for (int i = 1; i < n; ++i) { + for (int i = 1; i <= n; ++i) { if (temp[i] != temp[i-1]) { odata[num] = idata[i - 1]; num++; diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 36c5ef2..2a49784 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,22 +3,88 @@ #include "common.h" #include "efficient.h" +#define blockSize 128 + 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 kernZeroed(int totalN, int n, int *odata) + { + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= totalN) return; + + odata[index] = (index < n) ? odata[index] : 0; + } + + __global__ void kernUpSweep(int n, int d, int *odata) + { + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + int offset = 1 << (d + 1); + int i = (index + 1) * offset - 1; + + int val = 1 << d; + odata[i] += odata[i - val]; + if (i == n - 1) odata[i] = 0; + } + + __global__ void kernDownSweep(int n, int d, int *odata) + { + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + int i = index + 1; + int val = 1 << d; + int offset = 1 << (d + 1); + int temp = odata[i * offset - 1]; + odata[i * offset - 1] += odata[i * offset - val - 1]; + odata[i * offset - val - 1] = temp; + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ - void scan(int n, int *odata, const int *idata) { - timer().startGpuTimer(); - // TODO - timer().endGpuTimer(); + void scan(int n, int *odata, const int *idata) + { + int *dev_out; + int pow2n = 1 << ilog2ceil(n); + + cudaMalloc((void**)&dev_out, pow2n * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + + cudaMemcpy(dev_out, idata, pow2n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_out failed!"); + + timer().startGpuTimer(); + dim3 blocksPerGrid((pow2n + blockSize - 1) / blockSize); + kernZeroed << > > (pow2n, n, dev_out); + checkCUDAError("kernZeroed failed!"); + + for (int d = 0; d < ilog2ceil(pow2n); ++d) { + dim3 blocksPerGrid((pow2n /(1 << (d + 1)) + blockSize - 1) / blockSize); + kernUpSweep << > > (pow2n, d, dev_out); + checkCUDAError("kernUpSweep failed!"); + } + + for (int d = ilog2ceil(pow2n) - 1; d >= 0; --d) { + dim3 blocksPerGrid((pow2n / (1 << (d + 1)) + blockSize - 1) / blockSize); + kernDownSweep << > > (pow2n, d, dev_out); + checkCUDAError("kernDownSweep failed!"); + } + + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + cudaFree(dev_out); } /** diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 44a16a6..252a718 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -18,16 +18,14 @@ namespace StreamCompaction { { int index = (blockIdx.x * blockDim.x) + threadIdx.x; if (index >= n) return; - - odata[index] = (n >= val) ? idata[index] + idata[index - val] : idata[index]; + odata[index] = (index >= val) ? idata[index] + idata[index - val] : idata[index]; } /** * 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 *dev_in; int *dev_out; @@ -45,20 +43,21 @@ namespace StreamCompaction { cudaMemcpy(dev_out, odata, n * sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy dev_out failed!"); - for (int d = 1; d < ilog2ceil(n); ++d) { + timer().startGpuTimer(); + for (int d = 1; d <= ilog2ceil(n); ++d) { int val = 1 << (d - 1); kernNaiveScan << > > (n, val, dev_out, dev_in); std::swap(dev_in, dev_out); checkCUDAError("kernNaiveScan failed!"); } - cudaMemcpy(odata, dev_in, n * sizeof(int), cudaMemcpyDeviceToHost); + timer().endGpuTimer(); + + cudaMemcpy(odata + 1, dev_in, n * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); cudaFree(dev_in); cudaFree(dev_out); - - timer().endGpuTimer(); } } } From 705bd52241c157156d7d90e2073d461cf79c5a03 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Thu, 14 Sep 2017 16:38:08 -0400 Subject: [PATCH 04/27] scatter --- src/main.cpp | 2 +- stream_compaction/common.cu | 10 ++++++++++ stream_compaction/efficient.cu | 36 ++++++++++++++++++++++++++++++---- stream_compaction/thrust.cu | 34 ++++++++++++++++++++++++++------ 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f51985c..2f11606 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -140,7 +140,7 @@ int main(int argc, char* argv[]) { printDesc("work-efficient compact, non-power-of-two"); count = StreamCompaction::Efficient::compact(NPOT, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(count, c, true); + printArray(count, c, true); printCmpLenResult(count, expectedNPOT, b, c); system("pause"); // stop Win32 console from closing on exit diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 8fc0211..a66ea91 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -24,6 +24,10 @@ namespace StreamCompaction { */ __global__ void kernMapToBoolean(int n, int *bools, const int *idata) { // TODO + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + bools[index] = (idata[index] != 0 || index == n - 1) ? 1 : 0; } /** @@ -33,6 +37,12 @@ namespace StreamCompaction { __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools, const int *indices) { // TODO + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + if (bools[index] == 1) { + odata[indices[index]] = idata[index]; + } } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 2a49784..d22624b 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -96,10 +96,38 @@ namespace StreamCompaction { * @param idata The array of elements to compact. * @returns The number of elements remaining after compaction. */ - int compact(int n, int *odata, const int *idata) { - timer().startGpuTimer(); - // TODO - timer().endGpuTimer(); + int compact(int n, int *odata, const int *idata) + { + // TODO + int *bools; + int *dev_in; + + cudaMalloc((void**)&bools, (n + 1) * sizeof(int)); + checkCUDAError("cudaMalloc bools failed!"); + + cudaMalloc((void**)&dev_in, (n + 1) * sizeof(int)); + checkCUDAError("cudaMalloc dev_in failed!"); + + cudaMemcpy(dev_in, idata, (n + 1) * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_in failed!"); + + timer().startGpuTimer(); + + dim3 blocksPerGrid((n + blockSize) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (n+1, bools, dev_in); + checkCUDAError("kernMapToBoolean failed!"); + + /*scan(n + 1, odata, bools); + + dim3 blocksPerGrid((n + blockSize) / blockSize); + StreamCompaction::Common::kernScatter << > > (n + 1, odata, idata, bools, indices); + checkCUDAError("kernScatter failed!");*/ + + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_in, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + return -1; } } diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 36b732d..351b8dd 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -8,21 +8,43 @@ 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) { + + int *dev_in; + int *dev_out; + + cudaMalloc((void**)&dev_in, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_in failed!"); + + cudaMalloc((void**)&dev_out, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + + cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_in failed!"); + + cudaMemcpy(dev_out, odata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_in failed!"); + 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::exclusive_scan(dev_in, dev_in + n, dev_out); + + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + } } } From 861fd8e3cb0282ad8a2c8b041bf7406d9c004013 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Fri, 15 Sep 2017 17:26:21 -0400 Subject: [PATCH 05/27] race conditions? --- src/main.cpp | 45 ++++---- stream_compaction/common.cu | 11 +- stream_compaction/common.h | 200 ++++++++++++++++----------------- stream_compaction/cpu.cu | 22 ++-- stream_compaction/efficient.cu | 60 ++++++---- stream_compaction/thrust.cu | 36 +++--- 6 files changed, 193 insertions(+), 181 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2f11606..ea2d683 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,8 +13,7 @@ #include #include "testing_helpers.hpp" -//const int SIZE = 1 << 8; // feel free to change the size of array -const int SIZE = 1 << 3; +const int SIZE = 1 << 5; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int a[SIZE], b[SIZE], c[SIZE]; @@ -26,10 +25,8 @@ int main(int argc, char* argv[]) { printf("** SCAN TESTS **\n"); printf("****************\n"); - //genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case - //a[SIZE - 1] = 0; - - for (int i = 0; i < SIZE; ++i) a[i] = i; + genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case + a[SIZE - 1] = 0; printArray(SIZE, a, true); @@ -102,46 +99,46 @@ int main(int argc, char* argv[]) { a[SIZE - 1] = 0; printArray(SIZE, a, true); - int count, expectedCount, expectedNPOT; + int countSIZE, countNPOT, expectedSIZE, expectedNPOT; // initialize b using StreamCompaction::CPU::compactWithoutScan you implement // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. zeroArray(SIZE, b); printDesc("cpu compact without scan, power-of-two"); - count = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); + countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - expectedCount = count; - printArray(count, b, true); - printCmpLenResult(count, expectedCount, b, b); + expectedSIZE = countSIZE; + printArray(expectedSIZE, b, true); + printCmpLenResult(countSIZE, expectedSIZE, b, b); zeroArray(SIZE, c); printDesc("cpu compact without scan, non-power-of-two"); - count = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); + countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - expectedNPOT = count; - printArray(count, c, true); - printCmpLenResult(count, expectedNPOT, b, c); + expectedNPOT = countNPOT; + printArray(countNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); zeroArray(SIZE, c); printDesc("cpu compact with scan"); - count = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(count, c, true); - printCmpLenResult(count, expectedCount, b, c); + printArray(countSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); zeroArray(SIZE, c); printDesc("work-efficient compact, power-of-two"); - count = StreamCompaction::Efficient::compact(SIZE, c, a); + countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(count, c, true); - printCmpLenResult(count, expectedCount, b, c); + printArray(expectedSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); zeroArray(SIZE, c); printDesc("work-efficient compact, non-power-of-two"); - count = StreamCompaction::Efficient::compact(NPOT, c, a); + countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(count, c, true); - printCmpLenResult(count, expectedNPOT, b, c); + printArray(expectedNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index a66ea91..2ba70c7 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -34,16 +34,15 @@ namespace StreamCompaction { * Performs scatter on an array. That is, for each element in idata, * if bools[idx] == 1, it copies idata[idx] to odata[indices[idx]]. */ - __global__ void kernScatter(int n, int *odata, - const int *idata, const int *bools, const int *indices) { + __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; if (index >= n) return; - if (bools[index] == 1) { - odata[indices[index]] = idata[index]; + int idx = bools[index]; + if (bools[index + 1] != idx) { + odata[idx] = idata[index]; } } - } -} +} \ No newline at end of file diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 55f1b38..9d0a895 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -1,14 +1,14 @@ #pragma once -#include -#include - -#include -#include -#include -#include +#include +#include + +#include +#include +#include +#include #include -#include +#include #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) @@ -35,98 +35,98 @@ namespace StreamCompaction { __global__ void kernMapToBoolean(int n, int *bools, const int *idata); __global__ void kernScatter(int n, int *odata, - const int *idata, const int *bools, const int *indices); - - /** - * This class is used for timing the performance - * Uncopyable and unmovable - * - * Adapted from WindyDarian(https://github.com/WindyDarian) - */ - class PerformanceTimer - { - public: - PerformanceTimer() - { - cudaEventCreate(&event_start); - cudaEventCreate(&event_end); - } - - ~PerformanceTimer() - { - cudaEventDestroy(event_start); - cudaEventDestroy(event_end); - } - - void startCpuTimer() - { - if (cpu_timer_started) { throw std::runtime_error("CPU timer already started"); } - cpu_timer_started = true; - - time_start_cpu = std::chrono::high_resolution_clock::now(); - } - - void endCpuTimer() - { - time_end_cpu = std::chrono::high_resolution_clock::now(); - - if (!cpu_timer_started) { throw std::runtime_error("CPU timer not started"); } - - std::chrono::duration duro = time_end_cpu - time_start_cpu; - prev_elapsed_time_cpu_milliseconds = - static_cast(duro.count()); - - cpu_timer_started = false; - } - - void startGpuTimer() - { - if (gpu_timer_started) { throw std::runtime_error("GPU timer already started"); } - gpu_timer_started = true; - - cudaEventRecord(event_start); - } - - void endGpuTimer() - { - cudaEventRecord(event_end); - cudaEventSynchronize(event_end); - - if (!gpu_timer_started) { throw std::runtime_error("GPU timer not started"); } - - cudaEventElapsedTime(&prev_elapsed_time_gpu_milliseconds, event_start, event_end); - gpu_timer_started = false; - } - - float getCpuElapsedTimeForPreviousOperation() //noexcept //(damn I need VS 2015 - { - return prev_elapsed_time_cpu_milliseconds; - } - - float getGpuElapsedTimeForPreviousOperation() //noexcept - { - return prev_elapsed_time_gpu_milliseconds; - } - - // remove copy and move functions - PerformanceTimer(const PerformanceTimer&) = delete; - PerformanceTimer(PerformanceTimer&&) = delete; - PerformanceTimer& operator=(const PerformanceTimer&) = delete; - PerformanceTimer& operator=(PerformanceTimer&&) = delete; - - private: - cudaEvent_t event_start = nullptr; - cudaEvent_t event_end = nullptr; - - using time_point_t = std::chrono::high_resolution_clock::time_point; - time_point_t time_start_cpu; - time_point_t time_end_cpu; - - bool cpu_timer_started = false; - bool gpu_timer_started = false; - - float prev_elapsed_time_cpu_milliseconds = 0.f; - float prev_elapsed_time_gpu_milliseconds = 0.f; + const int *idata, const int *bools); + + /** + * This class is used for timing the performance + * Uncopyable and unmovable + * + * Adapted from WindyDarian(https://github.com/WindyDarian) + */ + class PerformanceTimer + { + public: + PerformanceTimer() + { + cudaEventCreate(&event_start); + cudaEventCreate(&event_end); + } + + ~PerformanceTimer() + { + cudaEventDestroy(event_start); + cudaEventDestroy(event_end); + } + + void startCpuTimer() + { + if (cpu_timer_started) { throw std::runtime_error("CPU timer already started"); } + cpu_timer_started = true; + + time_start_cpu = std::chrono::high_resolution_clock::now(); + } + + void endCpuTimer() + { + time_end_cpu = std::chrono::high_resolution_clock::now(); + + if (!cpu_timer_started) { throw std::runtime_error("CPU timer not started"); } + + std::chrono::duration duro = time_end_cpu - time_start_cpu; + prev_elapsed_time_cpu_milliseconds = + static_cast(duro.count()); + + cpu_timer_started = false; + } + + void startGpuTimer() + { + if (gpu_timer_started) { throw std::runtime_error("GPU timer already started"); } + gpu_timer_started = true; + + cudaEventRecord(event_start); + } + + void endGpuTimer() + { + cudaEventRecord(event_end); + cudaEventSynchronize(event_end); + + if (!gpu_timer_started) { throw std::runtime_error("GPU timer not started"); } + + cudaEventElapsedTime(&prev_elapsed_time_gpu_milliseconds, event_start, event_end); + gpu_timer_started = false; + } + + float getCpuElapsedTimeForPreviousOperation() //noexcept //(damn I need VS 2015 + { + return prev_elapsed_time_cpu_milliseconds; + } + + float getGpuElapsedTimeForPreviousOperation() //noexcept + { + return prev_elapsed_time_gpu_milliseconds; + } + + // remove copy and move functions + PerformanceTimer(const PerformanceTimer&) = delete; + PerformanceTimer(PerformanceTimer&&) = delete; + PerformanceTimer& operator=(const PerformanceTimer&) = delete; + PerformanceTimer& operator=(PerformanceTimer&&) = delete; + + private: + cudaEvent_t event_start = nullptr; + cudaEvent_t event_end = nullptr; + + using time_point_t = std::chrono::high_resolution_clock::time_point; + time_point_t time_start_cpu; + time_point_t time_end_cpu; + + bool cpu_timer_started = false; + bool gpu_timer_started = false; + + float prev_elapsed_time_cpu_milliseconds = 0.f; + float prev_elapsed_time_gpu_milliseconds = 0.f; }; } } diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index c107c81..dbd5ffd 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -12,21 +12,25 @@ namespace StreamCompaction { return timer; } + void scan_implementation(int n, int *odata, const int *idata) + { + // TODO + int sum = 0; + for (int i = 0; i < n; ++i) { + odata[i] = sum; + sum += idata[i]; + } + } + /** * CPU scan (prefix sum). * For performance analysis, this is supposed to be a simple for loop. * (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) { + void scan(int n, int *odata, const int *idata) + { timer().startCpuTimer(); - - // TODO - int sum = 0; - for (int i = 0; i < n; ++i ) { - odata[i] = sum; - sum += idata[i]; - } - + scan_implementation(n, odata, idata); timer().endCpuTimer(); } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index d22624b..de549e1 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -48,6 +48,23 @@ namespace StreamCompaction { odata[i * offset - val - 1] = temp; } + void scan_implementation(int n, int *dev_out) + { + int pow2n = 1 << ilog2ceil(n); + + for (int d = 0; d < ilog2ceil(pow2n); ++d) { + dim3 blocksPerGrid((pow2n / (1 << (d + 1)) + blockSize - 1) / blockSize); + kernUpSweep << > > (pow2n, d, dev_out); + checkCUDAError("kernUpSweep failed!"); + } + + for (int d = ilog2ceil(pow2n) - 1; d >= 0; --d) { + dim3 blocksPerGrid((pow2n / (1 << (d + 1)) + blockSize - 1) / blockSize); + kernDownSweep << > > (pow2n, d, dev_out); + checkCUDAError("kernDownSweep failed!"); + } + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ @@ -62,23 +79,12 @@ namespace StreamCompaction { cudaMemcpy(dev_out, idata, pow2n * sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy dev_out failed!"); - timer().startGpuTimer(); dim3 blocksPerGrid((pow2n + blockSize - 1) / blockSize); kernZeroed << > > (pow2n, n, dev_out); checkCUDAError("kernZeroed failed!"); - - for (int d = 0; d < ilog2ceil(pow2n); ++d) { - dim3 blocksPerGrid((pow2n /(1 << (d + 1)) + blockSize - 1) / blockSize); - kernUpSweep << > > (pow2n, d, dev_out); - checkCUDAError("kernUpSweep failed!"); - } - - for (int d = ilog2ceil(pow2n) - 1; d >= 0; --d) { - dim3 blocksPerGrid((pow2n / (1 << (d + 1)) + blockSize - 1) / blockSize); - kernDownSweep << > > (pow2n, d, dev_out); - checkCUDAError("kernDownSweep failed!"); - } - + + timer().startGpuTimer(); + scan_implementation(n, dev_out); timer().endGpuTimer(); cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); @@ -99,10 +105,12 @@ namespace StreamCompaction { int compact(int n, int *odata, const int *idata) { // TODO - int *bools; + int *dbools; int *dev_in; + int *dev_out; + int *indices; - cudaMalloc((void**)&bools, (n + 1) * sizeof(int)); + cudaMalloc((void**)&dbools, (n + 1) * sizeof(int)); checkCUDAError("cudaMalloc bools failed!"); cudaMalloc((void**)&dev_in, (n + 1) * sizeof(int)); @@ -113,22 +121,26 @@ namespace StreamCompaction { timer().startGpuTimer(); - dim3 blocksPerGrid((n + blockSize) / blockSize); - StreamCompaction::Common::kernMapToBoolean << > > (n+1, bools, dev_in); + dim3 blocksPerGrid1((n + blockSize) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (n+1, dbools, dev_in); checkCUDAError("kernMapToBoolean failed!"); - /*scan(n + 1, odata, bools); + scan_implementation(n + 1, dbools); - dim3 blocksPerGrid((n + blockSize) / blockSize); - StreamCompaction::Common::kernScatter << > > (n + 1, odata, idata, bools, indices); - checkCUDAError("kernScatter failed!");*/ + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools); + checkCUDAError("kernScatter failed!"); timer().endGpuTimer(); - cudaMemcpy(odata, dev_in, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + int *num = (int *)malloc(sizeof(int)); + cudaMemcpy(num, dbools + n , sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); - return -1; + return *num; } } } diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 351b8dd..e10c811 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -19,31 +19,31 @@ namespace StreamCompaction { */ void scan(int n, int *odata, const int *idata) { - int *dev_in; - int *dev_out; + //int *dev_in; + //int *dev_out; - cudaMalloc((void**)&dev_in, n * sizeof(int)); - checkCUDAError("cudaMalloc dev_in failed!"); + //cudaMalloc((void**)&dev_in, n * sizeof(int)); + //checkCUDAError("cudaMalloc dev_in failed!"); - cudaMalloc((void**)&dev_out, n * sizeof(int)); - checkCUDAError("cudaMalloc dev_out failed!"); + //cudaMalloc((void**)&dev_out, n * sizeof(int)); + //checkCUDAError("cudaMalloc dev_out failed!"); - cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); - checkCUDAError("cudaMemcpy dev_in failed!"); + //cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); + //checkCUDAError("cudaMemcpy dev_in failed!"); - cudaMemcpy(dev_out, odata, n * sizeof(int), cudaMemcpyHostToDevice); - checkCUDAError("cudaMemcpy dev_in failed!"); + //cudaMemcpy(dev_out, odata, n * sizeof(int), cudaMemcpyHostToDevice); + //checkCUDAError("cudaMemcpy dev_in failed!"); - 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_in, dev_in + n, dev_out); + // 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_in, dev_in + n, dev_out); - timer().endGpuTimer(); + //timer().endGpuTimer(); - cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); - checkCUDAError("cudaMemcpyDeviceToHost failed!"); + //cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + //checkCUDAError("cudaMemcpyDeviceToHost failed!"); } } From f69f9c119d70c4165d67389954ad721b3fb96064 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Fri, 15 Sep 2017 17:49:28 -0400 Subject: [PATCH 06/27] thrust --- src/main.cpp | 2 +- stream_compaction/thrust.cu | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ea2d683..e75f631 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,7 @@ #include #include "testing_helpers.hpp" -const int SIZE = 1 << 5; // feel free to change the size of array +const int SIZE = 1 << 8; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int a[SIZE], b[SIZE], c[SIZE]; diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index e10c811..35ea3dc 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -19,31 +19,18 @@ namespace StreamCompaction { */ void scan(int n, int *odata, const int *idata) { - //int *dev_in; - //int *dev_out; + thrust::host_vector host_in = thrust::host_vector(idata, idata + n); + thrust::host_vector host_out = thrust::host_vector(odata, odata + n); - //cudaMalloc((void**)&dev_in, n * sizeof(int)); - //checkCUDAError("cudaMalloc dev_in failed!"); + thrust::device_vector dev_in = thrust::device_vector(host_in); + thrust::device_vector dev_out = thrust::device_vector(host_out); - //cudaMalloc((void**)&dev_out, n * sizeof(int)); - //checkCUDAError("cudaMalloc dev_out failed!"); + // TODO + timer().startGpuTimer(); + thrust::exclusive_scan(dev_in.begin(), dev_in.end(), dev_out.begin()); + timer().endGpuTimer(); - //cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); - //checkCUDAError("cudaMemcpy dev_in failed!"); - - //cudaMemcpy(dev_out, odata, n * sizeof(int), cudaMemcpyHostToDevice); - //checkCUDAError("cudaMemcpy dev_in failed!"); - - // 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_in, dev_in + n, dev_out); - - //timer().endGpuTimer(); - - //cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); - //checkCUDAError("cudaMemcpyDeviceToHost failed!"); + thrust::copy(dev_out.begin(), dev_out.end(), odata); } } From 14893cf2f5216a01bde09ebb114a8ff981a89a83 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Fri, 15 Sep 2017 20:55:53 -0400 Subject: [PATCH 07/27] performance --- performance.xlsx | Bin 0 -> 19609 bytes src/main.cpp | 2 +- stream_compaction/common.h | 1 + stream_compaction/efficient.cu | 2 -- stream_compaction/naive.cu | 2 -- 5 files changed, 2 insertions(+), 5 deletions(-) create mode 100644 performance.xlsx diff --git a/performance.xlsx b/performance.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..653579af2c4a5438ad0d96961daac924e5b3db03 GIT binary patch literal 19609 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 literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index e75f631..478bd58 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 << 12; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int a[SIZE], b[SIZE], c[SIZE]; diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 9d0a895..8229c25 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 128 /** * 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 de549e1..a9267fb 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,8 +3,6 @@ #include "common.h" #include "efficient.h" -#define blockSize 128 - namespace StreamCompaction { namespace Efficient { using StreamCompaction::Common::PerformanceTimer; diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 252a718..713eaa3 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -3,8 +3,6 @@ #include "common.h" #include "naive.h" -#define blockSize 128 - namespace StreamCompaction { namespace Naive { using StreamCompaction::Common::PerformanceTimer; From 7675dbbf3408828adde4a3f9f5fe2e3a4d5bb9a8 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Sun, 17 Sep 2017 19:26:20 -0400 Subject: [PATCH 08/27] radix sort, untested --- stream_compaction/CMakeLists.txt | 2 + stream_compaction/efficient.cu | 15 +++- stream_compaction/radix.cu | 148 +++++++++++++++++++++++++++++++ stream_compaction/radix.h | 11 +++ 4 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 stream_compaction/radix.cu create mode 100644 stream_compaction/radix.h diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index 595d731..68d8d1f 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/efficient.cu b/stream_compaction/efficient.cu index a9267fb..25fce23 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -106,7 +106,7 @@ namespace StreamCompaction { int *dbools; int *dev_in; int *dev_out; - int *indices; + // int *indices; cudaMalloc((void**)&dbools, (n + 1) * sizeof(int)); checkCUDAError("cudaMalloc bools failed!"); @@ -125,6 +125,9 @@ namespace StreamCompaction { scan_implementation(n + 1, dbools); + cudaMalloc((void**)&dev_out, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools); checkCUDAError("kernScatter failed!"); @@ -137,8 +140,16 @@ namespace StreamCompaction { int *num = (int *)malloc(sizeof(int)); cudaMemcpy(num, dbools + n , sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + int ret = *num; + free(num); + + cudaFree(dbools); + cudaFree(dev_in); + cudaFree(dev_out); + // cudaFree(indices); - return *num; + return ret; } } } diff --git a/stream_compaction/radix.cu b/stream_compaction/radix.cu new file mode 100644 index 0000000..3856d55 --- /dev/null +++ b/stream_compaction/radix.cu @@ -0,0 +1,148 @@ +#include +#include +#include "common.h" +#include "efficient.h" + +namespace StreamCompaction { + namespace Radix { + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; + } + + /** + * Maps an array to an array of 0s and 1s for bit n. + */ + __global__ void kernMapToBoolean(int n, int k, int *bools, const int *idata) { + // TODO + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + int val = 1 << k; + bools[index] = (idata[index] & val != 0) ? 0 : 1; + } + + /** + * Computes t array: t[i] = i - f[i] + totalFalses; f = idata, t = odata + */ + __global__ void kernComputeT(int n, int totalFalses, int *odata, const int *idata) { + // TODO + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + odata[index] = index - idata[index] + totalFalses; + } + + /** + * Computes d array: d[i] = e[i] ? f[i] : t[i]; + */ + __global__ void kernComputeD(int n, int *e, const int *f, const int *t) { + // TODO + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + e[index] = (e[index] != 0) ? f[index] : t[index]; + } + + /** + * Computes scattered array based on D indices + */ + __global__ void kernScatterD(int n, int *odata, int *indices, const int *idata) { + // TODO + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + odata[indices[index]] = idata[index]; + } + + void sort_implementation(int n, int k, int* last_e, int* last_f, + int *e_arr, int *f_arr, int *t_arr, int *dev_in) + { + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + + // Step 1: compute e array + kernMapToBoolean<<>>(n, k, f_arr, dev_in); + checkCUDAError("kernMapToBoolean failed!"); + + cudaMemcpy(e_arr, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); + checkCUDAError("cudaMemcpyDeviceToDevice failed!"); + + // Step 2: exclusive scan e + scan_implementation(n, f_arr); + + // Step 3: compute totalFalses + cudaMemcpy(last_e, e_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("last_e cudaMemcpyDeviceToHost failed!"); + + cudaMemcpy(last_f, dbools + n - 1 , sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("last_f cudaMemcpyDeviceToHost failed!"); + + int totalFalses = *last_e + *last_f; + + // Step 4: compute t array + kernComputeT<<>>(n, totalFalses, t_arr, f_arr); + checkCUDAError("kernComputeT failed!"); + + // Step 4: scatter based on address d + kernComputeD<<>>(n, e_arr, f_arr, t_arr); + checkCUDAError("kernComputeD failed!"); + + kernScatterD<<>>(n, f_arr, e_arr, dev_in); + checkCUDAError("kernScatterD failed!"); + } + + /** + * Performs radix sort on idata, storing the result into odata. + * + * @param n The number of elements in idata. + * @param odata The array into which to store elements. + * @param idata The array of elements to compact. + * @returns The number of elements remaining after compaction. + */ + void sort(int n, int *odata, const int *idata) + { + // TODO + int *e_arr; + int *f_arr; + int *t_arr; + int *dev_in; + + int *last_e = (int *)malloc(sizeof(int)); + int *last_f = (int *)malloc(sizeof(int)); + + cudaMalloc((void**)&e_arr, n * sizeof(int)); + checkCUDAError("cudaMalloc e_arr failed!"); + + cudaMalloc((void**)&f_arr, n * sizeof(int)); + checkCUDAError("cudaMalloc f_arr failed!"); + + cudaMalloc((void**)&t_arr, n * sizeof(int)); + checkCUDAError("cudaMalloc t_arr failed!"); + + cudaMalloc((void**)&dev_in, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_in failed!"); + + cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_in failed!"); + + timer().startGpuTimer(); + for (int k = 0; k < 8 * sizeof(int); ++k) { + sort_implementation(n, k, last_e, last_f, e_arr, f_arr, t_arr, dev_in); + } + timer().endGpuTimer(); + + cudaMemcpy(odata, f_arr, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + free(last_e); + free(last_f); + + cudaFree(e_arr); + cudaFree(f_arr); + cudaFree(t_arr); + cudaFree(dev_in); + } + } +} 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); + } +} From 50e566d69edaa635c87f42806e85ca6ff7ef27ce Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Sun, 17 Sep 2017 23:58:36 -0400 Subject: [PATCH 09/27] testing --- src/main.cpp | 36 ++++++++++++++++++++++++++++++++++++ stream_compaction/cpu.cu | 19 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 478bd58..3a6c4b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -140,5 +140,41 @@ int main(int argc, char* argv[]) { printArray(expectedNPOT, c, true); printCmpLenResult(countNPOT, expectedNPOT, b, c); + printf("\n"); + printf("*****************************\n"); + printf("** RADIX SORT TESTS **\n"); + printf("*****************************\n"); + + // Radix Tests + + genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case + printArray(SIZE, a, true); + + zeroArray(SIZE, b); + printDesc("cpu sort, power-of-two"); + StreamCompaction::CPU::sort(SIZE, b, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(SIZE, b, true); + + zeroArray(SIZE, c); + printDesc("cpu sort, non-power-of-two"); + StreamCompaction::CPU::sort(NPOT, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(NPOT, b, true); + + zeroArray(SIZE, c); + printDesc("radix sort, power-of-two"); + StreamCompaction::Radix::sort(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, c, true); + printCmpResult(SIZE, b, c); + + zeroArray(SIZE, c); + printDesc("radix sort, non-power-of-two"); + StreamCompaction::Radix::sort(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, c, true); + printCmpResult(NPOT, b, c); + system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index dbd5ffd..8ea6230 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -92,5 +92,24 @@ namespace StreamCompaction { timer().endCpuTimer(); return num; } + + /** + * CPU sort + */ + void sort_implementation(int n, int *odata, const int *idata) + { + // TODO + } + + /** + * CPU sort + */ + void sort(int n, int *odata, const int *idata) + { + timer().startCpuTimer(); + sort_implementation(n, odata, idata); + timer().endCpuTimer(); + } + } } From 8908c5e80880c74c4f2e1b92e930dbb13ea48e38 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Mon, 18 Sep 2017 10:21:31 -0400 Subject: [PATCH 10/27] radix cpu --- stream_compaction/cpu.cu | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 8ea6230..7d7ac6a 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -93,12 +93,46 @@ namespace StreamCompaction { return num; } + int findMax(int n, const int *idata) + { + int max = idata[0]; + for (int i = 1; i < n; ++i) { + int val = idata[i]; + if (val > max) { + max = val; + } + } + } + + void countSort(int n, int d, int *odata, int *idata) + { + int count[10] = {0}; + + for (int i = 0; i < n; ++i) { + count[(idata[i]/d)%10] ++; + } + + for (int i = 1; i < 10; ++i) { + count[i] += count[i - 1]; + } + + for (int i = n - 1; i >= 0; --i) { + odata[ count[(idata[i]/d)%10] - 1] = idata[i]; + count[(idata[i]/d)%10] --; + } + } + /** * CPU sort */ void sort_implementation(int n, int *odata, const int *idata) { // TODO + int max = findMax(n, idata); + for (int d = 1; max/d > 0; d *= 10) { + countSort(n, d, odata, idata); + std::swap(idata, odata); + } } /** From 5a668e39946db1cadc62ee224bd5712acc098716 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Mon, 18 Sep 2017 15:29:41 -0400 Subject: [PATCH 11/27] fixed dev_in overwriting --- src/main.cpp | 21 +++++++------ stream_compaction/common.cu | 4 +-- stream_compaction/common.h | 2 +- stream_compaction/cpu.cu | 41 ++++++++++++++---------- stream_compaction/cpu.h | 2 ++ stream_compaction/efficient.cu | 57 +++++++++++++++++----------------- stream_compaction/efficient.h | 2 ++ stream_compaction/radix.cu | 39 ++++++++++++----------- 8 files changed, 91 insertions(+), 77 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3a6c4b9..6798008 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,9 +11,10 @@ #include #include #include +#include #include "testing_helpers.hpp" -const int SIZE = 1 << 12; // feel free to change the size of array +const int SIZE = 1 << 3; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int a[SIZE], b[SIZE], c[SIZE]; @@ -147,7 +148,7 @@ int main(int argc, char* argv[]) { // Radix Tests - genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case + genArray(SIZE - 1, a, 7); printArray(SIZE, a, true); zeroArray(SIZE, b); @@ -167,14 +168,14 @@ int main(int argc, char* argv[]) { StreamCompaction::Radix::sort(SIZE, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); printArray(SIZE, c, true); - printCmpResult(SIZE, b, c); - - zeroArray(SIZE, c); - printDesc("radix sort, non-power-of-two"); - StreamCompaction::Radix::sort(NPOT, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, c, true); - printCmpResult(NPOT, b, c); + //printCmpResult(SIZE, b, c); + + //zeroArray(SIZE, c); + //printDesc("radix sort, non-power-of-two"); + //StreamCompaction::Radix::sort(NPOT, c, a); + //printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(NPOT, c, true); + //printCmpResult(NPOT, b, c); system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 2ba70c7..b50e1e3 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -22,12 +22,12 @@ namespace StreamCompaction { * Maps an array to an array of 0s and 1s for stream compaction. Elements * 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) { + __global__ void kernMapToBoolean(int pos2, int n, int *bools, const int *idata) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; if (index >= n) return; - bools[index] = (idata[index] != 0 || index == n - 1) ? 1 : 0; + bools[index] = (index < n && idata[index] != 0) ? 1 : 0; } /** diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 8229c25..9e120a4 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -33,7 +33,7 @@ inline int ilog2ceil(int x) { namespace StreamCompaction { namespace Common { - __global__ void kernMapToBoolean(int n, int *bools, const int *idata); + __global__ void kernMapToBoolean(int pos2, int n, int *bools, const int *idata); __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools); diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 7d7ac6a..3644788 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -102,6 +102,8 @@ namespace StreamCompaction { max = val; } } + + return max; } void countSort(int n, int d, int *odata, int *idata) @@ -122,28 +124,33 @@ namespace StreamCompaction { } } - /** - * CPU sort - */ - void sort_implementation(int n, int *odata, const int *idata) - { - // TODO - int max = findMax(n, idata); - for (int d = 1; max/d > 0; d *= 10) { - countSort(n, d, odata, idata); - std::swap(idata, odata); - } - } - /** * CPU sort */ void sort(int n, int *odata, const int *idata) { - timer().startCpuTimer(); - sort_implementation(n, odata, idata); - timer().endCpuTimer(); - } + // TODO + int* temp = new int[n]; + for (int i = 0; i < n; ++i) { + odata[i] = idata[i]; + } + + timer().startCpuTimer(); + int max = findMax(n, idata); + bool eo = true; + for (int d = 1; max / d > 0; d *= 10) { + countSort(n, d, temp, odata); + std::swap(temp, odata); + eo = !eo; + } + timer().endCpuTimer(); + + if (!eo) { + std::swap(temp, odata); + std::memcpy(odata, temp, n * sizeof(int)); + } + delete[] temp; + } } } diff --git a/stream_compaction/cpu.h b/stream_compaction/cpu.h index 236ce11..9ba529e 100644 --- a/stream_compaction/cpu.h +++ b/stream_compaction/cpu.h @@ -11,5 +11,7 @@ namespace StreamCompaction { int compactWithoutScan(int n, int *odata, const int *idata); int compactWithScan(int n, int *odata, const int *idata); + + void sort(int n, int *odata, const int *idata); } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 25fce23..c1279c3 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -23,10 +23,9 @@ namespace StreamCompaction { __global__ void kernUpSweep(int n, int d, int *odata) { int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n) return; - int offset = 1 << (d + 1); int i = (index + 1) * offset - 1; + if (i >= n) return; int val = 1 << d; odata[i] += odata[i - val]; @@ -36,20 +35,19 @@ namespace StreamCompaction { __global__ void kernDownSweep(int n, int d, int *odata) { int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n) return; + int offset = 1 << (d + 1); + int i = (index + 1) * offset - 1; + if (i >= n) return; - int i = index + 1; int val = 1 << d; - int offset = 1 << (d + 1); - int temp = odata[i * offset - 1]; - odata[i * offset - 1] += odata[i * offset - val - 1]; - odata[i * offset - val - 1] = temp; + + int temp = odata[i]; + odata[i] += odata[i - val]; + odata[i - val] = temp; } - void scan_implementation(int n, int *dev_out) + void scan_implementation(int pow2n, int *dev_out) { - int pow2n = 1 << ilog2ceil(n); - for (int d = 0; d < ilog2ceil(pow2n); ++d) { dim3 blocksPerGrid((pow2n / (1 << (d + 1)) + blockSize - 1) / blockSize); kernUpSweep << > > (pow2n, d, dev_out); @@ -82,7 +80,7 @@ namespace StreamCompaction { checkCUDAError("kernZeroed failed!"); timer().startGpuTimer(); - scan_implementation(n, dev_out); + scan_implementation(pow2n, dev_out); timer().endGpuTimer(); cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); @@ -106,26 +104,35 @@ namespace StreamCompaction { int *dbools; int *dev_in; int *dev_out; - // int *indices; - cudaMalloc((void**)&dbools, (n + 1) * sizeof(int)); - checkCUDAError("cudaMalloc bools failed!"); + int pow2n = 1 << ilog2ceil(n + 1); + + cudaMalloc((void**)&dbools, pow2n * sizeof(int)); + checkCUDAError("cudaMalloc dbools failed!"); - cudaMalloc((void**)&dev_in, (n + 1) * sizeof(int)); + cudaMalloc((void**)&dev_in, n * sizeof(int)); checkCUDAError("cudaMalloc dev_in failed!"); - cudaMemcpy(dev_in, idata, (n + 1) * sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy dev_in failed!"); timer().startGpuTimer(); - dim3 blocksPerGrid1((n + blockSize) / blockSize); - StreamCompaction::Common::kernMapToBoolean << > > (n+1, dbools, dev_in); + dim3 blocksPerGrid1((pow2n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, dbools, dev_in); checkCUDAError("kernMapToBoolean failed!"); + + // TODO: THIS IS CLOBBERING DEV_IN!! + scan_implementation(pow2n, dbools); // requires power of 2 - scan_implementation(n + 1, dbools); + int *num = (int *)malloc(sizeof(int)); + cudaMemcpy(num, dbools + n, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); - cudaMalloc((void**)&dev_out, n * sizeof(int)); + int ret = *num; + free(num); + + cudaMalloc((void**)&dev_out, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dev_out failed!"); dim3 blocksPerGrid((n + blockSize - 1) / blockSize); @@ -137,17 +144,9 @@ namespace StreamCompaction { cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); - int *num = (int *)malloc(sizeof(int)); - cudaMemcpy(num, dbools + n , sizeof(int), cudaMemcpyDeviceToHost); - checkCUDAError("cudaMemcpyDeviceToHost failed!"); - - int ret = *num; - free(num); - cudaFree(dbools); cudaFree(dev_in); cudaFree(dev_out); - // cudaFree(indices); return ret; } diff --git a/stream_compaction/efficient.h b/stream_compaction/efficient.h index 803cb4f..6653205 100644 --- a/stream_compaction/efficient.h +++ b/stream_compaction/efficient.h @@ -6,6 +6,8 @@ namespace StreamCompaction { namespace Efficient { StreamCompaction::Common::PerformanceTimer& timer(); + void scan_implementation(int n, int *dev_out); + void scan(int n, int *odata, const int *idata); int compact(int n, int *odata, const int *idata); diff --git a/stream_compaction/radix.cu b/stream_compaction/radix.cu index 3856d55..220b013 100644 --- a/stream_compaction/radix.cu +++ b/stream_compaction/radix.cu @@ -69,28 +69,28 @@ namespace StreamCompaction { cudaMemcpy(e_arr, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); checkCUDAError("cudaMemcpyDeviceToDevice failed!"); - // Step 2: exclusive scan e - scan_implementation(n, f_arr); + //// Step 2: exclusive scan e + //StreamCompaction::Efficient::scan_implementation(n, f_arr); - // Step 3: compute totalFalses - cudaMemcpy(last_e, e_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); - checkCUDAError("last_e cudaMemcpyDeviceToHost failed!"); + //// Step 3: compute totalFalses + //cudaMemcpy(last_e, e_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + //checkCUDAError("last_e cudaMemcpyDeviceToHost failed!"); - cudaMemcpy(last_f, dbools + n - 1 , sizeof(int), cudaMemcpyDeviceToHost); - checkCUDAError("last_f cudaMemcpyDeviceToHost failed!"); + //cudaMemcpy(last_f, f_arr + n - 1 , sizeof(int), cudaMemcpyDeviceToHost); + //checkCUDAError("last_f cudaMemcpyDeviceToHost failed!"); - int totalFalses = *last_e + *last_f; + //int totalFalses = *last_e + *last_f; - // Step 4: compute t array - kernComputeT<<>>(n, totalFalses, t_arr, f_arr); - checkCUDAError("kernComputeT failed!"); + //// Step 4: compute t array + //kernComputeT<<>>(n, totalFalses, t_arr, f_arr); + //checkCUDAError("kernComputeT failed!"); - // Step 4: scatter based on address d - kernComputeD<<>>(n, e_arr, f_arr, t_arr); - checkCUDAError("kernComputeD failed!"); + //// Step 4: scatter based on address d + //kernComputeD<<>>(n, e_arr, f_arr, t_arr); + //checkCUDAError("kernComputeD failed!"); - kernScatterD<<>>(n, f_arr, e_arr, dev_in); - checkCUDAError("kernScatterD failed!"); + //kernScatterD<<>>(n, f_arr, e_arr, dev_in); + //checkCUDAError("kernScatterD failed!"); } /** @@ -128,12 +128,15 @@ namespace StreamCompaction { checkCUDAError("cudaMemcpy dev_in failed!"); timer().startGpuTimer(); - for (int k = 0; k < 8 * sizeof(int); ++k) { + for (int k = 1; k < 2; ++k) { sort_implementation(n, k, last_e, last_f, e_arr, f_arr, t_arr, dev_in); + + cudaMemcpy(dev_in, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); + checkCUDAError("cudaMemcpyDeviceToDevice failed!"); } timer().endGpuTimer(); - cudaMemcpy(odata, f_arr, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, e_arr, n * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); free(last_e); From dfb5ee8010699f63350229f8f665553c18e47867 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Mon, 18 Sep 2017 15:57:30 -0400 Subject: [PATCH 12/27] radix sort --- src/main.cpp | 30 ++++++++++---------- stream_compaction/common.cu | 4 +-- stream_compaction/cpu.cu | 2 +- stream_compaction/efficient.cu | 1 - stream_compaction/radix.cu | 50 ++++++++++++++++++---------------- 5 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6798008..f98c2fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,9 +14,9 @@ #include #include "testing_helpers.hpp" -const int SIZE = 1 << 3; // feel free to change the size of array +const int SIZE = 1 << 4; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two -int a[SIZE], b[SIZE], c[SIZE]; +int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; int main(int argc, char* argv[]) { // Scan tests @@ -148,7 +148,7 @@ int main(int argc, char* argv[]) { // Radix Tests - genArray(SIZE - 1, a, 7); + genArray(SIZE - 1, a, 50); printArray(SIZE, a, true); zeroArray(SIZE, b); @@ -161,21 +161,21 @@ int main(int argc, char* argv[]) { printDesc("cpu sort, non-power-of-two"); StreamCompaction::CPU::sort(NPOT, c, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(NPOT, b, true); + printArray(NPOT, c, true); - zeroArray(SIZE, c); + zeroArray(SIZE, d); printDesc("radix sort, power-of-two"); - StreamCompaction::Radix::sort(SIZE, c, a); + StreamCompaction::Radix::sort(SIZE, d, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, c, true); - //printCmpResult(SIZE, b, c); - - //zeroArray(SIZE, c); - //printDesc("radix sort, non-power-of-two"); - //StreamCompaction::Radix::sort(NPOT, c, a); - //printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(NPOT, c, true); - //printCmpResult(NPOT, b, c); + printArray(SIZE, d, true); + printCmpResult(SIZE, b, d); + + zeroArray(SIZE, d); + printDesc("radix sort, non-power-of-two"); + StreamCompaction::Radix::sort(NPOT, d, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, d, true); + printCmpResult(NPOT, c, d); system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index b50e1e3..711612f 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -22,10 +22,10 @@ namespace StreamCompaction { * Maps an array to an array of 0s and 1s for stream compaction. Elements * which map to 0 will be removed, and elements which map to 1 will be kept. */ - __global__ void kernMapToBoolean(int pos2, int n, int *bools, const int *idata) { + __global__ void kernMapToBoolean(int pos2n, int n, int *bools, const int *idata) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n) return; + if (index >= pos2n) return; bools[index] = (index < n && idata[index] != 0) ? 1 : 0; } diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 3644788..275ef45 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -129,7 +129,7 @@ namespace StreamCompaction { */ void sort(int n, int *odata, const int *idata) { - // TODO + // TODO (from GeeksforGeeks Radix Sort) int* temp = new int[n]; for (int i = 0; i < n; ++i) { diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index c1279c3..0f004ad 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -122,7 +122,6 @@ namespace StreamCompaction { StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, dbools, dev_in); checkCUDAError("kernMapToBoolean failed!"); - // TODO: THIS IS CLOBBERING DEV_IN!! scan_implementation(pow2n, dbools); // requires power of 2 int *num = (int *)malloc(sizeof(int)); diff --git a/stream_compaction/radix.cu b/stream_compaction/radix.cu index 220b013..1d9eb32 100644 --- a/stream_compaction/radix.cu +++ b/stream_compaction/radix.cu @@ -15,13 +15,13 @@ namespace StreamCompaction { /** * Maps an array to an array of 0s and 1s for bit n. */ - __global__ void kernMapToBoolean(int n, int k, int *bools, const int *idata) { + __global__ void kernMapToBoolean(int pow2n, int n, int k, int *bools, const int *idata) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n) return; + if (index >= pow2n) return; int val = 1 << k; - bools[index] = (idata[index] & val != 0) ? 0 : 1; + bools[index] = ((idata[index] & val) != 0 || index >= n) ? 0 : 1; } /** @@ -62,35 +62,37 @@ namespace StreamCompaction { { dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + int pow2n = 1 << ilog2ceil(n + 1); + // Step 1: compute e array - kernMapToBoolean<<>>(n, k, f_arr, dev_in); + kernMapToBoolean<<>>(pow2n, n, k, f_arr, dev_in); checkCUDAError("kernMapToBoolean failed!"); cudaMemcpy(e_arr, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); checkCUDAError("cudaMemcpyDeviceToDevice failed!"); - //// Step 2: exclusive scan e - //StreamCompaction::Efficient::scan_implementation(n, f_arr); + // Step 2: exclusive scan e + StreamCompaction::Efficient::scan_implementation(pow2n, f_arr); - //// Step 3: compute totalFalses - //cudaMemcpy(last_e, e_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); - //checkCUDAError("last_e cudaMemcpyDeviceToHost failed!"); + // Step 3: compute totalFalses + cudaMemcpy(last_e, e_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("last_e cudaMemcpyDeviceToHost failed!"); - //cudaMemcpy(last_f, f_arr + n - 1 , sizeof(int), cudaMemcpyDeviceToHost); - //checkCUDAError("last_f cudaMemcpyDeviceToHost failed!"); + cudaMemcpy(last_f, f_arr + n - 1 , sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("last_f cudaMemcpyDeviceToHost failed!"); - //int totalFalses = *last_e + *last_f; + int totalFalses = *last_e + *last_f; - //// Step 4: compute t array - //kernComputeT<<>>(n, totalFalses, t_arr, f_arr); - //checkCUDAError("kernComputeT failed!"); + // Step 4: compute t array + kernComputeT<<>>(n, totalFalses, t_arr, f_arr); + checkCUDAError("kernComputeT failed!"); - //// Step 4: scatter based on address d - //kernComputeD<<>>(n, e_arr, f_arr, t_arr); - //checkCUDAError("kernComputeD failed!"); + // Step 4: scatter based on address d + kernComputeD<<>>(n, e_arr, f_arr, t_arr); + checkCUDAError("kernComputeD failed!"); - //kernScatterD<<>>(n, f_arr, e_arr, dev_in); - //checkCUDAError("kernScatterD failed!"); + kernScatterD<<>>(n, f_arr, e_arr, dev_in); + checkCUDAError("kernScatterD failed!"); } /** @@ -109,13 +111,15 @@ namespace StreamCompaction { int *t_arr; int *dev_in; + int pow2n = 1 << ilog2ceil(n); + int *last_e = (int *)malloc(sizeof(int)); int *last_f = (int *)malloc(sizeof(int)); cudaMalloc((void**)&e_arr, n * sizeof(int)); checkCUDAError("cudaMalloc e_arr failed!"); - cudaMalloc((void**)&f_arr, n * sizeof(int)); + cudaMalloc((void**)&f_arr, pow2n * sizeof(int)); checkCUDAError("cudaMalloc f_arr failed!"); cudaMalloc((void**)&t_arr, n * sizeof(int)); @@ -128,7 +132,7 @@ namespace StreamCompaction { checkCUDAError("cudaMemcpy dev_in failed!"); timer().startGpuTimer(); - for (int k = 1; k < 2; ++k) { + for (int k = 0; k < 8 * sizeof(int); ++k) { sort_implementation(n, k, last_e, last_f, e_arr, f_arr, t_arr, dev_in); cudaMemcpy(dev_in, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); @@ -136,7 +140,7 @@ namespace StreamCompaction { } timer().endGpuTimer(); - cudaMemcpy(odata, e_arr, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, f_arr, n * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); free(last_e); From 25aa07e382ac19284f4837d5536264347aabe65f Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 10:10:33 -0400 Subject: [PATCH 13/27] readme --- README.md | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b71c458..f0bbe23 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,102 @@ CUDA Stream Compaction **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 2** -* (TODO) YOUR NAME HERE -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Sarah Forcier +* Tested on GeForce GTX 1070 -### (TODO: Your README) +### Description +#### Scan +#### Stream Compaction +#### Radix SOrt -Include analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) +### Output +``` +**************** +** SCAN TESTS ** +**************** + [ 15 26 19 6 48 18 4 40 8 13 32 26 32 37 14 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 0.000277ms (std::chrono Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 0.000277ms (std::chrono Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 0.012288ms (CUDA Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + passed +==== naive scan, non-power-of-two ==== + elapsed time: 0.010496ms (CUDA Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 0.017664ms (CUDA Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 0.017472ms (CUDA Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + passed +==== thrust scan, power-of-two ==== + elapsed time: 10.5801ms (CUDA Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 0.014368ms (CUDA Measured) + [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** + [ 3 1 1 1 2 1 1 0 3 1 0 2 3 0 1 0 ] +==== cpu compact without scan, power-of-two ==== + elapsed time: 0.000277ms (std::chrono Measured) + [ 3 1 1 1 2 1 1 3 1 2 3 1 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 0.000277ms (std::chrono Measured) + [ 3 1 1 1 2 1 1 3 1 2 3 ] + passed +==== cpu compact with scan ==== + elapsed time: 0.001387ms (std::chrono Measured) + [ 3 1 1 1 2 1 1 3 1 2 3 1 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 0.216224ms (CUDA Measured) + [ 3 1 1 1 2 1 1 3 1 2 3 1 ] + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 0.099584ms (CUDA Measured) + [ 3 1 1 1 2 1 1 3 1 2 3 ] + passed + +***************************** +** RADIX SORT TESTS ** +***************************** + [ 21 23 29 15 10 21 29 36 13 17 36 14 41 12 31 0 ] +==== cpu sort, power-of-two ==== + elapsed time: 0.000554ms (std::chrono Measured) + [ 0 10 12 13 14 15 17 21 21 23 29 29 31 36 36 41 ] +==== cpu sort, non-power-of-two ==== + elapsed time: 0.000555ms (std::chrono Measured) + [ 10 13 14 15 17 21 21 23 29 29 36 36 41 ] +==== radix sort, power-of-two ==== + elapsed time: 0.099584ms (CUDA Measured) + [ 0 10 12 13 14 15 17 21 21 23 29 29 31 36 36 41 ] + passed +==== radix sort, non-power-of-two ==== + elapsed time: 0.099584ms (CUDA Measured) + [ 10 13 14 15 17 21 21 23 29 29 36 36 41 ] + passed + ``` + +### Performance Analysis + +### Q&A + +#### Compare GPU Scan implementations to the serial CPU version? + +#### Where are the performance bottlenecks? From 293259d5c50653bc8779a284c53f7c968432f547 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 10:13:14 -0400 Subject: [PATCH 14/27] formatting --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f0bbe23..9f531c9 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,15 @@ CUDA Stream Compaction * Tested on GeForce GTX 1070 ### Description -#### Scan -#### Stream Compaction -#### Radix SOrt +#### * Scan +#### * Stream Compaction +#### * Radix Sort -### Output +### Test Output + +#### * Scan ``` -**************** -** SCAN TESTS ** -**************** [ 15 26 19 6 48 18 4 40 8 13 32 26 32 37 14 0 ] ==== cpu scan, power-of-two ==== elapsed time: 0.000277ms (std::chrono Measured) @@ -49,10 +48,11 @@ CUDA Stream Compaction elapsed time: 0.014368ms (CUDA Measured) [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] passed +``` -***************************** -** STREAM COMPACTION TESTS ** -***************************** +#### * Stream Compaction + +``` [ 3 1 1 1 2 1 1 0 3 1 0 2 3 0 1 0 ] ==== cpu compact without scan, power-of-two ==== elapsed time: 0.000277ms (std::chrono Measured) @@ -74,10 +74,11 @@ CUDA Stream Compaction elapsed time: 0.099584ms (CUDA Measured) [ 3 1 1 1 2 1 1 3 1 2 3 ] passed +``` + +#### * Radix Sort -***************************** -** RADIX SORT TESTS ** -***************************** +``` [ 21 23 29 15 10 21 29 36 13 17 36 14 41 12 31 0 ] ==== cpu sort, power-of-two ==== elapsed time: 0.000554ms (std::chrono Measured) From 17f34b4525cdc5d7de15202cd83faa8a8651283e Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 15:13:52 -0400 Subject: [PATCH 15/27] graphs --- README.md | 18 +-- performance.xlsx | Bin 19609 -> 39991 bytes src/main.cpp | 259 +++++++++++++++++---------------- stream_compaction/common.cu | 14 +- stream_compaction/common.h | 2 +- stream_compaction/cpu.cu | 11 +- stream_compaction/efficient.cu | 33 +++-- stream_compaction/radix.cu | 16 +- stream_compaction/radix.h | 2 +- 9 files changed, 188 insertions(+), 167 deletions(-) diff --git a/README.md b/README.md index 9f531c9..d268d41 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,17 @@ CUDA Stream Compaction **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 2** -* Sarah Forcier -* Tested on GeForce GTX 1070 +Sarah Forcier +Tested on GeForce GTX 1070 -### Description -#### * Scan -#### * Stream Compaction -#### * Radix Sort +### Algorithm Descriptions +#### Scan +#### Stream Compaction +#### Radix Sort ### Test Output -#### * Scan +#### Scan ``` [ 15 26 19 6 48 18 4 40 8 13 32 26 32 37 14 0 ] @@ -50,7 +50,7 @@ CUDA Stream Compaction passed ``` -#### * Stream Compaction +#### Stream Compaction ``` [ 3 1 1 1 2 1 1 0 3 1 0 2 3 0 1 0 ] @@ -76,7 +76,7 @@ CUDA Stream Compaction passed ``` -#### * Radix Sort +#### Radix Sort ``` [ 21 23 29 15 10 21 29 36 13 17 36 14 41 12 31 0 ] diff --git a/performance.xlsx b/performance.xlsx index 653579af2c4a5438ad0d96961daac924e5b3db03..8d322e608c85fbea8ccd90514c552ed1f20c092f 100644 GIT binary patch delta 23466 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 delta 9901 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 a`Csj;A`b`u7Xt6?Gx4@%Zj$=z>3;wnj6&Q1 diff --git a/src/main.cpp b/src/main.cpp index f98c2fe..e6d611f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,133 +13,137 @@ #include #include #include "testing_helpers.hpp" - -const int SIZE = 1 << 4; // feel free to change the size of array +const int SIZE = 1 << 12; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two -int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; +//int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; int main(int argc, char* argv[]) { // Scan tests - printf("\n"); - printf("****************\n"); - printf("** SCAN TESTS **\n"); - printf("****************\n"); - - genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case - a[SIZE - 1] = 0; - - printArray(SIZE, a, true); - - // initialize b using StreamCompaction::CPU::scan you implement - // We use b for further comparison. Make sure your StreamCompaction::CPU::scan is correct. - // At first all cases passed because b && c are all zeroes. - zeroArray(SIZE, b); - printDesc("cpu scan, power-of-two"); - StreamCompaction::CPU::scan(SIZE, b, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(SIZE, b, true); - - zeroArray(SIZE, c); - printDesc("cpu scan, non-power-of-two"); - StreamCompaction::CPU::scan(NPOT, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(NPOT, b, true); - printCmpResult(NPOT, b, c); - - zeroArray(SIZE, c); - printDesc("naive scan, power-of-two"); - StreamCompaction::Naive::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"); - StreamCompaction::Naive::scan(NPOT, c, a); - printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, c, true); - printCmpResult(NPOT, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient scan, power-of-two"); - StreamCompaction::Efficient::scan(SIZE, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - 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); - printCmpResult(NPOT, b, c); - - zeroArray(SIZE, c); - printDesc("thrust scan, power-of-two"); - StreamCompaction::Thrust::scan(SIZE, c, a); - printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, c, true); - printCmpResult(SIZE, b, c); - - zeroArray(SIZE, c); - printDesc("thrust scan, non-power-of-two"); - StreamCompaction::Thrust::scan(NPOT, c, a); - printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, c, true); - printCmpResult(NPOT, b, c); - - printf("\n"); - printf("*****************************\n"); - printf("** STREAM COMPACTION TESTS **\n"); - printf("*****************************\n"); - - // Compaction tests - - genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case - a[SIZE - 1] = 0; - printArray(SIZE, a, true); - - int countSIZE, countNPOT, expectedSIZE, expectedNPOT; - - // initialize b using StreamCompaction::CPU::compactWithoutScan you implement - // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. - zeroArray(SIZE, b); - printDesc("cpu compact without scan, power-of-two"); - countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - expectedSIZE = countSIZE; - printArray(expectedSIZE, b, true); - printCmpLenResult(countSIZE, expectedSIZE, b, b); - - zeroArray(SIZE, c); - printDesc("cpu compact without scan, non-power-of-two"); - countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - expectedNPOT = countNPOT; - printArray(countNPOT, c, true); - printCmpLenResult(countNPOT, expectedNPOT, b, c); - - zeroArray(SIZE, c); - printDesc("cpu compact with scan"); - countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(countSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient compact, power-of-two"); - countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient compact, non-power-of-two"); - countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedNPOT, c, true); - printCmpLenResult(countNPOT, expectedNPOT, b, c); + int* a = reinterpret_cast(malloc(SIZE * sizeof(int))); + int* b = reinterpret_cast(malloc(SIZE * sizeof(int))); + int* c = reinterpret_cast(malloc(SIZE * sizeof(int))); + int* d = reinterpret_cast(malloc(SIZE * sizeof(int))); + + // printf("\n"); + // printf("****************\n"); + // printf("** SCAN TESTS **\n"); + // printf("****************\n"); + + // genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case + // a[SIZE - 1] = 0; + + // printArray(SIZE, a, true); + + // // initialize b using StreamCompaction::CPU::scan you implement + // // We use b for further comparison. Make sure your StreamCompaction::CPU::scan is correct. + // // At first all cases passed because b && c are all zeroes. + // zeroArray(SIZE, b); + // printDesc("cpu scan, power-of-two"); + // StreamCompaction::CPU::scan(SIZE, b, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(SIZE, b, true); + + // zeroArray(SIZE, c); + // printDesc("cpu scan, non-power-of-two"); + // StreamCompaction::CPU::scan(NPOT, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(NPOT, b, true); + // printCmpResult(NPOT, b, c); + + // zeroArray(SIZE, c); + // printDesc("naive scan, power-of-two"); + // StreamCompaction::Naive::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"); + // StreamCompaction::Naive::scan(NPOT, c, a); + // printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(NPOT, c, true); + // printCmpResult(NPOT, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient scan, power-of-two"); + // StreamCompaction::Efficient::scan(SIZE, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // 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); + // printCmpResult(NPOT, b, c); + + // zeroArray(SIZE, c); + // printDesc("thrust scan, power-of-two"); + // StreamCompaction::Thrust::scan(SIZE, c, a); + // printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(SIZE, c, true); + // printCmpResult(SIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("thrust scan, non-power-of-two"); + // StreamCompaction::Thrust::scan(NPOT, c, a); + // printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(NPOT, c, true); + // printCmpResult(NPOT, b, c); + + // printf("\n"); + // printf("*****************************\n"); + // printf("** STREAM COMPACTION TESTS **\n"); + // printf("*****************************\n"); + + // // Compaction tests + + // genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case + // a[SIZE - 1] = 0; + // printArray(SIZE, a, true); + + // int countSIZE, countNPOT, expectedSIZE, expectedNPOT; + + // // initialize b using StreamCompaction::CPU::compactWithoutScan you implement + // // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. + // zeroArray(SIZE, b); + // printDesc("cpu compact without scan, power-of-two"); + // countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + //expectedSIZE = countSIZE; + // printArray(expectedSIZE, b, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, b); + + // zeroArray(SIZE, c); + // printDesc("cpu compact without scan, non-power-of-two"); + //countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // expectedNPOT = countNPOT; + // printArray(countNPOT, c, true); + // printCmpLenResult(countNPOT, expectedNPOT, b, c); + + // zeroArray(SIZE, c); + // printDesc("cpu compact with scan"); + //countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(countSIZE, c, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient compact, power-of-two"); + //countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(expectedSIZE, c, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient compact, non-power-of-two"); + //countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(expectedNPOT, c, true); + // printCmpLenResult(countNPOT, expectedNPOT, b, c); printf("\n"); printf("*****************************\n"); @@ -148,7 +152,8 @@ int main(int argc, char* argv[]) { // Radix Tests - genArray(SIZE - 1, a, 50); + int k = 6; + genArray(SIZE - 1, a, 1 << k); printArray(SIZE, a, true); zeroArray(SIZE, b); @@ -165,15 +170,15 @@ int main(int argc, char* argv[]) { zeroArray(SIZE, d); printDesc("radix sort, power-of-two"); - StreamCompaction::Radix::sort(SIZE, d, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + StreamCompaction::Radix::sort(SIZE, k + 1, d, a); + printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); printArray(SIZE, d, true); printCmpResult(SIZE, b, d); zeroArray(SIZE, d); printDesc("radix sort, non-power-of-two"); - StreamCompaction::Radix::sort(NPOT, d, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + StreamCompaction::Radix::sort(NPOT, k + 1, d, a); + printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); printArray(NPOT, d, true); printCmpResult(NPOT, c, d); diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 711612f..22be71c 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -34,15 +34,15 @@ namespace StreamCompaction { * Performs scatter on an array. That is, for each element in idata, * if bools[idx] == 1, it copies idata[idx] to odata[indices[idx]]. */ - __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools) { + __global__ void kernScatter(int n, int *odata, + const int *idata, const int *bools, const int *indices) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n) return; - - int idx = bools[index]; - if (bools[index + 1] != idx) { - odata[idx] = idata[index]; - } + if (index >= n) return; + + if (bools[index] == 1) { + odata[indices[index]] = idata[index]; + } } } } \ No newline at end of file diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 9e120a4..6aabc39 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -36,7 +36,7 @@ namespace StreamCompaction { __global__ void kernMapToBoolean(int pos2, int n, int *bools, const int *idata); __global__ void kernScatter(int n, int *odata, - const int *idata, const int *bools); + const int *idata, const int *bools, const int *indices); /** * This class is used for timing the performance diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 275ef45..e513108 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -62,12 +62,13 @@ namespace StreamCompaction { * @returns the number of elements remaining after compaction. */ int compactWithScan(int n, int *odata, const int *idata) { - timer().startCpuTimer(); + // TODO int* temp = new int[n + 1]; temp[n] = 0; int num = 0; + timer().startCpuTimer(); // compute temporary array for (int i = 0; i < n; ++i) { temp[i] = (idata[i] == 0) ? 0 : 1; @@ -87,9 +88,8 @@ namespace StreamCompaction { num++; } } - + timer().endCpuTimer(); delete[] temp; - timer().endCpuTimer(); return num; } @@ -135,9 +135,10 @@ namespace StreamCompaction { for (int i = 0; i < n; ++i) { odata[i] = idata[i]; } - - timer().startCpuTimer(); + int max = findMax(n, idata); + + timer().startCpuTimer(); bool eo = true; for (int d = 1; max / d > 0; d *= 10) { countSort(n, d, temp, odata); diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 0f004ad..4698a07 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -24,6 +24,7 @@ namespace StreamCompaction { { int index = (blockIdx.x * blockDim.x) + threadIdx.x; int offset = 1 << (d + 1); + if (index >= n >> (d + 1)) return; int i = (index + 1) * offset - 1; if (i >= n) return; @@ -36,6 +37,7 @@ namespace StreamCompaction { { int index = (blockIdx.x * blockDim.x) + threadIdx.x; int offset = 1 << (d + 1); + if (index >= n >> (d + 1)) return; int i = (index + 1) * offset - 1; if (i >= n) return; @@ -72,7 +74,7 @@ namespace StreamCompaction { cudaMalloc((void**)&dev_out, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dev_out failed!"); - cudaMemcpy(dev_out, idata, pow2n * sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(dev_out, idata, n * sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy dev_out failed!"); dim3 blocksPerGrid((pow2n + blockSize - 1) / blockSize); @@ -82,6 +84,7 @@ namespace StreamCompaction { timer().startGpuTimer(); scan_implementation(pow2n, dev_out); timer().endGpuTimer(); + checkCUDAError("scan_implementation failed!"); cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); @@ -102,14 +105,18 @@ namespace StreamCompaction { { // TODO int *dbools; + int *indices; int *dev_in; int *dev_out; - int pow2n = 1 << ilog2ceil(n + 1); + int pow2n = 1 << ilog2ceil(n); cudaMalloc((void**)&dbools, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dbools failed!"); + cudaMalloc((void**)&indices, pow2n * sizeof(int)); + checkCUDAError("cudaMalloc indices failed!"); + cudaMalloc((void**)&dev_in, n * sizeof(int)); checkCUDAError("cudaMalloc dev_in failed!"); @@ -119,33 +126,41 @@ namespace StreamCompaction { timer().startGpuTimer(); dim3 blocksPerGrid1((pow2n + blockSize - 1) / blockSize); - StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, dbools, dev_in); + StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, indices, dev_in); checkCUDAError("kernMapToBoolean failed!"); - - scan_implementation(pow2n, dbools); // requires power of 2 + + cudaMemcpy(dbools, indices, pow2n * sizeof(int), cudaMemcpyDeviceToDevice); + checkCUDAError("cudaMemcpyDeviceToDevice failed!"); int *num = (int *)malloc(sizeof(int)); - cudaMemcpy(num, dbools + n, sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); int ret = *num; + + scan_implementation(pow2n, indices); // requires power of 2 + + cudaMemcpy(num, indices + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + ret += *num; free(num); - cudaMalloc((void**)&dev_out, pow2n * sizeof(int)); + cudaMalloc((void**)&dev_out, ret * sizeof(int)); checkCUDAError("cudaMalloc dev_out failed!"); dim3 blocksPerGrid((n + blockSize - 1) / blockSize); - StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools); + StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools, indices); checkCUDAError("kernScatter failed!"); timer().endGpuTimer(); - cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, dev_out, ret * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); cudaFree(dbools); cudaFree(dev_in); cudaFree(dev_out); + cudaFree(indices); return ret; } diff --git a/stream_compaction/radix.cu b/stream_compaction/radix.cu index 1d9eb32..b87cfcc 100644 --- a/stream_compaction/radix.cu +++ b/stream_compaction/radix.cu @@ -62,7 +62,7 @@ namespace StreamCompaction { { dim3 blocksPerGrid((n + blockSize - 1) / blockSize); - int pow2n = 1 << ilog2ceil(n + 1); + int pow2n = 1 << ilog2ceil(n); // Step 1: compute e array kernMapToBoolean<<>>(pow2n, n, k, f_arr, dev_in); @@ -78,7 +78,7 @@ namespace StreamCompaction { cudaMemcpy(last_e, e_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("last_e cudaMemcpyDeviceToHost failed!"); - cudaMemcpy(last_f, f_arr + n - 1 , sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(last_f, f_arr + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("last_f cudaMemcpyDeviceToHost failed!"); int totalFalses = *last_e + *last_f; @@ -103,7 +103,7 @@ namespace StreamCompaction { * @param idata The array of elements to compact. * @returns The number of elements remaining after compaction. */ - void sort(int n, int *odata, const int *idata) + void sort(int n, int d, int *odata, const int *idata) { // TODO int *e_arr; @@ -132,15 +132,15 @@ namespace StreamCompaction { checkCUDAError("cudaMemcpy dev_in failed!"); timer().startGpuTimer(); - for (int k = 0; k < 8 * sizeof(int); ++k) { + for (int k = 0; k < d; ++k) { sort_implementation(n, k, last_e, last_f, e_arr, f_arr, t_arr, dev_in); - - cudaMemcpy(dev_in, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); - checkCUDAError("cudaMemcpyDeviceToDevice failed!"); + std::swap(dev_in, f_arr); + /*cudaMemcpy(dev_in, f_arr, n * sizeof(int), cudaMemcpyDeviceToDevice); + checkCUDAError("cudaMemcpyDeviceToDevice failed!");*/ } timer().endGpuTimer(); - cudaMemcpy(odata, f_arr, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, dev_in, n * sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); free(last_e); diff --git a/stream_compaction/radix.h b/stream_compaction/radix.h index aa489d9..cbadf0d 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 d, int *odata, const int *idata); } } From 24e19a087d3032275cc08d89f6f54b7b5293d074 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 16:28:58 -0400 Subject: [PATCH 16/27] images --- README.md | 82 ++++++++------- img/compact20k.png | Bin 0 -> 12219 bytes img/compact4m.png | Bin 0 -> 9639 bytes img/radix20k.png | Bin 0 -> 10029 bytes img/radix4m.png | Bin 0 -> 6802 bytes img/scan20K.png | Bin 0 -> 12516 bytes img/scan4m.png | Bin 0 -> 14558 bytes src/main.cpp | 242 ++++++++++++++++++++++----------------------- 8 files changed, 168 insertions(+), 156 deletions(-) create mode 100644 img/compact20k.png create mode 100644 img/compact4m.png create mode 100644 img/radix20k.png create mode 100644 img/radix4m.png create mode 100644 img/scan20K.png create mode 100644 img/scan4m.png diff --git a/README.md b/README.md index d268d41..edd77c6 100644 --- a/README.md +++ b/README.md @@ -11,93 +11,105 @@ Tested on GeForce GTX 1070 #### Stream Compaction #### Radix Sort -### Test Output +### Test Program Output #### Scan ``` - [ 15 26 19 6 48 18 4 40 8 13 32 26 32 37 14 0 ] + [ 0 31 19 29 27 6 28 18 48 16 43 0 5 49 24 0 ] ==== cpu scan, power-of-two ==== - elapsed time: 0.000277ms (std::chrono Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + elapsed time: 0ms (std::chrono Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 270 319 343 ] ==== cpu scan, non-power-of-two ==== - elapsed time: 0.000277ms (std::chrono Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + elapsed time: 0ms (std::chrono Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 ] passed ==== naive scan, power-of-two ==== - elapsed time: 0.012288ms (CUDA Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + elapsed time: 0.011904ms (CUDA Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 270 319 343 ] passed ==== naive scan, non-power-of-two ==== - elapsed time: 0.010496ms (CUDA Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + elapsed time: 0.0112ms (CUDA Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 ] passed ==== work-efficient scan, power-of-two ==== - elapsed time: 0.017664ms (CUDA Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + elapsed time: 0.018048ms (CUDA Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 270 319 343 ] passed ==== work-efficient scan, non-power-of-two ==== - elapsed time: 0.017472ms (CUDA Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + elapsed time: 0.017888ms (CUDA Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 ] passed ==== thrust scan, power-of-two ==== - elapsed time: 10.5801ms (CUDA Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 287 324 338 ] + elapsed time: 10.8968ms (CUDA Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 270 319 343 ] passed ==== thrust scan, non-power-of-two ==== - elapsed time: 0.014368ms (CUDA Measured) - [ 0 15 41 60 66 114 132 136 176 184 197 229 255 ] + elapsed time: 0.013568ms (CUDA Measured) + [ 0 0 31 50 79 106 112 140 158 206 222 265 265 ] passed ``` #### Stream Compaction ``` - [ 3 1 1 1 2 1 1 0 3 1 0 2 3 0 1 0 ] + [ 0 3 3 3 1 0 0 0 2 2 3 2 1 3 2 0 ] ==== cpu compact without scan, power-of-two ==== elapsed time: 0.000277ms (std::chrono Measured) - [ 3 1 1 1 2 1 1 3 1 2 3 1 ] + [ 3 3 3 1 2 2 3 2 1 3 2 ] passed ==== cpu compact without scan, non-power-of-two ==== elapsed time: 0.000277ms (std::chrono Measured) - [ 3 1 1 1 2 1 1 3 1 2 3 ] + [ 3 3 3 1 2 2 3 2 1 ] passed ==== cpu compact with scan ==== - elapsed time: 0.001387ms (std::chrono Measured) - [ 3 1 1 1 2 1 1 3 1 2 3 1 ] + elapsed time: 0.000278ms (std::chrono Measured) + [ 3 3 3 1 2 2 3 2 1 3 2 ] passed ==== work-efficient compact, power-of-two ==== - elapsed time: 0.216224ms (CUDA Measured) - [ 3 1 1 1 2 1 1 3 1 2 3 1 ] + elapsed time: 0.217408ms (CUDA Measured) + [ 3 3 3 1 2 2 3 2 1 3 2 ] passed ==== work-efficient compact, non-power-of-two ==== - elapsed time: 0.099584ms (CUDA Measured) - [ 3 1 1 1 2 1 1 3 1 2 3 ] + elapsed time: 0.201632ms (CUDA Measured) + [ 3 3 3 1 2 2 3 2 1 ] passed ``` #### Radix Sort ``` - [ 21 23 29 15 10 21 29 36 13 17 36 14 41 12 31 0 ] + [ 8 15 7 7 13 12 12 8 14 14 3 2 1 3 10 0 ] ==== cpu sort, power-of-two ==== - elapsed time: 0.000554ms (std::chrono Measured) - [ 0 10 12 13 14 15 17 21 21 23 29 29 31 36 36 41 ] + elapsed time: 0.00111ms (std::chrono Measured) + [ 0 1 2 3 3 7 7 8 8 10 12 12 13 14 14 15 ] ==== cpu sort, non-power-of-two ==== elapsed time: 0.000555ms (std::chrono Measured) - [ 10 13 14 15 17 21 21 23 29 29 36 36 41 ] + [ 1 2 3 7 7 8 8 12 12 13 14 14 15 ] ==== radix sort, power-of-two ==== - elapsed time: 0.099584ms (CUDA Measured) - [ 0 10 12 13 14 15 17 21 21 23 29 29 31 36 36 41 ] + elapsed time: 0.784896ms (CUDA Measured) + [ 0 1 2 3 3 7 7 8 8 10 12 12 13 14 14 15 ] passed ==== radix sort, non-power-of-two ==== - elapsed time: 0.099584ms (CUDA Measured) - [ 10 13 14 15 17 21 21 23 29 29 36 36 41 ] + elapsed time: 0.656448ms (CUDA Measured) + [ 1 2 3 7 7 8 8 12 12 13 14 14 15 ] passed ``` ### Performance Analysis +#### Scan + +![](img/scan20k.png) ![](img/scan4k.png) + +#### Stream Compaction + +![](img/compact20k.png) ![](img/compact4k.png) + +#### Radix Sort + +![](img/radix20k.png) ![](img/radix4k.png) + ### Q&A #### Compare GPU Scan implementations to the serial CPU version? diff --git a/img/compact20k.png b/img/compact20k.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba058fbe4996d019ddda615c5e35c9972bc1e3e GIT binary patch literal 12219 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 IDq4T|AKIRJ%m4rY literal 0 HcmV?d00001 diff --git a/img/radix4m.png b/img/radix4m.png new file mode 100644 index 0000000000000000000000000000000000000000..d01e48e5ea0f75e340be00bf90d1c876d5245040 GIT binary patch literal 6802 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 Oq#&y*Qz2#Y<$nNl4h<>* literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index e6d611f..053af8c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,7 @@ #include #include #include "testing_helpers.hpp" -const int SIZE = 1 << 12; // feel free to change the size of array +const int SIZE = 1 << 4; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; @@ -25,125 +25,125 @@ int main(int argc, char* argv[]) { int* c = reinterpret_cast(malloc(SIZE * sizeof(int))); int* d = reinterpret_cast(malloc(SIZE * sizeof(int))); - // printf("\n"); - // printf("****************\n"); - // printf("** SCAN TESTS **\n"); - // printf("****************\n"); - - // genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case - // a[SIZE - 1] = 0; - - // printArray(SIZE, a, true); - - // // initialize b using StreamCompaction::CPU::scan you implement - // // We use b for further comparison. Make sure your StreamCompaction::CPU::scan is correct. - // // At first all cases passed because b && c are all zeroes. - // zeroArray(SIZE, b); - // printDesc("cpu scan, power-of-two"); - // StreamCompaction::CPU::scan(SIZE, b, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(SIZE, b, true); - - // zeroArray(SIZE, c); - // printDesc("cpu scan, non-power-of-two"); - // StreamCompaction::CPU::scan(NPOT, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(NPOT, b, true); - // printCmpResult(NPOT, b, c); - - // zeroArray(SIZE, c); - // printDesc("naive scan, power-of-two"); - // StreamCompaction::Naive::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"); - // StreamCompaction::Naive::scan(NPOT, c, a); - // printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(NPOT, c, true); - // printCmpResult(NPOT, b, c); - - // zeroArray(SIZE, c); - // printDesc("work-efficient scan, power-of-two"); - // StreamCompaction::Efficient::scan(SIZE, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // 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); - // printCmpResult(NPOT, b, c); - - // zeroArray(SIZE, c); - // printDesc("thrust scan, power-of-two"); - // StreamCompaction::Thrust::scan(SIZE, c, a); - // printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(SIZE, c, true); - // printCmpResult(SIZE, b, c); - - // zeroArray(SIZE, c); - // printDesc("thrust scan, non-power-of-two"); - // StreamCompaction::Thrust::scan(NPOT, c, a); - // printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(NPOT, c, true); - // printCmpResult(NPOT, b, c); - - // printf("\n"); - // printf("*****************************\n"); - // printf("** STREAM COMPACTION TESTS **\n"); - // printf("*****************************\n"); - - // // Compaction tests - - // genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case - // a[SIZE - 1] = 0; - // printArray(SIZE, a, true); - - // int countSIZE, countNPOT, expectedSIZE, expectedNPOT; - - // // initialize b using StreamCompaction::CPU::compactWithoutScan you implement - // // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. - // zeroArray(SIZE, b); - // printDesc("cpu compact without scan, power-of-two"); - // countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - //expectedSIZE = countSIZE; - // printArray(expectedSIZE, b, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, b); - - // zeroArray(SIZE, c); - // printDesc("cpu compact without scan, non-power-of-two"); - //countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // expectedNPOT = countNPOT; - // printArray(countNPOT, c, true); - // printCmpLenResult(countNPOT, expectedNPOT, b, c); - - // zeroArray(SIZE, c); - // printDesc("cpu compact with scan"); - //countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(countSIZE, c, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, c); - - // zeroArray(SIZE, c); - // printDesc("work-efficient compact, power-of-two"); - //countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(expectedSIZE, c, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, c); - - // zeroArray(SIZE, c); - // printDesc("work-efficient compact, non-power-of-two"); - //countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(expectedNPOT, c, true); - // printCmpLenResult(countNPOT, expectedNPOT, b, c); + printf("\n"); + printf("****************\n"); + printf("** SCAN TESTS **\n"); + printf("****************\n"); + + genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case + a[SIZE - 1] = 0; + + printArray(SIZE, a, true); + + // initialize b using StreamCompaction::CPU::scan you implement + // We use b for further comparison. Make sure your StreamCompaction::CPU::scan is correct. + // At first all cases passed because b && c are all zeroes. + zeroArray(SIZE, b); + printDesc("cpu scan, power-of-two"); + StreamCompaction::CPU::scan(SIZE, b, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(SIZE, b, true); + + zeroArray(SIZE, c); + printDesc("cpu scan, non-power-of-two"); + StreamCompaction::CPU::scan(NPOT, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(NPOT, b, true); + printCmpResult(NPOT, b, c); + + zeroArray(SIZE, c); + printDesc("naive scan, power-of-two"); + StreamCompaction::Naive::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"); + StreamCompaction::Naive::scan(NPOT, c, a); + printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, c, true); + printCmpResult(NPOT, b, c); + + zeroArray(SIZE, c); + printDesc("work-efficient scan, power-of-two"); + StreamCompaction::Efficient::scan(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + 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); + printCmpResult(NPOT, b, c); + + zeroArray(SIZE, c); + printDesc("thrust scan, power-of-two"); + StreamCompaction::Thrust::scan(SIZE, c, a); + printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, c, true); + printCmpResult(SIZE, b, c); + + zeroArray(SIZE, c); + printDesc("thrust scan, non-power-of-two"); + StreamCompaction::Thrust::scan(NPOT, c, a); + printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, c, true); + printCmpResult(NPOT, b, c); + + printf("\n"); + printf("*****************************\n"); + printf("** STREAM COMPACTION TESTS **\n"); + printf("*****************************\n"); + + // Compaction tests + + genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case + a[SIZE - 1] = 0; + printArray(SIZE, a, true); + + int countSIZE, countNPOT, expectedSIZE, expectedNPOT; + + // initialize b using StreamCompaction::CPU::compactWithoutScan you implement + // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. + zeroArray(SIZE, b); + printDesc("cpu compact without scan, power-of-two"); + countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + expectedSIZE = countSIZE; + printArray(expectedSIZE, b, true); + printCmpLenResult(countSIZE, expectedSIZE, b, b); + + zeroArray(SIZE, c); + printDesc("cpu compact without scan, non-power-of-two"); + countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + expectedNPOT = countNPOT; + printArray(countNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); + + zeroArray(SIZE, c); + printDesc("cpu compact with scan"); + countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(countSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); + + zeroArray(SIZE, c); + printDesc("work-efficient compact, power-of-two"); + countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); + + zeroArray(SIZE, c); + printDesc("work-efficient compact, non-power-of-two"); + countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); printf("\n"); printf("*****************************\n"); @@ -152,7 +152,7 @@ int main(int argc, char* argv[]) { // Radix Tests - int k = 6; + int k = 4; genArray(SIZE - 1, a, 1 << k); printArray(SIZE, a, true); From 213a2a074344216fd2cffff6952b092ec6c6ab5f Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 16:30:17 -0400 Subject: [PATCH 17/27] rename files --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index edd77c6..d65e04e 100644 --- a/README.md +++ b/README.md @@ -100,15 +100,15 @@ Tested on GeForce GTX 1070 #### Scan -![](img/scan20k.png) ![](img/scan4k.png) +![](img/scan20k.png) ![](img/scan4m.png) #### Stream Compaction -![](img/compact20k.png) ![](img/compact4k.png) +![](img/compact20k.png) ![](img/compact4m.png) #### Radix Sort -![](img/radix20k.png) ![](img/radix4k.png) +![](img/radix20k.png) ![](img/radix4m.png) ### Q&A From e516e3ce9b6e867fa76908fb5870d961063dbee8 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 16:38:09 -0400 Subject: [PATCH 18/27] image format --- README.md | 14 +++++++++++--- img/compact20k.png | Bin 12219 -> 9919 bytes img/compact4m.png | Bin 9639 -> 10517 bytes img/radix20k.png | Bin 10029 -> 8442 bytes img/radix4m.png | Bin 6802 -> 7287 bytes img/scan20K.png | Bin 12516 -> 16106 bytes img/scan4m.png | Bin 14558 -> 15429 bytes 7 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d65e04e..8045131 100644 --- a/README.md +++ b/README.md @@ -100,15 +100,23 @@ Tested on GeForce GTX 1070 #### Scan -![](img/scan20k.png) ![](img/scan4m.png) +| Scan for SIZE < 20K | Scan for SIZE > 4M | +| ------------- | ----------- | +| ![](img/scan20K.png) | ![](img/scan4m.png) | + +![](img/scan20k.png) ![](img/scan4K.png) #### Stream Compaction -![](img/compact20k.png) ![](img/compact4m.png) +| Compact for SIZE < 20K | Compact for SIZE > 4M | +| ------------- | ----------- | +| ![](img/compact20k.png) | ![](img/compact4m.png) | #### Radix Sort -![](img/radix20k.png) ![](img/radix4m.png) +| Radix Sort for SIZE < 20K | Radix Sort for SIZE > 4M | +| ------------- | ----------- | +| ![](img/radix20k.png) | ![](img/radix4m.png) | ### Q&A diff --git a/img/compact20k.png b/img/compact20k.png index 2ba058fbe4996d019ddda615c5e35c9972bc1e3e..987cfe68c40f2b062084288d3d768a6567e046e5 100644 GIT binary patch literal 9919 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 N?t?O@RMI%$e*m9*f6f2^ literal 12219 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 literal 9639 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 IDq4T|AKIRJ%m4rY diff --git a/img/radix4m.png b/img/radix4m.png index d01e48e5ea0f75e340be00bf90d1c876d5245040..9bee8c2bde2c07f0fbec24aa8248da491c506549 100644 GIT binary patch literal 7287 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�Div$dXFgmP%_N#DD2 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 literal 6802 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 literal 12516 zcmb_?Wl&sE)8-H~L4reYCpZKR8Z5X3g1bWocNv@zf_rd+2N~Rh26vyqJ-EBGH~a3- z-P-+XzaLXmGj;Ag-RE>a-TicbS5=n5d`0pK1Oj2o$x5k#KnUBwhYsxp@J||^{Ttv5 z!9`6*0#rUqwhR0~vJzJk2Z5?$&>u{Yf!{A3Wp!LYAgr!`AA~-KU*;eXrp zXWf@#jT`mRj3>0)num))^u$he0})#l8(&;X6-gxQ74CPmaBP~N0m8zb0U@^(Y#)&<%H<&d06h0&`LB3k8}@@<)&Q9OlBhGwDUVNfhyf0c_j3A@|CKw zUHTIJw7dM|GjdF%n7^Z3!@b$??r0-=_L6Bu7+1ZG4?QgfSbqH_>x^9g;skE*dhxf{ zH)4T#2U<++t<5IKdaX5n%zZ(>^YxeHGN+UV_lqK-1HOlcTgJbQlMKz0;J*iG>rtQ& z$gpT|qomTz&*bmbCPTH@vC(bOE9MYs)x#aug4`pk#-+Xban=1aicn69@3iExXu2~X zvD~2BPxP)@c@!U)70Ys1r))y}1*wh#>NYY1f+KNB4dp-5e)m~JSPTYV_W_=^HAtQ*qgn3R|PBy~z0Rr3`%}>^&A5_iUKVj$l z(%0ghl|j^piwD~4f;G;xU)WA@@fGhk3JiRUaLypo_^{4vkq0D*81?d9<426Vs zM17=So*|4Up4SN@C45R8xS%8XMEB?XfkN6Ul-auJmHcyX9$ zAM$?vHYToM3uu;<#H{Jsf!#t!h`NO6v9&tpsRDk!&U|>$Klw>)pNz@gOuG}U2`_Y& zUGg$^hb5h20HQ@J_^P7Zv>B6ykL4YOO#80L~tKhI35x$=hThXju?}h z#*beVrxg}z6Am;7P8 zNunqsR@m7c^QV{zL6mYl!_H)_Qg1#R%>}m0vf&^D;>1c9kfi5|t9}!YY@d_7nqz0{?$p=>O_*VS#ms3B9D2-u#5fg)#6k^4B2H zsoXRa8kWkG8dAnzRTTz1VGeu;0)<)S+8qXbyBrFU`(&K-nFs`0$M@0GGcd-aldVMn z1yug7OL9N#cJ3loMF3GLSJl-?entTW+;qcQ;{pj704=B}zBkwD0PiL-5cjGIKF1?<78j~zd5TNAN9hI? z0;oGuSY^LPVU*LTYyML&4lJ}5p%R^*$X;2`OF7|^a+~16>#^@8>hfw2)tNxYyc#d) zgQ9?u2YB=jJ-5P0QD4+*C9me)lWZqTV87Y(vaHz{9f+!A+IQ-HbgM$jNUXtf?f~Nm ztSvMswKQK6>PCBuuX8Tl6b22dMF_)TJM>6CYRSL73v4*g(z{IQl2R84Qz|%&S})JV!u`whzCR*N5%sv z@-Q4P8Ny|EkAE{y4#c0vSYZ_wAM;SiOzsu(9I??5-p-EqS3p!9( z;%_~OdvkUfxug=-=C|Ep_I^h0qz;+KivArc^70BUX|BE9IT7qv3VzSs70B2@cmB9i z#!}HY)5oc(q5Yc{GV|SZrLdEqW|MyuGkJVWA(@j-_iFhLt{r%aZHiq>pFuG^p9BQ@ zceMlqKb|>@cD}1<{eiDZ$WMGvc_@9E(j=Mj`CuP*`aWW88p`LNHKUkQh!&EnBdplV2vz5STFJFWdQhHu} zC$68za%nazGyNv7u1QmgJ&0Y2EuMW|YQ#@5JS6>N1cM9$RhG3)d(EYBSKe`Q%3br$ zSzDkuWyPL(nFe13Q3Cs97X5bQpLuuexK=&ckaWw&B~Uj`R$6pOei|y_rtojestDf^ z0mrA%&BZDiwSk7g@&Q^woCMPc!YyfpskbbyNl66mm9ecpw20sr3ZU-SBFljX3Gi$K zXUlaN(x?Oxwo%_FbKmH62stvo3O9bv+wUg1{+RrcnzURj;5OsTj^tNd(+wIhhEkLZ zlDqg?@U~kb+fA;1{$X@Ljkxf{?4Cg!=~J#u&*xfNk)85HB^C#fNa zAlhSOko(UQ+lBp77NrDmxDq}37$3!kMyK|77qE*Sw->mWA4J7E|Jzpx%gE=8O`DB# z>)Y*tj6FI6e{U^ z@Zb#ahB3f4=X*5|jSuI|El0Z6-(PF?WA%A&TEserO?A;zRmUwiN|QQql9orhnw8b`OCb~$ zI9dzkqe|(8w|AF`eep3w=kHc&cm}Ks9C>fXse>#40lWG&fbR;OHEX4d?u5@{ZG!$?YTVtlq& z=H~wV8Q@?40&rJZIk`{Q&^L4Kipdi&#|@;t8}P5YmpAnYJZK@rG9^@Nga~>nEvsr_4d4kv}6Icbbprpv3eIU%k?!clU!z!;%KV84;m7sU0;yHYRht$%9X4yZ|a!%gE$7INh;kJ&E`+T zG~;&0r>8$_Y9=Qq_hPbrKw*qY81d4;_F}E&1L1VmZk)b$35Qu3uJL{_N2A^!9v%)4 z4^L-vlY|aP8np|!K6yY$fyFg^1p~T*WY&8iV_V?BqK!ODHvcFYB5Dt=t{O{9O3KN} z$;-duuLUKzX}O$^*I7tf`3rr%APNLc{3-EKnj{oq^F=b|`OjHb7d&EBAh7<~KK~l) z=I(x_mBi>%VXHB@H%Yl~Zg4?#N&58e`tNgx2NF$;8w|!PtX_`^4xRwi@mx8G2a;h3 z;>xMK@o;R}{{DVML_|~8Wo#LE?5I`!zAZx&-O2lOg<+i=hLW4&{InxI}xxf9;K#?#RZ?>(G+E`#sSyqZ5!iUm3X)t8El6Y7f-}N*=X# z-$rfHHi=$q3obDm-TwUid{EGfax0OZrgUAFpa%Um{*Tx|5@1d62EDblm6w;duv&SpruA$GH8YE`o#P&O3+r^P z_b;z5)fJ7l-#Iz;BxB{@#U>Jcy{90CpxmGym_0j(Ocxq4(_w?&+aA9E+`x$~X$8_p zw1mqX$#0E0$kpmv`hs_Rhw9h;(J%?wQu;6F9*3ScGQ;rN50qXAVT79X;L=}*b0c?F zGYFh!#^WB%)JDSlpjdtdU(n4s*Vo;6K7YfpIoj6!K&b#&RpZR(Ou z)ti;%_&GqI06#kCqI=4rBbIz2F)?nK;BG%6gi3+utJEn-F~R)ql`Kp{Lt}1kPJhzx zEwsGfyS#M=UY%EmmZceSodI^3_pQ?B=u(Es$XC-5xM%Sq zy}Z2iXV&s(to+`)T0E(0y;2z zODdcxC>Wq^ZFc=0nGRyQD89a?D`vgZzt;jAd#kJzN&X zH?cxw_Q`cc>-EQ|U1Cu}4!caz)4VAE6m_X;iuRM~l8fdD%q0jncF6Mba!Cnu6@9+> z3Rs*Q%rf}}$3Z4y_But#f$WaL?yJS&e7M%jLd`quO`;@inweLh@J+u_)$`QC58j^_ z+wgDHfCi*AI%w0hOfH>k$I*N* z7|wo-&KG(-@!Eq^M@7$z9jK98>@BtJ7aP}3J-e@8BPo@a9%&g$VZZ5alL=3`6sh0F z%DgLvteL%>Cw&Z6SB?B5Li;jo75vZ)t7U@{Y4#xf)=QVnHoN_eiDYbcL#GZTHkZTs zDw;K1kOW*|pn5aLSgG`ET~13QajJD2-)z3GXiQ zS1x`2${nW4lQ*-5t}he*)zw-k{2f+R{gY+zPFLY8E_d#5vzsTL3RmefixwY#G7=J! z@JqacUb-erjJvz=WF=T)Cf8-TUepgy9mU3a#kQAbG4oo}1`#x$eh?7d!yS+RXI$fZ zr_1y)a&F#L=RuG@NPy2V<|Y{-Qu^=rr&eO-;9s1aJLp`Y4(n%bW$8`;`QeqN$)opL zK}+k$Mf5o_13Xe---j;2`it5RWFi)nbw0cv$;wymRjRcvc0uf!oelxdnyL86nn*`H zVOX{p*-j;~|B|MLD-pg>hqJTr%^(JhRZ_z2F)ckkmXRI&u1(#%*0wLl=n- zf0tT@Gh@|&(1)^~EcY3;Q_c-Z1GNN~%S8_n6nsmJ1m<=a@qe3TbtB$L@p9Kv;2bg7;0szqw9JMx8_)4ew9G9U5>)Z0O;qHXX zAFP48j~07YX%!wy4|3|aIEEnGF=8n69yOSP$3`Ids4d!9{j0UvjiHf2s_&U#mJlT& z->NR;BExv#GSlo?F4=850USDg-FW@gsJrnPClY&e{&Z-r*NnRN}EIzQ-v}&6-VF^i8+y9c$Fmalh|0V*tKu6Oju%Mbl#_uICtQX|*Q)W0ek z8peHEjNBgW%E`-<^uEaWx!Jrme)F{c%sM0p8>mBhuY1nhl#Vfq9)KubeyBT3+!k{d z)OG|`3$oJiCQpNQb?#rnU@(%ELD_-2Tb4I=vHIKqxG-wAl`#1L7i(Qnv2O8?mthY9 z^n>}Gb3tBn4EIHt{V6IgF3!&nQJ8;C53loz!6bX;s4lZh(B~e%-jO%9yY4W&PI5eX zF9)0dOnuPg0;q;rFf%eT0z{pjo}Tr*?a0Yte!-Y$&1BxMcJbgS!1TM@`f@E205!3C zZ4aHVtlQ2OizsTrGBGt#eJ~=9SfK6%c%*-5>@uXh+QUWN=(O?C*Z1-Ed>j4Mt9%qN zrhIt?nXlO{66Qu2O8sA~gp^fD>jureH@IG-P zquqI(v}!;@`7E>t!;*wnaT4fG&k?w%sid<3w9>Sk7T zx(ZsM9|u0ry^fHyjC%))$G)uGXNHA2Vm{^aH*L#$P3OHfgQFQv4Gno;e;^QXS%PbD z7F1p7c8~V^f2XwUbeR9ISY7=^MOe&Zd1hv2dRnUZqROl<|FfWw8}eL}?K4lc%VUm@ z?%9*ictiR(G#^GdNdpOog<`9MI^P|I3`j*pBjWZ49yCiqZ^)sqO)o-M_U6r3H_<<~ z_0{`P(u9U3c*QnMM(T~)?|6GI490{X=d36hwYnD~%urBKnUczji%&g;k&%&yN55V9 zNx1_#NA$s>>kWH#&4BQ)HKdn!566iOJBCWcU+y5k&SzD}-uoH*xU`;y%wBuCZ_BiR zLJ;IWs>d}7>&lv;81P!rS8IfC^m-$Kfs7&=(@8Thp>XgH%uT4{U5u6c=&rDr%I0z{ z!ak4|wdNzVtNI}9vAnP_)VubH*&x0qN#Y()c>)hoC z3_9{7js2hn;(eI(XPbip5;Cnw4dx#{dC;$NIb;dXtZ-02u)PnBj-$B}VGz6Iz7WAe zO_fr|gGV;X>up(Fd{egQ9kGd8Q3|xXd4(rI82Y^crdh5^-{O)yDkc@TRc zk-$GinPmR2>ip5r@|&i$8w%K%cdMP&S^MQMn5C_u^rU@o9+P|YL9NPViM3~x|BA)^ z%3vGSk%Rrn=VIDb`1j_pZ;e9PDO2TFp6DAcTINt4me* zXldtlj-#C(K7#(SKLx5}_3Np3jq;mh3)Sv=5P^3oWh2QRlxP3!xUymESPge@OTML zc&>O{TpR^AK{z@h0WkdH+$K<8mfOv$LCxEt~o$6{6VghhDcO@Tma42>zXY%jvst>n&5?B_C63 zUR3^eK@57e+Db0-WT;ky-=OeR+~8bNVe{?285LU4+E(KI+?*GYt?ajFrRzKr1go9# z^c2BX>F$_!>d}JhiY>OgTb4Y041%judI@IQ~bvTj`e{^Q?u+T-qKC(FiIDqv?N^-_?0 zX-F^|{q%NqmbD-R&N)Vw{Gggzw(;e~-Ro~XaG%l~p8Jc!+jTwk$he2;F(5-LUv9@j ztO`UavqJznLh z=PU$PEw>t@U0n>*gW5L9szSG?e|E;FoS|)RTU`%XoyN1cuG&r_@K}tXBP(vDr?@M) zAOvlni`X)tCsqU%?h7SU(mwmTx$kw)h;OiLMQIe_V8hk+f{WuYIJ|6|#QFJ}Q=OIk zIq;n|$xAm+Yecbb_#iPYQ0AJuI15_tB6ht1$D{xh?$yA4T3Kp^(XHBb{xDDw4z)H; zEl_Us?vFdz$SEwVrHIDh?yXV2xqi@3t;_QYR<~3SXQM{(3yTxkU*?v338W&PKWK?@ zD%~47b;fl3#S?gYXpfJxnhz}|;4a*h^F~cv3~gB3Y;0v;({T4pvfL+d_pTNjeV-hq zLby+YX*`x2YlOsd2U9*0M3QLx5CeUZk2>nY8L@(P_dIzOzwdMT-M$Do*qErNz$lxo zX1S&Z6+MZvr6kB1h;KR@4@rlAS?k45{c9g0g3~3dN6%{+=w<*~+tcyW-Qs62-8K;` zQM-2XIl=+Q+7+K1>k9?zq z)K1o0B=ly5NndW1ztF^GEYd_|1^=2}w3?OIh+>hoZr2XX_I_NuH0Qi!oK6>(V_Yia+6?2TRQ>AG z;h+f`WoYa6U;m|t^>(P|!!x`8!Lw}D)~^2&@8LD-mawDiu1j&Y(%sFHKmLLwAH-9o zvoMwRu}|P$%cW9AH`2VYj2U1I7_PsM<{J4KJsfZLS~Dp>y8iMOru=ZYc}gL|2G75@ z#F#AbJP-alU2aOUZeElV%seH!yL0;fB)CO!u6A>OEQTk(&kGaVV7=7f_vW7wpfT3R zAx!Vasip{&WOM5>zT!?|n2c}87&de*IJrGa z@OYhtcFRg5J@6VauZU|FQ7YxB^Vo%BF{5oi{_Q@{H#=el+w320CoLjn8B1SRtOVl+;SEVX0T1Lbzwl`32b|LR>Hiwe~l%|bbIG2Darw(9o1o0 zuEocgyeRG(B8^emWqxevOc0A}WkvSs{~9&W72-vuTiFSpHx?zlh|^ql?ior_q#m-? z$^Dnmn8y+L)k4_}V_luZBR+cK?X~S1WP8y=bnx;macg(LlMMo2!*(+Ya^w^gScICP zyBB|s&iX>(Jjhe7;CF>4FDAZWwk4ySfBHxN6lZ8Tqi*8yW-|1%Of}{0P76kXll3ZC zy)a^G_uZK~$}fJXA(*aBR1ixt!&svnF?}~OVwwg%e|INoWwfyszSorfV&Q}U=Z_r> zOC5%E>kSl$>qdtyj~fk}97FFjdU(lj)!x6%tW|bCwio`{Qc$qxS70HjRzqy%U#j?J zzQyEMX=FAMsA|Kx^!l7OD!zi~pp*kjYN@($jo2on@y+L&-j%hr$akVb`{W%E-$yYu{phTVk{`dr%7hXoXCi;Ig3rO#T_sSRGirY6o+fcCTL4gI^sA24l) z?N*Ed59%P@_;nsBATK6nI0SBfu_-fJFh%@{Cklb`q$af3j2D(`9AE_|kYLY-iSPGKk?VUKY zCyg`Pw_tlR^hz~5y3hFyj(IL5WgBP>ItvRc3F?_V{O8mYaG*uhvZz^XO@t^GP-@dS zXGI1P;fE?`$jx|EsoGRN-H6Ifu>v+Vu`TCf9_+Tb$_E}&7bQ?EExE-29@%fYv8!-8 zag%@%@Fnbdi0~h0jHr>6iQPoy+q^31^fvmFS<+=)>5gPyQ@^#}gW9V>@GM_nLri>w zppW1+CvbDOu?XHg?IhK@m-le9^D~^}K`-dM8!vj)qT!uJkU}HU^*Md=QQm&cJg_GG z_mtFWf%3-ce)k`TH1-T?@^4=%MYE(NwtWzkyX;`eyh?$AlpO|@shjh)Z7c(tXwW``XEI26u^2rUau0`-=lE&E$I2x3FYOo^-ML>6^WAp^CP{J zP%v)0A%9nGXBx)xZ;nons*`&JQ6G9ogz_3b&}e?sIo4d$jT+;em%0=8oR__Brll2= zrNi6Vdgog$g^`61_E5izs~i z3aNP2Yum2D13g_IxBIS_L@TE~s$#QI!x({~gwVd(GU|~&x*k%}2-y*^rX3Y8<;@M7 zn#;_$4f^xYH<>JbZj4HYOF}DvkB=q5{0qobQv2Rx0Yg}p-C-jTv~@h(D#9ir`}jB= zIzqp$d7e-^nDO`X`lO+OQR$(=_)OB}=gj;i&OGq>x%u|OH&J>abzCL)k9jg7IE*@O zxb+S7>$dJzyM!|CC+Gfb;F!N4RE1ihK)sQllc=xWCX8u%PHy1hc%yvccw~jch zV$+ypM?87Bnyt?*@yr_P8yj{^Jirki^n4y@-7jG2eL*vVFfculAzHd`)niobE`?sK#M zIB6MMxhh(p9BhLREOg39X>x8nLL%a0$udIHmoQ$2V*}7d2fk}Wa@WsE8sa{sBP#_* zdbMHVgVm-O1c}dhw9fIDjU)4uW2Ap9oM_kJa80p1X@y)bNWz()`uya$6R*QU(#E}{ zjKOV{0u@GDTH1}uPXg^yTS6g0U{FH*QoBZ0K)IUY;^Pa@fiys2#=G=U6o9RY z?AohxKk$K;Jer5uuviuYJhKd^Ygl~$(2T^*`2ZA(TsNJ=O z2P1p6JJ4LdZ+>f(neyoQhDjwOJ4yO^ZnM<3=6Bc6gmwP6TSYRW8QB`_!n8yJv~_P$ z{G%9(@b@d4*AhS5UTJu+mD^H(pHcbo#+CiTtN@aE=p=z4HvclS&d$;Ak4_jP{!jw9 zn7d;8-Xzo9Vd;_KqV=Knldar%@vq`o-?qVvJOU~Po3!_?MYgWWf3##D_&)(@VK@Q=dO8coJtoEx9}?5M{qkQZaLEW0=sheK;7uyiI68BQ@SY}4yHvvsCO?#u zd+D3o-KFAI!nOL8jV%5$W|`!LymeHodP<-2jpEVcHg)|HsviERwY16Z^iQDPWm#Zo zlHwI#%p}kkW?MNTy918F$tZxs>;D_8VV%#+IR-gsO?@2ZD_Yk3How z0cy|zFn!n?h8&M^5S08-&#tn$&jUt(`{J5qUKPy_Q40|q%w_6G2R+FnK--VRlR)1h zAmojN!7|8Q5v@rZiGcUxoE83*?Md;A`Z9!Yd`Dl3k7FyjM6nZ0chv#IC@-dm$o~*LolMdMe z>PNmHHA@aULWH5&_kFYG zy*IMf%>2=d)y=w9b*uI{d!KXagel5PzCnGD`r^flH_}odZZXh0 z@aLtovZUyXicz9n;0wHkh@8la7u7Ln4@L;UcN7OHE$0_6(7T^MFLCK)zP@9viC)XEdb2%RE#ahg>YxfZaEziCvZ_=5Y5tukhTRF;yP_ zNvn&KardGu+T6?XyH&Soe&JNoE_YyGlynvGP_>}j#@k3$btc|KW5&ebE@~8%*caq~ zTt^#ivPx9Mapy|bR8NI$FlU6wLgUJl+OHcsGuZ52U}9oIM01`JLPJAszjl2FflMi1 zn^RCw5E`*z1OGw}ObHF`m%twefk52dhBOouHJFH;n3!=*`zZ$1fn{fg6vu!kj72^VC+n3H(^b0c#dRU?ecPf?<>AUM zE`C3H^{%ej!c!gu!l67M9j=g=Ho>?6X*ss?MM9hr1e{luRaN1LS={@#fwfe3Z*?6= z=%6W%Y+6!KXp`F#4<9uky2Ph(8d6Z?+*qs|y8WJ+2(H+Aud1e&UDC01-ZGI7RRG5J zvn3ivKUiiJ*S#zM8}@yWPtEL*ju|OcXEn?cPdm;3Oj+_@Gf;3x%c5vdS})-)uPayd zGT{HP6o&&>{4+b5TL7>xmIzfaM|xmB-2b!<{|`I&pB}OGYgIk5A=0xfD+%#sI{viu zv=n>Yv|z0?wYcedRHlB-1Ds3`Dj2D@^-WZT@<9R{xBlF$i;2RNe!L9ZT#Hin?|H@( zlM-!3-A2;3@4!NhgWHp8h+74-Z5imVFxFmt(LhqvG774p6Bnl*Uv(-4K%m4_^+;07 zWTv4;V9$ZwFdEyMszf;!)%chD8!Ipy(gKq6?lR2>E&_Yk9?RmAVA??0YK_d|Mr#}{ zo*iIMPAiWONsU$#7A`{9+Dt{4qqkqy;x`jM{7{s(_ZxJWVv#qO3~?Q!+s zEo7Mhxcv#+HtX*rzw~nALl8?_h;7{UmG`PHN9)x;&xU*j#VV9w6m`OEZp|*Q#_einM){TwxrKJ3^einsZa%gyrTvF-m z*qD%5Rl~y0drx~h3Z=)&mD1t>RZb)E$B*?m7{TCV4T#@ulO+wy@|}-9Z`(ZS&l~ zLiS590uF5OjE8B-+W|BCiYDXAPqXWC4(hp9tkYOr>4%ncW9`f-dQn9j!t+{TgPC7G zUg;#(lpoI>c$tO+-m5M$4-VYq!>>-Au4q#HtHW!Ev7aTqnO~;%khl+n#S9yhIoE$q z=rLEfPIHPJvq|s{JSEQSqBX)m2UlK$DEPArNhKX4g@@(;&lOHg9sMP!g zPvc1l)+2>Qy5tOIDJin%dHW9LqXb7;TsV`%=z3qb&4mYa@dXv6jc}#8P24YkptL?wEb!UR#=z5^aVnsy3mH=> z=mOUE`u1a(lMAOsJn=oBj0D9}wt|79$1&fAKG@R{ z*-TPW=1p}5aW#6Y#e|yo<=ax^u(jMgz1&Fud&qpX*N46Vg%s;!k04n9;5DMao!>q7 zT_zm-ts>sP{8Z;9_rc)V^n?Aa8*d|Y;?g{1qWTJJ*?jlO)eTv@hGoOP_G!^t-#u3_Fvp9|=qR4RJ4(4YSV2tu<)!iXOl6i0K||Lg;Y?kLzIzcM;|1+w%Oi zCXBLAxcxf?Ye{_M3Zp~6aPx%_4(6~P3-^fs+blVay#-hO=;IQw!EKN9GD`14h{Q51^Sah#6z^R~L9_hV9ue(;sgut^Mq3kp8wtrmmSc*) zwgOIr7D5qYX0Ls;6*J-;_LrpA9oxWeg%HYc`>o`dveJnvXP%SKQW6%QAx z8CHYd1Av&((HC(uV(R_G6n2AOcoEUkWS7CGld2p>O2c)}kn1D7L3>7PW6 zcOQ1t9bEc0y2kf`3s6E8SXCsI-`Ntk&&=P&5|BcFGMsLBK0AUHB`XTlkX3y=r?H0= zl9x#ZjX$5ACuPn_m@*r`Vx)PUwuO0E5{JhvGNm3L$Vl z*2LMq;90T(UDnXUd$AM>7OyTQJ*{Cg+v7CPYH_+uG*<2K5$gl8MLSC?R*~w{FOpWx z`JaY^XU%^uwqD7BKKQ*luFr9>?EIJeZ8?O_Q0DZ9O)59oH+zbd4$i)_NhM188-fUp zqYG@LP9wiLWuVBpCEOK`jyK_N>(LKXNsGIzHetHTDGJqp7E@gv^B_}aWq-k0Pox@b z@U({u1BS}N-?$XNi1*my+5q%rm6VqK5!Ds2<3`?)`p!T5XF;zem^qz_s<$2_0#Slj3y-ByHf zKD>}0Y0pF${dR(*$>HIij_46A$RWyCkNS_G>fgKDubivQ`OT@5DHdk0Ogs08I2sVF zJ^ICJd}zM+RWn~x>8n~OJQL?8@83_7FH38}EXAAu%{%44j{eO%KQe;!2NO4~>~+iw zu}3qFRd1Nh&~9(ME;P~FRP*aydHH`L^MVL>EJIwT1GGlJY5AeXF%sCcT>qq>=Yzvk zf{#Sc?48~>TW(E|EI^IZy`qU|?^n;Mi$4^#XvGFI3A=uDJNB<_pYp)KRN4UOb%qkd zOH7NQs!-^HNi4;dR;J6g>Hx*#qoROwUuGyB1)~1_2S6^3QyMy~W5nt8;*CvzN#2RpJ|+~3@KJ!-fgfd zS<;T(PEW)xm-^k#VoC%nYJ>wDdJ#Hh97@RyD6eaN;NT8Rl7GFTIcE0I7t%zEACuGA zSJte@(m88Y>vV7xRO5B{3DYZ2HkGgO+aRjo0?WU`pl8j*IQAb^mg9Yl33vP$M%222 zK7U9h7wnw^(NRwr=Y-Xr$OK-!VIsAa6_c_Gbd7g~xpq1DVo<-gBOipLlLvQymJM#l zo&OKItM5DXN?&Ash;(INA^nfP!F4eKXHVk}anjytooK1so@BIgd@eZiIjR*y8oaJn z!N(jaKOR3eaqU(Tgk$+~^U{g9^@5JONgiXBHS4fDtFb*K+MRW`kVJ>ubk*h>XCJdC zjSivqVi4UjxZuk}vVq!_(={`7&iur)RDJfmznX_DvsVgO_v6~56y!@EO;U*cj(d&> zhGsVB%DWBJZPmd;`EwgPg*f)WIc-|SaG#^g3BDdw8CX&x8OMqOI28x4*Y8C}FMsrb~O~+!lnrT0BvXljC-PNv`d}PIlb5SqTL)X%P_=va@jUFXa zYb$@3x!;YX!L>T+eoallxlDmsZO9g4ttP=ivaJ47RI3}ZH&_b$8U}SE+m7%n%~BKq zm~Lozt_=)v&rIo(2Cb6e&YNVolkrzeMoAW)edYHxTQFwT%JIFkB#pj&y-zDdjj(I& z#^g_Axi-9j@43aFyyL49bq-q#y-Qe=jlW7>+Tp(bu}QL(WBq|kEw`u{_aH$IB+KP} z12{B5Gwis+780|)PckBIV#*6ul{5_LhBB)Uh=)j=4CxdUB3B2|-rzrUZMSECK4tXU zPHq*zov#=rQC07kHn|$4$;sb8^uPfGspKy}cAjxBRZ0#iTt#LHdA$Ua`XTv&$D=Ab zlpaaQsOd$5PYisvfNTWw%&dQ}!V^}~(-vmEx1EfXym&9|^)7I_MThKQ9kWzBj{L8s zFXtPxB!7llI(k8G&~Wtc5&=EqqNg{N>YHRwP)cu3gjo_)K#k+EX`+lt6 z8kdY@y`NcS@GKu@Ta#XlO(aWuT3iSFhN266S>irXup2u5NSPStH>FW|3<|o(_ms??2xTxalNFQ| z5>5dzJ3p^1{_&E)X4UAwZixuCY1+%jw^1Fx8nn12xsx~3rj#T3F5gr?1(~EmXJSC0 zf{wseMYhM1=Qur(TEXzL9@m5%b$79EjSVb&9M5kQ8|o|~&Stvr z^>bbEc?j|I(O}lo5z|U6hIu5tii%kdz4t3L)X(<59NC`1q_d$*>(Oh5U1c4pIkxW- z{>tbTwy#@Or5nrs<31LkdrkNe?Onc^d>vu-;!7XKY+d3-TnCFlIUttqzhdd|dr=B5 zy+q#WL&r%Ju8@qYo&QFb{aMe&WGAaLd`MxoWL=R4BBps?dGpK?3e-Uup_@x_Ii^VGDHOXE!3Y|Cju4RX}x;;{dZ4ZXty&{vg~M0F*TB~%9FSWGKHy`W-y~sF+@aywe&<@9%|zUa2-_wdZgLU5(;32~`^Len8j0vkf5pv}E#3a?=3fq*=giaK z&TB+_zfTEk&pdTOEfBgm$cYvYZY7sub2^Z&FpHNUpOvM};|=|QGEj2ktgbti1L983 z&$6;3T(s_-^D0{KM(bNWQjX_s9Un2I3Ag%BNtAcqObm-}L`35RH@aX-yBdznJ$eN0 zehAHee}}_uw7=sonKURO7!cDXQLwt^<3)6a8p|EW^(lU=Gl==>oMQ0%Id;i~h?fA% zQC_63HC?!FEJ!v#H%xT6>`ajP0$1#y6AdCLYYdcHcRHWMY+bIG1_}All1lpDqj|yW zO0^-`xOM!L%zhq$4y)JyzTe!>2BJWNn$(ZzyfUN9Sw&4dA;Z16FZ%biHTL@oudKI~ z7g|k5hz0XixavQEwb|G`Hhd6-Me(4lM=BhtB+P+UaUh23L&GCG#<>_2sBAze88%wJ zY|L8xOTH}^d$+kODUcHKmI|N#=sTq%=bg?r?{tdkRbzov*r;-Y`<8Bi%+W1YT=u_{ zvDyq(A>57R_EV46w&5<%a}H|15AL^x$Xqsd+%uMpN6;zfwDs9SIJcNmEqnF=G7UD7 z1Kv(^;p;!ynw%+ME{JgATE)a~SV@+Llw;DKefuiSV^Cs(dre`Z7_&)XEwNzFL@{f) zs@zl!uAk?VKVYhLlNTMQcyw(S%z_-fy9T00keF#3E9A4`YN2{RTS0)}Libng5E$a| zz*ipJ8c=T%jm*;XWBZKE+%I2^{cON-4?9fftatU%za_P0ODRP-HN2MWEL{?eE8E2E z7E);g5?NZhY>#+{Y=(NUfi%K%UTm>q%#$B{Nqqq7stB}(-t6Z3aE_9oX%!?wPL;<< zLO5*v_QUOKn{0TsIDeDXP6{q@Eo+sOwW;SW+v{p9uG#evT`1?0WjVvXG+LkQKJ(&Z zbNUS6sH+#R+4dRiJz};csFQu5L`Uq{<*LtVH7DB;Kpi_+b4FLd5YQjCP+RUKW;hw? zH@<&L?5>ak92sYLYb06XCv(R+ryo`OpcMCadui=_+G1nL?e0|ZEdj&EVm_mSI~B!} zG0gyFm3OGp>t>q|t1ri3jG1!QblEt8J2H$v~ckYNrOX#XpKO#s_<6 zz@93P_u@nv1lq4DJeCs$`q0j|UASg{=6V}wY6MUc4(Ed(pH?k8f-Q2>Ll5>J4ZJad zm~;>GDbih~fYq1idY}6IrDUenBI>Q${*3oVmqD6_@ zL`|4iYt|I~8K7P|+p;$z;WU2!mAoBmKqUIU{nc3B6BWg?KRfTQaj`qJ2izHlY;^F` zY~g6;?;jz)udjE|q&{bARg+wIwTS{_SPsAu2H+HC_VPrKic74CUp{pWMBzickoV^# zEZi7~TQ`tZ4IPt$9GMO%g-?f)R=i-;pYup26dtJM;#V5pV639?dwNO;0311ygJ6UF zJ<$OHR=-iJ`Qt3}J&8rm)j>mB~lkwZPVU~^Ko|;(* zft~+Vm=HW;`mQV}JgzAxXKrZs*X^MB(Rp6kCBs+dG!#e!qjBqq#R{`Nspw`sISaxe zatj8}%&G4vZAdxJ^*g)zK9=V<$wq&IGRKl~r9ag?o4>Z4VM@9QP(eoC_Su6&WDXFy%qj5$iww856=2u;j#&*Pom?=cGA!!}=Q_Ke7xfrZnP2Fa6E z8{=H<^zOc`uCj%6wWQqKo=G)vwV4!Ry^B66N%kNQ5<>ALPy_kUWalBV5)YpqK8c1q znJoU0eoaC>xzyigKwvSv8;+qYIxh(X-buQ`}V)=GBVvR+n+Kv*gHme7Ob>LB8zt=X2J;K$m3+@fRg}8XE6t~nGUFM-#|HtyF zhUJh*Bx~Cl=$$T1OWGCjYf$^xDrZgvbXVz1cMuat)5Z0A|elMmoJw z?5_nw>e7GQ6?dlp!B}1AS&C_G@KzQkKkEZD13AY~0^}%+lMoBFd zGq}%8$k9HQm~-84LPzwsQnJ^U{oF>g@v+qlhh$Ph<*${Dj@%C%_x$4rF)kH-c@BQx zvm|1V{Rf4(j=f~xJyy~Iv>wx8TO(UtOsm=$HayDBXR`92w7@^L?|*#r zk~ihSYQpM9V{StgH*fb$8JLgHihfh7JhLygWVYyj=7`hO`BU;&@E>rM`8JwYoeS2V z8e3w`#r!)R4R0`@v3;-ZtlBPSBk<+D5Q+)#E>yDM^L|pf(+U|}dE#v0>=%O0@d!E1 zbMSG?PWHM_l2KQCP7ZDh_VTx>>JOMqJV}^=d{N%Nau1LDvQs*-hXOOt;&syNWRBja!q8dvZ!b<<5h#}shtBZ=RDmStfvzX?pS%q$Dm$V@qz|BhN| z8Z+lN=57?MF##ynz(e^m`Hy=93WY0YQLGem)v{4|LkISD?X+4_eJolH(Qb}O7H$vk zmOoB~*Ddk{a>Gf>(fyLF^n6PSJtK?ZQ)X z9co|d1s#yWs0m>L5BT=z0fuu_32JZJ-!#bR^EVmG^~-q$DTU4`JmQ)qt!LX|tZup5 zUbdFCxs!vBELiFzGe+GmaQfVQFauN6skF=!H_f%&qE%NDm?YEWJ{l)5>0x9(2}_{D z;B5-@rxl`NKIfi~f5gIDIY^7bwEb*Sh+$3Z#7$nA5?;&u zB82{VR2w-iQ|(O_L%#*~OtFXGp|tl}Ts;1-)UTKkQh9P8=(sQqxAwnxUiq@GCG zr~vQL$JQmwGS}RuB7%`SXWr6%#YN>;=Z#=LKODAX`ht`s=AhCOnSM;ll+(fCIr(6X zI0|O25FqF00(-d;*+?nqXdd`_N|~W5-z14i2kD)=G`=jIWXrQ75%xU9L2tiS$*UA1 zs>77R;;6P;XIXR~A|Y{|^mQH$ruCco`V{AUC%w@h{>MkB<0~=sB(7ZakXz2@%lx+; zkkVYPi%7_VX34bKu8k4uCGYjm)&dg2EleHz<4EPEk0vyzESjqc2lsioE< zq1#XAPkzNO!ay!;!KG;b#+LIJ{M$0qMRe=YP}hOBli zyMi{(;nYHt3$iL0NECU|O7gjl_($_K8FERgE@0q$=pZ& z*{-~g4zQ4`mES$?HJG90(jO7+O9iqF(c9yR51cuYt%85NO-!j84&S`=X2>3)lsMJ* zsK)_RKKsK{Cxz9C_=Y@jinF>meKFCL=QTy)My-+6TVtS-C`$`>uOs{8t<^iMF96WD z>T7R$2Dal8=LqUBLz~Q&SPt5r^hsR9sW}rf1^aR%r-9>$qDt7F?XEKHF~}U#`ZoHr zs|^o*{k#~Cbeu81Di-DfVs=pGi$2?{$l*375VHj5sobgK{hLZ-H5 znogy|x3RejPVj?(Udppc(jCFCpi~65bhV#8z2m}pqf!{_qDaMSlEM4n?q13FFwhoW zl%4ropw`t3CJoU<)f{<^zXK${BgHmx-pz(vX(eVV)S{=nlzk!lc4%1BydNiZarwjK zInMVGeNiFw-NG&{i=O7W2Noa|bqS`B4R5VzduZH4j{g_;V<$e%ZXMjLgt<{|5}`nl zO-+uX=3N7sG=?A=IrDf6UAp@c;)amczwPjE-6FfRyav3i%q`{HlNJaUkF&`0{GGiI%%7X0Dt zDr3Hut(Mo_*1Q%y4Blf|y`ZtQ?!})HwN6C;p>F-p&(!TrLd)6~-qvkG9>ce!?~T`B-x3n_$+9Or z#!&s=`J%GLHCFY{l38`_ZC*#Wo+IH&UIc%<2ej70j!cpT7-c6cW-2)vGTAd@{s@lop6`~`-&ut zqd$sr_R7|rklXo~m!#U5@9v!wL6EC@+w>5bXdFT1u(uf^6Q@xMrcP=8w%Aqpk6HbQ zjhu3+{)M0BJ@j)db`92}(VK&xQiwzN_Ud|)afc3)-AS--|BNVK$-LDp>IvW7(L6DG zyGx34U#5BGZFa12^;Phtw>H9=Xn$P6#+puC-4l%ocbooWYTIf-71ztt(dZa_XzuXu zY(jr3i`;`$1>?EPEOW}YIb`_5+`xF7wd0IfzdZ?pT*kj^RcfIyuQJX|piy(`YlX|} zs^pk=b5NqYS6ctz<@enWG$1s3XkixWn(NO*2oaq z!itRc8Wh} z;KCr-7M^0G=m$IpfYiz63H5~+2b>BsAco{uozYug#Bxh%6Ne^yYZ($ZP!E;^U z4U~UfPS}ucWc10pxO!vRw}B;M1eR|OwIT_|v4<31fCNP9?f)5SIga z_Bbet3|T4;L~4CQ_@dU?L~C*Bj;$m(hle8J#1?tD^*t=QdM}Wusr7cw?)kc&_#=-d zbP%1B;on*RgHON$bTz2HTb z^efR8mjTd;;aL{62`W7Xd*tj3e3S6D=o8){>_);vyhO%t^TwrJ7Os?xI3E>$VaK-}XWg6rn_6A2l7(DqNF5l0U6#METBBSmX} zz2-D{MNqrupe{PpQJIdQZ%tjttT6Aj+I zQ2VQxgLqDuGqc&gqaM4qd60Q%j2(kmVT(yNe8MtW7Gv@@=Au!rVJ4FL=Y>8|i=Npb zG7c5uA$^qg`QLN<|=6!Zfg=56X@qD+je2{?8GPIWl8yy|x9W8CjM2R~9$qY<80 zsEi$e;LabYp%{I5EO#M0^Fd6Q_aTGS4bq7aj#37qIGiB){4rUa6DftRcTuFedN?hCF zE&;BubcI`i*#R?bf8bE3g%_r@QBD$}N}?pM$05)_i}TnORb|LFYrX*`S$v!EIST(f zrN+p3m!b#9L(Ptx=3+G4azL@JC8YdaIjLN8|A881!dDRP+w@rlth!Xp{vI!N0IS;7 z%?62Mim@hWD^)FJzHJ#VwOC?)(e2So@QkjtS*o+9kyL2C+dz2NZ^nYk=V@K%^ia5I z!J|Ij@Cw$RDIX^;ft=Pk_uIKolsH^4i;OH;a22SNKOV)s-g;r+w?@TSKxqrqP#*_P zyjR%RR`=f~cwAC_rx66(6HMvV0&I5I+qk-S6D74f_Q`2(7ePZ*cAiE?VTUYX+!>+b zmWkb{TcAIAy0Xrpo$?XwQ@NC|3N&;9!TI$GMI6IGhKaY7?2gLT{=jf=l2m1%V zuLqAKMwg2p=AE%L5WP!5*RVN@i_)77yLMapr&I$rLS5kQY-wA1Lear)A}YK6YI06Q z`$K1R^q2kPxg1yE5-rgRnxDIF=UHF46$WIAxYPCltwQcK?A?^c@)YIo4eC5yA6bmZ z*q-_HBz~splRsXs-`I6;G@F{H6N`5XpdJP_VrjFO^)GxiFwn0w?~z4Wtb4t#6)Q`S z$YA9ps9YfUhIg3S3<4dI9@41f+49Uxsfdk zIcEU*K*u^%`q;R=rDMJhwJ+fdU3ZWW_?aiM=D?PM?ejH#PI;l*g*RP>=!$n1url9- zm4wE!I*=*8uo7)hwIQEF3M1C^oWqS@R9GpVV?Oj6uj^t%?em*^1D4niK(62yl9W8M z(3DOZd(cR!z)(#bRg%bsK?l0Vy*lOX;s@mrbBrH_G(zEj(p~XCFN8**cuGl)^@0Oy z`m(85L3gQ}(E1~G5@c67?3av><)mDmkO#lqyr)$@qkN4&&R|Y1hf*mpcOdk-mA=9U9zY4BWNhO*O9# zcCN#PkTeN6iQZS?8d#4J%e{rlY-ZlNbnDpI_=JtnP9X#vZ?%qWDk>^6!JhN6PDeSu zGv}$e_}Cyd0-NdDgK0G>IdtDY%=2e^x?ftq1fq_4aF{<_zs1k-=bS*ZZ+*DZV=aN$ zZ8QqMqtLXhSlFAc6bKkG=Ttu*lnIY)LNiZc<}u7_bYgK3Na}c{6C3A5k}}Yx!z6>B ziGLGI;+Y=o_o*d>XKm1Q2ay7g#>oMb-s{7U195%)OM8@*`n@_|F5%+hq=4n%RxI7l zS&fV~ZJw^CPmIs#pa%7fT3}{e^Q3 zpvL#6HTX4LjwkZFRA=Uw+Xjue#ad4~OrVVzz|cuaRt(-V%JsI`#HQBP3BsB;bkF&X zTAL`6|HOaT(8q@CldCwL&0L2ckaKcki;GuJ2u8m9_Iw!^#Es?GWgGicXii&iS+7V5 z+%O4gdTuq!(M%}vqke8VGW@SCM>wxG;^lHrJ5OVt+l;t3By{YU|1NsrvrpXdo%fa4 z0^LXiC`0d)li>r zK8cFLTVAjGgd!u;GQN53y5&b`l=s||L6=7|7qN5mG?(k-A9f+%c{pLe@=Za=I+7}# z@T-q`ARWq_*F|zWeO^lZvj9+>@^|W#P$my(eqVIVgoX_LRayI>{-E6OfwH*dtZhbn zmP1squs`Jz%mTwa8>1)@g?aWHIBne@)WhRfZk=DNs@bJsvajNmE518(={iLMPxSiFUN0fh#GBe5Xabe#Mc6>O9ZobZX|35AXTYlks8cf;b6(1#nI%|}k zVms!;5KwSL$YBDeZb}%cgkzgNa<=Y-jPpV|6eDMs-1S4-5( z?Nztz-=SZ_H=*Bjc()#}l~BSdPoVwfo%gQZr_HiTU`E)U`=y3HDpI(tHV&{AbqAZPJGg!YL>lQb^}9 zSWXG+1p4*V;^g+2boLd2Z>ArO66g6b<8Yp)k8pz}icTVMGm+H++NFBR5u@ z)6U^Uu;XUJif9%Wt~n3i?sEIuYcUPT+n z*SUM4b!{LOQXs(y!^+0}NL^j;1Ll|PNP6=%8*9ecTi?$x4a+P+4=mq2rIQo$WLzZ!RnlVLn%PA` z-+yXV`!9WgN`LyxKSkZq6i7K{S2v8@$bfKIJ;D&m9VDvMTyx5-Si5~Czb~RrYi+gr z49sXEoPQ_VAJKBsQF(PW($+kX_r)RL6jn>(>;8H-Eo0-{Es@JVNdRa*8%++Q_%j1R zw@8tfrOew0Zq64TCoWGdy?3EGoNtG^!(3E|8Dt|LxP*~p6tyfm#yqB^b+xxZU<=dj zO%RSCP&YC(ZO~EM^s%Yi$Q)KIKQ2XWi9Zmv0HcJ9=|=0cxE~R;w3fdd5ub4$3nK2J zvpSAE`Ob?ejux0g7u))#{!*|5Vx>pzwP!Oyvuo2<*~5Qc{!PWa`rhp~d8Z^oy{keq zGCF6n>~&5{5dl|k-*kz>2c&hRz*L~S@jl-PFV$w46!`*1YUCY9@%TN|nDn1<3H3$= z$8~K(nPOH21r6O@G*GdFnKvwn`E`l6ybUTEaHsmL`gLyV&6B{9_J6g zfD$|#23E>u`{GPln+phLU&)R3*De}L1xk^k#kEk17b{ND;4Kt)*Wgl|7BB7^C@orC60AUrdvFN^io3h! z?Eb!U=AQZH-nnzn{UgI9Bzy07z0Z2qv(~#-(NNdH3;?(H;ut)5kNY;302PM&Bw;BKK!{daPHEqh38W%l?A&k*|5YEAXYcWd^dy znN=}#+!{CIzm4>NeXw6>YitgWLp7ls*(j&GC;mPvt@zsg;zfK^P{adz(;)hbfz>w| z85d{?G_Uor0dHS+V|L%g$zd-#yD?toay<>Lx#rsV76f{a1v?Z0fnH&#Q-UNF;*lVb z;+KiXp!bCN0-&HoIv55h`C$nz=o=Fl0s_5!XNL)Th5i5b)fr>T<({!7H+c;fNQRx4 z6W7WChNKM`@=f$gA^GF<-cP=#WTPGE4B474k3+T3fgx^-Jc5qpPUiSvEUrTzqIavt zco)rzZGw#w(Z3ff=PM&d(NEtKpT-BJ+cjr2eLWA;iaOLG)@>4QOf>Umuzj2>HS4*g z@TF;+(6zpI^GXu@@oC%q1!_S%eer+D0hnyioq7wDeV;*5Y-olBwJ zeKU3tZN9)^6UVz!dkPK5#D>I$1=bQWh1mgPUz#-W{*j(bnxNrA>QnONxiKf>ZSghh>?jEGqi`fARm&-eF4p3e**f+$$ulbb63FWkrZw;d)9|N=+9#TB!Z+pUxJ+El6C6ygo)L z9e4epe$C5uZ^{XPsH=y-`0kjMDTKiIJe0@8hW&i+OA6lpsJuvXATsXW|kjCt$r+)_C6N(#dPnrmn3glwDoOz$Y z?G!?XD7foduyu4yE(i}fJMg(@CydFb!z(?0cE);%eYbhKshn29!4x2U`U&wO>*08$ z3m6Mi-FKK#)0CqJ(ek%C2jAXxy-`d#b)=uPpnS`GZCC29>7*0!7H%>FZ@R>bd)XK!b{98gpaF5u?xM z#TXzf*6tD&{9aPk-xW?ja1T~0F+g;6FN)yRu4L2}`F1KVCq0_$)5r&2Hx!bJ{~F>@ zF_6s|MdLvpfF$Rw?w_xBLsMT1oFL}Gubq72RzFn%^eNfN1(?KSeVOM39|W?(`Txq8 z|J^jpRU5gBoMp?n2#)MgJP^VA!GF(h!#Ss#nDN+cnv|k15eg^YlGe|Ps_p=YT7S?N z9G${flaaU_WE;(k!~lJXlx`C!$z@eniQ=zwPF|gYmSfp~g5EF3BQ58y+!%MhW`!n` zI_@qQ>Q77r%|Cvhx}bqLYx50u#uz1Q6JqM_=O`TJtc>PlyJ*1#VV9#Fl=iz05E|6a zE9kGya**rYa`&emW7{?-`!n!5ffFxhIgucSnQK)G&wJUg{hS8U%AEo0xz;(fSrZ!> zt1KDo8-gMPAi{zCA>mmUjl!m^x*llb_1w*@e}urlHP((^7E7ci`eUX=xrGNf> z;#)iXvF3TNxTE1hIrZ+nK|I|G1i&ku0lbyynv2FPL2Q}5-=H}hl}p54PTl3$yBm;O<8-To?>nG;HJgD#8G3!aJcy3`EJ z&+$}KJ-1WxT;ZmOYH(D#)k^)(B{26ctV$8_VI2k3tXGCU3yPk`3hd>$DzdO!bqCW_ z7i$e(?GEGc7J)glEzZb|H-xA5n7>cUZqP{XbEQ1!N&Zq8ZLKFC)gH~2%3K#)M-9h9 zMs7iQlgoXWy{keV>h~nLDPMsf^?`F$u(^0`yGz6ol)H&vsqgxxOu>Ue3^rFbN3_sA?OPQt?-7ZPEG|p5k6!) zl1!_yjFq1}Yp;Y`;bQ;9+RlFE087L!0>Q1R?d3)8)#wWrt;}D3dj+r~=(Eu74@QW+ z+ea3Kx&8ihoh!$}Kh1I4M-R>oScFgGL6RnSv|_&*vR>$&I*iG})&DIDR2EJn`0RiX zsVjnOpJN7z5CO!=<+j+JU+bFb)c%LX4^{UnQ(-a$;S;1cr(OGg2-3NIT=?AqNYWu% zXQ+h5ar~#8g71iCrmb-N_aPJfcMK8UZE&<+0K%?7k0>i-CGZKz%xug`lXkI}VQ!r- zzrq_g0cr!ld|5Bxi$u_%nd8RK(o5GSfMDze^=}VGm_afb9pb`GXifnHVrfjZ{L_cr zmJqRrk&Jk5;K7(%RSuCRc&9&H7z94uM=Kr8FMJMd8x(Lffq-ARfcI+l>JH4k3|)BV z%yB@3ASmCPv&0eAn}GYT@;a1+D!1$Qlx+3s!p#8IvA+SXcmJN+{^I8p<vlO`9NicMP$wM)Gi0hSHtWqKDqn1W(4)dpW3_wM4O?p#G-&I8kWxE7Mg7kUwX)$k zm&? z7L4)!^G(0>MP~fLet`R}Q|T{a-;v>0_tLnKT2`Ps_JbL|O+8N6->f;qudpsE2i)y^ z=K@ipz_=hX?h+%yu|~3Yc1s=5ohj?8`bCHbp$y2OL5`Lifz{>(7TjgD#pcr>VJ8s9M_*r>Djvn$r&F49kxtRCXmzy{YMF_=UYuohn z#?RnBVSJmMj5?)w@j+$OaaFy{K5l4n492W@!5ZviN4VJO$0vQm?hNCkrm|q&Mky`( zfmEa+73y~!r&Ydh*%av&O~^Bl%arf7P{(CkEnKsH(zzo}S7bE50>x0bDvh(3zm(YX z*_y^@9dx%>oyHYEfWsvr$Av-n?wQdir)}!;9mCk$ZC~rNiPeb1-`P@$k!r662@UY8 z2VEs(0+QwreO$lCmmBMEu2`2&^vPms2N!IDB2E1^vrkNf=H3Dzwds%B0@x|9QEr|? z`bEq<@=pd5c`4FPL%GbWJUNLn>^8)nu8bK42Qh6_#l_Z@TmHw&L~M&)wmXj4!V51b z*6lHw8t>z1OcGR{arlrXl)FElLQ1uP>6T*yKm>wm__tLf=QvYvt3AH5JPlUKQHve= zqicnZ`G#?Ik}`e$U4GYt_U$bjLMQK5O1fJNtI~@Jx2v?)4y4wQRd7iL?A_?U4VOKY00O*yc&ZNdC}I@zxKe6fYrJtbC#>mSbSoloiTgz!YTlBFc}7k`h@g3_+q?Lcg94Nn-RF)O}$5QKiOb*jsXJe zOi9N@CHM>7eUR}yPT+zmj<{*8q&1$6H6qjrovHRSwU= zEMd>twkPe5j6o!_Z$_G7>+)Mw@pC%4vc0*^@hRVR!M}B9tE80~fgn2kou%9tk8=r- z*G`oEx#o~`5`o!4dV%7p(#&AyG39C}D!vwv=toocULZU)od(jEB zUYtXOc+ri9!pfV{OxINEjNCX3lye@tH&)BSzeG!1}^D0!s68^(L&_K!ZXn(i_=N24=fw1&ZEj1UzGmcZ)X=V_J_D z7$?1`Co^9oz4*%p>g@ow;;lPvltVLHhc~J;Vz*JDV&eQ1_b9q+q2(GxkOxpn?+2*G zUY;z%isG<#m+GaqU0Mnmf8;pXmTgPA^aHxwfhPevfBm9h<+>s#l?&ZS?k9b3DOmT4 z@nHh$yA5PFyJD5@ZNq51-`SJC+l{wMi>8oLtJ*&kgGg?{E6P+WxawYm01;MW&B6lr@t0P!prsbD9vgwi6l#WF3@YDlh3DU zbS?)RRvu5qGM+Rp<+dWP@XM{|+FlSlx)^M=N6R0)BITsJUR8vcSJ$xwpSy%)N)y&T zx&b}46gzD&-F`XMntgBcPfCbz?&3|)vD_%Q+(p$l*=m7 zsA7mW!U*V7-N*j)oImaBcoFmPaLV`k%5R{f4E3Y+hsj-58MSY)xdv0^MZg%#9=5`C zfkOlH#s1Fmy0vYnK7lk(t~A4tr&m+dMQ7DT8z#5>|B_rb3L=}Yhxn)?2C(uiO_o!B zwCou_OO(=Y=yDOV%~UBpQLsq*OX}z{KXcQTas5kdN574*g1#SEmpXSXF3fgqej>8& zQF@F*mPgGBvnTSpfj6yrYh@-*GUwOZrVa4H=>GGiOzp% z*aXi7HN5I90*LFGy?&F9JiM`>q}cOfAIZ??I0qsqOu)?2u@Esp9$BJER(cmMW`D=& z4d0$ls@htlar9k}b|>a)aiqw>?d@E5hr;rV#XA`&%@kU%kWlwAEU2QCwVpXGVGwyO z+-YFtywOpGtwu^j<<{frkU!H;CUuaUw5`BkSx)I{NQ0Z zbKiX=u5PCEgwkz{&zJ)$ACM5{JTN3QrlhzV8K)m=Pq?q0QsCqxT0lq7oH+0~R2z3X zzTr9P$tW0fI35Up*?h9&fNN1{=YJpOzZ-Ds=Sa=y%>ngP8AOaN1o~sJRx9Lj%qP;B zLVWM6D~?P(OUA4V7H_;t1hs0EBFOUvB(rC)Rc+!b%#-B8vXyvS{rG++$qjCVDHz?9 zz2h=Wce(KJ{!?fu;xilr7p328XEud;TE__U8aHS?^WpS%`Jh20Ascf*5wB`b!~z?w zb$E-Y7TjOJ6lT?(Vc?1-;smtrkxW{7ptC>x`q{tq3($i_8|4=GeFOW>dp8b$Q+|kP zhuO+<{nSZyL!Vu}yz*H>W&vAtd$$;God0J(pO{^t%`5zTTYtv#BCzx|z7(S5}r|si&c&cCa zK)KRu@v$ee2}t5zd(%@Cl_Pu#p0QRaM5;W6EM=~YO$90i-dud7fI3sZq}J{upN-Z- zl+&(YDk&RzWidC_AxXz|KYdAf>7Jp>UYGI7lFAMe)KKjyx-0|{+fbNQ)5i}ih{m73 ztlB%vRgkCV?<#%sGbehqc;yN`07bFZt(n~#&rh~Ji${8N4YeyewCT;AJZmjmU)C}5 zO>kPL1r5p|BCSOe%I97?S>*nDdyVi#pmQbsst;;0cxsf6&lXW84)dNvV#fXW&u58x z7GC)I)V`Q?nBcjo44`a|WQd|&arEfBjgs>u*dHh2SogGLRrwc1Gbxcm0bc4qs*8E) z&tv55FgyPMLFS|kR)*>+=lv*(KqlY-k1nwhWO?Zo$a}r4x&h{D{?T%snoavFzY@HF ziHJ_&C)pF(6d%|3awn-)Q4#|?czM>0Fq6&g%&Qeptia;A+i3`oi9)^9;+|Z?Fdo#N zLEqEzY)xY31G)KF3T^alod;!L;oySW_2Ztx5dB+4a)B9}K@}3mM}p_~PTh;%T2vk% zt=FwTijku}$fuJ48FXhdkdBSPQ=xE2FH7YzKf!h&zBj3NFMgcnX@d54X|(fGdKjQp zQfO`}nHc~$E1&%eECM86<K&{5P)9ET-I#oXUb{F z7g(%pk4&0)dEz+FJ1r*0wQ2L2$@S_tJ`SYK1Y$p>+L2kL<6CG|t=^q`cN+eKLoLE^ z=5>rJ01y=;8lw~NjtQ4IQ2vuiFfnYj(5@i9v z+%w|O-|?(2>Tl{#Q!UVwPP{+wF^FV|0k0DfJSKT_HPpji_-&kg@6_Q@5Yt#QnrovZ zw(9(MyKxvVf-5oQ&HX>pyq>nJlz!%jHaa&JH2oeS^-`)0PDvfIs^-)~z8BB_UnK&w zy@9Pb(uzAF`zOR#isZES;V(MfMV?2*&J+n?n<4gt3Xv#HQUo8d%R=NOQ#Qr3{>lFq z>-M;gfg3tUysP>87S-%a9#Vad_5*xC9w9WBQ?zR> z22K7d)(LtL@fK!VFQ>u6Kp_bf6QJ8VU2=2~)!^$wJoNaKr7r7AFpb&B{jX_HhQ{t_ zl{j;e1PcZY{K)q%KO``NwtXwJ|4W>v!4=i?)9eeP+e$uBn}ModI<>)@n;#Yk4w_D# zL;mI5DBiZbe>pcin$6O$p*y^1!Qq9(;gh9IT95p>NOl8y18FQN$D`^s$1G(Cszx=0 z;3ko=67u5>MPHyF*fBk-EIiQcg`bqoP8;M^U@V`Nf1&bQ=GYdVb04U+$aDYHfIGoz zDEJa=q1t>-_DLk+CkxN^i?1&<{N6*hkbe|S)a|BS&&=lh zchg5t+_fTn+WfQ&x^70ie7#} z`=QW5fwXUDER=WVGt&zyGj6sqv&>ae6|1e$o#l>p^V1MxTiacc3G>9UA8_J8zBI&a{;uue06E2Q2@!@vM+Ssaa7RlTY~ zmg*)Oya08N%Gb>b_&a`Il!Y+ZKDiDfi+tpL-PTZgSpj=YUl}q-99eN3`>n*Vga4DI zLr_}M1JuT(X6m;;?DAFvRo_u#vJ&BNA5-dP`FT7|%!n4#lVJ85YEH;Xmk&=35ZJS( z2hp-;lK^=~i`L8*uZ*<$cUX%gocf|UGvGuC|EW!&5Acn#$bcesd$;^Vbmh_= z_e?E_o)^Iz&XOw01NlM3+qX{^`@LEa$jZ|xKL<9Jm@8eRQwC|`FXj@l=B^m=|575g z02;lfR&W0nTspEGXB6y|Oc_tKRv9*=c64Xqgr@rK>-8MW@OQXP#aNOUXhao(pm#ib z`TeO7uh`;2dW>{NKm$}}e_CIN?wMV?Um8*~zV5-&?!R=4Jw=|2@_QdsFA4MD@m${B zl!tTO#z|kWHs4;Yx0EGp{_+vBS>$BdDm~wuuHZ`)Stckr44NLmJgs~&tC4@#o#U0q zKn0Qk%0B50>V>^We|~fy0P-5TBG~fXSEwCu({B7*)7_!R059y9MXq=1<8P#6W#O7PWP@q7mma6tln`$z;calc zaIE1Bm)|A)>UK_}NxB`T-~X`>7e`S17tM`&7nV9D9lJQ2rMjj$`r|R|!Jh6Iy!p-U z^nn^ezfa=BV|S4RuN-QpK%?xLH1#Sb|M3-M=`y$8gzetlL7dS}O-ttYAB(v%s`AL& z37GzrUrU`$hBJ=Y1E7!=6U1hDpLbcAwzFuyci+V|)co@+jL}-+E^qHl*hS>IkGoG7 zyupFxcubxamg_%RaiddkynCTiOdVChHQzAg-p2e$B)jvSfqK>fVndYrIOpEq3*CaI z4w{(*ge_&y&8>F-$8EG_$&b&5dbOSuQ=(nS=dLmMb4F<0d3>I#(`N^cfiSmKO_gnu zCDN6#!SOOwozF>(k~5a7XqPx_$o-x5zqsXFBcx(;kYw+iirX2CTDqRMYkuQ!Kwcf_ zSTI0=nZugob9M2r_T#9>pM_g!H5L1wfy%7P8lB*8{7W>!^_A?(S&ZUZZ}Y;TwQ-xJ zd8U9y!=odjA{xTPiT#&SiG?Gn74nJVPw5y*`XPpuF{#-A3Xd((UHYeCCB!)cUu z^)IQ0u!lhtVXN|Evv0Wn^wb4+@--9F;Ph=MXB_3Z4F|6+>psamHaE?I(@6Q%6M3Kg z?z<58wNySyklXQi8{D6vnHlKhA*-1hkmHO)_*k7Xai}lq2PV8EDmZE5rdysRTRglg zMDn|LBR!PK<6WU=BYn)rsj-Y{;4}d|hoqWR_=gr|tyaom+a3DOBLYly13~}G^OA*W zjapTl`uUoPX@AQuvHFw+Rs-qfcXq*F5)w0rhgrCg4oRx&inU5h)m!m0%#DL%v+1Rb zX?Yiot;c`vPN*wuJb?<;M&+jvm^J+&{o{+>h(E~FmURSrV|*I2El|E-Pm$Z70{2^> zo)nZwPvb<}xyEbXYGlEAD6q$?RfNHuQPQDI(7uAh8TU&A)t95n6a_frvjvAbpZc{%vzd_AInoZk>|)N#I|Z8W|?MdH|4P+Hk^m)Sq3?mM(W_ zhsY^%;NU-&9ubF`*`|NorXtGpBL#-{vNU}uClfm+jucga4Bv>y*QAd4rGFR zU{&L1Hl22=VlI>-J0|}r`ExfbFuG41-J#PE-3{n4~VVT z$}wxg{=(NZ>y2(Sl~*)g`hwR5~@ z&KHo0di$|gdpwDk;x*rTq2l$oBHGu{kHh`li--8sJVM}x$Wi-+e&DD8KQt1;!muBq z0wgwl#XfH+e#H8@_}?COrB3Xci`!ec|Gd>toxeyKyWx)E5~72>d+bmgFT)#U>&YrA zKuy@gl*~x}I-1b_MxbNWaVn=P|M|@pzPx_UVYINF`}JHKS)}hfs5#RDhoQQ|uj^XC(bL zy){m|Qc(e?xbRrHiBi4XHq%_^=V31#{#{uxw$%xG$zAl9Xem|S6nW+qxYbG-+IZYUq8W9^2#4EF8v1kPTfj1c3q(SiqQ2S4lh_Unkr`1y~xR*g3T-r9*Q z(!<{UK3B~|y{G@s#2q{_oc|?u_Pyz9cldCOd)xB%T$ZKN_(?eBW%_7-f(@;id#jwzx{=t11V>EiecGs&GyFceYI_3Ezpc$YafO)OgyucO#O_nOdGZHzozqbp0 zQC!=Q1K^YqtNvHa+bD-?T-HYyYsM`q4J7J+fnbQD2cmjigSbPh=#k^_?TYyL<*|Ai z>aO6)6fr7O+1>)^2obc1c96^ZezPHApQ6?Oj5Pu?`*u?mvLy_8{d+*+^Zv>9YaDe- zi+5(37N=y|-QY(m$ad5gIQ;3A?WmEy+bb;A(r^*ukGQw2J)^_S#y3^XZ^9<*sb;+_ zI0KyJipFLTnGk?2y8p4o!uZ135?P?)0D8naCR(qcrNa46yRuxl-`3A5*JmkZB_~p_ zhMNO*`4^Xe-*txVL&4d}Y02J=D_R@C!h`%T;@&Q&<4W-Hv@JsCB}ZqbGzH}o{}Cjh zXdY6%&MvVX*rwkYJ35_n$7xG#zNA^wn)&V(fx%jVK0P{$T5+->qq@lGPAlMFa6_d6 znCPO&(53&g-K-!NF@ZNBy?pYY8<~cIm6Pl;lPB|^o7p|dGAT;VYbUQhgT4?#hbQON z*FeL+q)Z00l2pt$*C@6ML}~Iq!``VDqy!{)K1%n8@eN&bHnqAz+wo`tzG_=S=G;=P zT$qk-gX!IIGXQXPqZTUn&Ul;zWQv@tJk@t%nnNG&pnDQV-=}hn^e+g9#_~z`uT5p$ zx7ts~Ldo;#=T#V5igLY9f2E4Ia%t=}!z73lbUD_js-pM36`PW;dsadv0u3B<_VzSc|nOcvFX_ zlk&A}0^M!QbfG)95m2rb^Z5*sGX9d|{XX`lz$r^u@~`k0Rm<0R8cw#g_*az)x~cW+ zQ}+ADmeHfw*x!i3kS>!QU9fsmrf{e8@+~_@-=;lTe$p4=cckR~1E#dpZ!daAEYH4` zx{I#t*U4(~8V1uy0qC3xbn_&-0lVC-=kablUL4SO?zN`K6@R%gFmO=Puq|Ge@HvQ( z2`1(*zr0YEv;U*m1OKJC%W@A8a_Lj+6UC3qo|c&NJ$iM1WMXd zfavAA(XBlt2>xH0e^~IjK^8~R4f2?b>J)H;?_&#fmvH?GWJGy|DJda@Pkj?Vp<-1n z^WO~u|C~Dz%EHPDG5pu&KVI-yBZPW_WSc@GCZh3pOuEiQx* zTXMjL=_=Jt6jtxmHi1V=Vj^kpJ8Ohza#VmqxTJqA<4vslivOF`$>9W}o|IZYIWHgu zDX2S?bmkTA4C1P&%-;8wn0B5Bq*%;co}1!q#k9AebHz?YGUa*IX-}};q`_bbq007o#izqmfC*ZoJI1@;OP-Riq*6>)S$VB8dl?o(SgZvYf3P zm3#1>@@pG)d4LWkCYH$c@ zE-~d5?>w=mrN7gSEy*a~#y_=3Fy9R&Bu{D>_E7Qtu&u0H=@&|zZpZvn!Y8b9bjFIK zRqRF3Em_B-5E#FKKs;T%2z(Z_g>Wa@%`Gt7a zc2Dwj8@|L+aW;hAX9lMHdb0IZ$Hl+ygb#aXzMT;eEl+E|3bOlx^bOfav#OX+Jjr=p z#7o=Za37iLjXQ?+pF1dW{1TDT-4lVWEVH`2RKnu>w!t+@T>doBt|$5wSIzTC0t^)u z6ct+ArL9gHaNMbqMpvUL$jwxE41;3%-#lf4f~maiZd8!iOMq;v%SyVz#BXz^TPAQy- z=ZNu}^SQ%QILWp{q332TACC5?LQi62iDn`)`R>Bjs*w*Phi(~dzy6LNJb!O%Ivciz z&(uSa(P3MDSd3ju@;6&53X@> zMkk(cHc0y@Y@4Z5Ck@Q5xk}Dnd*|1vu9jCQ!0~27^3rg$!#Gc|P%2{5a9*+-U0*ZT zuT1>*@^R56EeAFmL~Z`^x1@xPvX5r@@yq6Z1r!+D`G&h1y3}e^_f0t3`y?;=3Jt`hKrG{ovYB^Qc7F6w7+6 z-TTq(R#{6io&D&o!&FXg(mNWnyjY~Hp&<6>7U;GIOR0xi_5EEg2* z)%ekrBjT-2NhHzU1Ncu&E3ev`$X0ruuYm3Ak4-go*ug$k^4%rWNgBgR&^nskCebND zQH4OlWiIoi0X>)_k3@)0x^8j-V!UwkyWsavmhqjAwD$Ppcux?1f9{GzJF-|r#JXIc z#s94BrG`Bc+EOCJ`cOJvIA7(5VNbL+O^RLq>C-vM3Bu^qA)YNNytQV#&uLz~W8z#i z1F^+md*Jb#tV%M?vqnZbG5;Lj_${!f%II0rye^mXd(8RdDpxfz7vZjVzOTm(pcoep z3_g3MEW6V-H)DLzjrI)WJ1Jc;#3nC{QHQfu31;_Ir4OufFuEx>Y3HiI*3;`I#MQ#h z6?|^a&emYmpv;xbmZngpc;kJMd)m35z?;V0IVz+?i)}v@i=i&DQ015B{KsWSi=9x9 zsy>snx4rjjEY$nNE#!eWDOJ*nw)mMJ0v_NKG;g|>w?A%v*B)ncaXZddmhe{x${s5h zrVP0kp!DPW*FSc|n9{yL>F`kf*m1w!1z(HsL*{K76Og)9s$p@|uclw}nDNiaH|zM? zt-4Lm=uWLu1tTL@%1YLmgZFxfV-rdqb#z2gr}5jSb!+|!x5hTL>q*R-XvC2qHwNPVO<^yiWz?78V&jkFBV8L)vN9WUVTu-?Pcjti7}sn-)n)0d z=Z;H9sTg;XP&Bu1EcmW(uJ+Q|$LTf8apqd@MUH-M;i(JU~UN8Q1 z3qT%@Q6W9(aKe@51e+Ybd*!UxC<#)%{biKdBn#Dio7`k0nNm7tokKmA)W&hwao$QV zye66ZPT~cN;HLYm=IbIk`EivWu#(Bvo9)@6I_Y4k|K=Chr(zC&kdFSc#lg}>r zOg5P_M=hrhS<5|hmNBzrveTx_sXJ$z8-M=6K=itG5B2kZ-{}ZqGEN|v8TP3g`Dz5M^MSFae9J5+yTLga*nMNB*fN$Ki&Lkg5%RjebVaWsgx+vhUQl1r1sQ1>r zgQzLN)`~1dK}3|sq0Fh!oiWL^CB;()9`{rVYl0|rzyEFagj+C!vR)v}V@Cc9Fi-G%-qaS=SnF}kTin5P&>V{61_qhLejAVsskNE6 zo+Z}C=@}oP?4E*h+2A%trrZ>({k7CcA-J_`Zvoj*!HcR!3rd8w-|^kv1U&cv*&#BSo( z8iMBrT8?(5aW{((y9(h2upbSMf*-Vp_+caTkI*8L53g#{^^t5p#q{YgNdDT(wl+?> z!A=+UQPrF!gxcQ%{fF}H&YJjr+4gVXBZ-JfFGmu+=d5$867uRvNe8M&lzr~33;+5M zch_**A0g0q1c_WYw&HFEfOi3$>;=LpHM^ShZA@zQWn zwZaFjbU+6}c&FLc`Bh#w@ar5doRX*pkRsy+K^=Oo~)0%aHCi4QB$yvzL zaFTBN#pYybNS>&Nnv{LFi$l>^MB3+)IQ5B(=-NK8OI+neP|Qlh_$6j@*1 z=`_tySw)a`4NnXBGB*>s<2#y19Z+`)E}=sS+t~jz4&av}`oO;&ERK!CYu22|koV|P z$|dI!`(-_urH&;gFfq}e3k*(hr~RMJQ-L87TuM8tjptwa1(z-4(=n@ji3c-vUB8?; zC@e_NgH`8wW0{0SFy?BHXr${GSALxXXC$jhE0_~ilz`EBdHa`hJo*yIp2mnJ063Lz>s+S5)V|T5q@7wxxT+IH`peP_-3!u z04`?J2(&fYynY(6Ua&!c8I%u<31#T$d3~L9HT3Wj%N+qGmzIpmBa^%N{j8r1Iq^)Q zHae0am23D~xRd-4$N8m{+2wb?_Q`;0oZADC!m|?GH`VSQnQ$!m^cVk{o#%!yj;9^g z?JhqSy{zsUDa-7G5<5aic599oUn1G7DO`awnYXC|f z$7@_Mi>)*t!=A@6Z;SF9U!m9x>@(q_L~ZczrP%n@cqAPWvS^-tq8E6`DO1S4vsdP) zZBwP4VLVl3<2*iQK@^m^?!iTjk${#E#LAZpcs^`iw8>OwiO)j`eZ+DjJypz(m}T5N z`@v!60!v0Ii?`rKW7F!S!+P$i+V{<<7Bw#`u7qFIk~LCx(!>eG5Kd3p8ES5I%OTwm zfx$<>4l-Bj%^6DhCh*ukM{=|L7ZCnY-v9q`yZ=5s@_#$T7rb&W@jASV|5fQPUSK8> Oq#&y*Qz2#Y<$nNl4h<>* From 16dbe99329b6231d57a02988f7701aacbb3465cd Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 17:54:20 -0400 Subject: [PATCH 19/27] questions --- README.md | 23 +++++-- img/scan20K.png | Bin 16106 -> 13545 bytes performance.xlsx | Bin 39991 -> 40989 bytes src/main.cpp | 164 +++++++++++++++++++++++------------------------ 4 files changed, 98 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 8045131..277ba31 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,15 @@ CUDA Stream Compaction Sarah Forcier Tested on GeForce GTX 1070 -### Algorithm Descriptions +### Parallel Algorithm Descriptions #### Scan +Computes a exclusive sum of all integers that came before each element. + #### Stream Compaction +Removes 0's from an array of integers. + #### Radix Sort +Sorts an array of integers from low to high. ### Test Program Output @@ -98,28 +103,32 @@ Tested on GeForce GTX 1070 ### Performance Analysis -#### Scan - | Scan for SIZE < 20K | Scan for SIZE > 4M | | ------------- | ----------- | | ![](img/scan20K.png) | ![](img/scan4m.png) | -![](img/scan20k.png) ![](img/scan4K.png) - -#### Stream Compaction +The CPU method on non-power-of-two arrays is faster than that for power-of-two arrays because the CPU performs serially, and the non-power-of-two arrays have 3 fewer elements, so it finished faster because it has 3 less iterations in for-loops. The difference in performance between these differently sized arrays on the GPU side is the opposite because warps are allocated for 32 threads, so non-power-of-two sized arrays cannot fill an entire warp. Thus not all threads are utilized and the warp has lower occupancy. For an array with 3 less elements than a power-of-two (as was tested here), the different is marginal. But the difference is much more apparent for arrays with 1 more element than a power-of-two. | Compact for SIZE < 20K | Compact for SIZE > 4M | | ------------- | ----------- | | ![](img/compact20k.png) | ![](img/compact4m.png) | -#### Radix Sort +The difference in performance between the CPU method, the CPU method with scan, and the GPU efficient method illustrates why different algorithms are required for parallel and serial executes. The CPU method with scan is a CPU version of the GPU efficient method. Without multiple threads running at once, the CPU version must rely on multiple for-loops, more than its compaction implementation without scan. Therefore it is the slowest of the methods. | Radix Sort for SIZE < 20K | Radix Sort for SIZE > 4M | | ------------- | ----------- | | ![](img/radix20k.png) | ![](img/radix4m.png) | +Much like scan and compaction, GPU radix sort performs faster for large array sizes even though parallel radix sort requires more sort passes becauce the GPU works on bits in order to benefit from scan whereas the CPU version works on digits in decimal. The CPU algorithm calculates the maximum value in the array to determine how many sort passes are required. The maximum number of passes the GPU could do on an integer array is 32, but since the CPU version only loops for the maximum number of digits. So for performance comparison sake, the GPU method takes the number of bits in the input array that contain 1s, and the calculation of the CPU maximum is not included in the time. + ### Q&A #### Compare GPU Scan implementations to the serial CPU version? +The GPU version performs better for scan, stream compaction, and radix sort for large arrays (SIZE < 2^[18]). Since the intersection between the CPU and GPU methods occurs at the same sized array, it suggests that the slow GPU performance for small arrays is based on a overhead required for creating and distributing threads. One that is only surpassed with large arrays. #### Where are the performance bottlenecks? +For the work efficient implementation, the upsweep and downsweep kernel functions require a similar amount of time, because they have the same ratio of compute to memory instructions. Most time is spent in memory reads and writes, but since there are not many of either type of instruction, it is not possible to space out the memory instructions with computations. + +#### How does the GPU Scan implementation compare to thrust? +Thrust exclusive scan on power-of-two sized arrays performs poorly but consistently for most array size except the largest. The consistency indicates that the thrust implementation might have a large overhead. While other implementations' runtimes increase exponentially with array size, thrust with power-of-two arrays remains around 10ms for all array sizes. However, the thrust method on non-power-of-two arrays behaves more closely to the other gpu scan implementations with an exponential increase but with a much better performance. An explanation for the poor performance with power-of-two arrays might be that thrust implementation might allocate and compute on more memory with these sizes but not for non-power-of-two arrays - the opposite of what the work efficient method does. According to the Nsight performance analysis, thrust also has low warp occupancy (25%) and high number of required registers per thread (78), which could also explain the poor perform for these sized arrays. However, thrust makes good use of shared memory. + diff --git a/img/scan20K.png b/img/scan20K.png index e280bc719f02cec4ec0df6f30435bb2b68f8fe83..dc70d2382ab806b872ddad30e24b71c0a73f0b62 100644 GIT binary patch literal 13545 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 diff --git a/performance.xlsx b/performance.xlsx index 8d322e608c85fbea8ccd90514c552ed1f20c092f..4f17d0f5f429230b5b0e8432f82f3ba0809b688d 100644 GIT binary patch delta 16174 zcmZX*19T-_(>5I2wr$&**c0341QVUuKCvgZZ6_0FV%xSR$(Q?izxCeV|NPx+b=U4y zt4`PMz4xho)m1I6VA;K3*vfL?5Evj(ATS^xAfzC+SjF+6U?3osb=VYOfLVuC7L3p< z>I*`$Esep(wQ_4PuUUsw-6D77?Nw-#o#m9cwf?oM!C;$m8dyaN2blP*&$nq}dfuE3 zI~%o55s{1YEd3NU4gX|C>yC_up12;WE$sjmEz0Ny7E4_b_lD=c){m_Z{*d2wvl{56 zK7(A7Fz3PKj{5$j7r{4$1Mb-?Td`djHF|4`=WLm>V~qAFxbW;)JA#Tlx$2(Ve)V`L z<}{iQU0k+9aa#6!7Zin?CG}`MAh9`*7p3H7`BclaOAw3DRDzh;%Mx>-4uB6z$B^zp zr-LHoK-qWDm9gOt$a;6?EeexxSPEU1SG|e1kXu0xb-~=Ul$LpP16cnqgggLU&u&{s z%VrD1$8@YZo_vFInWS=%QpxeHU*-Apg(G*Q$D{m4l(KK|wCo)#_4&3f5ChNDdjj=X z;G-sZLjgf*dv6_K!iIdS42j=EKIcH#dgA4-l3B0F9ZQz5T1cyt6PCADG z1pyHTZ?J}@1qCFI+YGWGNIr#p1kH9kv-v8AI$O-DrrBru`8y@?$eTdx`tD!Zs`CBr zjd!SLmF|Bcis)DacvL-85aU^5n#sTgR=S&;+Cp9pjZcz?_gcx>Wm7_eLoOdJX?AGZ zB?u>ryA6?wh|&W;_y1ivi!X#%?B4 zaOyd6yR(F$#0Sww$}snNw1e9W(WOi)auK-P19_WLm|R+HXb`;Uww6aGrW;rtKl?@- zmXCx%K!EK0=naXm9$*kzdAP+uLWC^SAT4ZT5XN8k|vSSMu{=SKZ1x6t&uH` zE=14Ws|!jnYe1{fXrz2jeh&CZ5m!5-V2@&;;k9k3tAf1FL!3wZ0QiLjyA1cnK^>NOFI}xbsfA_Y;)EA-k z$%v1s^iY+@5u)V$P#GL=lq`c9#&+i5gJL!DD~i0kyF*fwvawv;!pl;}8Y$n@k3KeB!9wGvJ3pyB0Z+dNT zcgk;pg8o)*nz0B_q+{H1Hy;0?qQRL~e9l1K{x@R`jkU#xADA>DsF&{SX01%rXE+hPi_xxFn8N*nlY@ zdvPN#^{O5ktOEeC<|EH>fIy1b=a-n1l2v3G?fMq*{7bx=;AxVq+5TCeBfgB@mXn<1 z=#YPUQ<18=)c`{?z)Td9tC|BOvIAy-CIk=UO7&`M$v_7 zvMhhFECrDKcc+X+Vk7cEO_`bZSdKbI5xrvGI!8A@Mf~?c$|7h)0Z4A)$e*DU7`bFs zK+f|`_Wppgn&cTs2CRL7X!F2z zip~;ZSMXRu|7^K9bww*sCRo*G+7)`wEhu<72KDZoyg9o&{HzQ6+ODbb5B;rfOT2GpEZy+<`v}ITq5Y(IIO#S z6pv8z-$}e;1lw0gmL4!ZRN72PJS6Fbmo==o-Hy?N8*Fx{|vR#+VIJzwb?ygHGHE=K)#x@Nk6L!c!$wm+Ol^&MqV6!lY{Rb$EkZR$~_jMZXV#v zs_5tVp2#O|QYWWZocrIq#yvn?eAp3Cyn6xC)%&4>5bC9LA$IBYNqMxTz-mC28PwC) zO-H<&XrY7H(D`X2_LBQ>?v8b7F@g{1ar6VOI`s2TA~>AQCMtmW;mHHhT-;)vnW>1rPRQ@mrgU5G*;>#@52#? zP{XVa-0Uu7XYS9Kjfo={ukddxUVr5-uWeIQ2s?jy^d(Qg45qq}6-pWUA_6{|M3ysE zz(1Ch&wr()o4HG|4X17&hK1vXa&k1W!k^J^-e!Ha4T`D-#t~o}L-hcjokkDA4f6C?)YnV)gYs zB^NYeT`K5by>-hQv10%ySLsnbkRT(4ZchGGM6e<)Mva3mw};=dO#?e2U5Gk>q7dYD(+*tCQTK z=z%zs6|%de>Mzb2W&aBN@H}-2?+K=CKRsU6YCv4esK)H zQ*@fC_l+Y}h-EesW7`)Jr#~K+-gJ*FyVo3>iI4OTUp5p!>NbTOg}QS+KJQrgWID3n zjUR40z1IBpk2ZSle4h;80UvwkOYTocADq+3gpGjfI^nBsBBb1su1&x9jGmgu%}4f6 z|9$fgZ$rZCt&OM657*S1oG95V$FAO|z0Eh9yV+#Mtjkzy)3@7t?W3TJ*Aedz=lGcO z+m;2;*DFKrTvM-y_IMo5DoukI`@P2PF z@yE*iyR`Y-;i~1EdF1%=8ZT^`)1E!>=$hC=z;xHbt&;A+Zz9!g-vWp%H}&`VQO{f+ zuBdS~aA?W2^JE;V{q8th^NgSUIA$=}(*%GjFv0rlIukfzt{`>{TX|e^>wfw0@~145(nHh z5a&Gj^{+OG>DdG;>#5_;1d=l1%m&iyI4QsnH*ODqXQ;=_oS{?Gagu|-wCd|xlQVf@ zEBJocxZOu{Y>YG((Tm|{Oy)nVK2AG2ijl^)m4Yab3vahGgSJ|qKxx{1J%*7eRZ|tY zUd_W5BH=z~vRgPbSVkLl@!_ym*$S|&+wGQ2*N$Rytq^C!MJ{G(;?!^a(Q0>cT~{?w z@`_Yt9hqm>%ZU=UQks^^vRXf8=$TIx~K9t%l27!|8))Os# zbWk*w0=nzvfq{p7A)X6fUtI(Jk}MRPVYegjjw-?vN!;MjI;FX@a$ zxSqVLJP3m1&6F}_jQ1rII4zkj4%@>R?#V+7{6A31gp=-)*ep0?jo<;G-n9LZOAAbZ z%ds>s)Ep)hHIK(kGQ4hNg;iGOSaI8=udXFXd6;Axm@9HfaeHI0&>r!epfNX}wF5XT zj0^CgO&L6>*G#EtWf8#92RVEOXq^BP*exf?7|D*ATc=A&7;$UiwNKCGt36tiq-Axq z$2w{5#7$xQ-v9X5NB|aj$`UllWx)nyo*mdV@o?EgFQTFRRU>1V;p&vfiR-*7-ChJ! zomF~-L_4uHOLYWA4KI` zzmXv@I)jeqV};5RJdtJT=!CgyD55HoP8m&)8^f^!H8`FZYiaI(-Whw78Yv9A{RrXO zSMIE=0@Q@#leD5>#q-5UW`79O{f8d~}Zml7M6~^QF zb{H|RA;3(T=v{XOB@51o&_AOm@1SZ`n!pe_F*D&7Odb*4$?#yCC|8uE%hVZ~Ja$Xg zHsf;sorPH;J^9fkt_$x3x^8VlLN;Oiwu(R+5uiIxL|)icDVRR-r%EC+$UDi|i=sL> z-PNGGrcp-CG_dY>qL76-yUO5zMe%ggq6(gqX+u83LhW)KxT|$SbfrHht9taWBF<*< zv6Zd~}P4UF$@KfHy7@3ppw<=JIb0T?kumRbS6St5)=HAzK%gI$?X^d>^ zt{{(+VNrJY#1Wxqc9aIDUL%e(VRQ!mr-GSq@}Ffnv8ZbYiz^MX9oK>Ibc00Yqv}D@ ze#$w&8gl|;n^gg%2DDVNEl0aX3b5R>5CECG;GdXsZ`4C)+ktz)e)Izdz~OIkQoJ4vg$=-tK(xX>cxQ`k-gGQ;V)QfVJs+J!M)r92?gG}GbR zEYm@4L)w{B=@!w3f>+B>FFlnkM+R|Ba4Hc@65%*9cK2)O@sV;9%`{>dxMS8-3YZN{ zM5C?fFk?Xugcy(NNc>?)CTNOUd{5mygdE6B2PiE~^`lY82s zVHd~Bo^qhUV*GYkBbeDQHy3!pF;p~$%QoqbV9OjK7qU0HSwE46Kf*cgCx)yD#05pn#Q;i26*vUOphWa<>7r0G z3H}H#cRIitMR&cJ*Vb z06lQ4DiY_`HFt!C&rL|HzfWt0rj zG<0n_J-ltCF&{r^sSiEPg}tx zSxFx|o&7_L+*5vyPDyZ<1(=sgD7#I+i!w~1IvTxdAYfOO*~EuO=Fn$?B*gfTG{Bl5 z8O9+GPpNLK(%Z0JBoq@VLWDetoXEZ~8FM;%@(z_3(%?H!>|4_Cf^U@*!{FZ;YH(9Z zgq_$OGdz#N%zD(qRBcxc3)S6gytssLGaZ}gWlDRb3&$o^*3A?aY8Q<;FjDH^o~5pD ztWVNM4FFjvbSp1ySk`zW-Eq?~v{X+ghyB=6lxDNSZ9t4R*<4#?jlOyDb$tads36ts&+Fw@js~YmsZDxE=>U&dxBx;D%kGbUUqL;g%=K3o8>TxQd1%0Vq!!Ld%kF>B-`R8`56#pIso| zF#h5(ODek6e}d#6vi#whAT#E;Oe^H$I)1f6+pUjo$g45=G%cjLb$4R(#xJ7m# zVI}^4!`Fia0dWSBN)ZCiT-I7KKep1l!N-69Xr5yoin@$xG#z*5QuE%6=zKH%6s4f3 zg92p&c}dKD6Y~x4mdP!I##T)tlae)Cn5s^KRR{!uAd#}yN0z%;}W(8 z9CaWSv&yOR;kOEJ=wi$ZilI2YM$puA9Lm?0-RF&jCWx`(m#--n ztifFP^o~PKcE`s-WMaepRqnDc@Tn&1ha@u#+|{Mbls%|Fz3sMXWkOhxRqEkOD5KEI z6(}WF+IzX?JXO-V^_(P}DrCxl__lu|ITq3>A!b01^orIh>wVzOBM;j_+?s}xHlUv7 z5)ZaVtbdeK;IkcR2z>cQM8&BIKofWeDL^IuWiuCcBY$72>Z^yK2Zy5Kv~$8J5>j6$ z*@iX2cajHSX-)-MCw#0uc;Oz+*E6qgg(bMVt!3X?w%Fwh4SA7Ce*df^8q`3!CEYyGxBw7Kk zNfXm!l(QdiHmZO9tN70In?H7ob`5Z-go^h4P`H!LW^=9lQC`byMY`lV1q$aTR6E5~b)l0c5DF;?VilJ|y1xJsMtUUwC_{T|maAqbYL3M=YWK=r1`NRT2 zu)@Nf3s?$ge|{*@ZZV#UN9N-;XD5gtgVzsE=ncsSi z$a>1WxKAVTpzv(W0Qfotz;7Lr#V+O{a69=sY( zutCE{C`jA$LNg7;()rJg(JLl^uHBH=47^~^LbdNO&_sX02=c7Ckm&5l+bBE#^Y0sy zaMZWBb37w+P*;e*;~;{K82_LF?juD@Y?Ya>M#4V2jK+~_;V_5Z_lh#*xs)lBtT9}3%qBAlOtyf zpIfgdx7BwP`~^s)3Y@KO5nRLT zXBk@A4czobxr!L^mk%!Jnm)xYo&V^dyRrkU&EW~w%*F8W^L&CGiq72iD<1jtEVcLS z_Snk^PHhQ+PUZFmwE*I10BtmY3KgW0paKEA7TboX5Y+QhiEP|4%ef@M(xo*@LCqmo zjH;hc)cXFmjD~#;jAbKt$llx9Q!ioyaZ8)m_R6@sU1x3HD=E}kChVAQyg?)e3#P6U0P}Lwlik}m>(h>fPvMvA!Zrw`84>_A809{Nkd)l+|Uoe@1ZiOe7C z^f-GF`HDo;ZT_n=i}87P3KIxM3t5inl6d=>eeOF%cDWNwubDn@pHV#xc@9pKkP3gI z>U7FZg$bA*UaZteV0Y-y1GI&se*FrZCj0}pOIIVa4!|^hqYxKsD(-pnrI!t&agsoV z3ImcU7+|mbn6ef8Nty+k%Bo~8&?BNPOB5goEulVyg`uSe%GqWc693qkEgp)$YRGD4>JalMi4t)eL~hqm%jW@ZxaGl zUUogCC!lmZX>)fFO@GfX^ke8*0dLCyw9Y139+F#42cRZKeqCMkUh*uu$+8E*RnLNH zTDb%V-@l9jQ|f=j5Y`972ad&*4l1dE>e3U6fNw`Na9X%OR~5vaAg&a-d_b81^!`@U zj9u!VilqM2*`_T0V$@Jd_mSwCmGF%A^q4tK7qFnIN#7{PMp}}$QY>%Xvht0ERAd=S zNhAKuK3HaDA#n8mHWs8=gVx+!8Cq!rW#jwE)BP;r3U52VHLk%{RQ@Tk?}QZb9dG0Z z=JkYIRf;O6h@M|0b4PO@c}w3i}|jmUO`bp^aHPC1}_7S9eh&r-ppz;WoEJueu_ih zvUY5X4nfkY3AugMRl3eL1!uTp7a3?SWk+<`6dw^THj;yUa&Ilc4GtB13*sa5?mOVnfQf)#Suvq5uBA>PKAj4I#`y$HzYh<=fq-UE}bei@9H))}|e%nH>G zMJ$}~xto*elb5lVT`-^s{+RC&*}ZLEp=G{N(?w8Q{FiH{@AIEz0c=33>BPbpJ?S?P zXv73y4Mt8@S1V8i7FQv!A=gIJTKSWUXWnmJt)?9oc)lzD>D;GebH5Z^ULW919j|ax z<44wWPqtzYW)|4LPKoHWxnjFNdYVkd;ni1K%UaAo!1dZEY|j9E{AimpZ$HKQ698eK z+HW2@)@@i^y;hgV-PnO5x7lw)Y9{X8n&bg+U^;a6Z*uEcOjqbsxuMMZyD@A$ERG_MTZyRE4*AT#pm!&?9>@lS zveB}cDVF*^H#d3OB1OFWv?ePiThd4$!FJjShB$y ze1EKci@XUjdO~!3`}Ig!V~t#SHf94@A^lc-I)Cs)P%+@_;oj+Muju{uI|EuxGhUZ) z=2?PD+6ln`WlJ^NIM_0?iTs+ZmWAzlPi7l@#-v#;>RLXkB=tq4)^xUCn3gf|B$X>v z*1JL{9%pZ<0c^TB0aj6$pPf-C9BaR@vDP!4B;y6J(-=W! zro)iOA-MOu_n@;7(-Y`B(w#7aY&XhP*ULi!oPo}hte1;gmW^VJDwteF?)z{rhz+7$ zd$O?{c@QhO!5S&*y7*0yT9v}uS#94WP~P7V3ZlM)m@>|7Q@aIe{b@#CTZFBW1;~F4 z?SUpi4J|g-)k|z>^@(q_^6-}AGtsI| zb*}3rEo5i84Un`NKCm30fh_!-4Mp}rumFBk!hzH;YR@Ix7rp0;7U*fmY-(lf^27Ci zZX8UW_IBsGhW`+L06pn`&_vX(bD8*Rg&(@uWqUMkCFs15gAT;6PzmwD>@c+;X1YJm zzg4VG@>qLI%cgWHh3nmpcf@OGY=~&+A{J3N~>O=gVAv22%q(K6w1E{96vR;G< z>t_?W4T#{AvGo__y*r7zJ#TDh0y-7FPoimDwd0eZL?n(4R*@}-F}idVO4u{d34aH| zd2%PvQ9}_eG^WtHzz@0_RE#)xSVRQpfc%6A$YN26)qIOi1;Wam=%!D((nV*6PzKA#2(FIk#@uo@bT6y(8ztlNj5!Ez{zLiU_VE19kd0^n+|;s&g2$w>c0vc!FD#L_W+z+KLxH?a4E|#L z5HO)LIlhq|5In|PFCpp0pPJ&V)2ZHzzn^8%;6X_g&L9x5m;2!0c`7=^6pl2t4Hm71 zf$2uVhkTm-xCMY(6bOqgSs>iuu4%J+XFrL9qKLNAxFaf~-u~GP>Ena}MF6E*qg=i; z&8M}5DZ_aL-Z$7)dL%BF~-~IJrbDoT;Z-b(c zqpNjJM$T)E>SciA1O59r@VUPmj{hw-aSUE|JxX2Epb+rI`T33WhC59+&I~yrHql$1 z76Y1 zAr^w+*P*9GaEQj_QN(g_U>KtuMH6r!F?=(JjnLh1WpZjBha#DFf_{Nm3IRbnoJ&ZRMbjM6=XMxee1X4sXU> zD={*Ft4&qJ%cj&wZxG;?U<^$hN2~xx`vxj+9cS)=PsZ?Fs!Ql*%Oer_^b|aMJN);y zi&UA+$IIzP1>ab;eaMqISO$bQh6T*xlxOC)g$f`IMCf2%YqbNna7duGz_Ic#cDN%4 zG9~7dk#L)YAuKZ!nDWkpL&Y3i5XSdrw3VRKghJY7jf&0+uPMAQ!VmbdgzgvN2m3`U zQ0|NH^UxM_Q!XxhJ{IgGFTGc=lsngl-vCk2j}JC`XAF>^6b6t$!&yq>{4i-0)TS zMF-9S$*8&8m6l~wMH~&BJmle>ofau?;L%9?9SgnCBNdQwuUQ?^($TON{Yf(rvz!mvqzm0`HO36`Au_b1h7x$lYUGRT?~(7$Zh%@% zvosCoME`~l^2FEy>h~z&>NhU(a-8Jf)9vv61EXQ{`df6&-7M%SGx(_`*6EiQr2y&; z8llTeuDmD0JVkn0ybVtBE;U|;^7W_6# z!0f~BAM-#(?s95drXg3p(+{VXLqO?U%Eq?PC&Kmz7*(em%MOZ;-!JMrS9tqYA^t}E z>$SbCuF%`U4xw#P^jI3l^YbRy+o`E^f#2HGQl{1Rd}dUR-+sV}4tO-8$%b+ZqZ1q7 zCh#EIf6<44>qokatITDqtA3)%oQr3$bcJ^oU-Tib-$K>EK*_3N4MeI!L4eDXX}X5h zU<}3Od;^f#q$DXEQ|eJ+TiRKk19$}OqR?oT zNO3EPn9W4{!j2NZ!(de_EC6uk1bs3WnEu0E)@2wwzBXu`n~H|BY2{ny!^&uYufgv2 zU$IO0e^^AHk848ok0-T`teB5iF`!`r*oQC877oZD5Ias~=MT{r1-H5=XTp<+#iqY{ z!Ci6QXG*w8<`|EReo4ve%}pFF&KW3v(TFhRYNko{>eI~wQsvM60M{1LiYQn zFKM~{W*uBf4w~&8fJ0?+u$0QmqZ^{)cuQA@<>OHBW-fGjxe}!A_Jt1J$*VhW4Y`c6W+YwW@GNFV=D zidtTfD_CM57@Oaa9~ba#9B3be#HZN8C10E-{ybj&s5`R)0IJ}-EEy>v;<)Ix?2;xH zdsjM&f(*Tw0B>UxL5}bH;Pi%YxRIOF^11Mr1NGekbf)c|;6wdOuY+$ZYO2q3loH>! zOpLHACP-Daoq^-3lW3&5<@-cREh)6^?IZ8V6}IN1ar`ouYDbr2RK7cRn-&$C69t6<6u8W(@ut3iKaL z?*4&4r0tU5g_93P|^OC&TYOMO}|GT@p|s<4hK%A=)5! zacwz#dp2ey^yK^n0z{<#bY?L>rcam5aTGgxc8*$APtZY_OMpV}3osV)2TxK;%;p`n zWa0NiRbO${CM5V+;92?oU0ddW>mEhVh;AJXh{4}$Xa)3RVDiQT@NV?_*3N|*zJeB1 z=PsI9(;Up&R+%x?rup#@NU)39tO21cxz{5yOm(Dn9;@VN|C%SQgrd6bM5SbC4E#{| zB93^wl39C>DgmPg(F*2;M3shLy^gyM_!Up5lv!xQR21D(n|25Wi26@^gM92xDOkdO zDrF|>fVP1xvX~>lfM%ia&hJ|>oAXwn-p$b)3;ZG`dC}sZe zTTXoxfO(0Hg{m20GNVVH zd}VT;j3h{>hDb5qYq}s_=T8e9Z1``}-LtQTc_*YPsp=C!eg|W(vUetJ;GS#eQrV+! zCWD%Q1nM{w+z3-17|uV7qF-qWtME82YNF^+dzW+to@eILB0QfM+#2XX33w_)v!`Wu z7mUX^#aJ);&AvR$tLPE7U0A{oi5)#^dE`02Xosr1mWJ#e&dq$~Xb_Yc6%fY44vP;j zkvSx*D?F4{&<%ZX9e0uKD?HR>a(AW%{n%1K6*^XzMe0wQEc!8KNOxM*%WLd8-E7npAGYY3gvy_xXz0J~0c_ zKHi;bIz2snY{(-kCptCb7plO+N7DWeqEW2N|-C>64A=ci+G4y76Hqfy@8II3Q#0 z*X@73L*Yn4gX^sAKpq3VSrqDBgn+r={K}bc!ROQ1^&OP`op-YKwMZ$!6wzKn=00_=CoW zniLm3ja7WnDWSjJEpVJcNbb(nrQ`;M>G&)lBGy}jOZt+jRl!CI0ST z&K1PLL$#5cc)e)w=RMfNqbK;OJ0Q|NeQU4zAwsAGEO>KA-8)4^^a3_%U=%&m!#?a| zb*@egrufJSK=(|g~UB9A8g95%yOBrSc3(c56a3Yoy;733)`1}%Bc7Glk zVElD-6Kvwf&zO>e8@>2i5T!t;%vj+??k~nE)t@cPEfA^_2cM z`aL~p%$GOW&@fx~?tH8+=<^!W=F0cem_53{_lv+8bm^tAz*w|sIr;~}M1_l>f$uF> zcL;{GKz1@CHs<6M!1-=}u$cNW#%-wf^SU(GSHYZ~Qheb}F!{>GBB-vplUm0722Yl) z<{;vs+On|LLpHpqyU&RU%T?T`{*WM5GNnjgK%GS}-JX$!12gK)P=y;VJl7qtUXrzr zA+VZw(1onT;*fA?BaeyUGW`R>M-dhyCPxew>#I&fH6AyFOZSsuvZz}9sa6^NGqdjt zmr3e4>%p;}BedWX3SpWzC&#?2&4*;x#VGEte{|{1cmM<;{3l;9;pR?`Z2Xw?}<$*S?^`tiIR!u<@?_|9>Pa&@Cl2mM?M`P+7 z&_tME_?u+FH;vD>>xFvI)W*^&(pQmu`&MhEqGxDcNhOc($<+?E2eI4>Ororun%!*6 zFtS@AqG(F+pka1sN|=8sSlP*__h<*t8ooi012`qAeRGCKI130@l%9ezdp9me>ctI( zqoA>LMx%UQJL{ExI}$00&QfhPz2MK@ja|ul*xeS=V#UcUj>wR~9yn6EK07@rs=$L= zxQqm)W1E6u7s=)tlA@``$FF2eLx>A@kHBnlIC$#9?7fQX=}c`ua_98ox$cD~_l;?& z=S&w6NRd-7baufXzGF#Gc9u`%ZAyQ3!-`UwJF&5D5*7c7^dis8u#@ zVCaM_%i9yjCHwvKYhSfZ#v;}gmSPD!N|VpNeS>_t{06SPt9eoz<(j78yD=p1ML+g%VYmCyeV^ZSM70#Br}7T@hp6lf!2LLSVnxp zzb6DatQ1-_1&$0$qEVsnh}EKZ{>K+6|M>|HqAUjr#`pyq{{QNU5kWxEzxw$9Ie^%S zBA|RgtwbXHf6GfjK=A$_6%Y_ZU_#{6MX*>nAWB z$Okrn1?DU}X*LWP3x?{i8H;8v0nm?$TZC0Pl~gbNsuEC=Sy{dL0z>d?UfuafD&0(kz@ zw4sLs3Z&41CGh^I2}t1p`^EPkapFs?_E*MZgk8fmun^ zK>s8>uzoS%QmQD}tvC=bjf&uZi6KJ&?azQTP%ljcOhpx#lO_rlpa$IeQvcsi%a{Vq)9L>63hEZXi*#y&e^KfGHWq9N9E_R4aQQ2%I9f1R#h Lxvr$-e_Ht(Zz delta 15326 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 #include #include "testing_helpers.hpp" -const int SIZE = 1 << 4; // feel free to change the size of array +const int SIZE = 1 << 10; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; @@ -100,87 +100,87 @@ int main(int argc, char* argv[]) { // Compaction tests - genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case - a[SIZE - 1] = 0; - printArray(SIZE, a, true); - - int countSIZE, countNPOT, expectedSIZE, expectedNPOT; - - // initialize b using StreamCompaction::CPU::compactWithoutScan you implement - // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. - zeroArray(SIZE, b); - printDesc("cpu compact without scan, power-of-two"); - countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - expectedSIZE = countSIZE; - printArray(expectedSIZE, b, true); - printCmpLenResult(countSIZE, expectedSIZE, b, b); - - zeroArray(SIZE, c); - printDesc("cpu compact without scan, non-power-of-two"); - countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - expectedNPOT = countNPOT; - printArray(countNPOT, c, true); - printCmpLenResult(countNPOT, expectedNPOT, b, c); - - zeroArray(SIZE, c); - printDesc("cpu compact with scan"); - countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(countSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient compact, power-of-two"); - countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient compact, non-power-of-two"); - countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedNPOT, c, true); - printCmpLenResult(countNPOT, expectedNPOT, b, c); - - printf("\n"); - printf("*****************************\n"); - printf("** RADIX SORT TESTS **\n"); - printf("*****************************\n"); - - // Radix Tests - - int k = 4; - genArray(SIZE - 1, a, 1 << k); - printArray(SIZE, a, true); - - zeroArray(SIZE, b); - printDesc("cpu sort, power-of-two"); - StreamCompaction::CPU::sort(SIZE, b, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(SIZE, b, true); - - zeroArray(SIZE, c); - printDesc("cpu sort, non-power-of-two"); - StreamCompaction::CPU::sort(NPOT, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(NPOT, c, true); - - zeroArray(SIZE, d); - printDesc("radix sort, power-of-two"); - StreamCompaction::Radix::sort(SIZE, k + 1, d, a); - printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, d, true); - printCmpResult(SIZE, b, d); - - zeroArray(SIZE, d); - printDesc("radix sort, non-power-of-two"); - StreamCompaction::Radix::sort(NPOT, k + 1, d, a); - printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, d, true); - printCmpResult(NPOT, c, d); + // genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case + // a[SIZE - 1] = 0; + // printArray(SIZE, a, true); + + // int countSIZE, countNPOT, expectedSIZE, expectedNPOT; + + // // initialize b using StreamCompaction::CPU::compactWithoutScan you implement + // // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. + // zeroArray(SIZE, b); + // printDesc("cpu compact without scan, power-of-two"); + // countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + //expectedSIZE = countSIZE; + // printArray(expectedSIZE, b, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, b); + + // zeroArray(SIZE, c); + // printDesc("cpu compact without scan, non-power-of-two"); + //countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // expectedNPOT = countNPOT; + // printArray(countNPOT, c, true); + // printCmpLenResult(countNPOT, expectedNPOT, b, c); + + // zeroArray(SIZE, c); + // printDesc("cpu compact with scan"); + //countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(countSIZE, c, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient compact, power-of-two"); + //countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(expectedSIZE, c, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient compact, non-power-of-two"); + //countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(expectedNPOT, c, true); + // printCmpLenResult(countNPOT, expectedNPOT, b, c); + + // printf("\n"); + // printf("*****************************\n"); + // printf("** RADIX SORT TESTS **\n"); + // printf("*****************************\n"); + + // // Radix Tests + + //int k = 4; + //genArray(SIZE - 1, a, 1 << k); + // printArray(SIZE, a, true); + + // zeroArray(SIZE, b); + // printDesc("cpu sort, power-of-two"); + // StreamCompaction::CPU::sort(SIZE, b, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(SIZE, b, true); + + // zeroArray(SIZE, c); + // printDesc("cpu sort, non-power-of-two"); + // StreamCompaction::CPU::sort(NPOT, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(NPOT, c, true); + + // zeroArray(SIZE, d); + // printDesc("radix sort, power-of-two"); + // StreamCompaction::Radix::sort(SIZE, k + 1, d, a); + // printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(SIZE, d, true); + //printCmpResult(SIZE, b, d); + + // zeroArray(SIZE, d); + // printDesc("radix sort, non-power-of-two"); + // StreamCompaction::Radix::sort(NPOT, k + 1, d, a); + // printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(NPOT, d, true); + // printCmpResult(NPOT, c, d); system("pause"); // stop Win32 console from closing on exit } From d7cf32edb6a674065592a4d8f2bd847ca171be1e Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 19:55:51 -0400 Subject: [PATCH 20/27] descriptions --- README.md | 33 +++++++++++++++++++++++++++++---- img/downsweep.jpg | Bin 0 -> 81397 bytes img/naive.jpg | Bin 0 -> 83463 bytes img/upsweep.jpg | Bin 0 -> 61647 bytes performance.xlsx | Bin 40989 -> 41275 bytes src/main.cpp | 4 ++-- 6 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 img/downsweep.jpg create mode 100644 img/naive.jpg create mode 100644 img/upsweep.jpg diff --git a/README.md b/README.md index 277ba31..ac87187 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,39 @@ CUDA Stream Compaction Sarah Forcier Tested on GeForce GTX 1070 +### Overview +This project provides an introduction to parallel algorithms on integer arrays: +* Scan : Computes a exclusive sum of all integers that came before each element. +* Stream Compaction : Removes 0's from an array of integers. +* Radix Sort : Sorts an array of integers from least to most significant bits + ### Parallel Algorithm Descriptions -#### Scan -Computes a exclusive sum of all integers that came before each element. +#### Naive Scan + +The diagram below illustrates the naive parallel scan algorithm. It starts by adding adjacent values, and then adding those values, and so on. This requires log2n iterations, and also requires additional memory since the algorithm cannot work in place. +![](img/naive.jpg) + +#### Work Efficient Scan + +In contrast to the naive scan, the work efficient algorithm works in place. The idea behind this algorithm is to create a balanced binary tree of the input data (up-sweep) computing the partial sums at internal nodes, followed by a root-to-leaves sweep of this tree that builds the sum in place. An actual tree data structure is not required, as the structure can be flattened into an array. + +![](img/upsweep.jpg) + +In the down-sweep stage, the root of the tree is replaced with $0$ and at each step, the node of the current level is passed to its left child and the sum of its value and the left child is passed to the right, as seen below. + +![](img/downsweep.jpg) + +Each pass in up-sweep requires almost $n$ iterations, so n threads must be allocated even if some threads will not be used, so can retire early. However, for down-sweep an additional optimization can be used to only allocated the needed number of threads per level. + +Because the up-sweep and down-sweep algorithms rely on the size of the array being a power-of-two, non-power-of-two arrays must be right extended to the next largest power-of-two in order to maintain correct indexing. #### Stream Compaction -Removes 0's from an array of integers. + +The stream compaction algorithm start by creating a temporary boolean array where each element is $1$ if the value at that index in the input array is not zero and $0$ otherwise. Next this boolean array is scanned using the implementation above. The result of the scan is the index into the final array, so if the value of an index in the boolean array is $1$, then the value at that same index in the input array can be placed in the final array at the new index specified by the scanned array. #### Radix Sort -Sorts an array of integers from low to high. + +The parallel implementation for radix sort begins similarly to the above stream compaction algorithm. First for bit $k$, a temporary boolean array $b$ is created where is element is $0$ if the $k$-th bit in the input array is $1$ and visa versa. A scan is run on this boolean array. Next the total number of falses (or the number of values whose $k$-th bit is $0$) is calculated by summing the last element in the boolean array and the scanned result of this boolean array. This value is used to create another array $t$ where each value at index $i$ is equal to $ i - s[i] + totalFalses $ where $s$ is the scanned array. The last array to be computed contains the indices of each input element in the array sorted by $k$-th bit. The values in this array are equal to $b[i] ? f[i] : t[i]$. While this algorithm requires multiple passes and new arrays, it is not necessary to allocate space for each step. Some steps can be done in place, and later steps can overwrite previous ones once they are no longer needed. ### Test Program Output @@ -132,3 +156,4 @@ For the work efficient implementation, the upsweep and downsweep kernel function #### How does the GPU Scan implementation compare to thrust? Thrust exclusive scan on power-of-two sized arrays performs poorly but consistently for most array size except the largest. The consistency indicates that the thrust implementation might have a large overhead. While other implementations' runtimes increase exponentially with array size, thrust with power-of-two arrays remains around 10ms for all array sizes. However, the thrust method on non-power-of-two arrays behaves more closely to the other gpu scan implementations with an exponential increase but with a much better performance. An explanation for the poor performance with power-of-two arrays might be that thrust implementation might allocate and compute on more memory with these sizes but not for non-power-of-two arrays - the opposite of what the work efficient method does. According to the Nsight performance analysis, thrust also has low warp occupancy (25%) and high number of required registers per thread (78), which could also explain the poor perform for these sized arrays. However, thrust makes good use of shared memory. +Images taken from GPU Gems 3, Chapter 39 diff --git a/img/downsweep.jpg b/img/downsweep.jpg new file mode 100644 index 0000000000000000000000000000000000000000..88be7ff7ab58a060c91697d96e6a10b57a35c0cd GIT binary patch literal 81397 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 b6Z`(((N{7v*GB)IygPQq>3Qe2{=W$Tq)}g? literal 0 HcmV?d00001 diff --git a/img/upsweep.jpg b/img/upsweep.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22c4da0fbc2e363fc48ed254d14bcdabe5107a49 GIT binary patch literal 61647 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 t3>#N#Ex4PXAB!{{g9MRGk0- delta 4457 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 diff --git a/src/main.cpp b/src/main.cpp index 9d50934..fcbc299 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,8 +13,8 @@ #include #include #include "testing_helpers.hpp" -const int SIZE = 1 << 10; // feel free to change the size of array -const int NPOT = SIZE - 3; // Non-Power-Of-Two +const int SIZE = 1 << 4; // feel free to change the size of array +const int NPOT = SIZE - 12; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; int main(int argc, char* argv[]) { From 34075e959218fa1804adf61b1eb748cd7dde1074 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 20:04:26 -0400 Subject: [PATCH 21/27] final formatting? --- README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ac87187..13c8c0d 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,20 @@ CUDA Stream Compaction **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 2** Sarah Forcier + Tested on GeForce GTX 1070 ### Overview -This project provides an introduction to parallel algorithms on integer arrays: -* Scan : Computes a exclusive sum of all integers that came before each element. -* Stream Compaction : Removes 0's from an array of integers. +This project provides an introduction to parallel algorithms on integer arrays +* Scan : Computes a exclusive sum of all integers that came before each element in the array +* Stream Compaction : Removes 0's from an array of integers * Radix Sort : Sorts an array of integers from least to most significant bits -### Parallel Algorithm Descriptions +### Parallel Algorithms #### Naive Scan The diagram below illustrates the naive parallel scan algorithm. It starts by adding adjacent values, and then adding those values, and so on. This requires log2n iterations, and also requires additional memory since the algorithm cannot work in place. + ![](img/naive.jpg) #### Work Efficient Scan @@ -24,21 +26,23 @@ In contrast to the naive scan, the work efficient algorithm works in place. The ![](img/upsweep.jpg) -In the down-sweep stage, the root of the tree is replaced with $0$ and at each step, the node of the current level is passed to its left child and the sum of its value and the left child is passed to the right, as seen below. +In the down-sweep stage, the root of the tree is replaced with *0* and at each step, the node of the current level is passed to its left child and the sum of its value and the left child is passed to the right, as seen below. ![](img/downsweep.jpg) -Each pass in up-sweep requires almost $n$ iterations, so n threads must be allocated even if some threads will not be used, so can retire early. However, for down-sweep an additional optimization can be used to only allocated the needed number of threads per level. +Each pass in up-sweep requires almost *n* iterations, so *n* threads must be allocated even if some threads will not be used, so can retire early. However, for down-sweep an additional optimization can be used to only allocated the needed number of threads per level. Because the up-sweep and down-sweep algorithms rely on the size of the array being a power-of-two, non-power-of-two arrays must be right extended to the next largest power-of-two in order to maintain correct indexing. #### Stream Compaction -The stream compaction algorithm start by creating a temporary boolean array where each element is $1$ if the value at that index in the input array is not zero and $0$ otherwise. Next this boolean array is scanned using the implementation above. The result of the scan is the index into the final array, so if the value of an index in the boolean array is $1$, then the value at that same index in the input array can be placed in the final array at the new index specified by the scanned array. +The stream compaction algorithm start by creating a temporary boolean array where each element is *1* if the value at that index in the input array is not zero and *0* otherwise. Next this boolean array is scanned using the implementation above. The result of the scan is the index into the final array, so if the value of an index in the boolean array is *1*, then the value at that same index in the input array can be placed in the final array at the new index specified by the scanned array. #### Radix Sort -The parallel implementation for radix sort begins similarly to the above stream compaction algorithm. First for bit $k$, a temporary boolean array $b$ is created where is element is $0$ if the $k$-th bit in the input array is $1$ and visa versa. A scan is run on this boolean array. Next the total number of falses (or the number of values whose $k$-th bit is $0$) is calculated by summing the last element in the boolean array and the scanned result of this boolean array. This value is used to create another array $t$ where each value at index $i$ is equal to $ i - s[i] + totalFalses $ where $s$ is the scanned array. The last array to be computed contains the indices of each input element in the array sorted by $k$-th bit. The values in this array are equal to $b[i] ? f[i] : t[i]$. While this algorithm requires multiple passes and new arrays, it is not necessary to allocate space for each step. Some steps can be done in place, and later steps can overwrite previous ones once they are no longer needed. +The parallel implementation for radix sort begins similarly to the above stream compaction algorithm. First for bit *k*, a temporary boolean array *b* is created where is element is *0* if the *k*-th bit in the input array is *1* and visa versa. A scan is run on this boolean array. Next the total number of falses (or the number of values whose *k*-th bit is *0*) is calculated by summing the last element in the boolean array and the scanned result of this boolean array. This value is used to create another array *t* where each value at index *i* is equal to * i - s[i] + totalFalses * where *s* is the scanned array. The last array to be computed contains the indices of each input element in the array sorted by *k*-th bit. The values in this array are equal to *b[i] ? f[i] : t[i]*. While this algorithm requires multiple passes and new arrays, it is not necessary to allocate space for each step. Some steps can be done in place, and later steps can overwrite previous ones once they are no longer needed. + +*Images taken from GPU Gems 3, Chapter 39* ### Test Program Output @@ -155,5 +159,3 @@ For the work efficient implementation, the upsweep and downsweep kernel function #### How does the GPU Scan implementation compare to thrust? Thrust exclusive scan on power-of-two sized arrays performs poorly but consistently for most array size except the largest. The consistency indicates that the thrust implementation might have a large overhead. While other implementations' runtimes increase exponentially with array size, thrust with power-of-two arrays remains around 10ms for all array sizes. However, the thrust method on non-power-of-two arrays behaves more closely to the other gpu scan implementations with an exponential increase but with a much better performance. An explanation for the poor performance with power-of-two arrays might be that thrust implementation might allocate and compute on more memory with these sizes but not for non-power-of-two arrays - the opposite of what the work efficient method does. According to the Nsight performance analysis, thrust also has low warp occupancy (25%) and high number of required registers per thread (78), which could also explain the poor perform for these sized arrays. However, thrust makes good use of shared memory. - -Images taken from GPU Gems 3, Chapter 39 From 160374b19ce00403fa08c430e3335c3a280ef487 Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 20:05:43 -0400 Subject: [PATCH 22/27] final --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 13c8c0d..3b17394 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The stream compaction algorithm start by creating a temporary boolean array wher #### Radix Sort -The parallel implementation for radix sort begins similarly to the above stream compaction algorithm. First for bit *k*, a temporary boolean array *b* is created where is element is *0* if the *k*-th bit in the input array is *1* and visa versa. A scan is run on this boolean array. Next the total number of falses (or the number of values whose *k*-th bit is *0*) is calculated by summing the last element in the boolean array and the scanned result of this boolean array. This value is used to create another array *t* where each value at index *i* is equal to * i - s[i] + totalFalses * where *s* is the scanned array. The last array to be computed contains the indices of each input element in the array sorted by *k*-th bit. The values in this array are equal to *b[i] ? f[i] : t[i]*. While this algorithm requires multiple passes and new arrays, it is not necessary to allocate space for each step. Some steps can be done in place, and later steps can overwrite previous ones once they are no longer needed. +The parallel implementation for radix sort begins similarly to the above stream compaction algorithm. First for bit *k*, a temporary boolean array *b* is created where is element is *0* if the *k*-th bit in the input array is *1* and visa versa. A scan is run on this boolean array. Next the total number of falses (or the number of values whose *k*-th bit is *0*) is calculated by summing the last element in the boolean array and the scanned result of this boolean array. This value is used to create another array *t* where each value at index *i* is equal to *i - s[i] + totalFalses* where *s* is the scanned array. The last array to be computed contains the indices of each input element in the array sorted by *k*-th bit. The values in this array are equal to *b[i] ? f[i] : t[i]*. While this algorithm requires multiple passes and new arrays, it is not necessary to allocate space for each step. Some steps can be done in place, and later steps can overwrite previous ones once they are no longer needed. *Images taken from GPU Gems 3, Chapter 39* @@ -152,7 +152,7 @@ Much like scan and compaction, GPU radix sort performs faster for large array si ### Q&A #### Compare GPU Scan implementations to the serial CPU version? -The GPU version performs better for scan, stream compaction, and radix sort for large arrays (SIZE < 2^[18]). Since the intersection between the CPU and GPU methods occurs at the same sized array, it suggests that the slow GPU performance for small arrays is based on a overhead required for creating and distributing threads. One that is only surpassed with large arrays. +The GPU version performs better for scan, stream compaction, and radix sort for large arrays (*SIZE < 2^[18]*). Since the intersection between the CPU and GPU methods occurs at the same sized array, it suggests that the slow GPU performance for small arrays is based on a overhead required for creating and distributing threads. One that is only surpassed with large arrays. #### Where are the performance bottlenecks? For the work efficient implementation, the upsweep and downsweep kernel functions require a similar amount of time, because they have the same ratio of compute to memory instructions. Most time is spent in memory reads and writes, but since there are not many of either type of instruction, it is not possible to space out the memory instructions with computations. From c25edad3837af2dd2dda164bba2bf08cd47946ac Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Tue, 19 Sep 2017 20:12:59 -0400 Subject: [PATCH 23/27] undo testing comments and code --- src/main.cpp | 164 +++++++++++++++++++++++++-------------------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fcbc299..053af8c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ #include #include "testing_helpers.hpp" const int SIZE = 1 << 4; // feel free to change the size of array -const int NPOT = SIZE - 12; // Non-Power-Of-Two +const int NPOT = SIZE - 3; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; int main(int argc, char* argv[]) { @@ -100,87 +100,87 @@ int main(int argc, char* argv[]) { // Compaction tests - // genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case - // a[SIZE - 1] = 0; - // printArray(SIZE, a, true); - - // int countSIZE, countNPOT, expectedSIZE, expectedNPOT; - - // // initialize b using StreamCompaction::CPU::compactWithoutScan you implement - // // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. - // zeroArray(SIZE, b); - // printDesc("cpu compact without scan, power-of-two"); - // countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - //expectedSIZE = countSIZE; - // printArray(expectedSIZE, b, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, b); - - // zeroArray(SIZE, c); - // printDesc("cpu compact without scan, non-power-of-two"); - //countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // expectedNPOT = countNPOT; - // printArray(countNPOT, c, true); - // printCmpLenResult(countNPOT, expectedNPOT, b, c); - - // zeroArray(SIZE, c); - // printDesc("cpu compact with scan"); - //countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(countSIZE, c, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, c); - - // zeroArray(SIZE, c); - // printDesc("work-efficient compact, power-of-two"); - //countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(expectedSIZE, c, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, c); - - // zeroArray(SIZE, c); - // printDesc("work-efficient compact, non-power-of-two"); - //countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(expectedNPOT, c, true); - // printCmpLenResult(countNPOT, expectedNPOT, b, c); - - // printf("\n"); - // printf("*****************************\n"); - // printf("** RADIX SORT TESTS **\n"); - // printf("*****************************\n"); - - // // Radix Tests - - //int k = 4; - //genArray(SIZE - 1, a, 1 << k); - // printArray(SIZE, a, true); - - // zeroArray(SIZE, b); - // printDesc("cpu sort, power-of-two"); - // StreamCompaction::CPU::sort(SIZE, b, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(SIZE, b, true); - - // zeroArray(SIZE, c); - // printDesc("cpu sort, non-power-of-two"); - // StreamCompaction::CPU::sort(NPOT, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(NPOT, c, true); - - // zeroArray(SIZE, d); - // printDesc("radix sort, power-of-two"); - // StreamCompaction::Radix::sort(SIZE, k + 1, d, a); - // printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(SIZE, d, true); - //printCmpResult(SIZE, b, d); - - // zeroArray(SIZE, d); - // printDesc("radix sort, non-power-of-two"); - // StreamCompaction::Radix::sort(NPOT, k + 1, d, a); - // printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(NPOT, d, true); - // printCmpResult(NPOT, c, d); + genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case + a[SIZE - 1] = 0; + printArray(SIZE, a, true); + + int countSIZE, countNPOT, expectedSIZE, expectedNPOT; + + // initialize b using StreamCompaction::CPU::compactWithoutScan you implement + // We use b for further comparison. Make sure your StreamCompaction::CPU::compactWithoutScan is correct. + zeroArray(SIZE, b); + printDesc("cpu compact without scan, power-of-two"); + countSIZE = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + expectedSIZE = countSIZE; + printArray(expectedSIZE, b, true); + printCmpLenResult(countSIZE, expectedSIZE, b, b); + + zeroArray(SIZE, c); + printDesc("cpu compact without scan, non-power-of-two"); + countNPOT = StreamCompaction::CPU::compactWithoutScan(NPOT, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + expectedNPOT = countNPOT; + printArray(countNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); + + zeroArray(SIZE, c); + printDesc("cpu compact with scan"); + countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(countSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); + + zeroArray(SIZE, c); + printDesc("work-efficient compact, power-of-two"); + countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); + + zeroArray(SIZE, c); + printDesc("work-efficient compact, non-power-of-two"); + countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); + + printf("\n"); + printf("*****************************\n"); + printf("** RADIX SORT TESTS **\n"); + printf("*****************************\n"); + + // Radix Tests + + int k = 4; + genArray(SIZE - 1, a, 1 << k); + printArray(SIZE, a, true); + + zeroArray(SIZE, b); + printDesc("cpu sort, power-of-two"); + StreamCompaction::CPU::sort(SIZE, b, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(SIZE, b, true); + + zeroArray(SIZE, c); + printDesc("cpu sort, non-power-of-two"); + StreamCompaction::CPU::sort(NPOT, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(NPOT, c, true); + + zeroArray(SIZE, d); + printDesc("radix sort, power-of-two"); + StreamCompaction::Radix::sort(SIZE, k + 1, d, a); + printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, d, true); + printCmpResult(SIZE, b, d); + + zeroArray(SIZE, d); + printDesc("radix sort, non-power-of-two"); + StreamCompaction::Radix::sort(NPOT, k + 1, d, a); + printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, d, true); + printCmpResult(NPOT, c, d); system("pause"); // stop Win32 console from closing on exit } From 8fdd951f74a8dbce3abc2d6078bacbd6b65d836d Mon Sep 17 00:00:00 2001 From: Sarah Forcier Date: Fri, 29 Sep 2017 11:59:28 -0400 Subject: [PATCH 24/27] incorrect thread numbers spawned --- performance.xlsx | Bin 41275 -> 40989 bytes src/main.cpp | 229 +++++++++++++++----------- stream_compaction/CMakeLists.txt | 2 + stream_compaction/common.h | 3 + stream_compaction/efficient_shared.cu | 202 +++++++++++++++++++++++ stream_compaction/efficient_shared.h | 15 ++ 6 files changed, 351 insertions(+), 100 deletions(-) create mode 100644 stream_compaction/efficient_shared.cu create mode 100644 stream_compaction/efficient_shared.h diff --git a/performance.xlsx b/performance.xlsx index 466c3d797fae3e8621d0dfe937749a0408225c1e..010f062410747db2f722cce30cd3bd00d12157bb 100644 GIT binary patch delta 4430 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 delta 4823 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 diff --git a/src/main.cpp b/src/main.cpp index 053af8c..a4123d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,10 +10,11 @@ #include #include #include +#include #include #include #include "testing_helpers.hpp" -const int SIZE = 1 << 4; // feel free to change the size of array +const int SIZE = 1 << 3; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; @@ -31,7 +32,7 @@ int main(int argc, char* argv[]) { printf("****************\n"); genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case - a[SIZE - 1] = 0; + //a[SIZE - 1] = 0; printArray(SIZE, a, true); @@ -51,47 +52,61 @@ int main(int argc, char* argv[]) { printArray(NPOT, b, true); printCmpResult(NPOT, b, c); - zeroArray(SIZE, c); - printDesc("naive scan, power-of-two"); - StreamCompaction::Naive::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"); - StreamCompaction::Naive::scan(NPOT, c, a); - printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, c, true); - printCmpResult(NPOT, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient scan, power-of-two"); - StreamCompaction::Efficient::scan(SIZE, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - 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); - printCmpResult(NPOT, b, c); - - zeroArray(SIZE, c); - printDesc("thrust scan, power-of-two"); - StreamCompaction::Thrust::scan(SIZE, c, a); - printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, c, true); - printCmpResult(SIZE, b, c); - - zeroArray(SIZE, c); - printDesc("thrust scan, non-power-of-two"); - StreamCompaction::Thrust::scan(NPOT, c, a); - printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, c, true); - printCmpResult(NPOT, b, c); + // zeroArray(SIZE, c); + // printDesc("naive scan, power-of-two"); + // StreamCompaction::Naive::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"); + // StreamCompaction::Naive::scan(NPOT, c, a); + // printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(NPOT, c, true); + // printCmpResult(NPOT, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient scan, power-of-two"); + // StreamCompaction::Efficient::scan(SIZE, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // 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); + // printCmpResult(NPOT, b, c); + + //zeroArray(SIZE, c); + //printDesc("shared scan, power-of-two"); + //StreamCompaction::Efficient_Shared::scan(SIZE, c, a); + //printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(SIZE, c, true); + //printCmpResult(SIZE, b, c); + + zeroArray(SIZE, c); + printDesc("shared scan, non-power-of-two"); + StreamCompaction::Efficient_Shared::scan(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, c, true); + printCmpResult(NPOT, b, c); + + //zeroArray(SIZE, c); + //printDesc("thrust scan, power-of-two"); + //StreamCompaction::Thrust::scan(SIZE, c, a); + //printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(SIZE, c, true); + //printCmpResult(SIZE, b, c); + + //zeroArray(SIZE, c); + //printDesc("thrust scan, non-power-of-two"); + //StreamCompaction::Thrust::scan(NPOT, c, a); + //printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(NPOT, c, true); + //printCmpResult(NPOT, b, c); printf("\n"); printf("*****************************\n"); @@ -124,63 +139,77 @@ int main(int argc, char* argv[]) { printArray(countNPOT, c, true); printCmpLenResult(countNPOT, expectedNPOT, b, c); - zeroArray(SIZE, c); - printDesc("cpu compact with scan"); - countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(countSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient compact, power-of-two"); - countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); - - zeroArray(SIZE, c); - printDesc("work-efficient compact, non-power-of-two"); - countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); - printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedNPOT, c, true); - printCmpLenResult(countNPOT, expectedNPOT, b, c); - - printf("\n"); - printf("*****************************\n"); - printf("** RADIX SORT TESTS **\n"); - printf("*****************************\n"); - - // Radix Tests - - int k = 4; - genArray(SIZE - 1, a, 1 << k); - printArray(SIZE, a, true); - - zeroArray(SIZE, b); - printDesc("cpu sort, power-of-two"); - StreamCompaction::CPU::sort(SIZE, b, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(SIZE, b, true); - - zeroArray(SIZE, c); - printDesc("cpu sort, non-power-of-two"); - StreamCompaction::CPU::sort(NPOT, c, a); - printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - printArray(NPOT, c, true); - - zeroArray(SIZE, d); - printDesc("radix sort, power-of-two"); - StreamCompaction::Radix::sort(SIZE, k + 1, d, a); - printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(SIZE, d, true); - printCmpResult(SIZE, b, d); - - zeroArray(SIZE, d); - printDesc("radix sort, non-power-of-two"); - StreamCompaction::Radix::sort(NPOT, k + 1, d, a); - printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(NPOT, d, true); - printCmpResult(NPOT, c, d); + // zeroArray(SIZE, c); + // printDesc("cpu compact with scan"); + //countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(countSIZE, c, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient compact, power-of-two"); + //countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(expectedSIZE, c, true); + // printCmpLenResult(countSIZE, expectedSIZE, b, c); + + // zeroArray(SIZE, c); + // printDesc("work-efficient compact, non-power-of-two"); + //countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); + // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(expectedNPOT, c, true); + // printCmpLenResult(countNPOT, expectedNPOT, b, c); + + zeroArray(SIZE, c); + printDesc("shared compact, power-of-two"); + countSIZE = StreamCompaction::Efficient_Shared::compact(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); + + zeroArray(SIZE, c); + printDesc("shared compact, non-power-of-two"); + countNPOT = StreamCompaction::Efficient_Shared::compact(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); + + // printf("\n"); + // printf("*****************************\n"); + // printf("** RADIX SORT TESTS **\n"); + // printf("*****************************\n"); + + // // Radix Tests + + //int k = 4; + //genArray(SIZE - 1, a, 1 << k); + // printArray(SIZE, a, true); + + // zeroArray(SIZE, b); + // printDesc("cpu sort, power-of-two"); + // StreamCompaction::CPU::sort(SIZE, b, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(SIZE, b, true); + + // zeroArray(SIZE, c); + // printDesc("cpu sort, non-power-of-two"); + // StreamCompaction::CPU::sort(NPOT, c, a); + // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + // printArray(NPOT, c, true); + + // zeroArray(SIZE, d); + // printDesc("radix sort, power-of-two"); + // StreamCompaction::Radix::sort(SIZE, k + 1, d, a); + // printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(SIZE, d, true); + //printCmpResult(SIZE, b, d); + + // zeroArray(SIZE, d); + // printDesc("radix sort, non-power-of-two"); + // StreamCompaction::Radix::sort(NPOT, k + 1, d, a); + // printElapsedTime(StreamCompaction::Radix::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + // printArray(NPOT, d, true); + // printCmpResult(NPOT, c, d); system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index 68d8d1f..1d1f41d 100644 --- a/stream_compaction/CMakeLists.txt +++ b/stream_compaction/CMakeLists.txt @@ -7,6 +7,8 @@ set(SOURCE_FILES "naive.cu" "efficient.h" "efficient.cu" + "efficient_shared.h" + "efficient_shared.cu" "thrust.h" "thrust.cu" "radix.h" diff --git a/stream_compaction/common.h b/stream_compaction/common.h index 6aabc39..b8cc0fe 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -13,6 +13,9 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) #define blockSize 128 +#define bankSize 16 +#define log_bankSize 4 +#define conflictFreeOffset(n) ((n) >> bankSize + (n) >> (2 * log_bankSize)) /** * Check for CUDA errors; print and exit if there was a problem. diff --git a/stream_compaction/efficient_shared.cu b/stream_compaction/efficient_shared.cu new file mode 100644 index 0000000..f817418 --- /dev/null +++ b/stream_compaction/efficient_shared.cu @@ -0,0 +1,202 @@ +#include +#include +#include "common.h" +#include "efficient.h" + +namespace StreamCompaction { + namespace Efficient_Shared { + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; + } + + __global__ void kernScanShared(int n, int *odata, int *sumOfSums) + { + extern __shared__ int temp[]; + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + int offset = 1; + + // load shared memory + temp[2 * index] = odata[2 * index]; + temp[2 * index + 1] = odata[2 * index + 1]; + + // upsweep + for (int d = n >> 1; d > 0; d >>= 1) { + __syncthreads(); + if (index < d) { + int ai = offset * (2 * index + 1) - 1; + int bi = offset * (2 * index + 2) - 1; + + temp[bi] += temp[ai]; + } + offset *= 2; + } + + if (index == 0) { + sumOfSums[blockIdx.x] = temp[n - 1]; + temp[n - 1] = 0; + } + + // downsweep + for (int d = 1; d < n; d *= 2) { + offset >>= 1; + __syncthreads(); + if (index < d) { + int ai = offset * (2 * index + 1) - 1; + int bi = offset * (2 * index + 2) - 1; + + int t = temp[ai]; + temp[ai] = temp[bi]; + temp[bi] += t; + } + } + + __syncthreads(); + + odata[2 * index] = temp[2 * index]; + odata[2 * index + 1] = temp[2 * index + 1]; + } + + __global__ void kernAddSums(int n, int *odata, int *sumOfSums) + { + __shared__ int sum; + if (threadIdx.x == 0) sum = sumOfSums[blockIdx.x]; + __syncthreads(); + + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n) return; + + odata[index] += sum; + } + + void scan_implementation(int n, int *dev_out, int *sumOfSums) + { + int shMemBytes = sizeof(int) * blockSize; + int numBlocks = (n + blockSize - 1) / blockSize; + + kernScanShared << > > (numBlocks * blockSize, dev_out, sumOfSums); + checkCUDAError("kernScanShared 1 failed!"); + + if (n > blockSize) { + kernScanShared << > > (numBlocks, sumOfSums, sumOfSums); + checkCUDAError("kernScanShared 2 failed!"); + + kernAddSums << > > (pow2n, dev_out, sumOfSums); + checkCUDAError("kernAddSums failed!"); + } + } + + /** + * Performs prefix-sum (aka scan) on idata, storing the result into odata. + */ + void scan(int n, int *odata, const int *idata) + { + int *dev_out; + int *sumOfSums; + int pow2n = 1 << ilog2ceil(n); + + cudaMalloc((void**)&dev_out, pow2n * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + + cudaMalloc((void**)&sumOfSums, pow2n / blockSize * sizeof(int)); + checkCUDAError("cudaMalloc sumOfSums failed!"); + + cudaMemset(dev_out, 0, pow2n * sizeof(int)); + checkCUDAError("cudaMemset dev_out failed!"); + + cudaMemcpy(dev_out, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_out failed!"); + + timer().startGpuTimer(); + scan_implementation(pow2n, dev_out, sumOfSums); + timer().endGpuTimer(); + checkCUDAError("scan_implementation failed!"); + + cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + cudaFree(dev_out); + cudaFree(sumOfSums); + } + + /** + * Performs stream compaction on idata, storing the result into odata. + * All zeroes are discarded. + * + * @param n The number of elements in idata. + * @param odata The array into which to store elements. + * @param idata The array of elements to compact. + * @returns The number of elements remaining after compaction. + */ + int compact(int n, int *odata, const int *idata) + { + // TODO + int *dbools; + int *indices; + int *dev_in; + int *dev_out; + int *sumOfSums; + + int pow2n = 1 << ilog2ceil(n); + + cudaMalloc((void**)&dbools, pow2n * sizeof(int)); + checkCUDAError("cudaMalloc dbools failed!"); + + cudaMalloc((void**)&indices, pow2n * sizeof(int)); + checkCUDAError("cudaMalloc indices failed!"); + + cudaMalloc((void**)&dev_in, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_in failed!"); + + cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_in failed!"); + + timer().startGpuTimer(); + + dim3 blocksPerGrid1((pow2n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, indices, dev_in); + checkCUDAError("kernMapToBoolean failed!"); + + cudaMemcpy(dbools, indices, pow2n * sizeof(int), cudaMemcpyDeviceToDevice); + checkCUDAError("cudaMemcpyDeviceToDevice failed!"); + + int *num = (int *)malloc(sizeof(int)); + cudaMemcpy(num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + int ret = *num; + + cudaMalloc((void**)&sumOfSums, pow2n / blockSize * sizeof(int)); + checkCUDAError("cudaMalloc sumOfSums failed!"); + + scan_implementation(pow2n, indices, sumOfSums); // requires power of 2 + + cudaMemcpy(num, indices + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + ret += *num; + free(num); + + cudaMalloc((void**)&dev_out, ret * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools, indices); + checkCUDAError("kernScatter failed!"); + + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_out, ret * sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + + cudaFree(dbools); + cudaFree(dev_in); + cudaFree(dev_out); + cudaFree(indices); + cudaFree(sumOfSums); + + return ret; + } + } +} diff --git a/stream_compaction/efficient_shared.h b/stream_compaction/efficient_shared.h new file mode 100644 index 0000000..2a1561c --- /dev/null +++ b/stream_compaction/efficient_shared.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" + +namespace StreamCompaction { + namespace Efficient_Shared { + StreamCompaction::Common::PerformanceTimer& timer(); + + void scan_implementation(int n, int *dev_out); + + void scan(int n, int *odata, const int *idata); + + int compact(int n, int *odata, const int *idata); + } +} From 29a972c4c4db7b250df49689adf9994d4db69f5a Mon Sep 17 00:00:00 2001 From: sarahforcier Date: Fri, 29 Sep 2017 18:45:29 -0400 Subject: [PATCH 25/27] shared --- stream_compaction/efficient_shared.cu | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/stream_compaction/efficient_shared.cu b/stream_compaction/efficient_shared.cu index f817418..1891ce9 100644 --- a/stream_compaction/efficient_shared.cu +++ b/stream_compaction/efficient_shared.cu @@ -16,6 +16,7 @@ namespace StreamCompaction { { extern __shared__ int temp[]; int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= n / 2) return; int offset = 1; // load shared memory @@ -71,21 +72,22 @@ namespace StreamCompaction { odata[index] += sum; } - void scan_implementation(int n, int *dev_out, int *sumOfSums) + /** + * invariant: n must be power-of-2 + */ + void scan_implementation(int pow2n, int *dev_out, int *sumOfSums) { int shMemBytes = sizeof(int) * blockSize; - int numBlocks = (n + blockSize - 1) / blockSize; + int numBlocks = (pow2n + blockSize - 1) / blockSize; - kernScanShared << > > (numBlocks * blockSize, dev_out, sumOfSums); + kernScanShared << > > (pow2n, dev_out, sumOfSums); checkCUDAError("kernScanShared 1 failed!"); - - if (n > blockSize) { - kernScanShared << > > (numBlocks, sumOfSums, sumOfSums); - checkCUDAError("kernScanShared 2 failed!"); - kernAddSums << > > (pow2n, dev_out, sumOfSums); - checkCUDAError("kernAddSums failed!"); - } + kernScanShared << > > (pow2n, sumOfSums, sumOfSums); + checkCUDAError("kernScanShared 2 failed!"); + + kernAddSums << > > (pow2n, dev_out, sumOfSums); + checkCUDAError("kernAddSums failed!"); } /** @@ -96,11 +98,12 @@ namespace StreamCompaction { int *dev_out; int *sumOfSums; int pow2n = 1 << ilog2ceil(n); + int block2n = 1 << ilog2ceil(pow2n / blockSize); cudaMalloc((void**)&dev_out, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dev_out failed!"); - cudaMalloc((void**)&sumOfSums, pow2n / blockSize * sizeof(int)); + cudaMalloc((void**)&sumOfSums, block2n * sizeof(int)); checkCUDAError("cudaMalloc sumOfSums failed!"); cudaMemset(dev_out, 0, pow2n * sizeof(int)); @@ -140,6 +143,7 @@ namespace StreamCompaction { int *sumOfSums; int pow2n = 1 << ilog2ceil(n); + int block2n = 1 << ilog2ceil(pow2n / blockSize); cudaMalloc((void**)&dbools, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dbools failed!"); @@ -168,7 +172,7 @@ namespace StreamCompaction { int ret = *num; - cudaMalloc((void**)&sumOfSums, pow2n / blockSize * sizeof(int)); + cudaMalloc((void**)&sumOfSums, block2n * sizeof(int)); checkCUDAError("cudaMalloc sumOfSums failed!"); scan_implementation(pow2n, indices, sumOfSums); // requires power of 2 From 50282c98ede7631ed1725a1cd79c102514a94ba4 Mon Sep 17 00:00:00 2001 From: Sarah Forcier Date: Sat, 30 Sep 2017 12:45:45 -0400 Subject: [PATCH 26/27] shared correct --- src/main.cpp | 114 +++++++++++++------------- stream_compaction/common.h | 1 + stream_compaction/efficient_shared.cu | 48 +++++------ 3 files changed, 83 insertions(+), 80 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a4123d6..b98bd88 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ #include #include #include "testing_helpers.hpp" -const int SIZE = 1 << 3; // feel free to change the size of array +const int SIZE = 1 << 14; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; @@ -31,7 +31,9 @@ int main(int argc, char* argv[]) { printf("** SCAN TESTS **\n"); printf("****************\n"); - genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case + //genArray(SIZE - 1, a, 50); // Leave a 0 at the end to test that edge case + + for (int i = 0; i < SIZE; ++i) a[i] = i; //a[SIZE - 1] = 0; printArray(SIZE, a, true); @@ -52,40 +54,40 @@ int main(int argc, char* argv[]) { printArray(NPOT, b, true); printCmpResult(NPOT, b, c); - // zeroArray(SIZE, c); - // printDesc("naive scan, power-of-two"); - // StreamCompaction::Naive::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, power-of-two"); + StreamCompaction::Naive::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"); - // StreamCompaction::Naive::scan(NPOT, c, a); - // printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(NPOT, c, true); - // printCmpResult(NPOT, b, c); + zeroArray(SIZE, c); + printDesc("naive scan, non-power-of-two"); + StreamCompaction::Naive::scan(NPOT, c, a); + printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, c, true); + printCmpResult(NPOT, b, c); - // zeroArray(SIZE, c); - // printDesc("work-efficient scan, power-of-two"); - // StreamCompaction::Efficient::scan(SIZE, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(SIZE, c, true); - // printCmpResult(SIZE, b, c); + zeroArray(SIZE, c); + printDesc("work-efficient scan, power-of-two"); + StreamCompaction::Efficient::scan(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + 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); - // printCmpResult(NPOT, 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); + printCmpResult(NPOT, b, c); - //zeroArray(SIZE, c); - //printDesc("shared scan, power-of-two"); - //StreamCompaction::Efficient_Shared::scan(SIZE, c, a); - //printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(SIZE, c, true); - //printCmpResult(SIZE, b, c); + zeroArray(SIZE, c); + printDesc("shared scan, power-of-two"); + StreamCompaction::Efficient_Shared::scan(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, c, true); + printCmpResult(SIZE, b, c); zeroArray(SIZE, c); printDesc("shared scan, non-power-of-two"); @@ -94,19 +96,19 @@ int main(int argc, char* argv[]) { printArray(NPOT, c, true); printCmpResult(NPOT, b, c); - //zeroArray(SIZE, c); - //printDesc("thrust scan, power-of-two"); - //StreamCompaction::Thrust::scan(SIZE, c, a); - //printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(SIZE, c, true); - //printCmpResult(SIZE, b, c); + zeroArray(SIZE, c); + printDesc("thrust scan, power-of-two"); + StreamCompaction::Thrust::scan(SIZE, c, a); + printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(SIZE, c, true); + printCmpResult(SIZE, b, c); - //zeroArray(SIZE, c); - //printDesc("thrust scan, non-power-of-two"); - //StreamCompaction::Thrust::scan(NPOT, c, a); - //printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(NPOT, c, true); - //printCmpResult(NPOT, b, c); + zeroArray(SIZE, c); + printDesc("thrust scan, non-power-of-two"); + StreamCompaction::Thrust::scan(NPOT, c, a); + printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(NPOT, c, true); + printCmpResult(NPOT, b, c); printf("\n"); printf("*****************************\n"); @@ -160,19 +162,19 @@ int main(int argc, char* argv[]) { // printArray(expectedNPOT, c, true); // printCmpLenResult(countNPOT, expectedNPOT, b, c); - zeroArray(SIZE, c); - printDesc("shared compact, power-of-two"); - countSIZE = StreamCompaction::Efficient_Shared::compact(SIZE, c, a); - printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedSIZE, c, true); - printCmpLenResult(countSIZE, expectedSIZE, b, c); + //zeroArray(SIZE, c); + //printDesc("shared compact, power-of-two"); + //countSIZE = StreamCompaction::Efficient_Shared::compact(SIZE, c, a); + //printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(expectedSIZE, c, true); + //printCmpLenResult(countSIZE, expectedSIZE, b, c); - zeroArray(SIZE, c); - printDesc("shared compact, non-power-of-two"); - countNPOT = StreamCompaction::Efficient_Shared::compact(NPOT, c, a); - printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - printArray(expectedNPOT, c, true); - printCmpLenResult(countNPOT, expectedNPOT, b, c); + //zeroArray(SIZE, c); + //printDesc("shared compact, non-power-of-two"); + //countNPOT = StreamCompaction::Efficient_Shared::compact(NPOT, c, a); + //printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(expectedNPOT, c, true); + //printCmpLenResult(countNPOT, expectedNPOT, b, c); // printf("\n"); // printf("*****************************\n"); diff --git a/stream_compaction/common.h b/stream_compaction/common.h index b8cc0fe..b848ee1 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -24,6 +24,7 @@ void checkCUDAErrorFn(const char *msg, const char *file = NULL, int line = -1); inline int ilog2(int x) { int lg = 0; + x = std::max(0, x); while (x >>= 1) { ++lg; } diff --git a/stream_compaction/efficient_shared.cu b/stream_compaction/efficient_shared.cu index 1891ce9..0ecc2ed 100644 --- a/stream_compaction/efficient_shared.cu +++ b/stream_compaction/efficient_shared.cu @@ -16,37 +16,37 @@ namespace StreamCompaction { { extern __shared__ int temp[]; int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n / 2) return; + if (index >= n) return; int offset = 1; // load shared memory - temp[2 * index] = odata[2 * index]; - temp[2 * index + 1] = odata[2 * index + 1]; + temp[threadIdx.x] = odata[index]; + //temp[2 * index + 1] = odata[2 * index + 1]; // upsweep - for (int d = n >> 1; d > 0; d >>= 1) { + for (int d = blockSize >> 1; d > 0; d >>= 1) { __syncthreads(); - if (index < d) { - int ai = offset * (2 * index + 1) - 1; - int bi = offset * (2 * index + 2) - 1; + if (threadIdx.x < d) { + int ai = offset * (2 * threadIdx.x + 1) - 1; + int bi = offset * (2 * threadIdx.x + 2) - 1; temp[bi] += temp[ai]; } offset *= 2; } - if (index == 0) { - sumOfSums[blockIdx.x] = temp[n - 1]; - temp[n - 1] = 0; + if (threadIdx.x == 0) { + sumOfSums[blockIdx.x] = temp[blockDim.x - 1]; + temp[blockDim.x - 1] = 0; } // downsweep - for (int d = 1; d < n; d *= 2) { + for (int d = 1; d < blockSize; d *= 2) { offset >>= 1; __syncthreads(); - if (index < d) { - int ai = offset * (2 * index + 1) - 1; - int bi = offset * (2 * index + 2) - 1; + if (threadIdx.x < d) { + int ai = offset * (2 * threadIdx.x + 1) - 1; + int bi = offset * (2 * threadIdx.x + 2) - 1; int t = temp[ai]; temp[ai] = temp[bi]; @@ -56,8 +56,8 @@ namespace StreamCompaction { __syncthreads(); - odata[2 * index] = temp[2 * index]; - odata[2 * index + 1] = temp[2 * index + 1]; + odata[index] = temp[threadIdx.x]; + //odata[2 * index + 1] = temp[2 * index + 1]; } __global__ void kernAddSums(int n, int *odata, int *sumOfSums) @@ -75,18 +75,18 @@ namespace StreamCompaction { /** * invariant: n must be power-of-2 */ - void scan_implementation(int pow2n, int *dev_out, int *sumOfSums) + void scan_implementation(int pow2n, int block2n, int *dev_out, int *sumOfSums) { - int shMemBytes = sizeof(int) * blockSize; - int numBlocks = (pow2n + blockSize - 1) / blockSize; + int numBlocks1 = (pow2n + blockSize - 1) / blockSize; + int numBlocks2 = (block2n + blockSize - 1) / blockSize; - kernScanShared << > > (pow2n, dev_out, sumOfSums); + kernScanShared << > > (pow2n, dev_out, sumOfSums); checkCUDAError("kernScanShared 1 failed!"); - kernScanShared << > > (pow2n, sumOfSums, sumOfSums); + kernScanShared << > > (block2n, sumOfSums, sumOfSums); checkCUDAError("kernScanShared 2 failed!"); - kernAddSums << > > (pow2n, dev_out, sumOfSums); + kernAddSums << > > (pow2n, dev_out, sumOfSums); checkCUDAError("kernAddSums failed!"); } @@ -113,7 +113,7 @@ namespace StreamCompaction { checkCUDAError("cudaMemcpy dev_out failed!"); timer().startGpuTimer(); - scan_implementation(pow2n, dev_out, sumOfSums); + scan_implementation(pow2n, block2n, dev_out, sumOfSums); timer().endGpuTimer(); checkCUDAError("scan_implementation failed!"); @@ -175,7 +175,7 @@ namespace StreamCompaction { cudaMalloc((void**)&sumOfSums, block2n * sizeof(int)); checkCUDAError("cudaMalloc sumOfSums failed!"); - scan_implementation(pow2n, indices, sumOfSums); // requires power of 2 + scan_implementation(pow2n, block2n, indices, sumOfSums); // requires power of 2 cudaMemcpy(num, indices + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); From 2fde8210dd539b31b870cd3a58744604be978a4d Mon Sep 17 00:00:00 2001 From: Sarah Forcier Date: Sat, 30 Sep 2017 13:41:04 -0400 Subject: [PATCH 27/27] shared compact --- performance.xlsx | Bin 40989 -> 40974 bytes src/main.cpp | 75 ++++++++++++++------------ stream_compaction/common.cu | 17 +++--- stream_compaction/common.h | 9 ++-- stream_compaction/efficient.cu | 42 +++++++-------- stream_compaction/efficient_shared.cu | 70 ++++++++++++------------ 6 files changed, 106 insertions(+), 107 deletions(-) diff --git a/performance.xlsx b/performance.xlsx index 010f062410747db2f722cce30cd3bd00d12157bb..187a6479e340e04ed0b030b320ee76a14d4ab3e7 100644 GIT binary patch delta 16859 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 diff --git a/src/main.cpp b/src/main.cpp index b98bd88..94fdd03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ #include #include #include "testing_helpers.hpp" -const int SIZE = 1 << 14; // feel free to change the size of array +const int SIZE = 1 << 20; // must be <= 20 const int NPOT = SIZE - 3; // Non-Power-Of-Two //int a[SIZE], b[SIZE], c[SIZE], d[SIZE]; @@ -96,7 +96,14 @@ int main(int argc, char* argv[]) { printArray(NPOT, c, true); printCmpResult(NPOT, b, c); - zeroArray(SIZE, c); + zeroArray(SIZE, c); + //printDesc("thrust scan, power-of-two"); + StreamCompaction::Thrust::scan(SIZE, c, a); + //printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + //printArray(SIZE, c, true); + //printCmpResult(SIZE, b, c); + + zeroArray(SIZE, c); printDesc("thrust scan, power-of-two"); StreamCompaction::Thrust::scan(SIZE, c, a); printElapsedTime(StreamCompaction::Thrust::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); @@ -141,40 +148,40 @@ int main(int argc, char* argv[]) { printArray(countNPOT, c, true); printCmpLenResult(countNPOT, expectedNPOT, b, c); - // zeroArray(SIZE, c); - // printDesc("cpu compact with scan"); - //countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); - // printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); - // printArray(countSIZE, c, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, c); + zeroArray(SIZE, c); + printDesc("cpu compact with scan"); + countSIZE = StreamCompaction::CPU::compactWithScan(SIZE, c, a); + printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); + printArray(countSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); - // zeroArray(SIZE, c); - // printDesc("work-efficient compact, power-of-two"); - //countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(expectedSIZE, c, true); - // printCmpLenResult(countSIZE, expectedSIZE, b, c); + zeroArray(SIZE, c); + printDesc("work-efficient compact, power-of-two"); + countSIZE = StreamCompaction::Efficient::compact(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); - // zeroArray(SIZE, c); - // printDesc("work-efficient compact, non-power-of-two"); - //countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); - // printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - // printArray(expectedNPOT, c, true); - // printCmpLenResult(countNPOT, expectedNPOT, b, c); - - //zeroArray(SIZE, c); - //printDesc("shared compact, power-of-two"); - //countSIZE = StreamCompaction::Efficient_Shared::compact(SIZE, c, a); - //printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(expectedSIZE, c, true); - //printCmpLenResult(countSIZE, expectedSIZE, b, c); - - //zeroArray(SIZE, c); - //printDesc("shared compact, non-power-of-two"); - //countNPOT = StreamCompaction::Efficient_Shared::compact(NPOT, c, a); - //printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); - //printArray(expectedNPOT, c, true); - //printCmpLenResult(countNPOT, expectedNPOT, b, c); + zeroArray(SIZE, c); + printDesc("work-efficient compact, non-power-of-two"); + countNPOT = StreamCompaction::Efficient::compact(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); + + zeroArray(SIZE, c); + printDesc("shared compact, power-of-two"); + countSIZE = StreamCompaction::Efficient_Shared::compact(SIZE, c, a); + printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedSIZE, c, true); + printCmpLenResult(countSIZE, expectedSIZE, b, c); + + zeroArray(SIZE, c); + printDesc("shared compact, non-power-of-two"); + countNPOT = StreamCompaction::Efficient_Shared::compact(NPOT, c, a); + printElapsedTime(StreamCompaction::Efficient_Shared::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); + printArray(expectedNPOT, c, true); + printCmpLenResult(countNPOT, expectedNPOT, b, c); // printf("\n"); // printf("*****************************\n"); diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 22be71c..f85eec5 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -22,27 +22,24 @@ namespace StreamCompaction { * Maps an array to an array of 0s and 1s for stream compaction. Elements * which map to 0 will be removed, and elements which map to 1 will be kept. */ - __global__ void kernMapToBoolean(int pos2n, int n, int *bools, const int *idata) { + __global__ void kernMapToBoolean(int n, int *bools, const int *idata) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= pos2n) return; + if (index >= n || idata[index] == 0) return; - bools[index] = (index < n && idata[index] != 0) ? 1 : 0; + bools[index] = 1; } /** * Performs scatter on an array. That is, for each element in idata, * if bools[idx] == 1, it copies idata[idx] to odata[indices[idx]]. */ - __global__ void kernScatter(int n, int *odata, - const int *idata, const int *bools, const int *indices) { + __global__ void kernScatter(int n, int *odata, const int *idata, const int *indices) { // TODO int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if (index >= n) return; - - if (bools[index] == 1) { - odata[indices[index]] = idata[index]; - } + if (index >= n || idata[index] == 0) return; + + odata[indices[index]] = idata[index]; } } } \ No newline at end of file diff --git a/stream_compaction/common.h b/stream_compaction/common.h index b848ee1..158245d 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -12,10 +12,11 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) -#define blockSize 128 +#define blockSize 1024 #define bankSize 16 #define log_bankSize 4 -#define conflictFreeOffset(n) ((n) >> bankSize + (n) >> (2 * log_bankSize)) +//#define conflictFreeOffset(n) ((n) >> bankSize + (n) >> (2 * log_bankSize)) +#define conflictFreeOffset(n) 0 /** * Check for CUDA errors; print and exit if there was a problem. @@ -37,10 +38,10 @@ inline int ilog2ceil(int x) { namespace StreamCompaction { namespace Common { - __global__ void kernMapToBoolean(int pos2, int n, int *bools, const int *idata); + __global__ void kernMapToBoolean(int n, int *bools, const int *idata); __global__ void kernScatter(int n, int *odata, - const int *idata, const int *bools, const int *indices); + const int *idata, const int *indices); /** * This class is used for timing the performance diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 4698a07..80d8e47 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -105,17 +105,17 @@ namespace StreamCompaction { { // TODO int *dbools; - int *indices; int *dev_in; int *dev_out; int pow2n = 1 << ilog2ceil(n); + int block2n = 1 << ilog2ceil(pow2n / blockSize); cudaMalloc((void**)&dbools, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dbools failed!"); - cudaMalloc((void**)&indices, pow2n * sizeof(int)); - checkCUDAError("cudaMalloc indices failed!"); + cudaMemset(dbools, 0, pow2n * sizeof(int)); + checkCUDAError("cudaMemset dbools failed!"); cudaMalloc((void**)&dev_in, n * sizeof(int)); checkCUDAError("cudaMalloc dev_in failed!"); @@ -123,33 +123,28 @@ namespace StreamCompaction { cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy dev_in failed!"); + cudaMalloc((void**)&dev_out, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + timer().startGpuTimer(); - dim3 blocksPerGrid1((pow2n + blockSize - 1) / blockSize); - StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, indices, dev_in); + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (n, dbools, dev_in); checkCUDAError("kernMapToBoolean failed!"); - cudaMemcpy(dbools, indices, pow2n * sizeof(int), cudaMemcpyDeviceToDevice); - checkCUDAError("cudaMemcpyDeviceToDevice failed!"); - - int *num = (int *)malloc(sizeof(int)); - cudaMemcpy(num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + int num; + cudaMemcpyAsync(&num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); - int ret = *num; - - scan_implementation(pow2n, indices); // requires power of 2 + int ret = num; - cudaMemcpy(num, indices + n - 1, sizeof(int), cudaMemcpyDeviceToHost); - checkCUDAError("cudaMemcpyDeviceToHost failed!"); - ret += *num; - free(num); + scan_implementation(pow2n, dbools); // requires power of 2 - cudaMalloc((void**)&dev_out, ret * sizeof(int)); - checkCUDAError("cudaMalloc dev_out failed!"); + cudaMemcpyAsync(&num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpyDeviceToHost failed!"); + ret += num; - dim3 blocksPerGrid((n + blockSize - 1) / blockSize); - StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools, indices); + StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools); checkCUDAError("kernScatter failed!"); timer().endGpuTimer(); @@ -160,9 +155,8 @@ namespace StreamCompaction { cudaFree(dbools); cudaFree(dev_in); cudaFree(dev_out); - cudaFree(indices); - - return ret; + + return ret; } } } diff --git a/stream_compaction/efficient_shared.cu b/stream_compaction/efficient_shared.cu index 0ecc2ed..b773f7b 100644 --- a/stream_compaction/efficient_shared.cu +++ b/stream_compaction/efficient_shared.cu @@ -20,33 +20,40 @@ namespace StreamCompaction { int offset = 1; // load shared memory - temp[threadIdx.x] = odata[index]; + int idx = threadIdx.x; + //int bankOffset = conflictFreeOffset(idx); + int bankOffset = 0; + temp[idx + bankOffset] = odata[index]; //temp[2 * index + 1] = odata[2 * index + 1]; // upsweep for (int d = blockSize >> 1; d > 0; d >>= 1) { __syncthreads(); - if (threadIdx.x < d) { - int ai = offset * (2 * threadIdx.x + 1) - 1; - int bi = offset * (2 * threadIdx.x + 2) - 1; + if (idx < d) { + int ai = offset * (2 * idx + 1) - 1; + int bi = offset * (2 * idx + 2) - 1; + ai += conflictFreeOffset(ai); + bi += conflictFreeOffset(bi); temp[bi] += temp[ai]; } offset *= 2; } - if (threadIdx.x == 0) { - sumOfSums[blockIdx.x] = temp[blockDim.x - 1]; - temp[blockDim.x - 1] = 0; + if (idx == 0) { + sumOfSums[blockIdx.x] = temp[blockDim.x - 1 + conflictFreeOffset(blockDim.x - 1)]; + temp[blockDim.x - 1 + conflictFreeOffset(blockDim.x - 1)] = 0; } // downsweep for (int d = 1; d < blockSize; d *= 2) { offset >>= 1; __syncthreads(); - if (threadIdx.x < d) { - int ai = offset * (2 * threadIdx.x + 1) - 1; - int bi = offset * (2 * threadIdx.x + 2) - 1; + if (idx < d) { + int ai = offset * (2 * idx + 1) - 1; + int bi = offset * (2 * idx + 2) - 1; + ai += conflictFreeOffset(ai); + bi += conflictFreeOffset(bi); int t = temp[ai]; temp[ai] = temp[bi]; @@ -56,7 +63,7 @@ namespace StreamCompaction { __syncthreads(); - odata[index] = temp[threadIdx.x]; + odata[index] = temp[idx + bankOffset]; //odata[2 * index + 1] = temp[2 * index + 1]; } @@ -137,7 +144,6 @@ namespace StreamCompaction { { // TODO int *dbools; - int *indices; int *dev_in; int *dev_out; int *sumOfSums; @@ -148,8 +154,8 @@ namespace StreamCompaction { cudaMalloc((void**)&dbools, pow2n * sizeof(int)); checkCUDAError("cudaMalloc dbools failed!"); - cudaMalloc((void**)&indices, pow2n * sizeof(int)); - checkCUDAError("cudaMalloc indices failed!"); + cudaMemset(dbools, 0, pow2n * sizeof(int)); + checkCUDAError("cudaMemset dbools failed!"); cudaMalloc((void**)&dev_in, n * sizeof(int)); checkCUDAError("cudaMalloc dev_in failed!"); @@ -157,36 +163,31 @@ namespace StreamCompaction { cudaMemcpy(dev_in, idata, n * sizeof(int), cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy dev_in failed!"); + cudaMalloc((void**)&sumOfSums, block2n * sizeof(int)); + checkCUDAError("cudaMalloc sumOfSums failed!"); + + cudaMalloc((void**)&dev_out, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_out failed!"); + timer().startGpuTimer(); - dim3 blocksPerGrid1((pow2n + blockSize - 1) / blockSize); - StreamCompaction::Common::kernMapToBoolean << > > (pow2n, n, indices, dev_in); + dim3 blocksPerGrid((n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (n, dbools, dev_in); checkCUDAError("kernMapToBoolean failed!"); - cudaMemcpy(dbools, indices, pow2n * sizeof(int), cudaMemcpyDeviceToDevice); - checkCUDAError("cudaMemcpyDeviceToDevice failed!"); - - int *num = (int *)malloc(sizeof(int)); - cudaMemcpy(num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + int num; + cudaMemcpyAsync(&num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); - int ret = *num; + int ret = num; - cudaMalloc((void**)&sumOfSums, block2n * sizeof(int)); - checkCUDAError("cudaMalloc sumOfSums failed!"); - - scan_implementation(pow2n, block2n, indices, sumOfSums); // requires power of 2 + scan_implementation(pow2n, block2n, dbools, sumOfSums); // requires power of 2 - cudaMemcpy(num, indices + n - 1, sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpyAsync(&num, dbools + n - 1, sizeof(int), cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpyDeviceToHost failed!"); - ret += *num; - free(num); + ret += num; - cudaMalloc((void**)&dev_out, ret * sizeof(int)); - checkCUDAError("cudaMalloc dev_out failed!"); - - dim3 blocksPerGrid((n + blockSize - 1) / blockSize); - StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools, indices); + StreamCompaction::Common::kernScatter << > > (n, dev_out, dev_in, dbools); checkCUDAError("kernScatter failed!"); timer().endGpuTimer(); @@ -197,7 +198,6 @@ namespace StreamCompaction { cudaFree(dbools); cudaFree(dev_in); cudaFree(dev_out); - cudaFree(indices); cudaFree(sumOfSums); return ret;