英文原版 https://www.cs.virginia.edu/stream/ref.html
FAQ中有關於STREAM_ARRAY_SIZE NTIME OFFSET STREAM_TYPE的設置說明
在stream.c的源碼中也有。
最近由於工作需要,接觸到Stream benchmark。Stream benchmark是一個測試內存帶寬的基准測試程序。官方提供C和fortran兩個版本,鑒於如今C語言使用的廣泛形,本文僅從C語言版本的測試進行分析。關於Stream benchmark 的相關文檔請查看https://www.cs.virginia.edu/stream/ 。
1. 下載。要運行Stream benchmark, 首先需要下載。下載基准測試程序請移步https://www.cs.virginia.edu/stream/FTP/Code/。如果是使用C,你只需要下載一個文件stream.c。
2. 編譯。如果是C程序源碼,你可以使用gcc或g++進行編譯。編譯使用
gcc -O stream.c -o stream_exe
你也可以加入openmp編譯選項進行多核訪存帶寬的測試,加入openmp選項的編譯使用
gcc -O -fopenmp stream.c -o stream_omp_exe
本程序有三個重要參數需要設置,他們是STREAM_ARRAY_SIZE,NTIMES以及OFFSET。關於這三個參數的含義和設置規則我將在下文詳細介紹。設置這三個參數的方法有兩種,一是直接在源文件中修改,二是在編譯選項中加入編譯規則,即使用-D 選項定義。如要定義STREAM_ARRAY_SIZE為100M,NTIMES為12以及OFFSET為2,則使用以下編譯方法
gcc -O -fopenmp -DSTREAM_ARRAY_SIZE=100000000 -DNTIME=12 -DOFFSET=1022 stream.c -o stream_omp_exe
如果設置的STREAM_ARRAY_SIZE太大(大於2G),你可以增加編譯選項-mcmodel=medium,如果繼續增大這個size,可以進一步使用-mcmodel=large。除此之外,你還可以定義STREAM_TYPE,默認是double,基本不許要修改。
3. 運行及結果分析。直接使用./stream_omp_exe即可運行,如果多線程並未啟動,可在運行前手動設置運行的進程數,如export OMP_NUM_THREADS=20。以下是某Power機器上的運行結果
-------------------------------------------------------------
STREAM version $Revision: 5.10 $
-------------------------------------------------------------
This system uses 8 bytes per array element.
-------------------------------------------------------------
Array size = 100000000 (elements), Offset = 0 (elements)
Memory per array = 762.9 MiB (= 0.7 GiB).
Total memory required = 2288.8 MiB (= 2.2 GiB).
Each kernel will be executed 10 times.
The *best* time for each kernel (excluding the first iteration)
will be used to compute the reported bandwidth.
-------------------------------------------------------------
Number of Threads requested = 20
Number of Threads counted = 20
-------------------------------------------------------------
Your clock granularity/precision appears to be 1 microseconds.
Each test below will take on the order of 13857 microseconds.
(= 13857 clock ticks)
Increase the size of the arrays if this shows that
you are not getting at least 20 clock ticks per test.
-------------------------------------------------------------
WARNING -- The above is only a rough guideline.
For best results, please be sure you know the
precision of your system timer.
-------------------------------------------------------------
Function Best Rate MB/s Avg time Min time Max time
Copy: 134965.4 0.012672 0.011855 0.013730
Scale: 132362.0 0.013659 0.012088 0.017100
Add: 141218.4 0.018251 0.016995 0.019597
Triad: 136666.8 0.018566 0.017561 0.019594
-------------------------------------------------------------
Solution Validates: avg error less than 1.000000e-13 on all three arrays
-------------------------------------------------------------
上述結果已經很清晰顯示各種信息了,在這里不贅述。下面着重講一下4個操作Copy,Scale,Add和Triad。
Copy為最簡單的操作,即從一個內存單元中讀取一個數,並復制到另一個內存單元,有2次訪存操作。
Scale是乘法操作,從一個內存單元中讀取一個數,與常數scale相乘,得到的結果寫入另一個內存單元,有2次訪存。
Add是加法操作,從兩個內存單元中分別讀取兩個數,將其進行加法操作,得到的結果寫入另一個內存單元中,有2次讀和1次寫共3次訪存。
Triad是前面三種的結合,先從內存中讀取一個數,與scale相乘得到一個乘積,然后從另一個內存單元中讀取一個數與之前的乘積相加,得到的結果再寫入內存。所以,有2次讀和1次寫共3次訪存操作。
從上述的結果我們可以看出,測試的內存帶寬Add>Triad>Copy>Scale。這是因為訪存次數越多,內隱藏的訪存延遲越大,得到的帶寬越大。同理,運算的操作越復雜,操作時間就越長,程序運行時間就越長,得到的訪存帶寬就相應減少。這就是為什么3次訪存的操作得到的帶寬比2次訪存操作得到的要大,而相同訪存次數的操作,加法要比乘法得到的結果要好。
4. 參數含義及設置規則。
1)STREAM_ARRAY_SIZE。這個是測試數據集的大小,該大小應該遵循以下兩條規則。
A. 數據集大小應不小於L3 cache大小的4倍。舉例來說某10核Power機器中L3 cache為8MB/core,共80MB L3 cache,因此數據集的大小至少為80MB*4=320MB。由於數據集中每個元素大小為64bits,即8B。故,數據集大小應設置為不小與320MB/8B=40M (40million或40000000)。
B. 數據集大小應能確保程序輸出時間大於20個時鍾周期。該時鍾周期可在程序輸出信息中看到,如“Your clock granularity/precision appears to be 1 microseconds.“ 表示時鍾周期為1微秒,20個時鍾周期為20微秒。如果你的測試機器有200GB/s的帶寬,那你的數據集大小應不小於4MB,即0.5million個元素。
2) NTIME。該參數為kernel執行的次數,程序將輸出除第一次外其他結果中最好的結果,所以NTIME必須要大於1。該值默認為10,通常不許要修改。
3)OFFSET。該值為數組的偏移量,修改此值可改變數組的對齊,從而在一定程度上改變輸出的性能結果。一定程度在這指的是也許會改變,也許不會改變。本人在Power上的測試是沒有很大的改變。如果需要修改該參數,通常將其設置為靠近2^n的數,例如使用-DOFFSET=1022 (靠近2^10=1024)。
4) STREAM_TYPE。我們可以通過修改該參數設置測試集的數據類型,默認是double(8B)。如果將其改為float則數據集大小減少一半。
Stream benchmark已經推出stream2.0版本,相關資料及源碼下載請參考 https://www.cs.virginia.edu/stream/stream2/。最后感謝John和McCalpin提供這么簡單粗暴方便有效的測試方式。
你也可以加入openmp編譯選項進行多核訪存帶寬的測試,加入openmp選項的編譯使用
gcc -O -fopenmp stream.c -o stream_omp_exe
本程序有三個重要參數需要設置,他們是STREAM_ARRAY_SIZE,NTIMES以及OFFSET。關於這三個參數的含義和設置規則我將在下文詳細介紹。設置這三個參數的方法有兩種,一是直接在源文件中修改,二是在編譯選項中加入編譯規則,即使用-D 選項定義。如要定義STREAM_ARRAY_SIZE為100M,NTIMES為12以及OFFSET為2,則使用以下編譯方法
gcc -O -fopenmp -DSTREAM_ARRAY_SIZE=100000000 -DNTIME=12 -DOFFSET=1022 stream.c -o stream_omp_exe
如果設置的STREAM_ARRAY_SIZE太大(大於2G),你可以增加編譯選項-mcmodel=medium,如果繼續增大這個size,可以進一步使用-mcmodel=large。除此之外,你還可以定義STREAM_TYPE,默認是double,基本不許要修改。
3. 運行及結果分析。直接使用./stream_omp_exe即可運行,如果多線程並未啟動,可在運行前手動設置運行的進程數,如export OMP_NUM_THREADS=20。以下是某Power機器上的運行結果
-------------------------------------------------------------
STREAM version $Revision: 5.10 $
-------------------------------------------------------------
This system uses 8 bytes per array element.
-------------------------------------------------------------
Array size = 100000000 (elements), Offset = 0 (elements)
Memory per array = 762.9 MiB (= 0.7 GiB).
Total memory required = 2288.8 MiB (= 2.2 GiB).
Each kernel will be executed 10 times.
The *best* time for each kernel (excluding the first iteration)
will be used to compute the reported bandwidth.
-------------------------------------------------------------
Number of Threads requested = 20
Number of Threads counted = 20
-------------------------------------------------------------
Your clock granularity/precision appears to be 1 microseconds.
Each test below will take on the order of 13857 microseconds.
(= 13857 clock ticks)
Increase the size of the arrays if this shows that
you are not getting at least 20 clock ticks per test.
-------------------------------------------------------------
WARNING -- The above is only a rough guideline.
For best results, please be sure you know the
precision of your system timer.
-------------------------------------------------------------
Function Best Rate MB/s Avg time Min time Max time
Copy: 134965.4 0.012672 0.011855 0.013730
Scale: 132362.0 0.013659 0.012088 0.017100
Add: 141218.4 0.018251 0.016995 0.019597
Triad: 136666.8 0.018566 0.017561 0.019594
-------------------------------------------------------------
Solution Validates: avg error less than 1.000000e-13 on all three arrays
-------------------------------------------------------------
上述結果已經很清晰顯示各種信息了,在這里不贅述。下面着重講一下4個操作Copy,Scale,Add和Triad。
Copy為最簡單的操作,即從一個內存單元中讀取一個數,並復制到另一個內存單元,有2次訪存操作。
Scale是乘法操作,從一個內存單元中讀取一個數,與常數scale相乘,得到的結果寫入另一個內存單元,有2次訪存。
Add是加法操作,從兩個內存單元中分別讀取兩個數,將其進行加法操作,得到的結果寫入另一個內存單元中,有2次讀和1次寫共3次訪存。
Triad是前面三種的結合,先從內存中讀取一個數,與scale相乘得到一個乘積,然后從另一個內存單元中讀取一個數與之前的乘積相加,得到的結果再寫入內存。所以,有2次讀和1次寫共3次訪存操作。
從上述的結果我們可以看出,測試的內存帶寬Add>Triad>Copy>Scale。這是因為訪存次數越多,內隱藏的訪存延遲越大,得到的帶寬越大。同理,運算的操作越復雜,操作時間就越長,程序運行時間就越長,得到的訪存帶寬就相應減少。這就是為什么3次訪存的操作得到的帶寬比2次訪存操作得到的要大,而相同訪存次數的操作,加法要比乘法得到的結果要好。
4. 參數含義及設置規則。
1)STREAM_ARRAY_SIZE。這個是測試數據集的大小,該大小應該遵循以下兩條規則。
A. 數據集大小應不小於L3 cache大小的4倍。舉例來說某10核Power機器中L3 cache為8MB/core,共80MB L3 cache,因此數據集的大小至少為80MB*4=320MB。由於數據集中每個元素大小為64bits,即8B。故,數據集大小應設置為不小與320MB/8B=40M (40million或40000000)。
B. 數據集大小應能確保程序輸出時間大於20個時鍾周期。該時鍾周期可在程序輸出信息中看到,如“Your clock granularity/precision appears to be 1 microseconds.“ 表示時鍾周期為1微秒,20個時鍾周期為20微秒。如果你的測試機器有200GB/s的帶寬,那你的數據集大小應不小於4MB,即0.5million個元素。
2) NTIME。該參數為kernel執行的次數,程序將輸出除第一次外其他結果中最好的結果,所以NTIME必須要大於1。該值默認為10,通常不許要修改。
3)OFFSET。該值為數組的偏移量,修改此值可改變數組的對齊,從而在一定程度上改變輸出的性能結果。一定程度在這指的是也許會改變,也許不會改變。本人在Power上的測試是沒有很大的改變。如果需要修改該參數,通常將其設置為靠近2^n的數,例如使用-DOFFSET=1022 (靠近2^10=1024)。
4) STREAM_TYPE。我們可以通過修改該參數設置測試集的數據類型,默認是double(8B)。如果將其改為float則數據集大小減少一半。
Stream benchmark已經推出stream2.0版本,相關資料及源碼下載請參考 https://www.cs.virginia.edu/stream/stream2/。最后感謝John和McCalpin提供這么簡單粗暴方便有效的測試方式。