---
# System prepended metadata

title: 平行程式設計 作業一

---

# 平行程式設計 作業一

## Part1

### Q1

測試VECTOR_WIDTH 2 4 8 16的結果

![](https://i.imgur.com/ieFJGPE.jpg)

![](https://i.imgur.com/VphsjcA.jpg)

![](https://i.imgur.com/9XgXgP7.jpg)

![](https://i.imgur.com/Bai4qCG.jpg)

logger.cpp 印出，如: 
printf("Vector Utilization:        %.1f%%\n", (double)stats.utilized_lane / stats.total_lane * 100);

* Vector Utilization是一個非常重要的指標，它代表了向量運算單元在程式執行期間的使用情況。在程式碼中，透過使用printf()函式將Vector Utilization的值印出，可以方便地觀察到程式的運行情況。
* 依據數值資料顯示 VECTOR_WIDTH 增加時，非活動向量通道也會增加。原因是其他無須變動的參數，將等待最後一組參數進行n次迭代。
* 得知在 mask 中， 當VECTOR_WIDTH提高，不是向量相關的數量也會提高，造成向量使用降低。觀察程式運行時，當指數提高後，需要進行多次迭代才能運算出結果，並且降低向量使用降低，效能極差。如果指數運算時，想方法如何優化提高向量使用率提高。如，減少迭代的次數。並且使用遞迴的方式來指數運算，可減少向量使用率的數量，更能提升程式碼的效能。

### Q2-1: Fix the code to make sure it uses aligned moves for the best performance.

經由更改程式碼，如:
```c=1
a = (float *)__builtin_assume_aligned(a, 32);
b = (float *)__builtin_assume_aligned(b, 32);
c = (float *)__builtin_assume_aligned(c, 32);
int i=0;
int j=0;
while(i<I;) {
    while(j<N;) {
      c[j] = a[j] + b[j];
       j++;
    }
    i++;
}
```

因此得到，如下
>       vmovups (%rbx,%rcx,4), %ymm0
>       vmovups 32(%rbx,%rcx,4), %ymm1
>       vmovups 64(%rbx,%rcx,4), %ymm2
>       vmovups 96(%rbx,%rcx,4), %ymm3
>       vaddps  (%r15,%rcx,4), %ymm0, %ymm0
>       vaddps  32(%r15,%rcx,4), %ymm1, %ymm1
>       vaddps  64(%r15,%rcx,4), %ymm2, %ymm2
>       vaddps  96(%r15,%rcx,4), %ymm3, %ymm3
>       vmovups %ymm0, (%r14,%rcx,4)
>       vmovups %ymm1, 32(%r14,%rcx,4)
>       vmovups %ymm2, 64(%r14,%rcx,4)
>       vmovups %ymm3, 96(%r14,%rcx,4)
>       addq    $32, %rcx

得知AVX2引入了位的256ymm，同時處理256位的數據。使用AVX2指令集時，可以處理的資料寬度是32 bytes。

### Q2-2: What speedup does the vectorized code achieve over the unvectorized code? What additional speedup does using -mavx2 give (AVX2=1 in the Makefile)? You may wish to run this experiment several times and take median elapsed times; you can report answers to the nearest 100% (e.g., 2×, 3×, etc). What can you infer about the bit width of the default vector registers on the PP machines? What about the bit width of the AVX2 vector registers.


執行不同case各100次求得的平均執行時間。
|       | case1 | case2 | case3 |
| ----- | ----- | ----- | ----- |
| test1 | 8.31  |2.6    |   1.4 |

* 以上經由測試，vectorized比unvectorized快
學生上網查，是CPU周期內同時處理多個數據。並且能提高CPU效能，藉由向量化使得CPU
在相同的時間內，處理更多的數據，加快計算速度。
* AVX2比unvectorized快
學生上網查，透過AVX2是CPU的指令集，且增加更多的向量化指令。 從定義得知，相同CPU周期內處理更多的數據，提高CPU的效能。因此AVX2 執行向量化操作通常會比unvectorized更有效率。

經由Q1得知，mov add 等相關指令集，取出的資料時間寬度是32位元組，且需對齊，所以推論出ymm register，需要的寬度是32位元組。

以上用相同的方法跑100次，test2()和test3()，分別為

test2()時間為11.3541秒
test3()時間為21.8868秒

以2.6章節，修改後

test2()時間為2.2610秒
test3()時間為5.7283秒

### Q2-3: Provide a theory for why the compiler is generating dramatically different assembly.

針對code，如:
:::info

第一個

```c=1
c[j] = a[j];
if (b[j] > a[j])
    c[j] = b[j];
```

第二個

```c=1
if (b[j] > a[j]) 
    c[j] = b[j];
else 
    c[j] = a[j];
```
:::
比較兩者code差異性，發現出第一個方法的a[j]會全放進c[j]，再去做比較。且並非每次都會回寫，造成平行化困難。相對第二個方法會先把全部比較完，再回寫，使得a[j]與b[j]可以平行化。且效能比第一個方法快多，藉由此兩個方法，可以得知先後判斷能造成compiler處理方式不同，故影響平行化的效能。