# 2017q1 Homework3 (software-pipelining)
contributed by < `0xff07` >
作業要求在 [這裡](https://hackmd.io/s/rks62p1sl#)
作業區 [這裡](https://hackmd.io/IYUxBMGYEZxBaArAJnAM3gFgJwDZfzC4Dsw8AHJgEYzDTTIDGVuQA===#)
code 在 [這裡](https://github.com/0xff07/prefetcher)
# 論文
首先來看 [paper](http://www.cc.gatech.edu/~hyesoon/lee_taco12.pdf):
一開始就一堆 STR 、 GHB 什麼的,所以只好先找一下其他資料壓壓驚。結果找到[這篇](http://pages.saclay.inria.fr/olivier.temam/files/eval/Tem96.pdf)文章。前面提到了一些為何要 prefetch 的理由。 Prefetch 想要處理的問題跟 Cache 一樣,都是要降低 CPU 與記憶體日益擴大的存取時間差異。
處理這個問題有兩個策略:多層用幾層 Cache,或是 Prefetching. 前者已經在很多處理器上出現,比如說有 L1 ~ L3 的 Cache。但 Prefetch 根據論文表示是相對稀少的。然而,Prefetching 在一些狀況下,能夠提升的效能會比多層 cache 來的好。比如說有一個 `char a[64][64]`的陣列,要把這個陣列每列的前 3 個元素 +1。不加以做任何改良的話,很容易有 cache miss. 而如果使用 Prefetching 的策略,則很容易預測記憶體的存取模式大致是:
```
+1, +1, +1, +62, +1, +1, +1, +62, +1, +1, +1, +62 ...
```
進而增加 Cache 的使用效率。
## 一些基本的 prefetch 機制
* Stride Prefetch :
stride 有「跨大步」的意思(像跨過水溝哪種)。 這裡也是類似的意思。
當 cache miss 發生時,prefetch 距離這個位址 +s 單位處的資料,其中 s 是某個數。
可以更近一步把距離這個位址 +s, +2s, +3s ... + ds 的資料都 Prefetch 起來,而這個 d 叫做「 degree of prefetch 」,越大的 d 表示越「積極」(原文是 aggressive, 不過講成「兇狠」聽起來有點怪)的 Prefetch 策略。
* Markov Prefetch :
當 cache miss 發生在某位址時,紀錄所有在這個位址之後的下一個 cache miss 位址。比如說如果:
```
A, B, C, D, C, A, C, D, B, C, A
```
```
A : 找出所有 A 之後的下一個 Cache miss 位址:
A, "B", C, D, C, A, "C", D, B, C, A
-> A : B, C
B : 找出所有 B 之後的下一個 Cache miss 位址:
A, B, "C", D, C, A, C, D, B, "C", A
-> B : C
C : 找出所有 C 之後下一個 Cache miss 位址:
A, B, C, "D", C, "A", C, "D", B, C, "A"
-> C : D, A
D : 找出所有 D 之後下一個 Cache miss 位址:
A, B, C, D, "C", A, C, D, "B", C, A
->D : C, B
```
依照最後出現的優先的順序,建立以下的表:

以這種方式作為 prefetch 的依據。
另外可以注意的是,這種實作方式看起來跟 adjacent list 實作有向圖的方式類似。事實上這個表可以用一個有向圖表示:

邊上的權重表示往這個邊移動的機率。這種機制跟高中學的馬可夫鍊很像,所以就叫做 Markov Prefetch
* Distant Prefetch :
和 Markov Prefetch 的機制類似,但 Markov Prefetch 是「直接記下位址」,Distant Prefetch 是記「距離上個 Cache Miss 發生的位址有多遠」。比如說以上述 `char a[64][64]` 陣列的例子,存取位址的模式大概是:
```
Address : 0 1 2 64 65 66 128 129 130
```
可以發現如果用 Markov Prefetch 的策略很發揮作用,因為位址幾乎不重複。但是如果記下間隔的差值:
```
Distant : 1, 1, 62, 1, 1, 1, 62, 1, 1, 1, 62...
```
並建立類似 Markov Prefetch 的表:
```
1 : 1, 62
62 : 1
```
如果發現位址跳了 1, 就 prefetch 間隔 1 或是間隔 62 的資料; 如果發現位址跳了 62, 就 prefetch 間隔 1 的資料。
一樣可以畫成有向圖。在此略。
Markov Prefetch 與 Distant Prefetch 屬於一種叫「Table Prefetch」的分類,都是在建表,而且可以畫成有向圖。缺點是這個表可能會存了很久以前發生,但是將來不會再發生的 Cache Miss 紀錄,進而讓表紀錄很多多餘的資料,或是 Prefetch 很多不必要的資訊。
* GHB : global history buffer
使用一個 Table 與一個 FIFO 的 Linked-List (叫做 global history buffer):

GHB 會暫存一段 Cache Miss 的歷史紀錄,並且隨著新的 Cache Miss 出現,把舊的歷史紀錄刪除。
這樣的好處是可以實作以上幾種 Prefetch 策略。比如說上圖是個用 GHB 實做 Markov Prefetch 的方法。
不像上面的 Table Prefetch ,這裡的 Global History Buffer 跟 Index Table 的大小可以自由調整,Table Method 並沒有辦法預期每一列當中會有多少個元素,所以有可能長非常大。
除了可以實作上述幾種基本的 Prefetch, GHB 還可以實施更多元的 Prefetch。
以上講到的 Prefetch 策略及圖片都是來自 [這篇](http://www.eecg.toronto.edu/~steffan/carg/readings/ghb.pdf)論文。
* [STR](https://en.wikipedia.org/wiki/Cache_prefetching#Stream_buffers) : streaming prefeching

就是 Cache Miss 發生時,把發生 Cache Miss 位置附近連續位置的資料放到 stream buffer 裡面。
另外 stream 有的時候的的意思是「一連串的記憶體存取動作」,這時候就不一定是相鄰的位置的資料。
## 有用的 Prefetch
Prefetch 之所以叫 "Pre"-fetch,就是要在用到某資料前,就取出來。如果需要用的時後資料還沒到,那麼一點用都沒有。除了時間之外,如果重複取了已經在 Cache 裡面的資料,那麼一樣沒有用。更不用提取出錯誤的資料了。文中將 Prefetch 的成功與否,分類為下面這幾種:

其中:
1. timely : 時間剛好
2. Late/Early : 太晚或太早。太晚就是來不及,太早就是太早拿出來,結果要用之前,Cache 相應的位置已經被換成其他資料。
3. Redundant : 重複取
4. Incorrect : 取到~~廢物~~用不到的東西
因為送出 Prefetch 的要求,到實際拿到資料需要一段時間 (這個時間用 $l$ 表示)。並假定每經過 $s$ 的時間會存取這個資料結構一次(可以想成有個迴圈正在處逐一遍歷某個陣列),那麼,為了要可以及時取出需要的資料,每次 prefetch 都要取出:
$$當下往後 D \geq \bigg{\lceil} \frac {l}{s} \bigg{\rceil} 次迴圈後,會取出的資料$$
這樣才可以來的及在需要使用時,有正確的資料可以使用。不然每次 prefetch 都會來不及趕上。
這個 $D$ 又叫作「Prefetch Distance」,這個距離的大小會因為記憶底的存取速度,以及迴圈大小有關。
雖然說 $D$ 不能太小,但是也不能太大。如果太大,有可能 使Prefetch 到很久之後才會用到的資料,等到要用時,相應位置的 Cache 已經被換成其他資料了。這時候就會產生 Cache Miss。
>> $s$ 不一定是針對迴圈,$s$ 大概的意思就是「再過多久會需要用到這個資料」。
在論文的實驗中,有關於 Prefetch Distance 的相關數據:

如果會受到影響的話,通常趨勢都是 prefetch distance 太小不行,太大不行,只有一個中間區段會有作用。
但是表中也可以發現一半以上(7 個)的 testbench 對這件事並不敏感(真是 QQ)。
## Hardware vs. Software Prefetch
上述各種 Prefetch 機制,可以在軟體上實作,也可以設計成硬體。分別說明如下:
### Hardware Prefetching (HW)
直接實作 Prefetch 的硬體。
缺點是只能使用簡單而機械化的機制,較難使用複雜的 Prefetch 機制,不然就是需要複雜的硬體。
~~後面會一直打臉它。~~
### Software Prefecthing (SW)
在程式碼中插入一些提示,然後~~祈禱~~編譯器在編譯時,插入 Prefetch 相關的指令。以 Intel 為例,Intel 當中的 SSE SIMD 指令集中有提供 Prefetch 相關的指令:
```C
#include <mmintrinsics.h>
void _mm_prefetch(char * p , int i );
```
其中 `p` 是資料所在的位址,`i` 是要載入哪一層的 Cache, 使用以下的巨集指定:
```
_MM_HINT_T0 : 載入 L1 Cache
_MM_HINT_T1 : 載入 L2 Cache
_MM_HINT_T2 : 載入 L3 Cache
_MM_HINT_NTA : 這塊資料暫時不會用到
```
[這裡](http://stackoverflow.com/questions/37070/what-is-the-meaning-of-non-temporal-memory-accesses-in-x86)有關於 NTA 的解釋。大意是:如果資料在 Cache 中,而且有被污染,為了維持一致性,所以會「修改 Cache 資料 -> 回寫記憶體」。但是如果知道某資料將來不會用到,那大可省略對 Cache 中資料修改的動作, 直接把改變寫入記憶體中就好。
更多資訊可以查閱[MSDN](https://msdn.microsoft.com/zh-tw/library/cyxt4d09(v=vs.100).aspx)上的文件。
### 優點
這種 Prefetch 的好處,大致上來說是硬體只能做相對機械化的 prefetch 機制,而軟體上的 prefetch 能夠「比硬體有彈性」。論文中提到的好處有:
#### 1. 避開硬體限制
以 stream prefetcher 為例,硬體上能夠接受的 stream 的道數是有限的,而有些情況 (比如論文中的 lbm )確實會需要比硬體上最大數目還要多的 stream. 然而軟體上指令的安插可以避開這一點。
(硬體打臉 X1)
#### 2. 多而短的 stream
這裡的 stream 是指一連串記憶體存取的動作。
一樣是以 stream prefetch 為例。就硬體來說,stream 要夠長才能掌握 cache miss 的模式,才能確認是否真的需要 prefetch。然而,如果 stream 太短,硬體則沒有辦法有效的確認是否需要 prefetch,因此沒辦法做出有效的 prefetch。
>> If the length of stream is extremely short, there will not be enough cache misses to train a hardware prefetcher and load useful cache blocks
但是軟體上的 prefetch 來說,可以自由安插指令,所以可以針對狀況直接在程式中插入 prefetch 指令,因此這方面比硬體有彈性。
論文中提到有新的硬體設計( ASD )能夠處理短小的 stream,而在只有硬體的狀況下,這確實能夠處理:

主要是看 `milc` 那個,因為那主要都是短小的 stream。可以發現如過只有硬體的話,ASD 確實可以提昇效能。但是如果是加在已經有軟體 prefetch 上的實作上的話:

可以發現再已經有軟體層面的 prefetch 下,加上 ADS 後 `milc` 幾乎沒有效能上的提升。如果機器本身 prefetcher 相關硬體的話,ASD 對整體的提昇效應幾乎都在 2% 以內。
(硬體打臉 X2)
#### 3. 不規則的記憶體存取
比如說Linked-List, 因為下一個節點的記憶體位址並不確定,所以硬體很難有效的預測。但是程式上來說,可以插入 prefetch `node->next->next` 之類的指令。
(硬體打臉 X3)
#### 4. 可以指定放到哪一層 Cache
引用論文的原文:
>>Hardware prefetchers in today’s high-performance proces- sors such as Nehalem [Intel 2009] and Barcelona [AMD] place the data in the lower- level cache of the requesting core, whereas most software prefetched data is placed directly into the L1 cache.
通常硬體上的 Prefetch 會放在比較低階層的 Cache 上,而軟體上的如前面的 SSE SIMD 指令,可以指定放在不同層的 Cache 中。
(硬體打臉 X4)
#### 5. 避免越界
以 stride prefetch 為例,會機械式把 +s, +2s, +3s ... + ds 的資料通通 prefetch。但是以存取陣列為例,這些資料當中可能有些已經越界,最後取到無用的資料。然而硬體很難偵測到越界的情況。然而軟體上來說,prefetch 哪些資料可以由寫程式的人決定。
(硬體打臉 X5)
### 缺點
#### Prefetch 需要額外的指令
這裡有關於存取不同資料結構時,可能需要的 prefetch 機制:

而這些資料的存取大致上有兩種模式:
1. 直接:就是直接作 `*(a + i)`
比如說要 prefetch `a[i]` 的資料,概念上要增加如下的指令:
```
1. 計算 a[i] 位址
2. prefetch
```
2. 間接:比如說 prefetch `a[b[i]]`,因為需要先計算 `b[i]` ,才可以知道 `a[i]`, 所以叫做 indirect。這時後需要更多的指令:
```
1. 計算 b[i] 位址
2. load b[i]
3. 計算 a[b[i]] 位址
4. prefetch a[b[i]]
```
如果是如 hash 之類的話,就可能需要更多道指令。
但是,不管是哪種方式,都會需要額外的指令。不過出乎意料的是,有的狀況即使指令增加,prefetch 仍然可以帶來效應。
#### 不同硬體的 Prefetching Distance 可能不同
前面提到 pregetching distance 跟記憶體搬資料到 Cache 的時間,以及 Cache 大小有關。而這些可能隨著不同硬體而有所變化,因而最佳的 prefetching distance 也有所不同,但是 Prefetching distance 是寫死在程式裡的,這是難以調整的地方。
另外,針對擁有不同「積極」程度的硬體 prefetcher ,討論使用最佳的 prefetch distance 可以比普通積極的硬體增進多少效能
分別找出不同機器最佳的 prefetch distance 之後,再比較各自使用這些最佳的 prefetch distance 之下,效能增進的差異:
![Uploading file..._3xcl3thpa]()
得到的結論是:除了某些特殊情況,不然一般而言,就算硬體的 prefetch 機制有積極或不積極的取向,使得 prefetch distance 有所不同,這個不同也不會影響太大。
#### 可能需要改寫程式
前面提到另外一個影響 prefetching distance 大小的因素是「經過多久會存取到該資料結構一次」。如果迴圈每次執行的時間很短,就需要改寫程式,比如說把 loop-splitting 重新合併。
## Hardware + Software
兩個一起混合使用。
#### 讓軟硬體分別處理不同特性的 stream
前面提到 Hardware Prefetcher 比較難處理不規則,或是短小的 Stream, 所以可以把比較規則的 stream 給硬體處理,而由軟體上的 prefetcher 來處理不規則的 stream
#### 用 software 訓練 hardware
這個效應有好有壞。
因為硬體需要有一些規律才可以判定是否需要 prefetch, 但是軟體上的 prefetch 是預先指定要 prefetch 哪些資料,所以如果先用軟體上的 prefetch 來暗示硬體接下來要 prefetch 哪些資料的話,有機會讓硬體作更準確的 prefetch。
但是也有可能因為軟體只作部分的 prefetch, 而讓硬體「誤會」了接下來的資料存取規律,進而無法做出正確的 prefetch。另外,如果軟體上的 prefetch 取了錯誤的資料,也會把硬體教壞。
事實上,在論文的實驗當中,兩個一起用不是效能不會提升太多,就是讓效能變慢:

(硬體打臉 X5)
## 額外的議題
### Prefetch Coverage
大致上來說,就是「減少的 Cache Miss」與「所有 L2 Cache Miss」的比例。
實驗中首先看看只有硬體 Prefetcher 的 Coverage :

接著是硬體 + 軟體上的 Prefetch。底下不同的符號,表示搭配不同的硬體 Prefetcher:

可以發現大部分狀況下軟體大大大大增加了 Prefetcher Coverage
### 用 gcc 編譯
不指定其他 flag 的狀況下, gcc 會插入一些 prefetch, 但是 icc 沒指定就是完全不做。這裡讓 gcc 做 prefetch ,看效果如何。

NOSW 是叫 gcc 不要 prefetch,BASE 是讓 gcc 預設的 prefetch
gcc 大致夾在 SW (軟體上的優化)跟 BASE(什麼都不做)中間。結論是 gcc 可以掌握一些 prefetch (裡面的 NOSW 比上 BASE,BASE 比較好),但還是比不上直接在軟體層面做優化。
## 針對不同 testbench 的實驗
### Hardware 優於 Software 的
這裡的共同特徵是:
* irregular memory access
* `GemsFDTD`:有很多 indirect memroy access.
* `mcf` : 程式碼有 prefetch 應該是下一個迴圈要用的東西(那個 +8),可以發現下面有用到 +1
* 硬體也做得到,但軟體可以指定把東西塞在 L1 Cache : 大部分都是跟 3D 有關的運算。雖然硬體也可以預測的很好,但是硬體只會把他們塞在低層的 Cache 中
* `lbm` : 因為要讀取 3 維陣列,所以有很多方向的 stream. 因為相鄰層的元素都是加固定數目的差異,所以硬體也可以做到。
* `zeusmp` : 也是 3D 的,理由同上
* `libquantum` : 每次跳固定數目的位址。硬體也可以預測,但一樣
* 短小的 stream
* `milc` : 讀取許多小的 3X3 陣列,所以硬體不容易從這麼小的資料量來預測接下來要存取哪些記憶體。
### 兩者差不多(但是軟體還好一點點)的
* `bzip2` : 因為 branch 很多,所以 prefetch 很難起作用。
* `cactusADM` : 主要是 stream 的方向很多,使得 stream prefetcher 不能很好的發揮(因為 stream 總數有限)。但是 GHB 可以很有效的避免。不過加上軟體之後,兩者差距就變小了,充分印證前面「可以突破硬體限制」的理論。
* `slopex` : 因為 C++ 的 class overload 太複雜而難以 prefetch (XDDDDD)
* `bwaves` : 雖然 prefetch 指令大大減少了 Cache Miss, 但是為了 Prefetch 安插了太多的指令(instruction count 從 200M 變成 400M 囧)使得 Prefetch 帶來的好處幾乎消失。
### 硬體優於軟體的
* `sphinx3` : 因為都是很規律的 unit stride, 所以 stream prefetcher 可以大大發揮自己的功能。另一方面,因為軟體上的 prefetch 需要一定的 prefetch distance, 所以降低了能夠預先取得的資料數目。
* `leslied3` : 因為迴圈小,所以必須增大 prefetch distance 來做軟體上的 prefetch,使得能 prefetch 的資料變少了,但是這些 prefetch 帶來的好處又被需要多插入的指令所花費的時間抵銷掉。
>> 終於看完 囧
# Code
## naive_transpose
就是高中學的 $a_{ij} = b_{ji}$,一個元素一個元素作
## sse_transpose
參考[這篇](https://www.randombit.net/bitbashing/2009/10/08/integer_matrix_transpose_in_sse2.html)文章
1. 每 4 X 4 大小為單位,一次取出原矩陣 4 列
2. 用神奇的方法把它轉置。之所以覺得神奇是因為雖然看了 ` _mm_unpacklo_epi32` 與 `_mm_unpackhi_epi32` 的用法,但是完全不會想到可以用這種方法。
## sse_prefetch_transpose
概念同上一個,但是預取下下個 4X4 大小的區塊。
# SSE
參考自 [這份](http://www.tommesani.com/index.php/simd/46-sse-arithmetic.html)資料。
https://software.intel.com/en-us/node/524040
# 重現實驗
首先把 `impl.c` 稍微改一下, 把 3 個實作合併到同一個函數, 並且用 `#if defined ()` 來控制不同編譯條件下, 生成不同實作的 `transpose()` 函數。
然後寫個腳本跑 50 次, 看一下每個實作的大致花的時間:

可以發現 prefetch 很驚人的只有暴力版的 1/4。
想知道如果把矩陣變得更大, 那時間的差異會如何。 所以把大小從 4096 改成 8192, 並且測量時間:

可以發現 prefetch 之後, 相較於最直覺的版本,也只花約了 1/3 的時間, 節省了頗多時間。 但是轉置的資料相依性並不太多。 不知道針對像 LU 分解這種「前面沒算完, 後面就不能算」的運算該怎麼設計。
把大小改成 4096, 看 Cache miss 的話:
```
perf stat --repeat 5 -e \
cache-misses,cache-references,instructions,cycles \
./naive
239233 239428 243718 239172 240834
Performance counter stats for './naive' (5 runs):
16,835,896 cache-misses # 93.258 % of all cache refs ( +- 0.20% )
18,053,043 cache-references ( +- 0.06% )
1,448,488,607 instructions # 1.26 insn per cycle ( +- 0.00% )
1,150,179,077 cycles ( +- 0.95% )
0.415615113 seconds time elapsed ( +- 1.39% )
```
```
perf stat --repeat 5 -e \
cache-misses,cache-references,instructions,cycles \
./sse
112600 116646 113037 118392 113202
Performance counter stats for './sse' (5 runs):
4,539,040 cache-misses # 82.714 % of all cache refs ( +- 0.08% )
5,487,627 cache-references ( +- 0.04% )
1,236,483,076 instructions # 1.57 insn per cycle ( +- 0.00% )
787,858,864 cycles ( +- 0.77% )
0.278432573 seconds time elapsed ( +- 0.41% )
```
```
perf stat --repeat 5 -e \
cache-misses,cache-references,instructions,cycles \
./sse_prefetch
59732 60886 62060 62114 63249
Performance counter stats for './sse_prefetch' (5 runs):
4,558,413 cache-misses # 82.802 % of all cache refs ( +- 0.22% )
5,505,183 cache-references ( +- 0.05% )
1,282,891,547 instructions # 1.93 insn per cycle ( +- 0.02% )
665,314,624 cycles ( +- 0.16% )
0.230683673 seconds time elapsed ( +- 0.21% )
```
意外發現有 prefetch 的版本, cache miss 沒有顯著的比沒有 prefetch 高, 但是執行時間竟然比較短, Instruction Per Cycle 比沒有 prefetch 的版本還高。如果把陣列變大呢?感覺 prefetch 跟沒有 prefetch 的 cache miss 差距就會變少了吧?於是就把大小變成 4096, 並且用 perf 去評估:
```
perf stat --repeat 5 -e \
cache-misses,cache-references,instructions,cycles \
./naive
935892 926712 920060 922266 929593
Performance counter stats for './naive' (5 runs):
68,816,996 cache-misses # 95.271 % of all cache refs ( +- 0.04% )
72,232,734 cache-references ( +- 0.02% )
5,786,176,797 instructions # 1.27 insn per cycle ( +- 0.01% )
4,553,171,773 cycles ( +- 0.23% )
1.598882604 seconds time elapsed ( +- 0.27% )
```
```
perf stat --repeat 5 -e \
cache-misses,cache-references,instructions,cycles \
./sse
454538 484217 454627 478806 452107
Performance counter stats for './sse' (5 runs):
18,744,130 cache-misses # 85.265 % of all cache refs ( +- 0.19% )
21,983,341 cache-references ( +- 0.03% )
4,936,591,296 instructions # 1.57 insn per cycle ( +- 0.01% )
3,151,810,395 cycles ( +- 0.59% )
1.112335133 seconds time elapsed ( +- 0.61% )
```
```
perf stat --repeat 5 -e \
cache-misses,cache-references,instructions,cycles \
./sse_prefetch
293048 293569 287968 285066 293809
Performance counter stats for './sse_prefetch' (5 runs):
20,338,886 cache-misses # 80.488 % of all cache refs ( +- 0.41% )
25,269,313 cache-references ( +- 0.24% )
5,121,417,166 instructions # 1.86 insn per cycle ( +- 0.00% )
2,749,563,307 cycles ( +- 0.15% )
0.961060078 seconds time elapsed ( +- 0.11% )
```
果然是變小了。
不過話說回來,既然大小為 4096 的 cache miss 沒有顯著提升, 那是什麼讓執行時間變短了呢?
# perf raw counter
可以在 `perf list --help` 中的章節找到以下內容:
```
RAW HARDWARE EVENT DESCRIPTOR
Even when an event is not available in a symbolic form within perf right now, it can be encoded in a per processor
specific way.
For instance For x86 CPUs NNN represents the raw register encoding with the layout of IA32_PERFEVTSELx MSRs (see
[Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3B: System Programming Guide] Figure 30-1 Layout
of IA32_PERFEVTSELx MSRs) or AMD’s PerfEvtSeln (see [AMD64 Architecture Programmer’s Manual Volume 2: System
Programming], Page 344, Figure 13-7 Performance Event-Select Register (PerfEvtSeln)).
Note: Only the following bit fields can be set in x86 counter registers: event, umask, edge, inv, cmask. Esp.
guest/host only and OS/user mode flags must be setup using EVENT MODIFIERS.
Example:
If the Intel docs for a QM720 Core i7 describe an event as:
Event Umask Event Mask
Num. Value Mnemonic Description Comment
A8H 01H LSD.UOPS Counts the number of micro-ops Use cmask=1 and
delivered by loop stream detector invert to count
cycles
raw encoding of 0x1A8 can be used:
perf stat -e r1a8 -a sleep 1
perf record -e r1a8 ...
You should refer to the processor specific documentation for getting these details. Some of them are referenced in the
SEE ALSO section below.
```
大意就是除了用 `cache-misses` 這種文字之外, 也可以用 16 進位的代號來當作事件的名字。 [perf 的維基](https://perf.wiki.kernel.org/index.php/Tutorial)裡面的Hardware Events 也有提到。
比如說:
```bash
$ perf stat -e r1a8 -a sleep 1
```
會得到 :
```
Performance counter stats for 'system wide':
2,733,444 r1a8
1.001510401 seconds time elapsed
```
本來不是很確定要怎麼用這個, 不過發現 [學長的共筆](https://hackmd.io/s/ryTASBCT#)有提到這件事。