contributed by < jack81306
>
jack81306
hw prefetcher 難以處理太複雜的 prefetch,但是 sw prefetch 可以.
hw prefetcher 需要 cache missed 來訓練,但是當遇到 short stream 時便難以發揮,此時 sw prefetch 可以處理.
sw prefetch 可以很好的處理不規則資料.
程式設計者可以自己決定要把資料放到那一層 cache.
可以自行判斷回圈是否到底並不超出範圍 prefetch .
指令數增加
不能動態的改變 prefetch distacne
當 loop 過小時可能難以插入 prefetch instruction.或者是需要改變結構.
指令增加主要是 sw prefatch 的缺點
額外的指令除了 prefetch 指令外,還有處理邊界,或者是計算記憶體位子的指令.
儘管 gemesftdt 的指令增加超過 50 %,整體效能仍然是增加的,因為 prefetch 所帶來的增益超過指令增加的損失.
為了檢測是那種 sw overhead 影響效能最多,分別移除各種造成緩慢的原因進行測試.
移除 cache pollution :造成 cache pollution 的原因有可是過早或錯誤的 prefetch.移除後對實驗並無顯著影響,代表 cache pollution 並非影響效能的主因.
移除 bandwidth consumption :提升的效能十分的小,代表記憶體頻寬仍然夠用.
移除 latency : 提升的效能十分的大!因為 sw prefetch 並沒有完全的把 memory latency 隱藏起來.
移除 redundant prefetch : bwaves 受到蠻大的影響,但是影響其他程式效能小到可以忽略不計.
移除 instruction overhead :對前面實驗增加最多 instruction 的程式並沒有顯著的增加效能,反倒是 libquantum ,再前面實驗並沒有增加顯著的 instruction,卻再這裡提升非常多的效能.
除了 lbm 其他並無明顯的效能增加.
結論: machine configure 對最佳 prefetch distance 的效能並無顯著影響.
大部分的 cpu 可以容忍 l1 cache missed ,因此 hw prefetcher 通常將資料放到後面一點的 cache ,以免汙染 l1 cache.
太多的 l1 cache missed 仍會降低效能.
sw prefetch 可以精準的將資料放進 l1 cache.
實驗使用 T0 cache level hint (也就是將資料放進三層 cache).
T0 效能較高是因為降低 l1 cache miss.
通常 T0 效能會比其他來的高是因為可降低 l1 cache miss.
使用 sw prefetch 幫忙訓練 hw prefetch
結論: 雖然有些會效能會成長,但是一般通常會造成效能嚴重下降.
coverage 太低是造成效率無法提升的原因
因為 gcc 不支援 Fortan intrinsic 所以前面都是使用 icc.並將 intrinsic 再編譯後插入.
移除使用 fortan 的 benchmark.
gcc 插入更多的 sw prefatch 除了 mcf 和 lbm .
gcc 無法處理所有的 cache miss ,效能再 nosw 和 sw 之間.
使用 intel core2 和 Nehalem
使用全部的程式碼而非只有 simpointed 的部份
simpointed ???
除了 milc,gcc,zeusmp 之外,大部分摹擬的程式和整份程式有差不多的 prefetch 指令.
模擬系統的配置接近 core2
有幾個程式會再真實系統裡效能下降.
再 positive group 裡的程式效能都有上升.
Nehalem 的 hw prefetch 的效能大於 core2 ,而且,由於 Nehalem 有 mutiple cache level 導致 sw prefetch 的效能增加量下降.
PGO 的效能位在 SW prefetch 和 base 之間.
PGO 效能的優化不只是 SW prefetch ,還有其他優化方式.
PGO 的指令數比 BASE 還少.
HW prefetch 的缺點是難以處理 short streams.
解決辦法 : ASD HW prefetcher (仍未實作,僅為概念)
儘管 ASD 在 short stream 可以比一般的 HW prefetch 還快,但是仍然比 sw prefetch 還要慢.
到底什麼是 asd prefetcher 咧?
CDP 通常用來處理不規則的資料結構
雖然 CDP 有提升這些不規則的資料結構,但是仍然無法超越 SW prefetch (78% 效能提升) 的增益.
看不太懂 CDP 的意思
什麼是 prologue/epilogue transformations ?
sw prefetch 對某些 regular access pattern 比 hw prefetch 更有效率,如 short stream.
就算 hw configure 對 prefetch distance 不敏感,仍要小心設定.
儘管 ooo cpu 對 la cache missed 容忍率高,但是當l1 cache missed 超過 20% 時 ,可以藉由 prefetch 降低 l1 cache missed 進行優化.
無用的 prefetch instruction 對效能不太造成影響.
要小心的對 hw prefetch 訓練,否則容易造成效能降低.
17,142,240 cache-misses ( +- 0.48% )
1,448,569,562 instructions # 1.10 insn per cycle ( +- 0.00% )
1,316,109,257 cycles ( +- 1.23% )
71,907 L1-icache-load-misses ( +- 4.39% )
16,470,337 LLC-load-misses ( +- 0.07% )
0.424526315 seconds time elapsed ( +- 1.25% )
Performance counter stats for './sse' (5 runs):
4,874,075 cache-misses ( +- 1.74% )
1,236,561,529 instructions # 1.35 insn per cycle ( +- 0.00% )
917,252,607 cycles ( +- 1.34% )
71,434 L1-icache-load-misses ( +- 10.83% )
4,179,530 LLC-load-misses ( +- 0.17% )
0.300347588 seconds time elapsed ( +- 1.61% )
4,678,095 cache-misses ( +- 0.95% )
1,282,795,897 instructions # 1.79 insn per cycle ( +- 0.01% )
715,914,080 cycles ( +- 1.10% )
68,664 L1-icache-load-misses ( +- 9.53% )
4,188,387 LLC-load-misses ( +- 0.21% )
0.232151802 seconds time elapsed ( +- 1.46% )
可以從這結果中觀察到,因為 sse 和 sse_prefetch 的 cahce miss 和 instruction 都比 naive 少,因此會使用 sse 的結果會比 naive 快上許多.
但是,有疑問的是,sse_prefetch 和 sse 的測試結果差不多,可是時間卻差了將近 0.07 秒.
從 kaizsv的共筆 中得知,perf 中的 event 會隨著處理器架構不同而不同,因此要去 Intel® 64 and IA-32 Architectures Developer’s Manual: Vol. 3B 中察看自己的處理器以及想要觀察的事件號碼.
以下是想要觀察的事件
MEM_LOAD_UOPS_RETIRED.L1_MISS:Retired load uops missed L1 cache as data sources(D1H,08H)
MEM_LOAD_UOPS_RETIRED.L2_MISS:Retired load uops missed L2. Unknown data source excluded.(D1H,10H)
MEM_LOAD_UOPS_RETIRED.L3_MISS:Retired load uops missed L3. Excludes unknown data source (D1H,20H)
不太明白 UOPS 的意義,但就其他的敘述應該可以判斷這些指令是在偵測 L1 L2 L3 cache missed 的?
Performance counter stats for './naive' (5 runs):
16,849,839 cache-misses ( +- 0.19% ) (25.47%)
1,446,964,134 instructions # 1.12 insn per cycle ( +- 1.45% ) (38.36%)
1,296,977,715 cycles ( +- 0.89% ) (50.89%)
74,503 L1-icache-load-misses ( +- 3.57% ) (50.75%)
16,368,952 LLC-load-misses ( +- 0.84% ) (63.21%)
16,407,896 r08d1 ( +- 0.79% ) (60.06%)
15,712,873 r10d1 ( +- 1.90% ) (24.53%)
15,386,702 r20d1 ( +- 1.54% ) (24.90%)
Performance counter stats for './sse' (5 runs):
4,433,999 cache-misses ( +- 3.76% ) (24.92%)
1,241,345,259 instructions # 1.43 insn per cycle ( +- 1.55% ) (37.90%)
870,806,366 cycles ( +- 1.70% ) (50.51%)
72,335 L1-icache-load-misses ( +- 5.73% ) (51.22%)
4,036,982 LLC-load-misses ( +- 1.85% ) (64.11%)
4,226,923 r08d1 ( +- 1.90% ) (59.56%)
3,997,999 r10d1 ( +- 2.79% ) (24.59%)
3,882,275 r20d1 ( +- 2.22% ) (24.57%)
0.290662977 seconds time elapsed ( +- 1.37% )
4,855,312 cache-misses ( +- 2.83% ) (25.69%)
1,225,977,099 instructions # 1.70 insn per cycle ( +- 1.31% ) (38.77%)
719,123,446 cycles ( +- 0.61% ) (51.44%)
72,674 L1-icache-load-misses ( +- 5.77% ) (51.74%)
4,500,073 LLC-load-misses ( +- 4.51% ) (64.06%)
3,587,506 r08d1 ( +- 2.02% ) (58.10%)
88,901 r10d1 ( +- 28.17% ) (24.16%)
68,986 r20d1 ( +- 56.87% ) (25.29%)
測試結果中的 r08d1,r10d1,r20d1 分別是 L1 L2 L3 cache misses 的數量.
從增加了判斷 cache miss 在哪一層發生的事件後,可以很明顯的看出來說 sse_prefetch 多半只有發生 L1 cache miss 且大部份都在 L2 cache hit,而 sse 則是發生了許多 L1 L2 L3 cache miss,這應該就是兩者速度差異的原因了
struct timespec start, end;
int *src = (int *) malloc(sizeof(int) * TEST_W * TEST_H);
int *out = (int *) malloc(sizeof(int) * TEST_W * TEST_H);
srand(time(NULL));
for (int y = 0; y < TEST_H; y++)
for (int x = 0; x < TEST_W; x++)
*(src + y * TEST_W + x) = rand();
clock_gettime(CLOCK_REALTIME, &start);
transpose(src, out, TEST_W, TEST_H);
clock_gettime(CLOCK_REALTIME, &end);
printf("naive: \t\t %ld us\n", diff_in_us(start, end));
free(src);
free(out);
因為 avx 使用的是 256bit register 因此,對於 int 來說,變成一次要處理 8x8 的矩陣.
會使用的指令
再我第一次寫程式的時候,我原本以為會有 _mm256_unpacklo_epi128 這條指令讓我來使用,後來發現居然沒有這條指令!!
於是後來到了前幾屆的 共筆 中,找到了 _mm256_permute2x128_si256 這條指令.
這條指令的特別之處是可以藉由第3個參數,來決定 src1 和 src2 的前128 bit 或後 128 bit擺放順序.這樣的化就可以完成轉置矩陣的最後一個步驟.
Performance counter stats for './avx':
4,150,618 cache-misses (34.16%)
1,137,217,451 instructions # 1.67 insn per cycle (50.77%)
680,029,146 cycles (50.77%)
951,759 r08d1 (49.98%)
1,084,546 r10d1 (33.36%)
1,197,231 r20d1 (33.12%)
為何會有這樣的結果!!???