From 929a33b5d1345475e5705db64ae9a6c90244eb5a Mon Sep 17 00:00:00 2001 From: WENLI ZHAO Date: Sat, 16 Sep 2017 15:08:19 -0400 Subject: [PATCH 1/5] CPU and Naive --- src/main.cpp | 8 +++-- stream_compaction/cpu.cu | 59 +++++++++++++++++++++++++++------- stream_compaction/efficient.cu | 10 +++--- stream_compaction/naive.cu | 50 ++++++++++++++++++++++++---- stream_compaction/thrust.cu | 10 +++--- 5 files changed, 107 insertions(+), 30 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7305641..26ccc79 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ int main(int argc, char* argv[]) { 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); @@ -49,14 +50,17 @@ 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, a, true); + //printArray(SIZE, b, 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(SIZE, a, true); + //printArray(SIZE, b, true); + //printArray(SIZE, c, true); printCmpResult(NPOT, b, c); zeroArray(SIZE, c); diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 05ce667..d3c79d4 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -1,15 +1,15 @@ #include #include "cpu.h" -#include "common.h" +#include "common.h" namespace StreamCompaction { namespace CPU { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } /** @@ -18,9 +18,14 @@ namespace StreamCompaction { * (Optional) For better understanding before starting moving to GPU, you can simulate your GPU scan in this function first. */ void scan(int n, int *odata, const int *idata) { - timer().startCpuTimer(); - // TODO - timer().endCpuTimer(); + timer().startCpuTimer(); + //TODO + odata[0] = idata[0]; + for (int i = 1; i < n; ++i) { + odata[i] = odata[i - 1] + idata[i]; + } + timer().endCpuTimer(); + } /** @@ -30,9 +35,15 @@ namespace StreamCompaction { */ int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); - // TODO + int count = 0; + for (int i = 1; i < n; i++) { + if (idata[i] != 0) { + odata[count] = idata[i]; + count++; + } + } timer().endCpuTimer(); - return -1; + return count; } /** @@ -42,9 +53,33 @@ namespace StreamCompaction { */ int compactWithScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); + // TODO + int *temp = new int[n]; + int *temp2 = new int[n]; + for (int i = 0; i < n; i++) { + if (idata[i] != 0) { + temp[i] = 1; + } + else { + temp[i] = 0; + } + temp2[i] = 0; + } + // TODO: Figure out how to not call timer twice XD + timer().endCpuTimer(); + scan(n, temp2, temp); + timer().startCpuTimer(); + for (int i = 0; i < n; i++) { + if (temp[i] == 1) { + odata[temp2[i]] = idata[i]; + } + } + int count = temp2[n - 1] + 1; + delete[] temp; + delete[] temp2; timer().endCpuTimer(); - return -1; + return count; } } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 36c5ef2..fd1d622 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -5,11 +5,11 @@ namespace StreamCompaction { namespace Efficient { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } /** diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 9218f8e..06c3125 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -3,22 +3,60 @@ #include "common.h" #include "naive.h" +#define blockSize 128 + namespace StreamCompaction { namespace Naive { - using StreamCompaction::Common::PerformanceTimer; - PerformanceTimer& timer() - { - static PerformanceTimer timer; - return timer; + using StreamCompaction::Common::PerformanceTimer; + PerformanceTimer& timer() + { + static PerformanceTimer timer; + return timer; } // TODO: __global__ + __global__ void kernScan(int d, int *odata, int *idata) { + int k = threadIdx.x + (blockIdx.x * blockDim.x); + if (k >= d) { + int offset = k - d; + odata[k] = idata[k] + idata[offset]; + } + else { + odata[k] = idata[k]; + } + } + /** * 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 *inData; + int *outData; + + // smallest power of 2 >= n + int pow2 = pow(2,ilog2ceil(n)); + cudaMalloc((void**)&inData, (pow2) * sizeof(int)); + cudaMalloc((void**)&outData, (pow2) * sizeof(int)); + cudaMemcpy(inData, idata, sizeof(int)*n, cudaMemcpyHostToDevice); + cudaThreadSynchronize(); + + int levels = ilog2ceil(n); + dim3 fullBlocks((pow2 + blockSize - 1) / blockSize); + + for (int i = 0; i < levels; i++) { + int d = pow(2, i); + kernScan << > > (d, outData, inData); + cudaThreadSynchronize(); + int *temp = outData; + outData = inData; + inData = temp; + } + + cudaMemcpy(odata, inData, sizeof(int)*(n), cudaMemcpyDeviceToHost); + cudaFree(inData); + cudaFree(outData); timer().endGpuTimer(); } } diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 36b732d..e3b3268 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -8,11 +8,11 @@ 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. From cc67cf17cd1fc452368b176510472921893d9a7c Mon Sep 17 00:00:00 2001 From: WENLI ZHAO Date: Mon, 18 Sep 2017 15:58:01 -0400 Subject: [PATCH 2/5] parts 1-4 implemented --- src/main.cpp | 25 +++++++- stream_compaction/common.cu | 17 ++++++ stream_compaction/cpu.cu | 27 ++++----- stream_compaction/cpu.h | 2 + stream_compaction/efficient.cu | 103 ++++++++++++++++++++++++++++++++- stream_compaction/naive.cu | 10 +++- stream_compaction/thrust.cu | 19 ++++-- 7 files changed, 178 insertions(+), 25 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 26ccc79..526daab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,6 +52,7 @@ int main(int argc, char* argv[]) { printElapsedTime(StreamCompaction::Naive::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); //printArray(SIZE, a, true); //printArray(SIZE, b, true); + //printArray(SIZE, c, true); printCmpResult(SIZE, b, c); zeroArray(SIZE, c); @@ -63,10 +64,19 @@ int main(int argc, char* argv[]) { //printArray(SIZE, c, true); printCmpResult(NPOT, b, c); + + /*zeroArray(8, c); + printDesc("TESTING HERE"); + int d[8] = { 0,1,2,3,4,5,6,7 }; + StreamCompaction::Efficient::scan(8, c, d); + printArray(8, c, true); + printDesc("~~~~~~~~~~~~~~");*/ + 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, b, true); //printArray(SIZE, c, true); printCmpResult(SIZE, b, c); @@ -74,7 +84,8 @@ int main(int argc, char* argv[]) { 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(SIZE, b, true); + printArray(NPOT, c, true); printCmpResult(NPOT, b, c); zeroArray(SIZE, c); @@ -133,15 +144,23 @@ 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); 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); + zeroArray(6, c); + int d[7] = { 0,1,2,0,2,0,1 }; + int f[4] = { 1,2,2,1 }; + printDesc("Work efficient compact, SMALL TEST CASE"); + count = StreamCompaction::Efficient::compact(7, c, d); + printArray(count, c, true); + printCmpLenResult(count, 4, f, c); + system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 8fc0211..3d6e484 100644 --- a/stream_compaction/common.cu +++ b/stream_compaction/common.cu @@ -24,6 +24,16 @@ namespace StreamCompaction { */ __global__ void kernMapToBoolean(int n, int *bools, const int *idata) { // TODO + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n) { + return; + } + if (idata[index] != 0) { + bools[index] = 1; + } + else { + bools[index] = 0; + } } /** @@ -33,6 +43,13 @@ namespace StreamCompaction { __global__ void kernScatter(int n, int *odata, const int *idata, const int *bools, const int *indices) { // TODO + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n) { + return; + } + if (bools[index] != 0) { + odata[indices[index]] = idata[index]; + } } } diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index d3c79d4..d454591 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -20,14 +20,18 @@ namespace StreamCompaction { void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); //TODO - odata[0] = idata[0]; - for (int i = 1; i < n; ++i) { - odata[i] = odata[i - 1] + idata[i]; - } + scanImplementation(n, odata, idata); timer().endCpuTimer(); } + void scanImplementation(int n, int *odata, const int *idata) { + odata[0] = 0; + for (int i = 1; i < n; ++i) { + odata[i] = idata[i - 1] + odata[i - 1]; + } + } + /** * CPU stream compaction without using the scan function. * @@ -36,7 +40,7 @@ namespace StreamCompaction { int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); int count = 0; - for (int i = 1; i < n; i++) { + for (int i = 0; i < n; i++) { if (idata[i] != 0) { odata[count] = idata[i]; count++; @@ -52,11 +56,10 @@ 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]; int *temp2 = new int[n]; + timer().startCpuTimer(); + // TODO for (int i = 0; i < n; i++) { if (idata[i] != 0) { temp[i] = 1; @@ -67,15 +70,13 @@ namespace StreamCompaction { temp2[i] = 0; } // TODO: Figure out how to not call timer twice XD - timer().endCpuTimer(); - scan(n, temp2, temp); - timer().startCpuTimer(); - for (int i = 0; i < n; i++) { + scanImplementation(n, temp2, temp); + for (int i = 0; i <= n; i++) { if (temp[i] == 1) { odata[temp2[i]] = idata[i]; } } - int count = temp2[n - 1] + 1; + int count = temp2[n - 1]; delete[] temp; delete[] temp2; timer().endCpuTimer(); diff --git a/stream_compaction/cpu.h b/stream_compaction/cpu.h index 236ce11..b4dc3d8 100644 --- a/stream_compaction/cpu.h +++ b/stream_compaction/cpu.h @@ -8,6 +8,8 @@ namespace StreamCompaction { void scan(int n, int *odata, const int *idata); + void scanImplementation(int n, int *odata, const int *idata); + int compactWithoutScan(int n, int *odata, const int *idata); int compactWithScan(int n, int *odata, const int *idata); diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index fd1d622..dd8c7dd 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,6 +3,8 @@ #include "common.h" #include "efficient.h" +#define blockSize 128 + namespace StreamCompaction { namespace Efficient { using StreamCompaction::Common::PerformanceTimer; @@ -12,12 +14,64 @@ namespace StreamCompaction { return timer; } + __global__ void kernUpSweep(int d, int d1, int *idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + int k = d1 * index; + idata[k + d1 - 1] += idata[k + d - 1]; + } + + __global__ void kernDownSweep(int d, int d1, int*idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + int k = d1*index; + int t = idata[k + d - 1]; + idata[k + d - 1] = idata[k + d1 - 1]; + idata[k + d1 - 1] += t; + } + /** * 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_iData; + + // smallest power of 2 >= n + int pow2 = pow(2, ilog2ceil(n)); + int levels = ilog2ceil(n); + cudaMalloc((void**)&dev_iData, (pow2 + 1) * sizeof(int)); + cudaMemcpy(dev_iData, idata, sizeof(int)*n, cudaMemcpyHostToDevice); + + + for (int i = 0; i < levels; i++) { + int d = pow(2, i); + int d1 = pow(2, i + 1); + + int blocknum = ceil(pow2/ d1); + dim3 fullBlocks((blocknum + blockSize) / blockSize); + + kernUpSweep << > > (d, d1, dev_iData); + cudaThreadSynchronize(); + } + + int a = 0; + cudaMemcpy(&dev_iData[pow2 - 1], &a, sizeof(int), cudaMemcpyHostToDevice); + for (int i = levels - 1; i >= 0; i--) { + int d = pow(2, i); + int d1 = pow(2, i + 1); + + int blocknum = ceil(pow2 / d1); + dim3 fullBlocks((blocknum + blockSize) / blockSize); + + kernDownSweep << > > (d, d1, dev_iData); + cudaThreadSynchronize(); + } + + + cudaMemcpy(odata, dev_iData, sizeof(int)*(n), cudaMemcpyDeviceToHost); + cudaFree(dev_iData); + timer().endGpuTimer(); } @@ -33,8 +87,53 @@ namespace StreamCompaction { int compact(int n, int *odata, const int *idata) { timer().startGpuTimer(); // TODO - timer().endGpuTimer(); - return -1; + int *dev_bools; + int *dev_indices; + int *dev_odata; + int *dev_idata; + + cudaMalloc((void**)&dev_bools, n * sizeof(int)); + cudaMalloc((void**)&dev_indices, n * sizeof(int)); + cudaMalloc((void**)&dev_odata, n * sizeof(int)); + cudaMalloc((void**)&dev_idata, n * sizeof(int)); + + cudaMemcpy(dev_idata, idata, sizeof(int)*n, cudaMemcpyHostToDevice); + + dim3 otherName((n + blockSize - 1) / blockSize); + StreamCompaction::Common::kernMapToBoolean << > > (n, dev_bools, dev_idata); + + int *indices = new int[n]; + int *bools = new int[n]; + + cudaMemcpy(bools, dev_bools, sizeof(int)*n, cudaMemcpyDeviceToHost); + + timer().endGpuTimer(); + scan(n, indices, bools); + timer().startGpuTimer(); + + cudaMemcpy(dev_indices, indices, sizeof(int)*n, cudaMemcpyHostToDevice); + + + StreamCompaction::Common::kernScatter << > > (n, dev_odata, dev_idata, dev_bools, dev_indices); + + int count; + cudaMemcpy(&count, &dev_indices[n-1], sizeof(int), cudaMemcpyDeviceToHost); + + int lastBool; + cudaMemcpy(&lastBool, &dev_bools[n - 1], sizeof(int), cudaMemcpyDeviceToHost); + + + cudaMemcpy(odata, dev_odata, n * sizeof(int), cudaMemcpyDeviceToHost); + + + cudaFree(dev_bools); + cudaFree(dev_indices); + cudaFree(dev_idata); + cudaFree(dev_odata); + delete[] bools; + delete[] indices; + timer().endGpuTimer(); + return count + lastBool; } } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 06c3125..057f7f3 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -37,9 +37,13 @@ namespace StreamCompaction { // smallest power of 2 >= n int pow2 = pow(2,ilog2ceil(n)); - cudaMalloc((void**)&inData, (pow2) * sizeof(int)); - cudaMalloc((void**)&outData, (pow2) * sizeof(int)); - cudaMemcpy(inData, idata, sizeof(int)*n, cudaMemcpyHostToDevice); + cudaMalloc((void**)&inData, (pow2 + 1) * sizeof(int)); + cudaMalloc((void**)&outData, (pow2 + 1) * sizeof(int)); + + // shift the input array to the right and pad with a zero. + int a = 0; + cudaMemcpy(&inData[0], &a, sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(&inData[1], idata, sizeof(int)*n, cudaMemcpyHostToDevice); cudaThreadSynchronize(); int levels = ilog2ceil(n); diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index e3b3268..adede23 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -18,11 +18,22 @@ namespace StreamCompaction { * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { - timer().startGpuTimer(); - // 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::host_vector host_idata(n); + + thrust::device_vector dev_idata = host_idata; + thrust::device_vector dev_odata(n); + + // Copy host to device + thrust::copy(idata, idata + n,dev_idata.begin()); + + timer().startGpuTimer(); + // Scan + thrust::exclusive_scan(dev_idata.begin(), dev_idata.end(), dev_odata.begin()); timer().endGpuTimer(); + + thrust::copy(dev_odata.begin(), dev_odata.end(), odata); + } } } From 45caf864eca841e336b800aeeb3978fb7411c202 Mon Sep 17 00:00:00 2001 From: WENLI ZHAO Date: Tue, 19 Sep 2017 21:53:26 -0400 Subject: [PATCH 3/5] everything implemented --- img/Capture.PNG | Bin 0 -> 28062 bytes src/main.cpp | 39 +++++++++++-------------- stream_compaction/cpu.cu | 4 +-- stream_compaction/efficient.cu | 52 ++++++++++++++++++++++++--------- stream_compaction/naive.cu | 49 +++++++++++++++++++------------ stream_compaction/thrust.cu | 4 +-- 6 files changed, 87 insertions(+), 61 deletions(-) create mode 100644 img/Capture.PNG diff --git a/img/Capture.PNG b/img/Capture.PNG new file mode 100644 index 0000000000000000000000000000000000000000..f4f431d416dea03192134021d3df4afc2151a43c GIT binary patch literal 28062 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 j|Cg7YAkVtIOOhm6A6~HS-U+t__t(E9e #include "testing_helpers.hpp" -const int SIZE = 1 << 8; // feel free to change the size of array -const int NPOT = SIZE - 3; // Non-Power-Of-Two +const long SIZE = 1 << 8; // feel free to change the size of array +const long NPOT = SIZE - 3; // Non-Power-Of-Two int a[SIZE], b[SIZE], c[SIZE]; int main(int argc, char* argv[]) { @@ -64,14 +64,7 @@ int main(int argc, char* argv[]) { //printArray(SIZE, c, true); printCmpResult(NPOT, b, c); - - /*zeroArray(8, c); - printDesc("TESTING HERE"); - int d[8] = { 0,1,2,3,4,5,6,7 }; - StreamCompaction::Efficient::scan(8, c, d); - printArray(8, c, true); - printDesc("~~~~~~~~~~~~~~");*/ - + zeroArray(SIZE, c); printDesc("work-efficient scan, power-of-two"); StreamCompaction::Efficient::scan(SIZE, c, a); @@ -85,9 +78,10 @@ int main(int argc, char* argv[]) { StreamCompaction::Efficient::scan(NPOT, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); //printArray(SIZE, b, true); - 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); @@ -102,6 +96,7 @@ int main(int argc, char* argv[]) { //printArray(NPOT, c, true); printCmpResult(NPOT, b, c); + printf("\n"); printf("*****************************\n"); printf("** STREAM COMPACTION TESTS **\n"); @@ -111,7 +106,7 @@ int main(int argc, char* argv[]) { genArray(SIZE - 1, a, 4); // Leave a 0 at the end to test that edge case a[SIZE - 1] = 0; - printArray(SIZE, a, true); + //printArray(SIZE, a, true); int count, expectedCount, expectedNPOT; @@ -122,7 +117,7 @@ int main(int argc, char* argv[]) { count = StreamCompaction::CPU::compactWithoutScan(SIZE, b, a); printElapsedTime(StreamCompaction::CPU::timer().getCpuElapsedTimeForPreviousOperation(), "(std::chrono Measured)"); expectedCount = count; - printArray(count, b, true); + printArray(count, c, true); printCmpLenResult(count, expectedCount, b, b); zeroArray(SIZE, c); @@ -144,23 +139,23 @@ 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); 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); - zeroArray(6, c); - int d[7] = { 0,1,2,0,2,0,1 }; - int f[4] = { 1,2,2,1 }; - printDesc("Work efficient compact, SMALL TEST CASE"); - count = StreamCompaction::Efficient::compact(7, c, d); - printArray(count, c, true); - printCmpLenResult(count, 4, f, c); + //zeroArray(6, c); + //int d[7] = { 0,1,2,0,2,0,1 }; + //int f[4] = { 1,2,2,1 }; + //printDesc("Work efficient compact, SMALL TEST CASE"); + //count = StreamCompaction::Efficient::compact(7, c, d); + //printArray(count, c, true); + //printCmpLenResult(count, 4, f, c); system("pause"); // stop Win32 console from closing on exit } diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index d454591..d592d43 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -56,10 +56,9 @@ namespace StreamCompaction { * @returns the number of elements remaining after compaction. */ int compactWithScan(int n, int *odata, const int *idata) { + timer().startCpuTimer(); int *temp = new int[n]; int *temp2 = new int[n]; - timer().startCpuTimer(); - // TODO for (int i = 0; i < n; i++) { if (idata[i] != 0) { temp[i] = 1; @@ -69,7 +68,6 @@ namespace StreamCompaction { } temp2[i] = 0; } - // TODO: Figure out how to not call timer twice XD scanImplementation(n, temp2, temp); for (int i = 0; i <= n; i++) { if (temp[i] == 1) { diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index dd8c7dd..a5ec4f3 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,7 +3,7 @@ #include "common.h" #include "efficient.h" -#define blockSize 128 +#define blockSize 256 namespace StreamCompaction { namespace Efficient { @@ -14,14 +14,20 @@ namespace StreamCompaction { return timer; } - __global__ void kernUpSweep(int d, int d1, int *idata) { + __global__ void kernUpSweep(int n, int d, int d1, int *idata) { int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index > (n/d1)) { + return; + } int k = d1 * index; idata[k + d1 - 1] += idata[k + d - 1]; } - __global__ void kernDownSweep(int d, int d1, int*idata) { + __global__ void kernDownSweep(int n, int d, int d1, int*idata) { int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index > (n / d1)) { + return; + } int k = d1*index; int t = idata[k + d - 1]; idata[k + d - 1] = idata[k + d1 - 1]; @@ -32,7 +38,6 @@ namespace StreamCompaction { * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { - timer().startGpuTimer(); // TODO int *dev_iData; @@ -41,17 +46,21 @@ namespace StreamCompaction { int pow2 = pow(2, ilog2ceil(n)); int levels = ilog2ceil(n); cudaMalloc((void**)&dev_iData, (pow2 + 1) * sizeof(int)); + checkCUDAError("cudaMalloc dev_iData failed"); + cudaMemcpy(dev_iData, idata, sizeof(int)*n, cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_iData failed"); + timer().startGpuTimer(); for (int i = 0; i < levels; i++) { int d = pow(2, i); int d1 = pow(2, i + 1); int blocknum = ceil(pow2/ d1); - dim3 fullBlocks((blocknum + blockSize) / blockSize); + dim3 fullBlocks((blocknum + blockSize - 1) / blockSize); - kernUpSweep << > > (d, d1, dev_iData); + kernUpSweep << > > (n, d, d1, dev_iData); cudaThreadSynchronize(); } @@ -62,17 +71,16 @@ namespace StreamCompaction { int d1 = pow(2, i + 1); int blocknum = ceil(pow2 / d1); - dim3 fullBlocks((blocknum + blockSize) / blockSize); + dim3 fullBlocks((blocknum + blockSize - 1) / blockSize); - kernDownSweep << > > (d, d1, dev_iData); + kernDownSweep << > > (n, d, d1, dev_iData); cudaThreadSynchronize(); } - + timer().endGpuTimer(); cudaMemcpy(odata, dev_iData, sizeof(int)*(n), cudaMemcpyDeviceToHost); cudaFree(dev_iData); - timer().endGpuTimer(); } /** @@ -85,7 +93,6 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { - timer().startGpuTimer(); // TODO int *dev_bools; int *dev_indices; @@ -93,11 +100,22 @@ namespace StreamCompaction { int *dev_idata; cudaMalloc((void**)&dev_bools, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_bools failed"); + cudaMalloc((void**)&dev_indices, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_indices failed"); + cudaMalloc((void**)&dev_odata, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_odata failed"); + cudaMalloc((void**)&dev_idata, n * sizeof(int)); + checkCUDAError("cudaMalloc dev_idata failed"); cudaMemcpy(dev_idata, idata, sizeof(int)*n, cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_idata failed"); + + + timer().startGpuTimer(); dim3 otherName((n + blockSize - 1) / blockSize); StreamCompaction::Common::kernMapToBoolean << > > (n, dev_bools, dev_idata); @@ -106,25 +124,30 @@ namespace StreamCompaction { int *bools = new int[n]; cudaMemcpy(bools, dev_bools, sizeof(int)*n, cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpy dev_bools failed"); timer().endGpuTimer(); scan(n, indices, bools); timer().startGpuTimer(); cudaMemcpy(dev_indices, indices, sizeof(int)*n, cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy dev_indices failed"); StreamCompaction::Common::kernScatter << > > (n, dev_odata, dev_idata, dev_bools, dev_indices); + timer().endGpuTimer(); int count; cudaMemcpy(&count, &dev_indices[n-1], sizeof(int), cudaMemcpyDeviceToHost); + checkCUDAError("cudaMemcpy dev_indices failed"); int lastBool; cudaMemcpy(&lastBool, &dev_bools[n - 1], sizeof(int), cudaMemcpyDeviceToHost); - + checkCUDAError("cudaMemcpy dev_bools failed"); + cudaMemcpy(odata, dev_odata, n * sizeof(int), cudaMemcpyDeviceToHost); - + checkCUDAError("cudaMemcpy dev_bools failed"); cudaFree(dev_bools); cudaFree(dev_indices); @@ -132,8 +155,9 @@ namespace StreamCompaction { cudaFree(dev_odata); delete[] bools; delete[] indices; - timer().endGpuTimer(); return count + lastBool; } + + } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 057f7f3..bb07cc2 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -3,7 +3,7 @@ #include "common.h" #include "naive.h" -#define blockSize 128 +#define blockSize 256 namespace StreamCompaction { namespace Naive { @@ -15,8 +15,11 @@ namespace StreamCompaction { } // TODO: __global__ - __global__ void kernScan(int d, int *odata, int *idata) { + __global__ void kernScan(int n, int d, int *odata, int *idata) { int k = threadIdx.x + (blockIdx.x * blockDim.x); + if (k >= n) { + return; + } if (k >= d) { int offset = k - d; odata[k] = idata[k] + idata[offset]; @@ -30,38 +33,46 @@ namespace StreamCompaction { * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { - timer().startGpuTimer(); - int *inData; - int *outData; + int *dev_idata; + int *dev_odata; // smallest power of 2 >= n int pow2 = pow(2,ilog2ceil(n)); - cudaMalloc((void**)&inData, (pow2 + 1) * sizeof(int)); - cudaMalloc((void**)&outData, (pow2 + 1) * sizeof(int)); + cudaMalloc((void**)&dev_idata, (pow2 + 1) * sizeof(int)); + checkCUDAError("cudaMalloc error dev_idata"); + + cudaMalloc((void**)&dev_odata, (pow2 + 1) * sizeof(int)); + checkCUDAError("cudaMalloc error dev_odata"); + + // TIMER STARTS HERE + timer().startGpuTimer(); // shift the input array to the right and pad with a zero. int a = 0; - cudaMemcpy(&inData[0], &a, sizeof(int), cudaMemcpyHostToDevice); - cudaMemcpy(&inData[1], idata, sizeof(int)*n, cudaMemcpyHostToDevice); - cudaThreadSynchronize(); + cudaMemcpy(&dev_idata[0], &a, sizeof(int), cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy error 0 dev_idata naive"); + + cudaMemcpy(&dev_idata[1], idata, sizeof(int)*n, cudaMemcpyHostToDevice); + checkCUDAError("cudaMemcpy error dev_idata naive"); int levels = ilog2ceil(n); dim3 fullBlocks((pow2 + blockSize - 1) / blockSize); for (int i = 0; i < levels; i++) { int d = pow(2, i); - kernScan << > > (d, outData, inData); - cudaThreadSynchronize(); - int *temp = outData; - outData = inData; - inData = temp; + kernScan << > > (n, d, dev_odata, dev_idata); + int *temp = dev_odata; + dev_odata = dev_idata; + dev_idata = temp; } - cudaMemcpy(odata, inData, sizeof(int)*(n), cudaMemcpyDeviceToHost); - cudaFree(inData); - cudaFree(outData); - timer().endGpuTimer(); + // TIMER ENDS HERE + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_idata, sizeof(int)*(n), cudaMemcpyDeviceToHost); + cudaFree(dev_idata); + cudaFree(dev_odata); } } } diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index adede23..1681d1c 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -19,9 +19,7 @@ namespace StreamCompaction { */ void scan(int n, int *odata, const int *idata) { - thrust::host_vector host_idata(n); - - thrust::device_vector dev_idata = host_idata; + thrust::device_vector dev_idata(n); thrust::device_vector dev_odata(n); // Copy host to device From 4a4ef7d15bececceac3422961783ac9b3454ac45 Mon Sep 17 00:00:00 2001 From: wpchop Date: Tue, 19 Sep 2017 22:15:58 -0400 Subject: [PATCH 4/5] added chart and graph --- img/chart.png | Bin 0 -> 28558 bytes img/image.png | Bin 0 -> 44572 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/chart.png create mode 100644 img/image.png diff --git a/img/chart.png b/img/chart.png new file mode 100644 index 0000000000000000000000000000000000000000..e057c168a69e0b889bd6283d619e710809121366 GIT binary patch literal 28558 zcmce-Wn7hA_ccnh=`9k{Al)t9h=LN*DJ9a~(k0SeQUX%aNK1z_NOyOabe)CX_w)SE zdC&Q9KD;kq`2Aq-bzN(%xyBrG%&~$L3;QYfYq{r+X#KT^}U7Cd+YJ=Ja!=a>cygrjpe*UjAyk%@w}) z!IVV6JSInuMpn@{Um$3zWfCbA7MU&41Nr-bo>S;li(Ye~e%us~kEp@p=*8P$LtR}o zX}s&RYvJ=Ddq>BK^Z~x~YoYTL`-9IkQ7@^mP2qP~P+@~4pGHCasj$KCM-b^hzoF6K zzd@4ZR1cpD5`Fpf;kQpD_~1(_IEsfayhIRx_`?5&FOFCK?CiX~y``n0p~DF&uBfP( zp4JS8H(l}l)!O=$g~iG>d~9LiU};I;!eV!O``ZeQoSYmiENtvYRff9)NhKwv`T2QI zPfyeU@mIk*dS)$YkFl}Wt1X8@o4Ui<sSA4T!+x$V1^A8XY5_t zzMZYDCC|K?nwskBgc&ME#@_Mq_`z3Tp=+pGWla=?8{-oZ zC8wl>mN)nHF>!GzGsKmr+c-yD3tROsF6zB_@#0woSJ+dmSFc~cE>(H`8of&V$Y<>$ zSZiWv=nc!s%034bmA}^GHOy<2>cD0g)n*JDD~ju@EA_YH&we;;4Xf#T7@3*zU;CG6 z*ZOL`l8|WQG#S{-mDjwuyAon36?}wZxzGvZQXv2vFwrBwXx}a2sa7Z zk~m7pWM-bDt*xo0<=V5_52xEx-;Hf?h=_yl>Ui2hyoNl8g`uu;`f z>~iVCVI0dlB~4Npp(L3XiyR^{Nf#F`yJWRE*Dpv{IFNe8Vrjy{!UhHg;^X7#a@FaB zguX})^!6r)!R|71b63{Z5~L?KxnFWHen3J-)+h@gQ0>f)MlmM)zpbAjH+O(ihtV=^ z-=Y+exdG#1hNl!JCgvnOi|kqsky?LLPJKPGn_<8ONp&iQI7!J)xSJ}Gm#kO(S(Exm z8O-|>8)<2jGpD6iM7EE(zrT>5p%;7e>@x7ynMlvLQ$*RLXt@Qi<>JXcEFB+od~{UL z!|6J6WzC*kGT5vse`lh^??^qp?1j>?)|W_y7B?35(qz(Z^bA=)i-O)E4w)N-b#^o-PR_zQ}3T4ee6k7}vuiXzu)X2ZWP_b@ebk%Z`0m}hm&W)@pl3tJX1MIO*v94BH&R#Rp{{^6^ue?n(GRqQaUis)abov`n=-l^N0p1sC8 z?!dGzF6uGhs->X;D-z1D&86^e1^X!_Z!XA{lMOEOpZAWL@~I$+*YH>r zRAFko%Hx9`BQ6AK5xhsPq!MWqmBr=RT3N|z_|( z9<}TCfH}EkB!XHJPHhhy0b(l(4f^glO82EZLJ<@MI4fx_Euwhx2~*^Z9K)lKXUsdB zE@hf$U#Pnn1|fTUd-}b4H0=guIZaF=B4pH222zPjJ;FLwW9`g)UYX%;>jw(|EIQtbZhLri&ciM#KkLe)3b~%wk+A00-u}!&s zp|9{T#S6bwsc&s=ioQ27HHC$FFS6ZCQ4t#*7Z-OSO^0LmD)RP1{wtS{!bsW0^W=C( zhkA8pw_n)raG{yxA>rXjJ_j3$sT;zK?v1LVVuj`&mCu-R zUI{?PNYS#HiL>Kw)Y|%B6(u_;UJ<)`<|1f82JS??6<bXx^6kO{Q!wKmXgpc%e;9@#0{t z>!Y)?X8?S)P=f56`#s&=Z+5rK1*`&1L)J!-%+T@Zn zF|{={eYpNFGjD=rWa;D6H7m4J9{2|Y_$+`toFFOO^lb?I z0Q_AfR=yI{ORvFQX?)5-40&VFd~7GOB!wYj>-g=$uj^6tI4NW>U1V^Osw?mWKBK8g z+9#w5vyqwX$o)=uqGe# z7Ms}?lS_WX#KPKGk+FQh9Oehisr|_@QKB2Tv{GWze>qm5=Jxv2RzOm6adcF_G6(`sJG46x#*&<#rSn5s-$H6BBKSjS?gVA=2jP{&ZOw z=;+5MC$>tVRN<0>BG9LUSzIl0r4q9hb{+BQ>13*mOiYrb?;GGEH!5ck$2WMoU$wwUuw`OKw%`{(}hm2JKr1^=#!8od50bm>?t}GbwLQPFg1>&sOjRlXBgYiem zHv-y3g3L2dCC#*QHeGb;(&KtCxoHLnUy^M^E z9v&WL#)*l1K2XzS-Ewp3hXY7WZ^p0Ud5-c^%@ZGSFJbUj;3C*@AXT8#*^`ODM8@;v z7hoASCMiF6v-CD<4igifXzKu65AWiRhs7+53k*bl_Kvn$-euG*wt`0NlYqdpW&~{K zmoFjF*EgarAp2VMelY6j=&*JERQLl|h8<^#YRv=1D2xX0YU zpmkwESLs}MSX}aelIs5;RUT)60FslMntFb)ke;3{ay^lln24|IepJ>;dOebUH#$E4 z6A$DV;r7Q3lbtS>J&w{u}(VR+ci-91IL zW?rIroWR>V*h%EA#k2 zW*?8fZXsxBU6Ph1YTbs_Lw8H@=C5g+BKMc&;^HbSETn>3NkX4$2wv}g7ZMWMHP_T6 z>|36kOiWK-;2ad>WM|JP_f%6;qX#w4784HP2}`3{am3wKn7xq(noj-?9D368Lr!_S^GiQn1Zvq$QC*jMLIg19RW<1 zveap@PxRGxFVP@L_eyBu#bu$5jg47ZhW7R+T-@dYaI?va*8W zue|++jt;Xx^3*cx{`P3>l23f{$COIe1wR`bTfaFICqIAB=fT73Wx`>J#Lj3?9LcEd zAp1Y0+1T!P)=jrn;B9+)SetI_UcT&_oK!b4*&Hv@GFA&yRLxaT07LiY%VmtRW^3(n zw&v{$ALUiCymfMN0(r%~%hZgi&D6}Sr@ei3d#qpScvdZ~Wce z9az#pE4BCUX;kwH3IrTBf91#~m*R@hEBrIOxg3Z|5Ge_)x*ySYH#ZLt4{e;B*6ZZ+ z5Gi6KBlS#8HMF!s;7$OE{wdh>Efhf4ON~@K}ALE@R589{dY?{}_(MX3ThEe`j=FXI@!CexjnagrA) zb&WO$LL}1%P@yN0!Z@k4a?B)*=ENn~Ft{)q)4_i3qM;+C1tz4--`WDupRX=vURkud zG5gsj?UA_$yt0}y>U!#J{*_A_yvmk*#-w@%40bF;P;X#KAz|xk2hZ|g8is0)#&fdG zTa9BAt}k>|8J15`Y*3qdU3;Y&eOA�F$dq%7VQ} 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 z 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 Date: Tue, 19 Sep 2017 23:14:02 -0400 Subject: [PATCH 5/5] Update README.md --- README.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b71c458..87bd380 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,89 @@ 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) +* Wenli Zhao +* Tested on: Windows 7, i7-6700 CPU @ 3.40GHz, NVIDIA Quadro K620 (Moore 100C Lab) -### (TODO: Your README) +### README +This project GPU stream compaction in CUDA. The implemented features include: +1. CPU scan and stream compaction. + * primarily used for performance comparison. +2. Naive GPU scan algorithm. +3. Work efficient GPU scan and stream compaction algorithm. +4. Calling Thrust's implementation -Include analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) +Analysis +======== +In order to analyze the performance of stream compaction, I first found the highest multiple of 2 for which my program ran correctly and optimized for block size. I chose a block size of 256 which seemed to be optimized for my GPU implementation on 2^17 elements. I then collected and analyzed the runtimes for the scan algorithm. + +### Figure 1 +![](img/chart.png) + +### Figure 2 +#### Data corresponding to Figure 1 +![](img/image.png) + +Figure one shows the array size vs. the runtime of each implementation in ms. Unfortunately, the results were not quite what we wanted. My work efficient implementation is slower than my naive implementation, which is slower than my CPU implementation. This could be due to many factors. One is the amount of global memory access that I am performing in my work efficient. As the array size increases, the memory access becomes more and more costly. + +It is hard to accurately say, but the trend for work efficient is that its runtime is leveling off, whereas Naive and CPU have an upward trend. Potentially, the work efficient implementation will succeed for greater array sizes, but my implementation limits me to 2^17. + +The Thrust implementation seems relatively efficient, but has arbitrary spikes in performance time. I think this is a thrust-specific implementation. There is some behavior underlying thrust that makes the first invokation of my thrust scan slower. If I call the scan on the same array twice, the second time will run faster. Perhaps thrust caches the inputs and is quicker for later invocations. + +Although my GPU scan implementations are slower than the CPU implementation, the work-efficient compact is more efficient than cpu-compact-with-scan. + + +``` + +**************** +** SCAN TESTS ** +**************** + [ 28 17 26 2 41 12 6 34 18 12 12 33 23 ... 21 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 0.012919ms (std::chrono Measured) + [ 0 28 45 71 73 114 126 132 166 184 196 208 241 ... 200656 200677 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 0.012919ms (std::chrono Measured) + [ 0 28 45 71 73 114 126 132 166 184 196 208 241 ... 200635 200635 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 0.180576ms (CUDA Measured) + passed +==== naive scan, non-power-of-two ==== + elapsed time: 0.171488ms (CUDA Measured) + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 0.698912ms (CUDA Measured) + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 1.96842ms (CUDA Measured) + passed +==== thrust scan, power-of-two ==== + elapsed time: 0.080352ms (CUDA Measured) + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 0.030464ms (CUDA Measured) + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** +==== cpu compact without scan, power-of-two ==== + elapsed time: 0.034251ms (std::chrono Measured) + [ 0 28 45 71 73 114 126 132 166 184 196 208 241 ... 151975 152019 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 0.019829ms (std::chrono Measured) + [ 1 1 3 1 3 2 3 1 2 2 3 2 1 ... 3 3 ] + passed +==== cpu compact with scan ==== + elapsed time: 0.055282ms (std::chrono Measured) + [ 1 1 3 1 3 2 3 1 2 2 3 2 1 ... 3 2 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 0.047008ms (CUDA Measured) + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 0.048704ms (CUDA Measured) + passed +Press any key to continue . . .