---
# System prepended metadata

title: part1

---

# part1

# Q1
測試向量寬度從 2、4、8 到 16
![image](https://hackmd.io/_uploads/r18uJ150A.png)
![image](https://hackmd.io/_uploads/SJ95J1500.png)
![image](https://hackmd.io/_uploads/HkDTkycR0.png)
![image](https://hackmd.io/_uploads/S1jBkJ90R.png)

隨著VECTOR_WIDTH從 2、4、8 變為 16，向量利用率通常會降低
原因如下:
* 數據對齊和餘數：

如果資料集大小無法被 VECTOR_WIDTH 整除，則每個批次中將存在無法利用向量運算單元（餘數）的資料。
例如：當 VECTOR_WIDTH 為 2 時，對於較小的資料集，充分利用向量運算單元的機會較高。
隨著 VECTOR_WIDTH 增加（4、8、16），未使用運算單元的可能性也會增加，特別是在工作負載不完全適合 VECTOR_WIDTH 的情況下。這會導致向量利用率降低，因為一些向量運算單元並沒有完整使用到。

* 掩蔽開銷：

為了處理不完全適合 VECTOR_WIDTH 的數據，遮罩操作僅用於在活動通道上進行計算。隨著 VECTOR_WIDTH 的增加，屏蔽的cost會變得更加明顯(也就是0會更多)，從而降低有效利用率，因為更多的通道被屏蔽。

# Q2-1
修改後的程式碼,經查詢AX2是32bytes,所以將原本16的地方改為32
```c++
#include "test.h"

void test1(float *__restrict a, float *__restrict b, float *__restrict c, int N) {
  __builtin_assume(N == 1024);
  a = (float *)__builtin_assume_aligned(a, 32);
  b = (float *)__builtin_assume_aligned(b, 32);
  c = (float *)__builtin_assume_aligned(c, 32);

  for (int i=0; i<I; i++) {
    for (int j=0; j<N; j++) {
      c[j] = a[j] + b[j];
    }
  }
}
```
得到
```
        vmovaps(%rdi,%rcx,4), %ymm0
	vmovaps	32(%rdi,%rcx,4), %ymm1
	vmovaps	64(%rdi,%rcx,4), %ymm2
	vmovaps	96(%rdi,%rcx,4), %ymm3
	vaddps	(%rsi,%rcx,4), %ymm0, %ymm0
	vaddps	32(%rsi,%rcx,4), %ymm1, %ymm1
	vaddps	64(%rsi,%rcx,4), %ymm2, %ymm2
	vaddps	96(%rsi,%rcx,4), %ymm3, %ymm3
	vmovaps	%ymm0, (%rdx,%rcx,4)
	vmovaps	%ymm1, 32(%rdx,%rcx,4)
	vmovaps	%ymm2, 64(%rdx,%rcx,4)
	vmovaps	%ymm3, 96(%rdx,%rcx,4)
	addq	$32, %rcx
	cmpq	$1024, %rcx                     # imm = 0x400
```

# Q2-2

取10次平均

|      | case 1  |  case 2  |  case 3  |  I   |    N    |
| ---- | ------- |:--------:|:--------:|:----:|:-------:|
| time | 2.97sec | 0.737sec | 0.368sec | 1024 | 8388608 |

經測試可以得知, vectorized 比unvectorized快了接近4倍,而使用AVX2又比unvectorized快了8倍,又一個float有32bit,推論default vector registers on the PP machines有128bit,AVX2為256bit

# Q2-3
第一版
```cpp=
c[j] = a[j];
if (b[j] > a[j])
  c[j] = b[j];
```


第二版
```cpp=
if (b[j] > a[j]) 
  c[j] = b[j];
else 
  c[j] = a[j];
```
可以發現在第一版中是先對C[j]覆值,在檢查是否要再更改,然而不一定每次都會更改,造成平行化不易,然而第二版則會先平行化比較完,再回寫,避免了無條件的初始覆值,所以第二版會相較第一版快很多,而可以從這個例子發現,雖然程式碼的邏輯都一樣,但寫法的不同會造成再compile編譯時產生非常大的差異
