我正在嘗試在L1高速緩存中獲取完整帶寬,以用于Intel處理器上的以下功能float triad(float *x, float *y, float *z, const int n) { float k = 3.14159f; for(int i=0; i<n; i++) { z[i] = x[i] + k*y[i]; }}這是來自STREAM的三合會功能。使用具有此功能的SandyBridge / IvyBridge處理器(與NASM配合使用),可以得到約95%的峰。但是,使用Haswell只能達到峰值的62%,除非我展開循環。如果我解開16次,我將得到92%。我不明白我決定使用NASM在匯編中編寫函數。匯編中的主循環如下所示。.L2: vmovaps ymm1, [rdi+rax] vfmadd231ps ymm1, ymm2, [rsi+rax] vmovaps [rdx+rax], ymm1 add rax, 32 jne .L2結果在Agner Fog的“優化組裝”手冊中的示例12.7-12.11中,他y[i] = y[i] +k*x[i]對Pentium M,Core 2,Sandy Bridge,FMA4和FMA3 所做的幾乎相同(但針對)。我設法自己或多或少地復制了他的代碼(實際上,當他廣播時,他在FMA3示例中有一個小錯誤)。他在表中提供了每個處理器(FMA4和FMA3除外)的指令大小計數,融合操作,執行端口。我嘗試自己為FMA3制作這張桌子。 ports size μops-fused 0 1 2 3 4 5 6 7 vmovaps 5 1 ? ?vfmadd231ps 6 1 ? ? ? ?vmovaps 5 1 1 1add 4 ? ?jne 2 ? ?--------------------------------------------------------------total 22 4 ? ? 1 1 1 0 1 1大小是指指令長度(以字節為單位)。add和jne指令之所以只有半個μop,是因為它們被融合為一個宏操作(不要與仍然使用多個端口的μop融合相混淆),并且只需要端口6和一個μop。 該vfmadd231ps指令可以使用端口0或端口1。我選擇端口0。負載vmovaps可以使用端口2或3。我選擇2并vfmadd231ps使用端口3。為了與Agner Fog的表格保持一致,并且由于我認為說一條可以平均分配到不同端口的指令每次使用的時間都是1/2更為合理,因此我為端口分配了1/2 vmovaps并vmadd231ps可以至。根據該表以及所有Core2處理器每個時鐘周期都可以執行4μop的事實,看來該循環應該在每個時鐘周期都可行,但我還沒有設法獲得它。有人可以向我解釋為什么我不能不展開就無法接近Haswell上此功能的峰值帶寬嗎?如果不展開就可以嗎?如果可以,怎么辦?讓我清楚一點,我實際上是在嘗試為此功能最大化ILP(我不僅想要最大的帶寬),所以這就是我不想展開的原因。
2 回答

瀟湘沐
TA貢獻1816條經驗 獲得超6個贊
“為什么不使用端口7”很容易回答:端口7只能處理“簡單的” AGU操作(基址+立即偏移量,IIRC)。它不能執行基址+寄存器偏移量。您可以通過使用存儲地址作為加載操作數的偏移量來解決此問題。
- 2 回答
- 0 關注
- 527 瀏覽
添加回答
舉報
0/150
提交
取消