大家好,我是痞子衡,是正經搞技術的痞子,今天痞子衡給大家介紹的是記憶體讀寫正確性壓力測驗程式memtester,
在嵌入式系統中,記憶體(RAM)的重要性不言而喻,系統性能及穩定性都與記憶體息息相關,關于記憶體性能有很多個不同指標,其中最基礎的指標便是訪問可靠性(即讀寫的正確性),只有穩定可靠的記憶體訪問才能確保系統正常運行,很多時候簡單地記憶體讀寫測驗并不能發現隱藏的問題,因此我們需要一個完備的記憶體訪問壓力測驗程式,今天痞子衡就和大家詳細聊一聊memtester,
一、記憶體性能測驗程式集
在講memtester之前,痞子衡先給大家科普一下Linux系統下常用的記憶體性能測驗工具,它們分別是mbw、memtester、lmbench、sysbench,這幾個測驗工具(程式)各有側重點:
記憶體帶寬測驗工具 --mbw;
記憶體壓力測驗工具 --memtester;
記憶體綜合性能測驗工具 --lmbench;
記憶體申請與讀寫速度測驗工具 --sysbench;
二、memtester程式
memtester是Simon Kirby在1999年撰寫的測驗程式(v1版),后來由Charles Cazabon一直維護更新(v2及之后版本),主要面向Unix-like系統,官方主頁上介紹的是“A userspace utility for testing the memory subsystem for faults.”,其實就是為了測驗記憶體(主要DDR)的讀寫訪問可靠性(僅正確性,與速度性能無關),這是驗證板級硬體設備必不可少的一項測驗,
整個memtester測驗的視角就是從用戶的角度來看的,從用戶角度設立不同的測驗場景即測驗用例,然后針對性地進行功能測驗,注意是從系統級來測驗,也就是說關注的不單單是記憶體顆粒了,還有系統板級的連線、IO性能、PCB等等相關的因素,在這些因素的影響下,記憶體是否還能正常作業,
2.1 獲取程式
memtester程式的最新版本是4.5.0,早期的v1/v2/v3版本目前下載不到了,2012年Charles Cazabon重寫了程式并發布了全新v4.0.0,此后一直不定期更新,v4.x也是當前最流行的版本,
核心程式下載: http://pyropus.ca/software/memtester/
核心程式包下載后,在\memtester-4.5.0\下可找到源代碼,詳細源檔案目錄如下:
\memtester-4.5.0
\memtester.h
\memtester.c --主程式入口
\sizes.h --關于系統位數(32/64bit)的一些定義
\types.h --所用資料型別的定義
\tests.h
\tests.c --測驗演算法子程式
如果是移植到ARM Cortex-M平臺下裸系統運行,一般只需要簡單修改memtester.c檔案即可,其他源檔案就是一些頭檔案包含方面的改動,memtester本身并沒有太多移植作業,其原始碼本是用作在Unix-like系統上運行的,而在嵌入式系統里運行僅需要把一些跟系統平臺相關的代碼洗掉即可,此外就是列印函式的實作,
2.2 配置引數
memtester原始碼里的配置選項主要是如下五個宏:
/* 如下需用戶自定義 */
ULONG_MAX -- 確定系統是32bit還是64bit
TEST_NARROW_WRITES -- 確定是否要包含8/16 bit寫測驗
/* 如下借助linux頭檔案 */
_SC_VERSION -- posix system版本檢查
_SC_PAGE_SIZE -- 記憶體page大小獲取
MAP_LOCKED -- Linux里mmap里的swap特性
2.3 程式決議
讓我們嘗試分析memtester主函式入口main,main()函式最開始都是一些輸入引數決議,其實主要就是為了獲取三個重要變數:記憶體測驗起始地址、記憶體測驗總長度、壓力測驗回圈次數,有了這三個變數值之后便開始逐一跑tests.c檔案里各項測驗演算法小函式:
struct test {
char *name;
int (*fp)();
};
struct test tests[] = {
{ "Random Value", test_random_value },
{ "Compare XOR", test_xor_comparison },
{ "Compare SUB", test_sub_comparison },
{ "Compare MUL", test_mul_comparison },
{ "Compare DIV",test_div_comparison },
{ "Compare OR", test_or_comparison },
{ "Compare AND", test_and_comparison },
{ "Sequential Increment", test_seqinc_comparison },
{ "Solid Bits", test_solidbits_comparison },
{ "Block Sequential", test_blockseq_comparison },
{ "Checkerboard", test_checkerboard_comparison },
{ "Bit Spread", test_bitspread_comparison },
{ "Bit Flip", test_bitflip_comparison },
{ "Walking Ones", test_walkbits1_comparison },
{ "Walking Zeroes", test_walkbits0_comparison },
#ifdef TEST_NARROW_WRITES
{ "8-bit Writes", test_8bit_wide_random },
{ "16-bit Writes", test_16bit_wide_random },
#endif
{ NULL, NULL }
};
/* Function definitions */
void usage(char *me) {
fprintf(stderr, "\n"
"Usage: %s [-p physaddrbase [-d device]] <mem>[B|K|M|G] [loops]\n",
me);
exit(EXIT_FAIL_NONSTARTER);
}
int main(int argc, char **argv) {
ul loops, loop, i;
size_t bufsize, halflen, count;
void volatile *buf, *aligned;
ulv *bufa, *bufb;
ul testmask = 0;
// 省略若干變數定義代碼
printf("memtester version " __version__ " (%d-bit)\n", UL_LEN);
printf("Copyright (C) 2001-2020 Charles Cazabon.\n");
printf("Licensed under the GNU General Public License version 2 (only).\n");
printf("\n");
// 省略若干初始檢查代碼
// 從輸入引數里獲取physaddrbase計算出記憶體測驗起始地址aligned
// 從輸入引數里獲取mem及B|K|M|G計算出記憶體測驗總長度bufsize
halflen = bufsize / 2;
count = halflen / sizeof(ul);
bufa = (ulv *) aligned;
bufb = (ulv *) ((size_t) aligned + halflen);
// 壓力測驗的重要變數, loops即重復次數
for(loop=1; ((!loops) || loop <= loops); loop++) {
printf("Loop %lu", loop);
if (loops) {
printf("/%lu", loops);
}
printf(":\n");
printf(" %-20s: ", "Stuck Address");
fflush(stdout);
// 第一個測驗 stuck_address
if (!test_stuck_address(aligned, bufsize / sizeof(ul))) {
printf("ok\n");
} else {
exit_code |= EXIT_FAIL_ADDRESSLINES;
}
// 遍歷tests.c里的所有測驗子程式
for (i=0;;i++) {
if (!tests[i].name) break;
if (testmask && (!((1 << i) & testmask))) {
continue;
}
printf(" %-20s: ", tests[i].name);
// 可以看到將記憶體測驗總空間一分為二,傳給子程式做處理的
if (!tests[i].fp(bufa, bufb, count)) {
printf("ok\n");
} else {
exit_code |= EXIT_FAIL_OTHERTEST;
}
fflush(stdout);
/* clear buffer */
memset((void *) buf, 255, wantbytes);
}
printf("\n");
fflush(stdout);
}
}
tests.c檔案里才是最核心的壓力測驗演算法子程式,一共17個函式,涉及各種記憶體訪問經驗操作,具體可以看網上的一篇詳細決議文章 https://www.jianshu.com/p/ef203c360c4f,
| 測驗函式名 | 測驗作用 |
|---|---|
| test_stuck_address | 先全部把地址值交替取反放入對應存盤位置,然后再讀出比較,重復n次 |
| test_random_value | 等效test_random_comparison(bufa, bufb, count):資料敏感型測驗用例 |
| test_xor_comparison | 與test_random_value比多了個異或操作 |
| test_sub_comparison | 與test_random_value比多了個減法操作 |
| test_mul_comparisone | 與test_random_value比多了個乘法操作 |
| test_div_comparison | 與test_random_value比多了個除法操作 |
| test_or_comparison | 在test_random_comparison()里面合并了 |
| test_and_comparison | 在test_random_comparison()里面合并了 |
| test_seqinc_comparison | 是 test_blockseq_comparison的一個子集;模擬客戶壓力測驗場景 |
| test_solidbits_comparison | 固定全1后寫入兩個buffer,然后讀出比較,然后全0寫入讀出比較;這就是Zero-One演算法 |
| test_blockseq_comparison | 一次寫一個count大小的塊,寫的值是拿byte級的數填充32bit,然后取出對比,接著重復256次;也是壓力用例,只是次數變多了; |
| test_checkerboard_comparison | 把設定好的幾組Data BackGround,依次寫入,然后讀出比較 |
| test_bitspread_comparison | 還是在32bit里面移動,只是這次移動的不是單單的一個0或者1,而是兩個1,這兩個1之間隔著兩個空位/td> |
| test_bitflip_comparison | 也是32bit里面的一個bit=1不斷移動生成data pattern然后,每個pattern均執行 |
| test_walkbits1_comparison | 與test_walkbits0_comparison同理 |
| test_walkbits0_comparison | 就是bit=1的位置在32bit里面移動,每移動一次就全部填滿buffer,先是從低位往高位移,再是從高位往低位移動 |
| test_8bit_wide_random | 以char指標存值,也就是每次存8bit,粒度更細; |
| test_16bit_wide_random | 以unsigned short指標存值,也就是每次存16bit,不同粒度檢測; |
2.4 結果格式
在Unix-like系統下使用make && make install命令進行編譯可得到一個可執行的memtester,可以隨便執行memtester 10M 1,即申請10M的記憶體測驗1次,結果如下:
[root@as150 ~] memtester 10M 1
memtester version 4.5.0 (64-bit)
Copyright (C) 2001-2020 Charles Cazabon.
Licensed under the GNU General Public License version 2 (only).
pagesize is 4096
pagesizemask is 0xfffffffffffff000
want 10MB (10485760 bytes)
got 10MB (10485760 bytes), trying mlock ...locked.
Loop 1/1:
Stuck Address: ok
Random Value: ok
Compare XOR: ok
Compare SUB: ok
Compare MUL: ok
Compare DIV: ok
Compare OR: ok
Compare AND: ok
Sequential Increment: ok
Solid Bits: ok
Block Sequential: ok
Checkerboard: ok
Bit Spread: ok
Bit Flip: ok
Walking Ones: ok
Walking Zeroes: ok
8-bit Writes: ok
16-bit Writes: ok
Done.
至此,記憶體讀寫正確性壓力測驗程式memtester痞子衡便介紹完畢了,掌聲在哪里~~~
歡迎訂閱
文章會同時發布到我的 博客園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上,
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦,

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/270508.html
標籤:嵌入式
上一篇:我是如何查找RFC官方資料的
