---
# System prepended metadata

title: HW6 Report
tags: [Parallel Programming 2020]

---

HW6 Report
===
###### tags: `Parallel Programming 2020`
## Q1
我做了以下幾點來最佳化我的程式
### Replace `clCreateImage` with `clCreateBuffer`
使用 `clcreateBuffer` 而不是 `clCreateImage` 可以加快速度，我認爲的原因是因爲 `clcreateBuffer` 依賴這 `cl_image_desc` 這個 object ，這看起來又是對 raw memory bytes 更高一層的包裝，或許就是這樣其效果不如直接處理記憶體

### Tuning work group size
work-group size, a.k.a. local-work size，定義爲一個 work group 擁有多少 work items
如果 work-group size 太小，代表說 work group 的數量就會很多，造成計算資源的浪費；但如果 work-group size 太大，work group 數量很少，導致平行化的效果會不顯著，所以要找到一個適合的 work-group size

在作業中經過多次的實驗，我最後設定 worker-group size 爲 8 x 8 效果爲最好
### Compress filter array
因爲 filter 可能會存在很多 0 的元素，這樣去乘以 image 上面的任何一個 pixel 都會跟沒乘一樣，因此可以先預處理 filter，把非零元素與相對應的座標位置挑出來，再傳進去 kernel function ，這樣就可以少處理幾個 filter 元素

## Q2
### Subtask1
首先我用了 `cudaMalloc` 來爲 `filter`, `inputImage`, `outputImage` 在 GPU 分配記憶體，然後再利用 `cudaMemcpy` 把 filter 和 inputImage 的資料搬過去

接著我設定每個 block 的大小是 8 * 8 ，代表一個 block 有 8 * 8 = 64 個 threads ，然後讓每個 thread 去處理一個 pixel 以算出 filtered 後的 pixel，每個 thread 算完後在用 `cudaMemcpy` 把 `outputImage` 複製回 host

這是我用 `nvprof` 跑 `filter1.csv` 的結果
```
Reading filter data from filter1.csv
Filter width: 7
Reading input image from input.bmp
width = 600
height = 400
==19641== NVPROF is profiling process 19641, command: ./conv

[conv cuda]:            [0.835] ms

Writing output image to output.bmp
==19641== Profiling application: ./conv
==19641== Profiling result:
            Type  Time(%)      Time     Calls       Avg       Min       Max  Name
 GPU activities:   66.16%  2.9864ms        10  298.64us  297.99us  299.01us  convolution(int, float const *, int, int, float const *, float*)
                   17.27%  779.46us        10  77.946us  73.760us  115.17us  [CUDA memcpy DtoH]
                   16.57%  748.07us        20  37.403us     736ns  75.072us  [CUDA memcpy HtoD]
      API calls:   94.25%  158.04ms        30  5.2679ms  2.0740us  157.41ms  cudaMalloc
                    2.21%  3.7138ms        10  371.38us  357.06us  376.51us  cudaDeviceSynchronize
                    1.96%  3.2919ms        30  109.73us  6.7930us  276.61us  cudaMemcpy
                    0.85%  1.4211ms         1  1.4211ms  1.4211ms  1.4211ms  cuDeviceGetName
                    0.36%  595.89us        30  19.863us  2.5760us  75.126us  cudaFree
                    0.17%  286.10us         1  286.10us  286.10us  286.10us  cuDeviceTotalMem
                    0.13%  218.11us        97  2.2480us     296ns  86.428us  cuDeviceGetAttribute
                    0.06%  107.84us        10  10.783us  8.6080us  23.725us  cudaLaunchKernel
                    0.00%  6.1020us         1  6.1020us  6.1020us  6.1020us  cuDeviceGetPCIBusId
                    0.00%  2.2910us         3     763ns     378ns  1.4840us  cuDeviceGetCount
                    0.00%  1.4150us         2     707ns     318ns  1.0970us  cuDeviceGet
                    0.00%     579ns         1     579ns     579ns     579ns  cuDeviceGetUuid
```
### Subtask2
這是以不同 filter type 來做 OpenCL 與 CUDA 的比較圖表
![](https://i.imgur.com/R3sREPR.png)

雖然看起來圖表上 CUDA 與 OpenCL 是有差距的，但是實際測其實上速度並沒有差，有時候測起來 CUDA 快，有時候 OpenCL 快

### Subtask3

因爲同一張顯卡上，memory bandwidth bound等其他硬體限制都不變，並且這次跑得程式相對簡單不複雜，所以看不出什麼明顯差距

並且我其實並沒有特別使用 OpenCL 與 CUDA 的專門的 api function ，我兩個都只是做簡單的 memory copy 等基本操作，所以差距不大其實很合理




