# 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 2](https://hackmd.io/_uploads/B1fHt5WGp.png) ![Vector Width 4](https://hackmd.io/_uploads/HJWl99ZM6.png) ![Vector Width 8](https://hackmd.io/_uploads/H1QQq5WMT.png) ![Vector Width 16](https://hackmd.io/_uploads/H1DIqcZza.png) ### 結論 可以看出當 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. ![](https://hackmd.io/_uploads/rJoq1s-G6.png) 從原來的組語中可以觀察到,AVX2 指令都是每 32bits 的資料 move 到 register,可以推測 AVX2 的 vector width 為 32bits,故將 `__builtin_assume_aligned(*, 16)` 改為 `__builtin_assume_aligned(*, 32)` 後即可將 `vmovups` 變為 `vmovaps`。如下圖: ![](https://hackmd.io/_uploads/By9ReobGp.png) ## 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? ![](https://hackmd.io/_uploads/SkobViZGT.png) 從組語中 move 的資料寬度來看,PP machine 的 bit width 為 16bits。 * What about the bit width of the AVX2 vector registers? ![](https://hackmd.io/_uploads/By9ReobGp.png) 從組語中 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 效率低下。