# NYCU PP-f23 Programming Assignment I: SIMD
###### tags: `NYCU Parallel Programming f23`
[TOC]
## Q1-1: Does the vector utilization increase, decrease or stay the same as VECTOR_WIDTH changes? Why?
### 結果圖




### 結論
可以看出當 vector width 越大,vector utilization 會越小。
### 原因
當 vector width 越大,越有可能出現閒置的運算單元 (mask 出現 0 機會越高)。比如以這次作業的 `clampedExpVector()` 來說,單某些數字的 exponents 已經乘完了,但可能還有其他數字還沒乘完,於是乘完的會跟沒乘完的一起進入下一個 while loop,導致 vector 利用率降低。
而這種情況很明顯在 vector width 大時會特別嚴重,因為要等待所以數字乘完的 loops 會越多,導致 mask 中出現大量的 0,最後統計下來 vector utilization 就變比較低。
## Q2-1: Fix the code to make sure it uses aligned moves for the best performance.

從原來的組語中可以觀察到,AVX2 指令都是每 32bits 的資料 move 到 register,可以推測 AVX2 的 vector width 為 32bits,故將 `__builtin_assume_aligned(*, 16)` 改為 `__builtin_assume_aligned(*, 32)` 後即可將 `vmovups` 變為 `vmovaps`。如下圖:

## 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?
* What speedup does the vectorized code achieve over the unvectorized code?
* `Unvectorized`: 8.32s
* `Vectorized`: 2.64s (約為 unvectorized 3x 快)
* `AVX2`: 1.41s (約為 vectorized 2x 快,unvectorized 6x 快)
* What can you infer about the bit width of the default vector registers on the PP machines?

從組語中 move 的資料寬度來看,PP machine 的 bit width 為 16bits。
* What about the bit width of the AVX2 vector registers?

從組語中 move 的資料寬度來看,AVX2 的 bit width 為 32bits。
## Q2-3: Provide a theory for why the compiler is generating dramatically different assembly.
* Case1:
```cpp
c[j] = a[j];
if (b[j] > a[j])
c[j] = b[j];
```
* Case2:
```cpp
if (b[j] > a[j])
c[j] = b[j];
else
c[j] = a[j];
```
從 `MAXPS` 在 document 裡的 psudo code 來看:
```
MAX(SRC1, SRC2)
{
IF ((SRC1 = 0.0) and (SRC2 = 0.0)) THEN DEST := SRC2;
ELSE IF (SRC1 = NaN) THEN DEST := SRC2; FI;
ELSE IF (SRC2 = NaN) THEN DEST := SRC2; FI;
ELSE IF (SRC1 > SRC2) THEN DEST := SRC1;
ELSE DEST := SRC2;
FI;
}
```
`MAXPS` 會回傳較大的變數 (DEST) 進 register,因此 CPU 可以直接將回傳向量直接賦值給 c,因此 case2 直接將 a、b 做比較可以很容易用 `MAXPS` 達到上面說的效果。
而 case1 若要用 vectorized 的概念來思考的話,就變成先將 a 賦值給了 c,再來看 c 中那些 elements 需要被更新,而有些 elements 可能不用更新,有些可能要,但所有 elements 又必須一起處理。這就形成了與 Q1-1 類似的情況,可能會有許多無需運算的 elements 被 move,造成 utilization 效率低下。