From ec2a884415211930b0d62d9f77b1c31cae0a136e Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Mon, 17 Sep 2018 23:04:11 -0400 Subject: [PATCH 1/9] finish naive --- CMakeLists.txt | 16 +++++++++++- stream_compaction/CMakeLists.txt | 2 +- stream_compaction/cpu.cu | 44 ++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f654c9e..cea8daf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,21 @@ set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE ON) set(CUDA_SEPARABLE_COMPILATION ON) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CUDA_PROPAGATE_HOST_FLAGS OFF) + set(EXTERNAL_LIB_PATH "${EXTERNAL}/lib/osx") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(EXTERNAL_LIB_PATH "${EXTERNAL}/lib/linux" "/usr/lib64") +elseif(WIN32) + if(${MSVC_VERSION} MATCHES "1915") + set(EXTERNAL_LIB_PATH "${EXTERNAL}/lib/win/vc2017") + elseif(${MSVC_VERSION} MATCHES "1900") + set(EXTERNAL_LIB_PATH "${EXTERNAL}/lib/win/vc2015") + elseif(${MSVC_VERSION} MATCHES "1800") + set(EXTERNAL_LIB_PATH "${EXTERNAL}/lib/win/vc2013") + elseif(${MSVC_VERSION} MATCHES "1700") + set(EXTERNAL_LIB_PATH "${EXTERNAL}/lib/win/vc2012") + else() + MESSAGE("Error: unsupported MSVC_VERSION: " ${MSVC_VERSION}) + endif() endif() include_directories(.) diff --git a/stream_compaction/CMakeLists.txt b/stream_compaction/CMakeLists.txt index cdbef77..48e2f35 100644 --- a/stream_compaction/CMakeLists.txt +++ b/stream_compaction/CMakeLists.txt @@ -13,5 +13,5 @@ set(SOURCE_FILES cuda_add_library(stream_compaction ${SOURCE_FILES} - OPTIONS -arch=sm_20 + OPTIONS -arch=sm_60 ) diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 05ce667..004aee9 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -20,6 +20,12 @@ namespace StreamCompaction { void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + if (n > 0) { + odata[0] = 0; + for (int i = 1; i < n; ++i) { + odata[i] = idata[i - 1] + idata[i - 1]; + } + } timer().endCpuTimer(); } @@ -30,9 +36,16 @@ namespace StreamCompaction { */ int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); + int index = 0; + for (int i = 0; i < n; i++) { + if (idata[i] != 0) { + odata[index] = idata[i]; + index++; + } + } // TODO timer().endCpuTimer(); - return -1; + return index; } /** @@ -43,8 +56,35 @@ namespace StreamCompaction { int compactWithScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + int *temp = (int*) malloc(n * sizeof(int)); + + int finalSize = 0; + // First go through and puts 1s and 0s in temp + for (int i = 0; i < n; ++i) { + if (idata[i] == 0) { + odata[i] = 0; + } + else { + odata[i] = 1; + finalSize++; + } + } + + // Now run a scan on odata and save results in temp + temp[0] = 0; + for (int i = 1; i < n; ++i) { + temp[i] = odata[i - 1] + odata[i - 1]; + } + + // Now go through temp and save final results in odata + for (int i = 0; i < n; ++i) { + if (temp[i] != 0) { + odata[temp[i]] = idata[i]; + } + } + timer().endCpuTimer(); - return -1; + return finalSize; } } } From 4030861b754878b1f77572692011fc356a05d497 Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 14:40:01 -0400 Subject: [PATCH 2/9] finish naive gpu --- src/testing_helpers.hpp | 8 ++++++ stream_compaction/cpu.cu | 8 +++--- stream_compaction/naive.cu | 52 +++++++++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/testing_helpers.hpp b/src/testing_helpers.hpp index 46337ab..716f6be 100644 --- a/src/testing_helpers.hpp +++ b/src/testing_helpers.hpp @@ -52,9 +52,17 @@ void onesArray(int n, int *a) { void genArray(int n, int *a, int maxval) { srand(time(nullptr)); + /*if (n == 7) { + for (int i = 0; i < n; i++) { + a[i] = i; + } + return; + }*/ + for (int i = 0; i < n; i++) { a[i] = rand() % maxval; } + } void printArray(int n, int *a, bool abridged = false) { diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 004aee9..0757846 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -20,11 +20,9 @@ namespace StreamCompaction { void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO - if (n > 0) { - odata[0] = 0; - for (int i = 1; i < n; ++i) { - odata[i] = idata[i - 1] + idata[i - 1]; - } + odata[0] = 0; + for (int i = 1; i < n; ++i) { + odata[i] = odata[i - 1] + idata[i - 1]; } timer().endCpuTimer(); } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 9218f8e..0736d57 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -2,6 +2,7 @@ #include #include "common.h" #include "naive.h" +#include namespace StreamCompaction { namespace Naive { @@ -11,15 +12,64 @@ namespace StreamCompaction { static PerformanceTimer timer; return timer; } + // TODO: __global__ + __global__ void kernScan(int n, int power, int *read, int *write) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index < n) { + if (index >= power) { + write[index] = read[index - power] + read[index]; + } + else { + write[index] = read[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_read; + cudaMalloc((void**)&dev_read, n * sizeof(int)); + + int *dev_write; + cudaMalloc((void**)&dev_write, n * sizeof(int)); + + cudaMemcpy(dev_read, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + cudaDeviceSynchronize(); + + timer().startGpuTimer(); + + int D = ilog2ceil(n); + for (int d = 1; d < D + 1; ++d) { + int blockSize = 256; + int blocks = (n + blockSize - 1) / blockSize; + + int power = pow(2, d - 1); + kernScan << > > (n, power, dev_read, dev_write); + + cudaDeviceSynchronize(); + + int *temp = dev_read; + dev_read = dev_write; + dev_write = temp; + } + timer().endGpuTimer(); + + cudaMemcpy(odata, dev_read, n * sizeof(int), cudaMemcpyDeviceToHost); + + for (int i = n - 1; i >= 1; --i) { + odata[i] = odata[i - 1]; + } + odata[0] = 0; + } + + } } From 73e1d5f7eb5c8a89332762ceb675eb057e6d1b82 Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 16:11:54 -0400 Subject: [PATCH 3/9] got efficient power of two --- stream_compaction/efficient.cu | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 36c5ef2..fcb1a63 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -2,6 +2,8 @@ #include #include "common.h" #include "efficient.h" +#include + namespace StreamCompaction { namespace Efficient { @@ -12,13 +14,69 @@ namespace StreamCompaction { return timer; } + __global__ void kernUpsweep(int n, int power, int *array) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < n) { + for (int k = 0; k < n; k += 2 * power) { + array[k + (2 * power) - 1] = array[k + power - 1] + array[k + (2 * power) - 1]; + } + } + } + + __global__ void kernDownsweep(int n, int power, int *array) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < n) { + for (int k = 0; k < n; k += 2 * power) { + int t = array[k + power - 1]; + array[k + power - 1] = array[k + (2 * power) - 1]; + array[k + (2 * power) - 1] = t + array[k + (2 * power) - 1]; + } + } + } + + __global__ void kernSetZero(int n, int *array) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < n) { + if (index == n - 1) { + array[index] = 0; + } + } + } + /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ void scan(int n, int *odata, const int *idata) { + int *temp; + cudaMalloc((void**)&temp, n * sizeof(int)); + cudaMemcpy(temp, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + cudaDeviceSynchronize(); + timer().startGpuTimer(); + + int blockSize = 256; + int blocks = (n + blockSize - 1) / blockSize; + // TODO + for (int d = 0; d < ilog2ceil(n); ++d) { + kernUpsweep << > > (n, pow(2, d), temp); + cudaDeviceSynchronize(); + } + + kernSetZero << > > (n, temp); + + for (int d = ilog2ceil(n) - 1; d >= 0; --d) { + kernDownsweep << > > (n, pow(2, d), temp); + cudaDeviceSynchronize(); + } + timer().endGpuTimer(); + + cudaMemcpy(odata, temp, n * sizeof(int), cudaMemcpyDeviceToHost); } /** @@ -32,7 +90,9 @@ namespace StreamCompaction { */ int compact(int n, int *odata, const int *idata) { timer().startGpuTimer(); + // TODO + timer().endGpuTimer(); return -1; } From bb2e0fd629b9163890323fd269524b8ab32c8835 Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 17:26:04 -0400 Subject: [PATCH 4/9] efficient is working --- stream_compaction/efficient.cu | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index fcb1a63..42e46be 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -18,8 +18,8 @@ namespace StreamCompaction { int index = threadIdx.x + (blockIdx.x * blockDim.x); if (index < n) { - for (int k = 0; k < n; k += 2 * power) { - array[k + (2 * power) - 1] = array[k + power - 1] + array[k + (2 * power) - 1]; + if (index % (2 * power) == 0) { + array[index + (2 * power) - 1] = array[index + power - 1] + array[index + (2 * power) - 1]; } } } @@ -28,10 +28,10 @@ namespace StreamCompaction { int index = threadIdx.x + (blockIdx.x * blockDim.x); if (index < n) { - for (int k = 0; k < n; k += 2 * power) { - int t = array[k + power - 1]; - array[k + power - 1] = array[k + (2 * power) - 1]; - array[k + (2 * power) - 1] = t + array[k + (2 * power) - 1]; + if (index % (2 * power) == 0) { + int t = array[index + power - 1]; + array[index + power - 1] = array[index + (2 * power) - 1]; + array[index + (2 * power) - 1] = t + array[index + (2 * power) - 1]; } } } @@ -51,26 +51,33 @@ namespace StreamCompaction { */ void scan(int n, int *odata, const int *idata) { int *temp; - cudaMalloc((void**)&temp, n * sizeof(int)); - cudaMemcpy(temp, idata, n * sizeof(int), cudaMemcpyHostToDevice); + int size = 1; + while (size < n) { + size *= 2; + } + + cudaMalloc((void**)&temp, size * sizeof(int)); + cudaDeviceSynchronize(); + + cudaMemcpy(temp, idata, n * sizeof(int), cudaMemcpyHostToDevice); cudaDeviceSynchronize(); timer().startGpuTimer(); int blockSize = 256; - int blocks = (n + blockSize - 1) / blockSize; + int blocks = (size + blockSize - 1) / blockSize; // TODO - for (int d = 0; d < ilog2ceil(n); ++d) { - kernUpsweep << > > (n, pow(2, d), temp); + for (int d = 0; d < ilog2ceil(size); ++d) { + kernUpsweep << > > (size, pow(2, d), temp); cudaDeviceSynchronize(); } - kernSetZero << > > (n, temp); + kernSetZero << > > (size, temp); - for (int d = ilog2ceil(n) - 1; d >= 0; --d) { - kernDownsweep << > > (n, pow(2, d), temp); + for (int d = ilog2ceil(size) - 1; d >= 0; --d) { + kernDownsweep << > > (size, pow(2, d), temp); cudaDeviceSynchronize(); } From baecd3b4277389e9dabf18c8fd9c072216e22ac3 Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 17:37:13 -0400 Subject: [PATCH 5/9] finish thrust --- stream_compaction/thrust.cu | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 36b732d..898b8d5 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -22,6 +22,21 @@ namespace StreamCompaction { // 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()); + int *dev_odata; + cudaMalloc((void**)&dev_odata, n * sizeof(int)); + + int *dev_idata; + cudaMalloc((void**)&dev_idata, n * sizeof(int)); + + cudaMemcpy(dev_idata, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + thrust::device_ptr thrust_odata(dev_odata); + thrust::device_ptr thrust_idata(dev_idata); + + thrust::exclusive_scan(thrust_idata, thrust_idata + n, thrust_odata); + + cudaMemcpy(odata, dev_odata, n * sizeof(int), cudaMemcpyDeviceToHost); + timer().endGpuTimer(); } } From 5321c9439bfd605eda7c1f071808083a9eb2abc5 Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 19:34:42 -0400 Subject: [PATCH 6/9] add tests passing --- src/main.cpp | 2 +- src/testing_helpers.hpp | 4 +- stream_compaction/cpu.cu | 13 +++--- stream_compaction/efficient.cu | 75 ++++++++++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1850161..9461bc3 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 << 3; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int *a = new int[SIZE]; int *b = new int[SIZE]; diff --git a/src/testing_helpers.hpp b/src/testing_helpers.hpp index 716f6be..3216722 100644 --- a/src/testing_helpers.hpp +++ b/src/testing_helpers.hpp @@ -52,12 +52,12 @@ void onesArray(int n, int *a) { void genArray(int n, int *a, int maxval) { srand(time(nullptr)); - /*if (n == 7) { + if (n == 7) { for (int i = 0; i < n; i++) { a[i] = i; } return; - }*/ + } for (int i = 0; i < n; i++) { a[i] = rand() % maxval; diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 0757846..7ef3e23 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -18,13 +18,13 @@ 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(); + //timer().startCpuTimer(); // TODO odata[0] = 0; for (int i = 1; i < n; ++i) { odata[i] = odata[i - 1] + idata[i - 1]; } - timer().endCpuTimer(); + //timer().endCpuTimer(); } /** @@ -69,14 +69,11 @@ namespace StreamCompaction { } // Now run a scan on odata and save results in temp - temp[0] = 0; - for (int i = 1; i < n; ++i) { - temp[i] = odata[i - 1] + odata[i - 1]; - } - + scan(n, temp, odata); + // Now go through temp and save final results in odata for (int i = 0; i < n; ++i) { - if (temp[i] != 0) { + if (odata[i] != 0) { odata[temp[i]] = idata[i]; } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 42e46be..bbefa78 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,6 +3,9 @@ #include "common.h" #include "efficient.h" #include +#include +#include +#include namespace StreamCompaction { @@ -86,6 +89,29 @@ namespace StreamCompaction { cudaMemcpy(odata, temp, n * sizeof(int), cudaMemcpyDeviceToHost); } + __global__ void kernMapToBoolean(int n, int *read, int *write) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < n) { + if (read[index] == 0) { + write[index] = 0; + } + else { + write[index] = 1; + } + } + } + + __global__ void kernScatter(int n, int *idata, int *booleans, int *scan, int *odata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < n) { + if (booleans[index] == 1) { + odata[scan[index]] = idata[index]; + } + } + } + /** * Performs stream compaction on idata, storing the result into odata. * All zeroes are discarded. @@ -96,12 +122,53 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { - timer().startGpuTimer(); + //timer().startGpuTimer(); + + int blockSize = 256; + int blocks = (n + blockSize - 1) / blockSize; + + int *dev_idata; + int *booleans; + int *scanArray; + int *result; + + cudaMallocManaged(&dev_idata, n * sizeof(int)); + + cudaDeviceSynchronize(); - // TODO + for (int i = 0; i < n; ++i) { + dev_idata[i] = idata[i]; + } + + cudaMallocManaged(&booleans, n * sizeof(int)); + cudaMallocManaged(&scanArray, n * sizeof(int)); + cudaMallocManaged(&result, n * sizeof(int)); - timer().endGpuTimer(); - return -1; + cudaDeviceSynchronize(); + + // First map the initial array to booleans + kernMapToBoolean << > > (n, dev_idata, booleans); + + cudaDeviceSynchronize(); + + // Now do a scan + scan(n, scanArray, booleans); + + // Now do a scatter + int *dev_odata; + cudaMallocManaged(&dev_odata, n * sizeof(int)); + kernScatter << > > (n, dev_idata, booleans, scanArray, dev_odata); + + cudaDeviceSynchronize(); + + int finalCount = 0; + for (int i = 0; i < n; ++i) { + finalCount += booleans[i]; + } + + cudaMemcpy(odata, dev_odata, finalCount * sizeof(int), cudaMemcpyDeviceToHost); + + return finalCount; } } } From 85cf2113ec22c75b43bb2810cf5ca3f532ddb69b Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 19:42:09 -0400 Subject: [PATCH 7/9] make test arrays larger --- src/main.cpp | 2 +- src/testing_helpers.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9461bc3..1850161 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,7 +13,7 @@ #include #include "testing_helpers.hpp" -const int SIZE = 1 << 3; // 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 = new int[SIZE]; int *b = new int[SIZE]; diff --git a/src/testing_helpers.hpp b/src/testing_helpers.hpp index 3216722..716f6be 100644 --- a/src/testing_helpers.hpp +++ b/src/testing_helpers.hpp @@ -52,12 +52,12 @@ void onesArray(int n, int *a) { void genArray(int n, int *a, int maxval) { srand(time(nullptr)); - if (n == 7) { + /*if (n == 7) { for (int i = 0; i < n; i++) { a[i] = i; } return; - } + }*/ for (int i = 0; i < n; i++) { a[i] = rand() % maxval; From fe8df36a8703458708fad01f764a617a39e28f29 Mon Sep 17 00:00:00 2001 From: Ishan Ranade Date: Tue, 18 Sep 2018 20:50:31 -0400 Subject: [PATCH 8/9] add readme --- Capture1.JPG | Bin 0 -> 54650 bytes Capture2.JPG | Bin 0 -> 54190 bytes README.md | 193 ++++++++++++++++++++++++++++++++- stream_compaction/cpu.cu | 9 +- stream_compaction/efficient.cu | 53 ++++++++- 5 files changed, 244 insertions(+), 11 deletions(-) create mode 100644 Capture1.JPG create mode 100644 Capture2.JPG diff --git a/Capture1.JPG b/Capture1.JPG new file mode 100644 index 0000000000000000000000000000000000000000..1613567f2e9365e896271f568603055cefe547bb GIT binary patch literal 54650 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 AqW}N^ literal 0 HcmV?d00001 diff --git a/Capture2.JPG b/Capture2.JPG new file mode 100644 index 0000000000000000000000000000000000000000..e76479a0b45fb9625174e3019cec285b91773455 GIT binary patch literal 54190 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 > (size, pow(2, d), temp); + cudaDeviceSynchronize(); + } + + kernSetZero << > > (size, temp); + + for (int d = ilog2ceil(size) - 1; d >= 0; --d) { + kernDownsweep << > > (size, pow(2, d), temp); + cudaDeviceSynchronize(); + } + + cudaMemcpy(odata, temp, n * sizeof(int), cudaMemcpyDeviceToHost); + } __global__ void kernMapToBoolean(int n, int *read, int *write) { @@ -122,7 +169,7 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { - //timer().startGpuTimer(); + timer().startGpuTimer(); int blockSize = 256; int blocks = (n + blockSize - 1) / blockSize; @@ -152,7 +199,7 @@ namespace StreamCompaction { cudaDeviceSynchronize(); // Now do a scan - scan(n, scanArray, booleans); + scanEfficient(n, scanArray, booleans); // Now do a scatter int *dev_odata; @@ -168,6 +215,8 @@ namespace StreamCompaction { cudaMemcpy(odata, dev_odata, finalCount * sizeof(int), cudaMemcpyDeviceToHost); + timer().endGpuTimer(); + return finalCount; } } From f54d7aa7b6d8b9b09287161b586e00ab81886b79 Mon Sep 17 00:00:00 2001 From: IshanRanade Date: Tue, 18 Sep 2018 20:54:39 -0400 Subject: [PATCH 9/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a340ed..a895fda 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,6 @@ Press any key to continue . . . ## Discussion -One of the biggest performance hits for my work efficient implementation I believe is the bakin conflicts that are occurring, which are drastically reducing its efficiency. Another hit could be the mathematical operations that I am performing in my kernels, as I tended to repeat some calculations and did not save every value for future use. +One of the biggest performance hits for my work efficient implementation I believe is the bank conflicts that are occurring, which are drastically reducing its efficiency. Another hit could be the mathematical operations that I am performing in my kernels, as I tended to repeat some calculations and did not save every value for future use. -It seems that the thrust implementation took an extremely long time to finish. This could be because that thrust takes some time to warm up, and may have had a lot of cache misses the first time that I used it. In general my CPU version seemed to perform the best out of all of these. I believe this is because I did not properly use shared memory, avoid bank conflicts, and keep my kernels lightweight enough to fully utilize the power of the GPU. This assignment was a big eye opener in how to write better GPU code and what to look for in optimizing kernels. \ No newline at end of file +It seems that the thrust implementation took an extremely long time to finish. This could be because that thrust takes some time to warm up, and may have had a lot of cache misses the first time that I used it. In general my CPU version seemed to perform the best out of all of these. I believe this is because I did not properly use shared memory, avoid bank conflicts, and keep my kernels lightweight enough to fully utilize the power of the GPU. This assignment was a big eye opener in how to write better GPU code and what to look for in optimizing kernels.