Overview
前言
爲一究memtester原理,現對其每個函數均按照如下格式進行描述:
- 方法
- 原理
- 時間花銷
以下是對每個測試項的簡要描述:
memtester-4.3.0 | memtester-ARM |
---|---|
int test_stuck_address(bufa, count); | (√ ) 先全部把地址值交替取反放入對應存儲位置,然後再讀出比較,重複2次(官網的重複了16次):測試address bus |
int test_random_value(bufa, bufb, count); | (√ )等效test_random_comparison(bufa, bufb, count):數據敏感型測試用例 |
int test_xor_comparison(bufa, bufb, count); | (-) 與test_random_value比多了個異或操作,用戶場景之一,用例覆蓋。數據敏感/指令功能驗證,同時可驗證SAF; |
int test_sub_comparison(bufa, bufb, count); | (-)與test_random_value比多了個減法操作,用戶場景之一,用例覆蓋。數據敏感/指令功能驗證,同時可驗證SAF; |
int test_mul_comparison(bufa, bufb, count); | (-)與test_random_value比多了個乘法操作,用戶場景之一,用例覆蓋。數據敏感/指令功能驗證,同時可驗證SAF; |
int test_div_comparison(bufa, bufb, count); | (-)與test_random_value比多了個除法操作,用戶場景之一,用例覆蓋。數據敏感/指令功能驗證,同時可驗證SAF; |
int test_or_comparison(bufa, bufb, count); | (√ )在test_random_comparison()裏面合併了,用戶場景之一,用例覆蓋。數據敏感/指令功能驗證,同時可驗證SAF; |
int test_and_comparison(bufa, bufb, count); | (√ )在test_random_comparison()裏面合併了,用戶場景之一,用例覆蓋。數據敏感/指令功能驗證,同時可驗證SAF; |
int test_seqinc_comparison(bufa, bufb, count); | (√ )這是 test_blockseq_comparison的一個子集;模擬客戶壓力測試場景。 |
int test_solidbits_comparison(bufa, bufb, count); | (√ )固定全1後寫入兩個buffer,然後讀出比較,然後全0寫入讀出比較;這就是Zero-One算法,Breuer & Friedman 1976 ,檢測SAF的,算法是{w0,r0,w1,r1}時間複雜度是4N,又叫做MSCAN,驗證每個cell能讀寫,間接測試了stuck at fault |
int test_checkerboard_comparison(bufa, bufb, count); | (√ )把設定好的幾組Data BackGround,依次寫入,然後讀出比較 (注:論文裏說設計良好的Data background可以檢測出state coupling faults時間複雜度是4N,這是驗證相鄰位置是否互相影響從而設計的用例。 |
int test_blockseq_comparison(bufa, bufb, count); | (√ )一次寫一個count大小的塊,寫的值是拿byte級的數填充32bit,然後取出對比,接着重複256次;也是壓力用例,只是次數變多了; |
int test_walkbits0_comparison(bufa, bufb, count); | (√ )就是bit=1的位置在32bit裏面移動,每移動一次就全部填滿buffer,先是從低位往高位移,再是從高位往低位移動,(這麼做的目的是啥?其中的一個目的是檢測NPSF其次是CFs,其次是數據敏感型異常檢測,注這裏是32bit的,還有8bit的粒度更細了) |
int test_walkbits1_comparison(bufa, bufb, count); | (√ )與上同理,另注:早memtester86中這個算法叫做moving inversions algorithm |
int test_bitspread_comparison(bufa, bufb, count); | (√ )還是在32bit裏面移動,只是這次移動的不是單單的一個0或者1,而是兩個1,這兩個1之間隔着兩個空位,(是臨近耦合異常的一種data pattern變體:兩個1之間間隔1個位置,然後同步移動) |
int test_bitflip_comparison(bufa, bufb, count); | (√ )也是32bit裏面的一個bit=1不斷移動生成data pattern然後,每個pattern均執行:{取反交替寫入a、b緩衝區,寫完之後檢查一遍,然後不斷重複以下步驟八次{用八個DMA從a緩衝區搬數據到b緩衝區,並行搬,模擬短時間內反覆讀寫同一位置看是否有數據丟失異常}}核心思想:短時間內反覆讀寫同一位置。 |
int test_8bit_wide_random(bufa, bufb, count); | (√ )以char指針存值,也就是每次存8bit,粒度更細; |
int test_16bit_wide_random(bufa, bufb, count); | (√ )以unsigned short指針存值,也就是每次存16bit,不同粒度檢測; |
× | int test_crosstalk_comparison(bufa, bufb, count):[32個0,接着32bit裏面1個0移動]以這樣的模型疊加寫入內存;(只有上行,沒像有moving inversions algorithm一樣進行反轉) |
詳解函數
memtester-4.3.0 版本
方法test_stuck_address
函數名:int test_stuck_address(ulv *bufa, size_t count)
基本pattern按照下圖所示,j=0時,先把P1的地址值寫入對應的內存位置處,然後P2取反放入對應位置處,如此反覆;
然後下一輪開始,即j=1,把上述步驟反過來再進行一遍即可;
直到16輪結束,假若發生異常就把異常的地址直接返回即可!
目的(原理)
爲了驗證是否有地址無法訪問,驗證的是地址線。
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_stuck_address(ulv *bufa, size_t count) {
ulv *p1 = bufa;
unsigned int j;
size_t i;
off_t physaddr;
printf(" ");
fflush(stdout);
for (j = 0; j < 16; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
p1 = (ulv *) bufa;
printf("setting %3u", j);
fflush(stdout);
for (i = 0; i < count; i++) {
*p1 = ((j + i) % 2) == 0 ? (ul) p1 : ~((ul) p1);
*p1++;
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", j);
fflush(stdout);
p1 = (ulv *) bufa;
for (i = 0; i < count; i++, p1++) {
if (*p1 != (((j + i) % 2) == 0 ? (ul) p1 : ~((ul) p1))) {
if (use_phys) {
physaddr = physaddrbase + (i * sizeof(ul));
fprintf(stderr,
"FAILURE: possible bad address line at physical "
"address 0x%08lx.\n",
physaddr);
} else {
fprintf(stderr,
"FAILURE: possible bad address line at offset "
"0x%08lx.\n",
(ul) (i * sizeof(ul)));
}
printf("Skipping to next test...\n");
fflush(stdout);
return -1;
}
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
int test_stuck_address(unsigned int *bufa, unsigned int count)
{
unsigned int *p1 = bufa;
unsigned int j;
int i;
for(j = 0; j < 2; j++){
p1 = (unsigned int *)bufa;
for(i = 0; i < count; i++){
*p1 = ((j + i) % 2) == 0 ? (unsigned int)p1 : (~(unsigned int)p1);
p1++;
}
p1 = (unsigned int *)bufa;
for(i = 0; i < count; i++, p1++){
if (*p1 != (((j + i) % 2) == 0 ? (unsigned int) p1 : ~((unsigned int) p1))){
#ifdef PRINTK
printk("[DRAM]test_stuck_address: %x is %x error\n", p1,(unsigned int)*p1);
#endif
if(((j + i) % 2) == 0){
return (((unsigned int) p1)^(*p1));
}
else{
return ((~((unsigned int) p1))^(*p1));
}
}
}
}
return 0;
}
方法test_random_value
函數名:int test_random_value(ulv *bufa, ulv *bufb, size_t count)
開了兩個Buffer區域,然後同時寫入隨機值,寫完count個之後,用compare_regions(bufa, bufb, count)函數來對比驗證。
int compare_regions(ulv *bufa, ulv *bufb, size_t count) {
int r = 0;
size_t i;
ulv *p1 = bufa;
ulv *p2 = bufb;
off_t physaddr;
for (i = 0; i < count; i++, p1++, p2++) {
if (*p1 != *p2) {
if (use_phys) {
physaddr = physaddrbase + (i * sizeof(ul));
fprintf(stderr,
"FAILURE: 0x%08lx != 0x%08lx at physical address "
"0x%08lx.\n",
(ul) *p1, (ul) *p2, physaddr);
} else {
fprintf(stderr,
"FAILURE: 0x%08lx != 0x%08lx at offset 0x%08lx.\n",
(ul) *p1, (ul) *p2, (ul) (i * sizeof(ul)));
}
/* printf("Skipping to next test..."); */
r = -1;
}
}
return r;
}
目的(原理)
目的是測試data bus,以及某種數據pattern是否會導致cell無法讀寫,類似於軟件測試裏面的Monkey test;
其中有幾個注意點:
- 這裏開源版本是沒有底層加速優化的,一個個地往內存地址寫數據,每寫一個就要fflush操作一些,免得數據在stdout緩衝區內堆積而不會立即寫入DRAM,因此我們底層優化的時候要考慮cache的影響;
- 上述的對比函數就是一個一個值地對比,要是底層不做優化地話時間花銷基本上是neon加速後的四倍;
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_random_value(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
ul j = 0;
size_t i;
putchar(' ');
fflush(stdout);
for (i = 0; i < count; i++) {
*p1++ = *p2++ = rand_ul();
if (!(i % PROGRESSOFTEN)) {
putchar('\b');
putchar(progress[++j % PROGRESSLEN]);
fflush(stdout);
}
}
printf("\b \b");
fflush(stdout);
return compare_regions(bufa, bufb, count);
}
ARM A53移植版本
在公版的基礎上融合進來與或的操作,但是還是一個一個寫,驗證了一下全空間寫0的時間是neon寫的4倍。
arm平臺(平臺參數見上述描述)跑了24s左右。
int test_random_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count)
{
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
int i;
int q;
for(i = 0; i < count; i++, p1++, p2++){
*p1 = *p2 = rand_ul();
}
p1 = bufa;
p2 = bufb;
for(i = 0; i < count; i++, p1++, p2++){
if(i%2==0){
q=rand_ul();
*p1|=q;
*p2|=q;
}
else{
q=rand_ul();
*p1&=q;
*p2&=q;
}
}
return compare_regions(bufa, bufb, count);
}
讀出對比的時間,全1GB空間實測大概花了6s的樣子(A53平臺單核1.46GHz 32bit),時間大大減少。
int compare_regions(unsigned int *bufa, unsigned int *bufb, unsigned int count)
{
unsigned int ret = 0,i,ERRO_ADDR[2];
ret = mctl_neon_cmp(bufa,bufb,count<<2,&ERRO_ADDR[0]);
if(ret)
{
for(i=0;i<1000;i++)
{
if(__ADDR(ERRO_ADDR[0])==__ADDR(ERRO_ADDR[1]))
{
printk("[DRAM]addr0:%x!=addr1:%x___compare erro bit is :%x---read erro\n",ERRO_ADDR[0],ERRO_ADDR[1],ret);
break;
}
}
if(i==1000)
{
printk("[DRAM]addr0:%x!=addr1:%x___compare erro bit is :%x---write erro\n",ERRO_ADDR[0],ERRO_ADDR[1],ret);
}mctl_neon_write
}
return ret;
}
而減少的時間主要是利用了neon底層加速:註釋見代碼
由於穿進來的參數是(bufa, bufb, count),因此:
- r0 = bufa
- r1 = bufb
- r2 = count
基本思想就是對比,比完之後異或出現非零值就是出異常了,報警!返回異常值。
mctl_neon_cmp
PUSH {r3-r12, lr}
ADD r2,r2,r0 ;把count的值轉成最終的地址值了
neon_cmp
VLDM r0!,{q0-q3} ;一次從bufa加載4*128bit數據到4個neon的Q寄存器
VLDM r1!,{q4-q7} ;一次從bufb加載4*128bit數據到4個neon的Q寄存器
VEOR q8,q0,q4
VEOR q9,q1,q5
VEOR q10,q2,q6
VEOR q11,q3,q7
VORR q12,q8,q9
VORR q13,q11,q10
VORR q14,q12,q13
VORR d30,d28,d29
VMOV r4, r5, d30
ORR r6,r4,r5
CMP r6,#0x0
;上面這一段就是上圖的一個實現,爲什麼一次只操作2X4Q個數據,
;是因爲總共就16個Q,不夠用啊!
;要是支持VEOR q0, q0,q4的話這裏還可以加速的喲!
BNE rw_detect
;不爲0跳轉指令
;檢測是否出現異常了,出現異常則結果不爲0
;檢測是否全部對比完了
CMP r0,r2
BNE neon_cmp
;這裏應爲r0是返回值,因此測試正常則賦0
MOV r0,#0x0
POP {r3-r12, pc}
rw_detect
;這裏是假如中間出錯了要進行的操作
SUB r0,r0,#0x40
SUB r1,r1,#0x40
;bufa和bufb地址回退至4X16個32bit,及16個Q之前。
;(這裏是要對16個Q值均進行清算)
VMOV r4,r5,d16 ;d16解開
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d17;d17
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d18;d18
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d19;d19
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d20;d20
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d21;d21
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d22;d22
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
VMOV r4,r5,d23;d23
CMP r4,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
CMP r5,#0
BNE rw_detect_done
ADD r0,r0,#0x4
ADD r1,r1,#0x4
rw_detect_done
MOV r2,r3
STR r0,[r2];save erro addr
ADD r3,r3,#0x4
MOV r2,r3
STR r1,[r2];save erro addr
MOV r0,r6
POP {r3-r12, pc}
方法test_walkbits1_comparison/test_walkbits0_comparison
函數名:nt test_walkbits1_comparison(bufa, bufb, count);
首先設定一個初始值(以walk1爲例)爲0x00000001,然後左移一位之後寫入下一個地址,依此類推。
目的(原理)
This test is intended to uncover data or address bus problems both internal to the memory device as well as external.
同時也覆蓋測試臨近耦合缺陷。
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_walkbits1_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
unsigned int j;
size_t i;
printf(" ");
fflush(stdout);
for (j = 0; j < UL_LEN * 2; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
p1 = (ulv *) bufa;
p2 = (ulv *) bufb;
printf("setting %3u", j);
fflush(stdout);
for (i = 0; i < count; i++) {
if (j < UL_LEN) { /* Walk it up. */
*p1++ = *p2++ = UL_ONEBITS ^ (ONE << j);
} else { /* Walk it back down. */
*p1++ = *p2++ = UL_ONEBITS ^ (ONE << (UL_LEN * 2 - j - 1));
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", j);
fflush(stdout);
if (compare_regions(bufa, bufb, count)) {
return -1;
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
int test_walkbits1_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count)
{
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
unsigned int j;
int ret = 0;
for(j = 0; j <UL_LEN * 2; j++){
p1 = bufa;
p2 = bufb;
if(j < UL_LEN) {
neon_write(p1,p1+(count<<0),(ONE << j));
neon_write(p2,p2+(count<<0),(ONE << j));
}
else{
neon_write(p1,p1+(count<<0),(ONE << (UL_LEN * 2 - j - 1)));
neon_write(p2,p2+(count<<0),(ONE << (UL_LEN * 2 - j - 1)));
}
ret = compare_regions(bufa, bufb, count);
if(ret){
return ret;
}
}
return 0;
方法test_seqinc_comparison/test_blockseq_comparison
函數名:int test_seqinc_comparison(ulv *bufa, ulv *bufb, size_t count)
/``
目的(原理)
驗證連續按順序寫是否功能正常;
block模式則加上了壓力部分;
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_seqinc_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
size_t i;
ul q = rand_ul();
for (i = 0; i < count; i++) {
*p1++ = *p2++ = (i + q);
}
return compare_regions(bufa, bufb, count);
}
int test_blockseq_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
unsigned int j;
size_t i;
printf(" ");
fflush(stdout);
for (j = 0; j < 256; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
p1 = (ulv *) bufa;
p2 = (ulv *) bufb;
printf("setting %3u", j);
fflush(stdout);
for (i = 0; i < count; i++) {
*p1++ = *p2++ = (ul) UL_BYTE(j);
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", j);
fflush(stdout);
if (compare_regions(bufa, bufb, count)) {
return -1;
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
int test_blockseq_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count){
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
unsigned int j;
int i;
int ret = 0;
for(j = 0; j < 256; j++){
p1 = (unsigned int*)bufa;
p2 = (unsigned int*)bufb;
for(i = 0; i < count; i++, p1++, p2++){
*p1 = *p2 = (unsigned int)UL_BYTE(j);
}
ret = compare_regions(bufa, bufb, count);
if(ret){
return ret;
}
}
return 0;
}
方法 test_solidbits_comparison
函數名:int test_solidbits_comparison(ulv *bufa, ulv *bufb, size_t count)
取一個pattern(全1)然後取反交替寫入buffer區間,然後再檢測時候有問題,反覆64次;
移植版本里面假如了hammer操作,也即短時間內不斷快速讀寫同一個位置,看功能是否正常。
目的(原理)
hammer異常檢測;
全空間scan測試;
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_solidbits_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
unsigned int j;
ul q;
size_t i;
printf(" ");
fflush(stdout);
for (j = 0; j < 64; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
q = (j % 2) == 0 ? UL_ONEBITS : 0;
printf("setting %3u", j);
fflush(stdout);
p1 = (ulv *) bufa;
p2 = (ulv *) bufb;
for (i = 0; i < count; i++) {
*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", j);
fflush(stdout);
if (compare_regions(bufa, bufb, count)) {
return -1;
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
增加了並行讀寫操作(DMA部分)
**DMA_TRAN(1,(s32)bufa,(s32)bufb,0,count << 2)**參數解釋:
- “1”:是從sdram到sdram
- src_addr = bufa
- dst_addr = bufb
- 0~7八個DMA來並行搬運數據,搬運四分之一,那這裏模擬的就是對同一個位置反覆不斷地讀寫8次,最後再檢查一下有沒有出錯;
int test_solidbits_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count)
{
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
unsigned int j;
unsigned int q;
int ret = 0,done;
for(j = 0; j <64; j++){
q = (j% 2) == 0 ? UL_ONEBITS:~UL_ONEBITS;
p1 = (unsigned int *)bufa;
p2 = (unsigned int *)bufb;
mctl_neon_write(p1,p1+(count<<0),q);
mctl_neon_write(p2,p2+(count<<0),q);
ret = compare_regions(bufa, bufb, count);
if(ret==0){
DMA_TRAN(1,(s32)bufa,(s32)bufb,0,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,1,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,2,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,3,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,4,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,5,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,6,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,7,count << 2);
ret = (ret|compare_regions0(bufa, bufb, count));
done = (0xffff);
do{
done = (get_wvalue(0x03002000+0x30) & 0xfff);
}while(done != 0x0); //wait for dma transfor finish
}
if(ret)
return ret;
}
return ret;
}
方法
函數名:int test_bitflip_comparison(ulv *bufa, ulv *bufb, size_t count)
也是32bit裏面的一個bit=1不斷移動生成data pattern然後,每個pattern均執行:{
取反交替寫入a、b緩衝區,寫完之後檢查一遍,然後不斷重複以下步驟八次{
用八個DMA從a緩衝區搬數據到b緩衝區,並行搬,模擬短時間內反覆讀寫同一位置看是否有數據丟失異常}}
核心思想:短時間內反覆讀寫同一位置。
目的(原理)
對比上面的 test_solidbits_comparison可以發現不同之處就在於data pattern的設計,上面是固定的兩個值,這裏是walking bit 1,因此這個用例是 test_solidbits_comparison和test_walkbits1_comparison的組合技能。
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_bitflip_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
unsigned int j, k;
ul q;
size_t i;
printf(" ");
fflush(stdout);
for (k = 0; k < UL_LEN; k++) {
q = ONE << k;
for (j = 0; j < 8; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
q = ~q;
printf("setting %3u", k * 8 + j);
fflush(stdout);
p1 = (ulv *) bufa;
p2 = (ulv *) bufb;
for (i = 0; i < count; i++) {
*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", k * 8 + j);
fflush(stdout);
if (compare_regions(bufa, bufb, count)) {
return -1;
}
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
int test_bitflip_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count){
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
unsigned int j;
int k,q;
int ret = 0,done;
for (k = 0; k <UL_LEN; k++){
q = ONE << k;
for (j = 0; j < 8; j++){
q = ~q;
p1 = bufa;
p2 = bufb;
mctl_neon_write(p1,p1+(count<<0),q);
mctl_neon_write(p2,p2+(count<<0),q);
ret = compare_regions(bufa, bufb, count);
if(ret==0) {
//1:是從sdram到sdram
//src_addr = bufa
//dst_addr = bufb
//0~7八個DMA來並行搬運數據,搬運四分之一,那這裏模擬的就是對同一個位置反覆不斷地讀寫8次,最後再檢查一下有沒有出錯;
DMA_TRAN(1,(s32)bufa,(s32)bufb,0,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,1,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,2,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,3,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,4,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,5,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,6,count << 2);
DMA_TRAN(1,(s32)bufa,(s32)bufb,7,count << 2);
ret = (ret|compare_regions0(bufa, bufb, count));
done = (0xff);
do{
done = (get_wvalue(0x03002000+0x30) & 0xff);
}while(done != 0x0); //wait for dma transfor finish
}
if(ret) {
return ret;
}
}
}
return 0;
}
方法 test_checkerboard_comparison
函數名:int test_checkerboard_comparison(ulv *bufa, ulv *bufb, size_t count)
測64輪,每輪都是從兩個表格中取出一個data pattern來寫入內存,最後讀出對比即可;
目的(原理)
數據敏感型功能缺陷檢測,也就是說有可能memory就是無法存取某個值的情況,這也是從用戶視角出發的。
注:這裏並沒有給出checkboard的值。
注2: 雖然這裏有點類似於底層的NPSF(neighborhood pattern sensitive fault),但是這裏的錨點卻不是這個,而是:比如說我的客戶在把內存插入電腦後,使用過程中有這種pattern的數據寫入內存,會不會存在數據互相影響從而丟失的問題呢?這搞不好就是藍屏了啊!也就是說我們關注的是表層的狀態而不是底層的缺陷。
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_checkerboard_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
unsigned int j;
ul q;
size_t i;
printf(" ");
fflush(stdout);
for (j = 0; j < 64; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
q = (j % 2) == 0 ? CHECKERBOARD1 : CHECKERBOARD2;
printf("setting %3u", j);
fflush(stdout);
p1 = (ulv *) bufa;
p2 = (ulv *) bufb;
for (i = 0; i < count; i++) {
*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", j);
fflush(stdout);
if (compare_regions(bufa, bufb, count)) {
return -1;
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
這裏的checkboard選擇好隨意啊!!!
checkboard一般是選擇0x55跟0xaa交替寫, 檢測stuck bit cases and many adjacent cell dependency cases.
標準算法描述如下:
然後這個地方的移植······
int test_checkrboard_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count){
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
unsigned int j;
unsigned int q;
int ret = 0;
unsigned int CHECKERBOARD1[16]={0x00000000,0x11111111,0x22222222,0x33333333,
0x44444444,0x55555555,0x66666666,0x77777777,
0x88888888,0x99999999,0xaaaaaaaa,0xbbbbbbbb,
0xcccccccc,0xdddddddd,0xeeeeeeee,0xffffffff};
unsigned int CHECKERBOARD2[16]={0xffffffff,0xeeeeeeee,0xdddddddd,0xcccccccc,
0xbbbbbbbb,0xaaaaaaaa,0x99999999,0x88888888,
0x77777777,0x66666666,0x55555555,0x44444444,
0x33333333,0x22222222,0x11111111,0x00000000};
for(j = 0; j < 64; j++){
q = (j % 2) == 0 ? CHECKERBOARD1[(j/2)%16] : CHECKERBOARD2[(j/2)%16];
p1 = (unsigned int *)bufa;
p2 = (unsigned int *)bufb;
mctl_neon_write(p1,p1+(count<<0),q);
mctl_neon_write(p2,p2+(count<<0),q);
ret = compare_regions(bufa, bufb, count);
if(ret){
return ret;
}
}
return 0;
}
方法
函數名:int test_bitspread_comparison(ulv *bufa, ulv *bufb, size_t count)
跟walkbits1比起就是data pattern變了一點點而已,其餘不變,因此可以看作是walkbit1的一個擴展測試;
walkbit1: 00000001 -> 00000010
bitspread: 00000101 -> 00001010
目的(原理)
也是主要爲了檢測臨近耦合缺陷;
這是內部結構圖,有助於理解它內部的尋址
時間花銷
條件:
全空間1G Byte ,DDR帶寬1600M32bit,CPU: ARM A53 (1460~1800)M 32bit單核跑。
時間成本:
___Sec.
int test_bitspread_comparison(ulv *bufa, ulv *bufb, size_t count) {
ulv *p1 = bufa;
ulv *p2 = bufb;
unsigned int j;
size_t i;
printf(" ");
fflush(stdout);
for (j = 0; j < UL_LEN * 2; j++) {
printf("\b\b\b\b\b\b\b\b\b\b\b");
p1 = (ulv *) bufa;
p2 = (ulv *) bufb;
printf("setting %3u", j);
fflush(stdout);
for (i = 0; i < count; i++) {
if (j < UL_LEN) { /* Walk it up. */
*p1++ = *p2++ = (i % 2 == 0)
? (ONE << j) | (ONE << (j + 2))
: UL_ONEBITS ^ ((ONE << j) | (ONE << (j + 2)));
} else { /* Walk it back down. */
*p1++ = *p2++ = (i % 2 == 0)
? (ONE << (UL_LEN * 2 - 1 - j)) | (ONE << (UL_LEN * 2 + 1 - j))
: UL_ONEBITS ^ (ONE << (UL_LEN * 2 - 1 - j)
| (ONE << (UL_LEN * 2 + 1 - j)));
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b");
printf("testing %3u", j);
fflush(stdout);
if (compare_regions(bufa, bufb, count)) {
return -1;
}
}
printf("\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
return 0;
}
ARM A53移植版本
int test_bitspread_comparison(unsigned int *bufa, unsigned int *bufb, unsigned int count){
#define Q 2
unsigned int *p1 = bufa;
unsigned int *p2 = bufb;
unsigned int j;
int ret = 0;
for(j = 0; j <UL_LEN * 2; j++){
p1 = bufa;
p2 = bufb;
if(j < UL_LEN) {
mctl_neon_write(p1,p1+(count<<0),((ONE << j) | (ONE << (j + Q))));
mctl_neon_write(p2,p2+(count<<0),((ONE << j) | (ONE << (j + Q))));
}
else{
mctl_neon_write(p1,p1+(count<<0),((ONE << (UL_LEN * 2 - 1 - j)) | (ONE << (UL_LEN * 2 +Q- 1 - j))));
mctl_neon_write(p2,p2+(count<<0),((ONE << (UL_LEN * 2 - 1 - j)) | (ONE << (UL_LEN * 2 +Q- 1 - j))));
}
ret = compare_regions(bufa, bufb, count);
if(ret){
return ret;
}
}
return 0;
}
總結
整個memtester測試的視角就是從用戶的角度來看的,從用戶角度設立不同的測試場景即測試用例,然後針對性地進行功能測試,注意是從系統級來測試,也就是說關注的不單單是內存顆粒了,還有系統板級的連線、IO性能、PCB等等相關的因素,在這些因素的影響下,你的memory是否還能正常工作;
注2: checkboard這裏雖然有點類似於底層的NPSF(neighborhood pattern sensitive fault),但是這裏的錨點卻不是這個,而是:比如說我的客戶在把內存插入電腦後,使用過程中有這種pattern的數據寫入內存,會不會存在數據互相影響從而丟失的問題呢?這搞不好就是藍屏了啊!也就是說我們關注的是表層的狀態而不是底層的缺陷。
版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。本文鏈接:https://blog.csdn.net/weixin_34119545/article/details/87096872