From d4bc52c01c6f8c9293c0da006de3654164adae15 Mon Sep 17 00:00:00 2001 From: Cryszzz Date: Tue, 19 Sep 2023 19:04:53 -0400 Subject: [PATCH 1/3] changes made with ec1 and ec3 --- src/main.cpp | 2 +- stream_compaction/common.cu | 17 ++ stream_compaction/common.h | 1 + stream_compaction/cpu.cu | 41 ++++- stream_compaction/efficient.cu | 290 ++++++++++++++++++++++++++++++++- stream_compaction/naive.cu | 40 ++++- stream_compaction/thrust.cu | 10 +- 7 files changed, 390 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 896ac2b..07727cf 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 << 29; // feel free to change the size of array const int NPOT = SIZE - 3; // Non-Power-Of-Two int *a = new int[SIZE]; int *b = new int[SIZE]; diff --git a/stream_compaction/common.cu b/stream_compaction/common.cu index 2ed6d63..abf9a3d 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] = 0; + } + else { + bools[index] = 1; + } } /** @@ -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] == 1) { + odata[indices[index]] = idata[index]; + } } } diff --git a/stream_compaction/common.h b/stream_compaction/common.h index d2c1fed..750bc83 100644 --- a/stream_compaction/common.h +++ b/stream_compaction/common.h @@ -13,6 +13,7 @@ #define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__) +#define blockSize 64 /** * Check for CUDA errors; print and exit if there was a problem. */ diff --git a/stream_compaction/cpu.cu b/stream_compaction/cpu.cu index 719fa11..dabdb04 100644 --- a/stream_compaction/cpu.cu +++ b/stream_compaction/cpu.cu @@ -20,6 +20,10 @@ namespace StreamCompaction { void scan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + odata[0] = 0; + for (int i = 0; i < n-1; i++) { + odata[i+1] = idata[i]+odata[i]; + } timer().endCpuTimer(); } @@ -31,8 +35,14 @@ namespace StreamCompaction { int compactWithoutScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + int j = 0; + for (int i = 0; i < n; i++) { + if (idata[i] != 0) { + odata[j++] = idata[i]; + } + } timer().endCpuTimer(); - return -1; + return j; } /** @@ -43,8 +53,35 @@ namespace StreamCompaction { int compactWithScan(int n, int *odata, const int *idata) { timer().startCpuTimer(); // TODO + + int* temp=(int*)malloc(n * sizeof(int)); + int* temp2 = (int*)malloc(n * sizeof(int)); + + //mapping + for (int i = 0; i < n; i++) { + if (idata[i] == 0) { + temp[i] = 0; + } + else { + temp[i] = 1; + } + } + //scan + temp2[0] = 0; + for (int i = 0; i < n - 1; i++) { + temp2[i + 1] = temp[i] + temp2[i]; + } + //scatter + for (int i = 0; i < n; i++) { + if (temp[i]==1) { + odata[temp2[i]] = idata[i]; + } + } + int cnt = temp2[n - 1]; + free(temp); + free(temp2); timer().endCpuTimer(); - return -1; + return cnt; } } } diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index 2db346e..b3162a4 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -3,6 +3,7 @@ #include "common.h" #include "efficient.h" +bool upgrade = true; namespace StreamCompaction { namespace Efficient { using StreamCompaction::Common::PerformanceTimer; @@ -11,14 +12,203 @@ namespace StreamCompaction { static PerformanceTimer timer; return timer; } + __global__ void kernEffUpSweep(int n, int division, int* idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n) { + return; + } + if (((index+1) &(division-1)) == 0) { + int div = index-(int)(division >> 1); + idata[index] += idata[div]; + } + } + + __global__ void kernEffDownSweep(int n, int division, int* idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n) { + return; + } + + if (((index + 1) & (division - 1)) == 0) { + int div = index-(int)(division >> 1); + int temp = idata[index]; + idata[index] += idata[div]; + idata[div] = temp; + } + } + + __global__ void kernEffUpSweepNew(int n, int division,int iter, int* idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n/division) { + return; + } + //int current = (index + 1) * division - 1; + int current= (int)((index + 1) <>1)]; + } + __global__ void kernEffDownSweepNew(int n, int division, int iter, int* idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n / division) { + return; + } + //int current = (index + 1) * division - 1; + int current = (int)((index + 1) <> 1); + int temp = idata[current]; + idata[current] += idata[div]; + idata[div] = temp; + } /** * Performs prefix-sum (aka scan) on idata, storing the result into odata. */ - void scan(int n, int *odata, const int *idata) { - timer().startGpuTimer(); + __global__ void kernSMWorkEfficient(int blockIter,int n, int* increments, int* idata) { + __shared__ int offset; + offset = (blockIdx.x * blockSize); + __syncthreads(); + + int thisIdx = (int)(threadIdx.x << 1); + __shared__ int TMshared[blockSize]; + TMshared[thisIdx] = idata[thisIdx + offset]; + TMshared[thisIdx +1] = idata[thisIdx +1 + offset]; + __syncthreads(); + int division = 2; + for (int i = 1; i < blockIter; i++) { + if (threadIdx.x < (int)(1 << (blockIter - i))) { + int current = (int)((threadIdx.x + 1) << i) - 1; + TMshared[current] += TMshared[current - (int)(division >> 1)]; + } + division = division << 1; + __syncthreads(); + } + TMshared[blockSize - 1]=0; + //__syncthreads(); + for (int i = blockIter; i >= 1; i--) { + // 1<<(blockIter -i-1) + if (threadIdx.x < (int)(1 << (blockIter - i))) { + int current = (int)((threadIdx.x + 1) << i) - 1; + int temp = TMshared[current]; + TMshared[current] += TMshared[current - (int)(division >> 1)]; + TMshared[current - (int)(division >> 1)] = temp; + } + division = division >> 1; + __syncthreads(); + } + + idata[thisIdx + offset] = TMshared[thisIdx + 1]; + idata[thisIdx +1+ offset] = (thisIdx + 1== blockSize -1) ? TMshared[thisIdx + 1] + idata[thisIdx + 1 + offset] : TMshared[thisIdx + 2]; + __syncthreads(); + increments[blockIdx.x]= idata[blockSize - 1 + offset]; + + } + + __global__ void kernSMAddition(int n, int* increments, int* idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (blockIdx.x >= n) { + return; + } + __shared__ int incre; + incre= increments[blockIdx.x]; + idata[index] += incre; + } + void oldscan(int n, int* odata, const int* idata) { + // TODO + if (upgrade) { + dim3 threadsPerBlock(blockSize); + + int* buffer1; + + int iter = ilog2ceil(n); + int newsize = 1 << iter; + cudaMalloc((void**)&buffer1, newsize * sizeof(int)); + int numOfblock = (newsize + blockSize - 1) / blockSize; + cudaMemset(buffer1, 0, newsize * sizeof(int)); + cudaMemcpy(buffer1, idata, n * sizeof(int), cudaMemcpyHostToDevice); + int idx = 1; + timer().startGpuTimer(); + for (int i = 2; i < newsize; i = i << 1) { + numOfblock = (newsize/i + blockSize - 1) / blockSize; + kernEffUpSweepNew << > > (newsize, i, idx++,buffer1); + } + cudaMemset(&buffer1[newsize - 1], 0, sizeof(int)); + for (int i = newsize; i >= 2; i = i >> 1) { + numOfblock = (newsize / i + blockSize - 1) / blockSize; + kernEffDownSweepNew << > > (newsize, i, idx--,buffer1); + } + timer().endGpuTimer(); + + cudaMemcpy(odata, buffer1, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(buffer1); + //cudaFree(buffer2); + } + else { + dim3 threadsPerBlock(blockSize); + int numOfblock = (n + blockSize - 1) / blockSize; + int* buffer1; + + int iter = ilog2ceil(n); + int newsize = 1 << iter; + cudaMalloc((void**)&buffer1, newsize * sizeof(int)); + cudaMemset(buffer1, 0, newsize * sizeof(int)); + cudaMemcpy(buffer1, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + timer().startGpuTimer(); + for (int i = 2; i < newsize; i = i << 1) { + kernEffUpSweep << > > (newsize, i, buffer1); + } + cudaMemset(&buffer1[newsize - 1], 0, sizeof(int)); + for (int i = newsize; i >= 2; i = i >> 1) { + kernEffDownSweep << > > (newsize, i, buffer1); + } + timer().endGpuTimer(); + + cudaMemcpy(odata, buffer1, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(buffer1); + } + + } + + void scan(int n, int* odata, const int* idata) { + dim3 threadsPerBlock(blockSize/2); + dim3 threadsPerBlockl(blockSize); + + int* buffer1; + int* increments; + int newnumblock; + int idx = 1; + + int blockIter = ilog2ceil(blockSize); + int numOfblock = (n + blockSize - 1) / blockSize; + int newsize = numOfblock * blockSize; + cudaMalloc((void**)&buffer1, newsize * sizeof(int)); + cudaMalloc((void**)&increments, numOfblock * sizeof(int)); + + cudaMemset(buffer1, 0, newsize * sizeof(int)); + //cudaMemset(increments, 0, numOfblock * sizeof(int)); + cudaMemcpy(buffer1, idata, n * sizeof(int), cudaMemcpyHostToDevice); + + numOfblock = (n + blockSize - 1) / blockSize; + + timer().startGpuTimer(); + kernSMWorkEfficient << > > (blockIter, newsize, increments, buffer1); + + for (int i = 2; i < numOfblock; i = i << 1) { + newnumblock = (numOfblock / i + blockSize - 1) / blockSize; + kernEffUpSweepNew << > > (numOfblock, i, idx++, increments); + } + cudaMemset(&increments[numOfblock - 1], 0, sizeof(int)); + for (int i = numOfblock; i >= 2; i = i >> 1) { + newnumblock = (newsize / i + blockSize - 1) / blockSize; + kernEffDownSweepNew << > > (numOfblock, i, idx--, increments); + } + kernSMAddition << > > (numOfblock, increments, buffer1); timer().endGpuTimer(); + + odata[0] = 0; + cudaMemcpy(&odata[1], buffer1, (n-1) * sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(&(odata[n]), increments, (2) * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(buffer1); } /** @@ -31,10 +221,100 @@ namespace StreamCompaction { * @returns The number of elements remaining after compaction. */ int compact(int n, int *odata, const int *idata) { - timer().startGpuTimer(); + // TODO - timer().endGpuTimer(); - return -1; + if (upgrade) { + dim3 threadsPerBlock(blockSize); + + int* buffer1; + int* bools; + int* indices; + + int iter = ilog2ceil(n); + int newsize = 1 << iter; + cudaMalloc((void**)&buffer1, newsize * sizeof(int)); + cudaMalloc((void**)&bools, newsize * sizeof(int)); + cudaMalloc((void**)&indices, newsize * sizeof(int)); + cudaMemset(buffer1, 0, newsize * sizeof(int)); + cudaMemcpy(buffer1, idata, n * sizeof(int), cudaMemcpyHostToDevice); + int* outbuffer; + cudaMalloc((void**)&outbuffer, n * sizeof(int)); + int idx = 1; + int numOfblock = (newsize + blockSize - 1) / blockSize; + timer().startGpuTimer(); + Common::kernMapToBoolean << > > (newsize, bools, buffer1); + cudaMemcpy(indices, bools, newsize * sizeof(int), cudaMemcpyDeviceToDevice); + + for (int i = 2; i < newsize; i = i << 1) { + numOfblock = (newsize / i + blockSize - 1) / blockSize; + kernEffUpSweepNew << > > (newsize, i, idx++,indices); + } + cudaMemset(&indices[newsize - 1], 0, sizeof(int)); + for (int i = newsize; i >= 2; i = i >> 1) { + numOfblock = (newsize / i + blockSize - 1) / blockSize; + kernEffDownSweepNew << > > (newsize, i, idx--, indices); + } + numOfblock = (newsize + blockSize - 1) / blockSize; + //(int n, int *odata,const int* idata, const int* bools, const int* indices) + Common::kernScatter << > > (newsize, outbuffer, buffer1, bools, indices); + + timer().endGpuTimer(); + + int outputsize; + cudaMemcpy(&outputsize, &indices[newsize - 1], sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, outbuffer, outputsize * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(buffer1); + cudaFree(bools); + cudaFree(indices); + cudaFree(outbuffer); + + return outputsize; + } + else { + dim3 threadsPerBlock(blockSize); + int numOfblock = (n + blockSize - 1) / blockSize; + int* buffer1; + int* bools; + int* indices; + + int iter = ilog2ceil(n); + int newsize = 1<> > (newsize, bools, buffer1); + cudaMemcpy(indices, bools, n * sizeof(int), cudaMemcpyDeviceToDevice); + + for (int i = 2; i > > (newsize, i, indices); + } + cudaMemset(&indices[newsize - 1], 0, sizeof(int)); + for (int i = newsize; i >= 2; i = i >> 1) { + kernEffDownSweep << > > (newsize, i, indices); + } + + //(int n, int *odata,const int* idata, const int* bools, const int* indices) + Common::kernScatter << > > (newsize, outbuffer,buffer1,bools,indices); + + timer().endGpuTimer(); + + int outputsize; + cudaMemcpy(&outputsize, &indices[newsize - 1], sizeof(int), cudaMemcpyDeviceToHost); + cudaMemcpy(odata, outbuffer, outputsize * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(buffer1); + cudaFree(bools); + cudaFree(indices); + cudaFree(outbuffer); + + return outputsize; + + } } } } diff --git a/stream_compaction/naive.cu b/stream_compaction/naive.cu index 4308876..830147f 100644 --- a/stream_compaction/naive.cu +++ b/stream_compaction/naive.cu @@ -3,6 +3,7 @@ #include "common.h" #include "naive.h" + namespace StreamCompaction { namespace Naive { using StreamCompaction::Common::PerformanceTimer; @@ -12,14 +13,49 @@ namespace StreamCompaction { return timer; } // TODO: __global__ - + __global__ void kernNaiveScan(int n,int size, int* odata, int* idata) { + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= n) { + return; + } + if (index >= size) { + odata[index] = idata[index - size] + idata[index]; + } + else { + odata[index] = 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 numOfblock = (n + blockSize - 1) / blockSize; + dim3 threadsPerBlock(blockSize); + + int *buffer1; + int *buffer2; + int zerobuffer=0; + cudaMalloc((void**)&buffer1, n * sizeof(int)); + cudaMalloc((void**)&buffer2, n * sizeof(int)); + + cudaMemcpy(&(buffer1[1]), idata, (n-1) * sizeof(int),cudaMemcpyHostToDevice); + cudaMemcpy(buffer1, &zerobuffer, sizeof(int), cudaMemcpyHostToDevice); + int iter = ilog2ceil(n); + const int size = 1 << iter; + timer().startGpuTimer(); + for (int i = 1; i >> (n,i,buffer2,buffer1); + int *temp = buffer2; + buffer2 = buffer1; + buffer1 = temp; + } timer().endGpuTimer(); + cudaMemcpy(odata, buffer1, n * sizeof(int), cudaMemcpyDeviceToHost); + cudaFree(buffer1); + cudaFree(buffer2); + } } } diff --git a/stream_compaction/thrust.cu b/stream_compaction/thrust.cu index 1def45e..ff0f1ed 100644 --- a/stream_compaction/thrust.cu +++ b/stream_compaction/thrust.cu @@ -18,11 +18,19 @@ 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::device_vector dev_thrust_in(idata, idata + n); + thrust::device_vector dev_thrust_out(n); + timer().startGpuTimer(); + thrust::exclusive_scan(dev_thrust_in.begin(), dev_thrust_in.end(), dev_thrust_out.begin()); timer().endGpuTimer(); + int* dev_out = thrust::raw_pointer_cast(dev_thrust_out.data()); + cudaMemcpy(odata, dev_out, n * sizeof(int), cudaMemcpyDeviceToHost); + //cudaFree(dev_out); } } } From d336eafd5268fa29abf1f99fa93a5713d40512f6 Mon Sep 17 00:00:00 2001 From: Cryszzz Date: Tue, 19 Sep 2023 21:06:58 -0400 Subject: [PATCH 2/3] parts done --- README.md | 99 +++++++++++++++++++++++++++++++--- src/main.cpp | 30 ++++++++++- stream_compaction/efficient.cu | 38 +++++++------ stream_compaction/efficient.h | 2 + 4 files changed, 145 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0e38ddb..68bf3ad 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,99 @@ CUDA Stream Compaction **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 2** -* (TODO) YOUR NAME HERE - * (TODO) [LinkedIn](), [personal website](), [twitter](), etc. -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Xiaoxiao Zou + * [LinkedIn](https://www.linkedin.com/in/xiaoxiao-zou-23482a1b9/) +* Tested on: Windows 11, AMD Ryzen 9 7940HS @ 4.00 GHz, RTX 4060 Laptop -### (TODO: Your README) +### Implementations: +I implemented basic CPU scan & compact, GPU naive scan, GPU work efficient scan & compact, Thrust scan. In addition to those, I also implemented GPU work efficient scan Upgrade, GPU work efficient scan Upgrade with Shared Memory. + +The four basic implementations just followed the instructions from slide. + +GPU Work efficient: Benchmark with all modulo operations and multiply operations converted to bitwise operations (give fair amount of speedup). + +GPU Work efficient scan Upgrade: I calculated actual number of blocks will be needed will be needed for each round of up sweep and down sweep in order to reduce number of blocks (total number of threads) need to be launched each time. This gives around up to 5x speedup. + +GPU Work efficient scan Upgrade with Shared Memory: I used shared memory to do block-wise scan for each block, then, I do scan on the increments. At last, I add increments back to block. Here, I made a design choice for the scan on increments, for this scan, I use GPU Work efficient scan Upgrade method instead of GPU Work efficient scane Upgrade with shared memory. By implementing GPU Work efficient scan Upgrade with shared memory on increments array will result in recursive looping on increments array. (I tried to do it just by appending new increments array to old one). However, I found that actually slow the performance somehow due to the need to addition from new increments array to old arrays. I found just using simple GPU Work efficient scan Upgrade is not that bad. This overall give up to 16x speedup. + +Blocksize limitation: by doing shared memory, my block size will be limited to block size 64, (starting at 128, I think there is some memory conflict inside each block, which resulting in error). For other methods, blocksize does not influence performance that much starting at blocksize 32. (if block size too small, will slow down performance project 1) + +### Performance Analysis + +The one thing I noticed first is my CPU is way stronger than I thought. Only when it reachs array=2^24, it starts to show up slowdown on performance. But right after 2^28, my CPU is no longer compatible of doing this arithematics. + +For general GPU side performance, it starts to showing slowing down when it reachs 2^20. For thrust, it starts to slow down on 2^28. (I personally think it will 2^28 is the bottleneck, since at 2^29, 50ms implies 20fps and this only counts the calculation for scan not including those memory operations). My Work efficient method is not effiecient at all, however, the upgrade one gives fairly good opitimization compared to naive one. The one with upgrade SM gives fairly good optimization compared to upgrade especially at 2^28. + +Some potential opitimization: by observing thrust, I found there is some insufficient threads usage for my SM method. In upgrade method, there is a way to just not lauching the threads in kernel. However, for SM one, although I am only launching blocksize/2 threads for each block, but when they are sweeping, most time there is only part of threads are working in the block. I dont know is there any more wise way to use those threads (probably just do mutiple additions at once, like two or three layers all together when downsweep). Another opitimization I would think of, swapping is not essentially needed if there is a wise way to just caculated the index to do the computation. + +#### Output for arraysize=2^26 +``` + +**************** +** SCAN TESTS ** +**************** + [ 2 10 43 45 10 38 5 10 13 25 24 17 9 ... 33 0 ] +==== cpu scan, power-of-two ==== + elapsed time: 30.0245ms (std::chrono Measured) + [ 0 2 12 55 100 110 148 153 163 176 201 225 242 ... 1643506275 1643506308 ] +==== cpu scan, non-power-of-two ==== + elapsed time: 41.5261ms (std::chrono Measured) + [ 0 2 12 55 100 110 148 153 163 176 201 225 242 ... 1643506220 1643506227 ] + passed +==== naive scan, power-of-two ==== + elapsed time: 85.8092ms (CUDA Measured) + passed +==== naive scan, non-power-of-two ==== + elapsed time: 82.2282ms (CUDA Measured) + passed +==== work-efficient scan, power-of-two ==== + elapsed time: 135.767ms (CUDA Measured) + passed +==== work-efficient scan, non-power-of-two ==== + elapsed time: 130.076ms (CUDA Measured) + passed +==== work-efficient scan upgrade, power-of-two ==== + elapsed time: 31.5261ms (CUDA Measured) + passed +==== work-efficient scan upgrade, non-power-of-two ==== + elapsed time: 31.4493ms (CUDA Measured) + passed +==== work-efficient scan upgrade with SM, power-of-two ==== + elapsed time: 11.6919ms (CUDA Measured) + passed +==== work-efficient scan upgrade with SM, non-power-of-two ==== + elapsed time: 12.0757ms (CUDA Measured) + passed +==== thrust scan, power-of-two ==== + elapsed time: 5.33914ms (CUDA Measured) + passed +==== thrust scan, non-power-of-two ==== + elapsed time: 5.62893ms (CUDA Measured) + passed + +***************************** +** STREAM COMPACTION TESTS ** +***************************** + [ 3 0 3 2 2 3 3 3 0 3 1 1 0 ... 2 0 ] +==== cpu compact without scan, power-of-two ==== + elapsed time: 139.038ms (std::chrono Measured) + [ 3 3 2 2 3 3 3 3 1 1 2 1 2 ... 1 2 ] + passed +==== cpu compact without scan, non-power-of-two ==== + elapsed time: 129.736ms (std::chrono Measured) + [ 3 3 2 2 3 3 3 3 1 1 2 1 2 ... 3 1 ] + passed +==== cpu compact with scan ==== + elapsed time: 318.162ms (std::chrono Measured) + [ 3 3 2 2 3 3 3 3 1 1 2 1 2 ... 1 2 ] + passed +==== work-efficient compact, power-of-two ==== + elapsed time: 42.9237ms (CUDA Measured) + passed +==== work-efficient compact, non-power-of-two ==== + elapsed time: 43.177ms (CUDA Measured) + passed +Press any key to continue . . . +``` -Include analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) diff --git a/src/main.cpp b/src/main.cpp index 07727cf..52e9cdc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,13 +69,41 @@ int main(int argc, char* argv[]) { zeroArray(SIZE, c); printDesc("work-efficient scan, power-of-two"); - StreamCompaction::Efficient::scan(SIZE, c, a); + StreamCompaction::Efficient::oldscan(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::oldscan(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 upgrade, power-of-two"); + StreamCompaction::Efficient::scanupgrade(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 upgrade, non-power-of-two"); + StreamCompaction::Efficient::scanupgrade(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 upgrade with SM, 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 upgrade with SM, non-power-of-two"); StreamCompaction::Efficient::scan(NPOT, c, a); printElapsedTime(StreamCompaction::Efficient::timer().getGpuElapsedTimeForPreviousOperation(), "(CUDA Measured)"); //printArray(NPOT, c, true); diff --git a/stream_compaction/efficient.cu b/stream_compaction/efficient.cu index b3162a4..64a3fd6 100644 --- a/stream_compaction/efficient.cu +++ b/stream_compaction/efficient.cu @@ -111,62 +111,66 @@ namespace StreamCompaction { incre= increments[blockIdx.x]; idata[index] += incre; } + void oldscan(int n, int* odata, const int* idata) { // TODO - if (upgrade) { - dim3 threadsPerBlock(blockSize); + + dim3 threadsPerBlock(blockSize); + int numOfblock = (n + blockSize - 1) / blockSize; int* buffer1; int iter = ilog2ceil(n); int newsize = 1 << iter; cudaMalloc((void**)&buffer1, newsize * sizeof(int)); - int numOfblock = (newsize + blockSize - 1) / blockSize; cudaMemset(buffer1, 0, newsize * sizeof(int)); cudaMemcpy(buffer1, idata, n * sizeof(int), cudaMemcpyHostToDevice); - int idx = 1; + timer().startGpuTimer(); for (int i = 2; i < newsize; i = i << 1) { - numOfblock = (newsize/i + blockSize - 1) / blockSize; - kernEffUpSweepNew << > > (newsize, i, idx++,buffer1); + kernEffUpSweep << > > (newsize, i, buffer1); } cudaMemset(&buffer1[newsize - 1], 0, sizeof(int)); for (int i = newsize; i >= 2; i = i >> 1) { - numOfblock = (newsize / i + blockSize - 1) / blockSize; - kernEffDownSweepNew << > > (newsize, i, idx--,buffer1); + kernEffDownSweep << > > (newsize, i, buffer1); } timer().endGpuTimer(); cudaMemcpy(odata, buffer1, n * sizeof(int), cudaMemcpyDeviceToHost); cudaFree(buffer1); - //cudaFree(buffer2); - } - else { + + + } + void scanupgrade(int n, int* odata, const int* idata) { + dim3 threadsPerBlock(blockSize); - int numOfblock = (n + blockSize - 1) / blockSize; + int* buffer1; int iter = ilog2ceil(n); int newsize = 1 << iter; cudaMalloc((void**)&buffer1, newsize * sizeof(int)); + int numOfblock = (newsize + blockSize - 1) / blockSize; cudaMemset(buffer1, 0, newsize * sizeof(int)); cudaMemcpy(buffer1, idata, n * sizeof(int), cudaMemcpyHostToDevice); - + int idx = 1; timer().startGpuTimer(); for (int i = 2; i < newsize; i = i << 1) { - kernEffUpSweep << > > (newsize, i, buffer1); + numOfblock = (newsize / i + blockSize - 1) / blockSize; + kernEffUpSweepNew << > > (newsize, i, idx++, buffer1); } cudaMemset(&buffer1[newsize - 1], 0, sizeof(int)); for (int i = newsize; i >= 2; i = i >> 1) { - kernEffDownSweep << > > (newsize, i, buffer1); + numOfblock = (newsize / i + blockSize - 1) / blockSize; + kernEffDownSweepNew << > > (newsize, i, idx--, buffer1); } timer().endGpuTimer(); cudaMemcpy(odata, buffer1, n * sizeof(int), cudaMemcpyDeviceToHost); cudaFree(buffer1); - } - + //cudaFree(buffer2); + } void scan(int n, int* odata, const int* idata) { diff --git a/stream_compaction/efficient.h b/stream_compaction/efficient.h index 803cb4f..d5caf9b 100644 --- a/stream_compaction/efficient.h +++ b/stream_compaction/efficient.h @@ -7,6 +7,8 @@ namespace StreamCompaction { StreamCompaction::Common::PerformanceTimer& timer(); void scan(int n, int *odata, const int *idata); + void oldscan(int n, int* odata, const int* idata); + void scanupgrade(int n, int* odata, const int* idata); int compact(int n, int *odata, const int *idata); } From 50a71f302cfeacdfe8b4942be7035f05cc35a2f9 Mon Sep 17 00:00:00 2001 From: Cryszzz <69176305+Cryszzz@users.noreply.github.com> Date: Tue, 19 Sep 2023 21:09:08 -0400 Subject: [PATCH 3/3] update readme --- README.md | 3 +++ img/p1.png | Bin 0 -> 22503 bytes img/p2.png | Bin 0 -> 33247 bytes img/p3.png | Bin 0 -> 18665 bytes 4 files changed, 3 insertions(+) create mode 100644 img/p1.png create mode 100644 img/p2.png create mode 100644 img/p3.png diff --git a/README.md b/README.md index 68bf3ad..35f2f3c 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ The four basic implementations just followed the instructions from slide. Blocksize limitation: by doing shared memory, my block size will be limited to block size 64, (starting at 128, I think there is some memory conflict inside each block, which resulting in error). For other methods, blocksize does not influence performance that much starting at blocksize 32. (if block size too small, will slow down performance project 1) ### Performance Analysis +![](img/p1.png) +![](img/p2.png) +![](img/p3.png) The one thing I noticed first is my CPU is way stronger than I thought. Only when it reachs array=2^24, it starts to show up slowdown on performance. But right after 2^28, my CPU is no longer compatible of doing this arithematics. diff --git a/img/p1.png b/img/p1.png new file mode 100644 index 0000000000000000000000000000000000000000..1d879f0c0adc867143eb0ea93c06e9ff36e3c5f4 GIT binary patch literal 22503 zcmd43by!tV^fq__1r!7U0ck|(5)f$+DW$vN(kb1IqEZ4PCEX?6UD6>)cVAk%>oWVI zznE{n@0odKo|$L<;6ab)?6c3>Yp?ab?^@eHd0B}E_lfUAAdm-d--s$gAjs+v2$BOj zD!8(=;!+NQs1?2y6;^iD{WFW^`N$Y9WP5Xgg3sMcmSoC9{~^d!SoF@Lhw=~Ukv{}I z_-cTLwSk_7-uB^9=2I1mb)6?4e@mf%en>g;@HJ&f`D{7!yieo63}%^}bA(K#k;|dm zyrphztf}*f{;v{>q_xEeSUxk?)oC58u5GyN77ilU+)JvH+%?vVSO*=%j_lJmQMUHuhLn|x9|?|ms# z&jo?d)e{#VP3J0Q!(wVi+XC^ny~EuuFtB<;g|4cOjmV0$YhFK<2+hdIcvjQ3jEje7 z-WGt9h6RBvEc#MQ$;oB62NMRD#&VeUv|F#_U_Gq9T5PJx-ZU#wZxdqp;ODnORisg3 zaQFJ^a3GBZ0$E8^Lm}wx>A^LIdL2h;!&Jpak&q*VuDDK>$xe6YS$90Pr#Nf6EOBvh zMailW59q|+%`a+#Pp#Ick9Vz&8t$OR^0^eQM?dB;!L*vG4(~H5`^9-7H6ZekYI9>9!JlkJ3 z-x@3URLCgl?cM15pecHnP5{sTvDJUL+_!ET(4p(B-7eAc95)*GZU>021ke$X$uT}y zMC_uTNf)I<-i@UEF#BtPACo{^4J~U~coOZLWvT zCl6=K1#j_O^&B04-QDe5+x=sjIaO*LOcxv&7#<9P^x%h~GD(nB-D&ISnDPpd7Azt^ zbd5MWb7g;wnU?80V29!BnTWXRb8~%~W=zG!rFO-bG_c<^20lT;E=h}Ogq6Ng6`!1( zrGLL^Z+U4+G!J_`_$F##4V#QNLuV^ss-d+2gH|r-QNjJe!NH~P0}dD;dM1UMp7u93 zmODwx%8vDK^-5lzhms3uCM;j)p<8Azh}-epJ!L5pv~$z>ynV(Bbr=f;?3O-iXEZ>~g?vnf7*&*&Bk7iTksy(# zx)0Q6u3KgmV_0;)LDO`eMhxV2uJtDl_uE;1aQ8XqjrG(OSbdn<)7LlBpUmSR&Nl!p zKDe~C#7d4xo{@a}7H6#nKZhHbl5o5yti~Z=@o=Um#r|YqH=wMDRVMK$Szp1J`rLDS zF`BwDRIBG`#Dl=!?=DnL+f_kpuliE1{U-68)W0x|TT8;_3T``23GFQk&)rp<8knCP zkjxyL)^(wVymDI_^vzsqs`fcsMB9&XGBV28=^=rQbMt~VX=+oM(OFslJ5$~t)mq{L z0|hw1(?$r$B;sd2=!Z=q|J2EG=g$fpaEOVNY_PHO@s>#N@-p9SE6``J$S+SW3ewWx z{$t08QB^xp*FVSOarTz)SQG1tkVX69X-p@1?u`}CSMKx|PL7?s*kQR#mdDANk_~cy zjfp=WR_fx$N@frn2NH$p>5gBP0;YuWrnGY!$tq>XMB% zEsvnMn@yjOPrrqcCC1$TNVz9z*`G~Js$zMJj8R#W4b^#H*K!XqKVmq)4(4NZa7^@^ zBXcqc?MV=5G8?3_>(jC4cMj-e+RupIbh=oeY^vnuPYTddj$wrsRv>TGRgT^NB&X z+n?%;wbATiEDFK=x*tX(9$m|cBQ0$gcH9S-gf6

%8ane4A~gQ9K^HWGERv7Ga%x zx#JsJ6R`2* z{)AYmwmh&>a{6{LLF7U$9c$+}cH|UovjIZaM@p$4-JPNRd9yTEqR~m7iJsa+hnFYY zc%A&JpX-Frp%?tWU52w{miUD}KuM1kTpRrxXiv@rl>ZO&OsY#eJ6j)2r^?xTOzG_| z(;!P>0UPH{gX`Lxdb`zCk4^&!N!P^=7R?|lD|1*hVGnQ zYgAZ7RgcY`iJxCfy3c|Aa6At62`nAWQ|lE2xg}^EWeoheJwiph(C0%St*SCK+j=u5 z7OsnMIsVC1cUhqY)kaxCmJPR^A;%ZcM=oXi$yMC^9i4-Z$s4O0c(RQ``+E`2=OU5# zJ)PZjU<*xSdYb!)$GzYw=||XQ4hh;FeE)mi+#-#iQKA|%N27Ramrwn72gZxEs$^Lh zj=ZS_5OGs6`^(;uW;z7Y*uRAoyw8orGA;xn^!iniGyGtQjheJ@WS{in*0P7ty{na+ z{vX?5O{-t5xlulsJLsAfzw+h}q?OCj{AMh5*6Vq=`YWx_6We-lIZ$Xtc=cqiDd&(~ zVtkTs*W&Ly9eRn1>^hqWNx8X?_6a@A%yOz_h4c%qrqW3HoTd9X+fQM!Yi{#%{EDO* zXQxqG->ap*(B4FfgylIo9-m4ib|?DG8=uS-WvnG$=RY2QueA#kJ_aTYkw7MZxDvAJ zw6+A)(f0P7AFhd!RgYpoQtCyTktGiUkMdYQN87MvhF}2cfsHQj>SLGLju36iT+>z>s{?; zUayN6oYphn8Pp1;W#V6EI;{1Z8`H`rq)1SBMKY-7zd7CgzbuG0o!_5BLKDro?K zM3B3|aESR`pX)SwPG()fFL%c){mI<}cpcX%8$FIzPPlm~NJyl1>kqL6uJ&4w&X&W1 zPhUL7JTP7`MP|`!*!zhAfC5cVcXz7O*4UsFYePnq)9zg2hYug<1OyU4W05hyv0)ZO z5Xc=YEJ<)n=C63Jh(WUq3__OQBsTTJQZX!}g@b6+5#6G}1k7o`?`N%RlF|>YrYkdv zI7|ZMqY@IN!L$kIITz-^8)u!Tt(I;ceeuz-X}WeU_@b4178A4I^!N;Vzc3mJ@@lfH zuX1SAagEC`Nu^Qj35C}Y4zosS+bXGlK5NsJB44zhqOT#)N3aOFp-?iu@nNd>Wa!03SEl>go`HaqI1b(2<@W%DGhVik9kn#Y{<-7{t83mokTGe&OJ5 zC=iNcolpCko$Rf7B~nXwkL zzsn@?Yn0pCsilw>AHfXw>U}ZPFLwCdFbQrLDFp>}|8%yu4;qFEtlASnUZn(vRt3Bo zaJu^f*~YWPHvUfq1lvZ{DCM@;co|>g~Lv-MsYP*W=_5 zjvrPHb#V4Od9Ra6(-+Qv)c1q=-H*&R2h;s~5hgGhW{W^q7bdY^N%QU0ap1?Y1nDM? z_G9+Dg^~t-K}i*Db%11xzB|81%Rcly<}mI5eYx8thlWia$%(JXrQ4bFfj|>kNMnS_8Z9ZT_A}k(pD|V&iy%{+Trr@y` zeKB}2!31xIofl{`qd?GKDBZ}{&Z&|zHA*o*+@7h4(Dgc2`JqvkweB9zWs@XR!=Z2d zD~@xiV)Ta!UaHx0N5}y+F}(9KMcA(`!tW}HpHtqzAWgMjIHV4f=giJBDhRFG;cWSw z=sZyP4%0lYErNh*bLiQHqN_`=JR(0uf%FSEBSRo0MRG5Ke4{M(7IAhUf>?;#Uc4nz z#VO>KQ>1x^>N|9M*RK`_6P#jH=5Bz`Q|=&G?5i?IpGI``;mWmcF^D`eh`EpyqAC`( zJNX6S?E^%2A)$y^>zg(H=N(S5EUh|>3POi;hY13CC~cCaiidf0;EJ-6hJ?{fjd+wY zK}tEgYeR6jDy9o*5AF8S6;UQr_~Ea(gDO!h-@4n;o->MSP?-)U9n^qJe19)F#+Hiq z&pl=eM_FLF9lusqA-bz3?lZMLMEjHPT?i!78jNjznjZeJ2%_zexZ=p9szJ3D{7Ib( zt(gq*HNL78s?lBNZc^voAND}Z&7SwU(Gg_s=WCtZqTIX98rRit!Mk-_!5v>whAfL3 z!~+8ZKlP(T-a#aj-?WF3)b^pB=L2{j$NDhYp)$7aWyB!|%=Z^5D|~LeHvv#jJ^T?6 zfNnA0C;%2Qcyp{k3WTsvg_bkbZ0#K#L0<65jJJ3t$+59-8$3?45LrU-YEPu6r)Nkv zugbWWz;cCUC$D{w2$TV63^Agii|-eB4d#2pAwS9tbsFnhEzoD+P?K{D_9`h*JBwWd*K z^2-e1tjPFysorSjblN1>wBJtY5@A`NFbIRL#exY2fl5$u2*M+7kxrd+fwOMMlK`mA z%lLK=J3S@4SMh9ysGmN6R!kQUDL-rwMH_exe2#97C7VGCR(~zE z&&=Q07J(G36*pCG{?vPOpchbWnb=wifY3B^9;2m+_+tfLqdp)G7=IqzZh-goXwLi6 zYQI*%<3!%Ma(hVZHuk;i@BTB&$ip+a`j{UBIB-e=1|M)84uelV0>bOvzU|eS{#vE5 z!|@_$c6S7AFr-b#+WxEl`T6-#AIE^at}ZzuYf?#wsyTaFZHR#;3~9&^8P+L_Ua zbclfh(xci@AU9J=?U1D#8rpJ=@R**ObNwD%9tV*_7*(>#ccBQy`R#?H=(20^nB=GS zdkZD%Xjr7hJo6=n5^>yiRG&V64A>Er5dN%H+;{``Abzgr>s+YY;I4@g%~4%v)BTOw zKsstOH#-SeUvl+b!yhugON7@&I;5-7OTqqpafSyA$#=K-CDXvN?;o$Z`SMoL85 zZhntKhDwAb?wL=~+sePCx*(DH4|g#{_l8~A zc(qtPIv2bVn`~vqV>pTy-7q4`I{%+C7LQ_U)4%UTF$<@|FE=5TOA3 zc8zi~F!RvW5^2xJad{wc$gOYiy7n_6kEKwfDUEtUDVVQ=G|drp3?huY;(76( z;Vk`!S`j%l4UI)-{7b7eka?0{+RWuAE+3dCd#Um{6U=9GdxkW~RDi(nL$!c7gp6;@ zWPZ}44kQhe1NtW~Uq;Wlt&zE(E&6ZlcT!}x_@PC#=zV2nbh))mYM~N{SA|*nfut(Q zf?j5wp=4A0zDOuJO4+hY*+IP^73Pug^~U-t&2VB19DPMsB?xXenb#s6EdoIBg<%IK z&W~>q5$0!mi!U74<05UDOn zwGojIA-)KWQns#?nGO(Knwy&+wV+Y_P7f25oUL=oK00#T)+H6EkxP;WyKyK~1_B#N zPW)&x2>HsO1b+1;s%youeRObjxR&;Oimjs^q0 zh~Y%y%VS{xSnwA=v_h(8a=0m(w5z|ev$K~Qb}$Q2_*}7R6nsiAXxK~3W_2kaXbGJE zhb4_p;|9|uhJm6=$Hf(c5RYn!j>iF({PsmWeVus4Hl4N1U#RRK65W`oaj-9G<+Y1> z>e6a20C29j9RL1DRaIqyD+Jql#Zz`s4BT}<>+15}YZo*oYd7XM1%=laOZy7lUR z4hQU(I|8o}P=+MOMiVTyrR4u1sHYtYTIp&qiiI9NL20b*_j zSb}TL2gEOaqvkvGCXlwl+^46z9c`>KM5fBR+)>z;9F^ zb!zOz_=?oD1HPgJG24bO798?0w* z6`H)S-*w2^sVjDp+o`)=Y-Crk^E}MyJX{;dhF@P!N9MxDyGZXoyoM{u2~clR4MSVy zqm6D=?AR8~TFQ8>?i z$_p=VT>F*}cO4g+-@n%JVJPHk5^_3OtE*BYhHjjdbfb_B<*ed`%aL*P!2j_Uu^zWvUO=*L}9+ zHG6y)vc}Unk0p9;tVb3xR1qle;oMA2(&Yi&XT%=yjrG-D-UeYPq*YmVy~Tx~h$ACLN?RRogyvn0}dfN)*Y6orz%r}NsWudrFoq;(*T z4kmZcmHZ9O5(<(&4)FG)+4`S(JT9T!@H>Sc!jS=#_C#+UkQCzc&=zT{ zq>~(P__!<~fwXq3u&$h4caRUksVX(^L?(FS!b;4fw+sVdMgF?nmp32*U}z=_wAf9d*Nv1{nV{Ac~Wdleb}?%w^_D z5?#IhN|35EtP6+DN(AuawutxqO;NY6TWHoOLs$2U)&ujiL9a$2_)pBU$*jm@N85-g zkld!U_q+d`v1LMW|A~;Kx*0Vnn$D6WsLx?%wY393r zv$>9I2;F>ygCo2>T}3FjacJ6?SCm6K+M0~mq<5+{p14uzG0)}YzrmsV@Y7W3dc}sj z;coIQ&HPVP*0t9EmQsVi7y1Kv?EhLqEm3!tF=4G=-{>XVcCcMKMSt)h6VRl|hR#fXB;Fi-#uoAHYW5Z^3f9V<>R^V*mLFc z+EB}F7BKuEha&?_L)rX5CyOb(jEkl?x(lSOrRW$Crh~8V;nDnFY7cG~ydmYXPMEM6 z$_T6u6}Y)N)Xc-LGTG=fv3s?!!+yP=z~hhuSku&&@r5eYbrvhDb+U-0q-2nD{t$FH zMHt1ZnYXI1TUffVs==!P6aIkN8B6z2`Vj?lk${DibXR8>6c-^WiKiQK$9a!gZDI$D5ktsgv(mMyAqjGM5Z>@jr@u z_eOr#u=M&P>8n564xm!Xe$A=8r<_^4|WdGS3e@G>#qd6#|x> z`%Ie+Fhd^%aDCW36at{^wl}+?UOQu2tU_wf^L=d zY!0-^`=wzvH&d=*7&j9?5O_3WNzq4^fwZf11HZQFQ9iIV3Pld^zCrLFr|^xU#cXOa znHtLRmch&Q(OjiY6HJ1z{UtjMkkL0MN}kFjaEHHs{aQ4}SYel%;t~as4Is|{$>lqV zNVu#YL09>c-h_3c@4Jz6WGqou8noYMlMU$9+whA3FE_OAUK~qYUpI@lr)d&jrSn}s zJ%8KvPq?}7be&s0cLkqO>7GsI|2;G3bih_6N=;3@A&KwVl#)Uj6da7ltUlB513M>l zv(4|%)2C0{xhsI=!+XUs$@e#{BfUG;2QcTY7RuJW*K%*)ym=`6`bLy;*-&s`g<*%+ zbGPBNP05y&ZiGdQ1`YYzPF?-G8BWALh%sJnc9&OeifSb>5yD zsdcgp3Jfgq014gi(5;Y>s7e=Lus8fX>SZP}`=XiNf@}cv6!#cTRf~my_dQXm#D3Q(~V0VThoOJW@9dMl*veyYDkz9I+Gbwv&KKxBV!uPqU4c|ufFX4Ly#1jR#tHR+~m!87-&zz@?%ywN_c3@JF~ z*J4U5p3wmlj3H?>LF7@)gU8QPes2-5Xw#XnnAX#=%T>n4$1|D)t%-%J09cTzuIj(r zdUYSMY?NVh#nSYP4gKye0;L?} z-fMyfd8H@nwXr?=op}V6f9Q+K zq?$yD+2l)YFKMtl*I=+{qMO3a${N<6z$3ETbR$T{?AHQo(W~z9NT*j9 z(9!Xlay%OW?=80&WjN0SoiAzs81CD?A@Jmh zu%MOSWme4%DACMp{TK3)qhrvsQ-gwiA-YBA)0rzr^7?!^9M~RWY`OvW#3|0Q>6FLx zEd>Sp3V?UF2ggAB&F?1oG3yWc)DPbuKY&2^m+PErsPwEt+9FIK#_j1yTa%{A_)0e< zA>u!@Yf2vL;FN+!B@Xvr{RBvis|;DTXmpI^57evX-1ENEg`m|QDt){%dV+n0 zhy{C?5wSU=cTgJm=U&yAH6zn;fICSuT*&>DgHR{{_j`ML<6q%-n;7UP^3nXnAWSsZne52_lS{zEx9-e- ztCTcy005Z6tYzLWnp%D=I0iP(dKJWuyK8&e2%4gQ#cx zD;>%5`r_E2pV93KzXL#<>iMvE5XQznE#G@>E0jb>ny@yQp;Td^Qlg9n2gO;}xm$TS zZE5e0zWGR=S{Ueus#pe;ckudjUJgj3WBqnKtSD-V{{z}YR4wAYOn0|`05|H+{x~tA z?!K1jvcBj~LExZ+Mb7^n6V=aCqh@)~_c+Yw$`2?qE5pFiOjH>a;wdmkN-6b->}Q|1 z&1%A5YyRJrdCvHJ{!8WQOh*bPblI6K%YJjE3ilBL-`2LG4Dy|I6Y)ygx86F*tl85D zYLgW0C9N;HqPc{L^Y$D!r>`&nAL~E(%Mr$*$e0mY6-NbH7vnnBw(tL!Fx84&eEEL` zQx6UfM5Us86cVYZsB*k6Pn7dinfHkt!eV-WP!TAB63xGJ-w^m5|I`Y~m{8^Py59c`xtbiU4?1p+(D(fMg|9?!$CVDR4Sy=}ZP4tIPCBXek@3l%DPVlh zH5)y7Kof&3i?cfIjy=p;y%4QP>8cG+&dgX0ffhGFmDl$_b?P)+4vKt6rm zwR54po+!qZ7|?t`U(Y9_K}Gv=vO;(u`uk0guW?`vTk*816}ilj(}T6DR>@#xg+};= zA#7wTFNTt|^CeQ0q6|lYrKr!*W6eQQhxf2_y;m2p;dw&u2+f{{yATpuDL- z7z-!%)*KofzP2YLZ3xo^u^&-ee9TH7lWDJ<4NBreK-8dr_Ds}KgWwqSo(S!|X*S^D z;YqWJyTP{|5I7AmcGzh+)wLMT3NfQuu?HqjWcyqA9o>CkQz$ zQwRxH5UT^ZTt=ti$1{E|+?@Y!<)`Jy?�gOxi01?tN!utG?FLsmYmH zSY#%Bb|iO)U2ygAVv%*m>1@tpH;|kJ>(PaZ6zo-s5Ecdo9^W5?Vr$x5DBhIAH~ z&#)Wq67Ounk}{?$ER{e_jGl(3V+R0x?EbZyLZcaXPP5;X`!GF3jRP<0;=GM?G_aK+ z%zT-E6Dubaj*!KKn^Bp(HHE!3_kp#k*wpgX6|T?(JkN>|Wn^P3!;fIPzfs4dyVxjp ze>h_6UTCl&`{Lf8@NJi4>p}`v;^Z4-b^O%FA$L zUt8lH>LK}BBD3q+ZH}gqmb*b*t3uVSGv+v5#Ikc#-L` zHxaVW4Uu<8A}X#v1~5kF6S68oP@<)EH7NThD9MlMCg<=Af489Hcgrm6^G{Yot%9}= z&q8(<2EiOr_tL`n*F!p4*}Oma#*ptlsyGhnM%s$jvK~Bf^Zxd?M*&PaGEyIZ@y8)- zh&9}hQ(z!UNWr9p0D|M=mE`K10?ek|p+&wC!6JiMEmAg~c&Mjn&kh`1lcQ>QaIEOIB`vaXJR z!C_5x=FUiC^Wd;WXun5r_8im)3Wt}wG}7_E`<$Et%f@g!!{qw0zSd?jS(>TN{w6H! z+%pBF@7m>1zVh?Jk>b`)vAd7dx-H2!MF`}^2ROPol8TmryyZ}X2}xmMo{YH_kxpWu z^wFczSpwMfvwjB4)+Ijs*f4Jte7j<@F`{kYq&NyU# zW`UoBCJP=fAD>lVNoMuVFbcw7p`?!0`0JoZdUUZ>)EndeappsN@1wo6=qrlvgmr)Z zwI3L7{KaCyOgg8boW}9&)m}p6bNZo;XDfRp`mLz@kVmZNSlj=K^cATQ=B^%Y#szPBooCnPcGf>U@_`>xu-%M<@<_WI(ZEEZP03QX z)G_vleXlb<<;0sHAMc|<2`r(tR{&ME4-@YVA=md07F5kiV)O6$p6MM&l(>B(Eq3K} zgo~|eteg`@tX0`pAS~;}&8KxI|9f6${Lfj^<3je+(e``x3N^6xU?`U4)oh2bKW!IG zqf3Q9kH?>mh2**3tJHD3)5l?QCNtEX5mpDk@sjA1JfxKWJMY>PI&w27@+R}Aw1#~3 zIv!PSF##-Bz#Z^7=93Yb zlHgRM+ziL-@E6z8cb|hxzKaADkn|C8N4D|5z-*>@Gka!)`PzKfBgJq!T3Ht67*enO z-o<60_!uOcimi>&;>(Hu+S)BeIJ|peV}(?hhx^g^fxsvw&3v}7AL^8^Bl$8=lf~Pa z#p*>LEKjbwu}E0s7$UgP_4!(|0kkmL8!8mvkUsE9>kqfGeclX0@_B8DkbL@!_(1bm z!$A+@()Xfe@%s{|7|#%eMDNW%oFGAxb4XQ*hEjVM4hcLS)MR0(s;+wN9TysQULVx@ z{$c?yW<$%x73w7bedRRj$V!*c)8BL22%vu(31LWb@!6L77dFDYkX@SL*NB%X7Xk z)O=3Mu>fmMx8F50PG}Ga^{FWWFjZMfg30mJ=dxE{{}_t8^Q;5?f7i$}#pdsqrxrE2 z!}Dw-`O6y8j0MKnN^eXsCNsaR+frL#T18;p)zQifZpW#KTA?<*GL8Q$k2$YXoxxAJ zp(Lv%`t=VTK+kl!CF!VKVV-CHkUwV!QfQ}f?#Q?u8T@koCWv=q0F6D2h73z>MhFuE z+2L~V2lHBLIJZ|Q$)8-i|5N2I`=>dbujSUB!qF}sr#tw=ShkiJRd68Hi96>0W2#7D z`b#YCsw)SFV)(fJ{8g* zU{)txI6G9zEn2qIn>ok|MR9O!LTovwd9Tw+uUgQvsLl0{?odOiI_=?>#qZm@9{4U%WW>6ieY^d}AMSiYWIHfaZ8; z|0!&Yd}mIp#Nd+*QP}0u>B_0i-!hGvu{$a5xzpzGM}9&g3I}ebjonMY&w?Q|$%rYB zn>ciajU%dA2S}Ci_rP-$2qzN5+!l}ifwTP z9H>4Z7_=-ks;eJVp!^!7V3_q=>+BMPEYJXsdUMt(MB0B2?3!71TP4jXp!WRmJ3%b# zcU>FA#j#BJc-Ol!DPS{8>S|15AfDo(pIP4Jin)T-F5fdxbew^)yo#cv;@3;=%G%MCYR;+~` zagZU^EVl%uD~j6V!|(bVHshVV5g|ZUZ8@HiK_EgLLeijL$=WPQ8}^mcs|j5#OJMXq z7Lz?2q&gO`oQ7xyUCJ{1m7W80fC`6hf%k8-wYA6P2^Z=_Gv3bC+IJx2^4v%@0ffmg zjdv?7!cNO~Q;so&0rKts59He&O(%sF>#U+ui}oNJrU==CRG~2mcrb%lCGXzB&saff zlcLtd^>wn_)3~8h8;n~Wju`jDojZ^PiT~2eNZBbY!Ds3wJpq>TM|goonYiPnQMe1oM@bRH~$xdsxW7 zK7-2>J&_!_)3R*S16ExatR<(#2&G>OWil$nS8=oH4bX(HJ~&9hzGL%eVp_}1(ScW^ z0U-f#nsY8>hHZj6f)JFAw*+OaL+TneQwYoXgl}Y7`Xps|07^6 z1Sq=!@qz=ZHxsfTMt)B{TP`^ZRCg3IC8KgcbMPYyilQjHQ$4_q9Mw=Duk8K_KdY{R zq?SDdAYi<|L2P?t@F=1S8$bkkRaFAewi?Upv?+?{2?IPz5wyB(T%8{tNP%7c{>49) z2*$086PsQOFd<=6Ot55!LF&wJAq-qCwqaq2uLu}0icu{KbTE`8$HdTTmL_=~yp4Nl z73W9|fjpu`2uiX|pTwBL4JDrr_cIvXuZf~NE!Ebfn%q)VRP0@&GwhQGRpA6!xG(j< zNPj1zT46a4$fNxlPH(`@9a8O-yQ{fm$~fzXV+BjYEy;jp!$O%wn|o&Kq*zcPwBW3X z29ucuDugbCf(r=n`9hm#_g)`{6GpXctHtz)QGYvMR>vtE@;?RUO}SG~06Zq^yc2{ynSim>L0JNbbMIfXlD9I^4%CcqHeh2r*67Hj$K}c8Gw$>uxAu*_6i;( z;EM(fs4Wit-fI%vVG=34ezFto0HybvmOBX#PB5+beJnReSfKXVZFofyLiYp_fhY)K z(wM@Bx7E;?mF~85l~-jA34E`VU~$qs`8-Oco!L12KEFl`GYbupjVNoK6&EXkWq+zR zg)J~P@(?Usqr}-87Uv*pfsk)}mCC4UD6i=M-u$1c233n^n*Wf1>!Maomw7B+ zCq2rvzkwSW#0Al~x~G5J81On>#$G|Vw&$7BdZK}E9p`15_U5DE4Kuc4fm|m;c4*@> z#K4G#yR%}KY+%ba8p5Q_j&H^C8|3^`uUYJ|u;1O3*RdCS^%vRGL#h#-WX%#phxtnz zEr{?|W827puF4#>)AI4IeYleS%Od;wF3NH?2N<9>+`~Q z&t7L>qPH|b&2;n@BbsQm^w-9Oupmk_dkQ2^LCc%p%SXB(+w13p&r7S*hDGLg<3+yT z_7jW(`{e;5a(IqJT7k&eg0@0!pKqXv%66(^(XEv%&6aJA`7W%Eju6F{j=%BR_i%Rv*46JRiX_j!qP_uML?2ds_9w_PX#N1Z#ff75*43dgE6E?|>RZl9 zzx&&_w^%iczPU7Mu3w~8DslMWEN)t4tI-+EH@;q(n>yQ-@I9c?LmAs&?lcFzJulb( zac@ud8QgYeCB&(WYOQ}{N3nQigSfa4ElGa0QF6|6*@!J)BR2A&;|8_T|6K&|T@i#J zF|Jpn+aUUQ$YUvxmJW1+)UE!b(9N^`x}cW0!FJdIGS`>Zo*A_|3MTH~nS};M*9YnB z#n(*~-N5+5!1%6lpI=%{1t9H|4hUX;=?Ep0LiKwu9!4%B;C^Ha=y>xioVyTod~e5* z+`K7IfWHQ4!K8SnCoQ%=F*QT=LAyz4%n=Kvn{@Lzh+XwP?vKz%;ARJPn9MbBv18JBe&Z__nJ@OUSJaq`$QwsFKAu? zo4)Re6j1k15{WY95DEbrGh|Qj_O5Rxw@v2};iC0DQqMpRHb}33c5Yu+EhUfn zZg*b75g*z2^fuyr4G0Et@0tKKPO2|u(arjWCuTBkFSq=eYCbu9Jb@*zdb`uReu#kE zA}RqIiNh8EyHZY*QOBG@u9FhA^5!5Npeo&upc=Fw^0(j%Hxtw-ql&62`U$5_dd4KX z6IuZF7fV66Mb|g5tigZBq&+MZYYqzHh*;^10jOj68rFNigg7K}s3HUeyJ_*7$B=r& z+4W`#^?XsQMy|gF;%?gE9W($FzSy1*y>`VhWh-ugvSPkN+e1Q-R6!~hvA+#ur8G8* zU@y8#Hs(JZZa<71sl}mgIN*=%PXbXf1@ku81nAHL(~B4OJvrR30%J}rq2*u zZ(`fyKq7H&&B-S8$43hGQ5S5bp1+wi$TK!%CeeouWty*w%F-kY#7^Tow^RLsC^+*t zxz>WPnP1=;_`tFt=wL$kB5Loxen`YC$^M*nOQ$83qE18=J*~`^X1<+-iYxWbso5Yp)f$c4$z^Fn?s)z}LVTxppigFns8J^}tD%NjxbR0nKI zira?nj{x=bw(oZ?che8k((ZkyUmbhN~S$MUKh1Xie8 zp4-%dFcEReR!r6`cRLw+MxE)CVs!PGflpnZj6%cGVQSEaDAR{>;=tAm>4gA+yXXF4qxF&zW!i_B5n%Y+HU&Bna|w??-wGDjkJ_R&9xj2lQ8OiXHHM0M z!4S8gyC-P!4bKyoV5FU<{IbOHp163a++AmR)XF04N_rH?JmR2;yg29%1+XUEl4N+- zbAApmM+c0@1CEepAAw7Ip2Cgx5P*@-5SOuMsH*5E0j@q+2% zjPq$3f0WO0A-1?ciuaAtNCN=`>m7+Ga|e;x^`Iv^wBdDkQ9};E7Q8e~ZRw>4Aun!V z#1<8WgriXS=LudbctU7)TNi*55r}1~Z;2F-uFlmQr?i=83Vn#g$j~pnk=_XK2AUUh z(~zN}{gBxvG&py1^R!&=7*645E-~X>s*W+hfDP%ttuRwsuCkRTTm(p`x|p@}lvkm~ zvcmr(5Ji=khOrknh&YsLpL$klYnvd4@Uce_7kO%7s3w2*7V$5&h<(-uzXGXy zC-se{yyipnDz?Z=6VAWoi%%DqZe_f^lmDO<&SmJaYc0A;5)o26ylC0EQKmC*QJ^wo ze>}TLd?FMr=PG zqIc}{AT1FuuylB38tE^(j`ZbRei$ov^iW^YvS3Oro+;)&vZQyAXN`!Vgny82)Wi;T zX$DPiJGIFR{f7VszntY zhBn5#s7E}H(KL(QO{ZgyIx`!Lx(8@@_ed1vXGu~wo2qcG=OXCl>Kv?)BDoNYi=`f7 z+J(y@kEuNVVRYxR%ift=K{nsBMyYS#&e8lQHkEeb`b<=p(Kl8*NzXCP`}dP&Li}u` zEA|Ha2g`+?e4u;!-fWmIZSkfaCtrL{qWoAZtxxn^6|!)fHr-V@G$O{n@hquK(-VZ& zzZuJuYI}q!%ZM&_PMc2WF^b!B=Keg>(VY21R4sFy_bYF)lKu>x44g}!tTnazT$zgJ zX1myqAI7oj9Y2~a)`_B6H{j%Zdxoy>EqySGp`E`E;YZ{>-xVF|-cNQ$Q%cw3#rGTh zn6d?FELWiiqs|&-?DV_MsAw{(0l&nxPX>vz<5Df(h;7Uf-+ z?rjpDB#vpeTi*3{SXT>@38oHG7d~=WCQ1F_b2rV+23Kc-b{-W{k4VQooR(A8>=I6Z z0!wmf=3!m=Gubsgj1BVs5n6X?51$Z?6$;DVYM5hql+|{ndUvfRp{Td!kp!C>^N6Kv z<#&{=^-pPNFrN`#fynAu+xr30t-94 ztAHp0LWl1`XTsa)-r;V~J@eU=mt zRoV2u**f}7W#R(fNI7sOG}lEq2Q&x^-(hsBvo03mo-<+_{*1wwyA=%w{$gw;7w16r zy_AKlk!`w`IKSiC-)sPrihKkMB8Y_e=m(Z#_evAs2_S6EqpNzrWugxa1MG_?bmL>+ zx?Q?3&U&F-OziG#4QYNX*pl+eHk^KH-k$W1xQsVuE;+SazMBM%2}=`iY;7p+>8Coh zGMSok*paxql?aqsy<-0C9&^~F=y|v$2osGsKSn0USy!wts|pX|x_pMQ^zf6I{`tq{yP3%2CR*v(L~DV(ymu=~3e zSu-|BOt18M8l(*$eGnouirE5hp5q;H0xa$&KMBiEGuk2jMN2I z7<2m;E}q|&%ENa^_a`!NsYnY(JQ-yso!YCR);{ceiA!ZR@}7RgHj{nyr$cYu?`8pE zM|c-iUnSN<%7?`XzZ*PU5dT>aILbuK>qysdz8Zf(4Ow8R**D@$c(!${W7JTYz_jns zWxuG!=G^0%#upn_`RuU8w5$A7Kc1!O=d@KM-W6shwz&eG^ghAm&UCqHv&#!Fn5MhU zNbGCjpemOvBJ-mkq!(T`g4;rdS$VN;k$P`3$~Iy|<)?6}l3(g#X1WdLnVXE*6N6pK zCV?+^cD_U5*LIdm=r=#8nGFj;8Jqa972ymIm>few#st=^K4#$2&|qW&hsVf$uIx7M zLyCL9rI)i9lhRmjVwKV`J?qU(Zcnk7I`Ws48h%e>G^gVyomx9NBvrg((~x*D4iB-9 znG=~TyAke4zIhu96%eK0-m=i&oXV3~pFs06KVMVY=)KuV8Sl`|Se=Jvm_<41Zugn)^Y0v@v!*!U`k2Fc`ms6FE0=^$A_lo||D~%*2agQ{I-Mag9)ae$WQZ zJ2k%oiW^dWDqf6RR^a1@_y!3025`{-b=D2DX*f8*3M%2>3L)rBV>6`SL@wpwO1e=H z-@7^;-dE=mCJ`HZa*<7Ij6KtE-IlS~1Fok3t(Wr*Yw}#@KqQpYvQ=cs2oPDOjIasBkmTGi zUe`I_`{8`#3Rj*t&wJ;|^WM+z_csg45t?!xl(Ys*((dq*we&+Q`Bev;1e3maYOmK~ zVYG(eB2Tuj;C_{7FCD8?IBK*NhflemU_vjq>}>Qj>x`otchbXBGs9QXC}?iA-bJ~U z%E9nML-}Wgbk(3dgUBac+%&njN6vNe1t(A2_t?bby-ysz%zNnLO?kWO&}&ikL}oaa z|H&XZ`#RQ}DHx7adE@!L&h17M`Qp<>Mz`rEg#pe*rmM_?B@w5Y3Ew>R@b_Nn+SD(f zb6Y0Mi%AeqE|POIe@Qym`pxzLFZE`4^z<19CmaMClc#z(K^OjlUW{Z zsAm(+apRMM^SqW(76m;;`{GV(u#iIYIqZ=9EuqY69Lw+Zao8&OCjG>V%3g=rKNz@} zLs-UL$~v?DKps;=h*d&;zFD8CfT9sNBS&8+AS`A+co!hE-1t+)XKUlAaY$6;bPPzy z4<;rjo5LL)6%09pZaoJf#RK)7vWwn$RoB^~3b)p@CYJ)R=WM_?nSvfJNbI8aR=WOE zqKIn!&6O9*`D#-k703$;+d?~>k|57x@FvJM6PnKd`*Y#Xv0gfa6i4jpZsNmbh8Fk4;@LG%+=W z21UmLIrZu6-%^b!ub8zzyIHqBznIfg7r+W6ujN0T{S`VqAk0dy3K2M{vZ^YGyc=cF zvEX}7?U;&6Y(AXJ(y;dQ$`66oL0b?B<^dqy%~Nvfy1MpZq>P6aN+B_Tfhp5PTT+f( z!q7LL+I`d@x>*Nlmb}i%C0W2x;JiTVuBCO*S{$=g*7ff7rmi756 z25Y>oKGC^N*i^^@i}2{Vq<0MmPzvg_#>0h=LKhpd!g=iP{(Biyn8c+eKW z_!GB-^+I*Pn*2iBxALkKu3^I1Wihx=vu%4s299d)7b_x2%UFn|Y}f!`ho&{HLD3dJLh zmXaF}H^nw!eoxcXWlL~o+eQ@)DDlgUcez-)`wVn5Px*Z?&Iy2FhD(b|K2P1}VV1rP z-JUsCeyCNoBgyS$N4-d=vtr$J%3M2<`P=!&f3d_+%^EzoHPWF_8I%vz4f_6hwYa3l z6ASfoS~FscSC46&aS6#FY`wSE1sNC_4(zV6M|$Vaedx;wphd#TWGy$Dwv z2oY+X#XJ5WRPr45D^zZ{PkZgNVw4^=%4of$yo`OfRoxAUG8#K^aH}l@MC9tIx_k5$ zJsI0phHD#_Msjeu(0^6eZODpy)lQ0!Ss_fKWELjn-s|JEiZ4|Kz)QY}0Hf=SQIy9lCQ zu`D*snnt-qJlhAmlvxIqjDNeIjs;1onZE**#w240)0=NgOuAg8XVFVUV@d(qz^$JtEe8;|Hc^%M@T{?jScDPi+30 zP-(2d9V2Qw-S)d&#)p{E}mY8k;W1GXRZ$vLg{=7h8 zzzQyU;?oMq{Jl`B-z(||zH4}TLNXxWzVefC-1?o}Tz32C{~V6|q~y!cVo zQ7g;SKq+hG*4kx7$v9p^h5Y-l#HAs*u4-1!K*fT8-B$kYO=Gg~c$85MgWa)%*ofZg zN**YE%L)jcMHlyyVruZpBAcgn%51rf;;0HsT-k}g<8^gU+vHLYp24GtR?t2R^{paNIrt7E;uCb1SoQ6PE}7 E0S{AmZU6uP literal 0 HcmV?d00001 diff --git a/img/p2.png b/img/p2.png new file mode 100644 index 0000000000000000000000000000000000000000..83e39d4b2a5813a2b47bfba926049d75376e3589 GIT binary patch literal 33247 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 oSGY${GY