前言
為一究memtester原理,現(xiàn)對(duì)其每個(gè)函數(shù)均按照如下格式進(jìn)行描述:
- 方法
- 原理
- 時(shí)間花銷
以下是對(duì)每個(gè)測(cè)試項(xiàng)的簡(jiǎn)要描述:
memtester-4.3.0 | memtester-ARM |
---|---|
int test_stuck_address(bufa, count); | (√ ) 先全部把地址值交替取反放入對(duì)應(yīng)存儲(chǔ)位置,然后再讀出比較,重復(fù)2次(官網(wǎng)的重復(fù)了16次):測(cè)試address bus |
int test_random_value(bufa, bufb, count); | (√ )等效test_random_comparison(bufa, bufb, count):數(shù)據(jù)敏感型測(cè)試用例 |
int test_xor_comparison(bufa, bufb, count); | (-) 與test_random_value比多了個(gè)異或操作,用戶場(chǎng)景之一,用例覆蓋。數(shù)據(jù)敏感/指令功能驗(yàn)證,同時(shí)可驗(yàn)證SAF; |
int test_sub_comparison(bufa, bufb, count); | (-)與test_random_value比多了個(gè)減法操作,用戶場(chǎng)景之一,用例覆蓋。數(shù)據(jù)敏感/指令功能驗(yàn)證,同時(shí)可驗(yàn)證SAF; |
int test_mul_comparison(bufa, bufb, count); | (-)與test_random_value比多了個(gè)乘法操作,用戶場(chǎng)景之一,用例覆蓋。數(shù)據(jù)敏感/指令功能驗(yàn)證,同時(shí)可驗(yàn)證SAF; |
int test_div_comparison(bufa, bufb, count); | (-)與test_random_value比多了個(gè)除法操作,用戶場(chǎng)景之一,用例覆蓋。數(shù)據(jù)敏感/指令功能驗(yàn)證,同時(shí)可驗(yàn)證SAF; |
int test_or_comparison(bufa, bufb, count); | (√ )在test_random_comparison()里面合并了,用戶場(chǎng)景之一,用例覆蓋。數(shù)據(jù)敏感/指令功能驗(yàn)證,同時(shí)可驗(yàn)證SAF; |
int test_and_comparison(bufa, bufb, count); | (√ )在test_random_comparison()里面合并了,用戶場(chǎng)景之一,用例覆蓋。數(shù)據(jù)敏感/指令功能驗(yàn)證,同時(shí)可驗(yàn)證SAF; |
int test_seqinc_comparison(bufa, bufb, count); | (√ )這是 test_blockseq_comparison的一個(gè)子集;模擬客戶壓力測(cè)試場(chǎng)景。 |
int test_solidbits_comparison(bufa, bufb, count); | (√ )固定全1后寫(xiě)入兩個(gè)buffer,然后讀出比較,然后全0寫(xiě)入讀出比較;這就是Zero-One算法,Breuer & Friedman 1976 ,檢測(cè)SAF的,算法是{w0,r0,w1,r1}時(shí)間復(fù)雜度是4N,又叫做MSCAN,驗(yàn)證每個(gè)cell能讀寫(xiě),間接測(cè)試了stuck at fault |
int test_checkerboard_comparison(bufa, bufb, count); | (√ )把設(shè)定好的幾組Data BackGround,依次寫(xiě)入,然后讀出比較 (注:論文里說(shuō)設(shè)計(jì)良好的Data background可以檢測(cè)出state coupling faults時(shí)間復(fù)雜度是4N,這是驗(yàn)證相鄰位置是否互相影響從而設(shè)計(jì)的用例。 |
int test_blockseq_comparison(bufa, bufb, count); | (√ )一次寫(xiě)一個(gè)count大小的塊,寫(xiě)的值是拿byte級(jí)的數(shù)填充32bit,然后取出對(duì)比,接著重復(fù)256次;也是壓力用例,只是次數(shù)變多了; |
int test_walkbits0_comparison(bufa, bufb, count); | (√ )就是bit=1的位置在32bit里面移動(dòng),每移動(dòng)一次就全部填滿buffer,先是從低位往高位移,再是從高位往低位移動(dòng),(這么做的目的是啥?其中的一個(gè)目的是檢測(cè)NPSF其次是CFs,其次是數(shù)據(jù)敏感型異常檢測(cè),注這里是32bit的,還有8bit的粒度更細(xì)了) |
int test_walkbits1_comparison(bufa, bufb, count); | (√ )與上同理,另注:早memtester86中這個(gè)算法叫做moving inversions algorithm |
int test_bitspread_comparison(bufa, bufb, count); | (√ )還是在32bit里面移動(dòng),只是這次移動(dòng)的不是單單的一個(gè)0或者1,而是兩個(gè)1,這兩個(gè)1之間隔著兩個(gè)空位,(是臨近耦合異常的一種data pattern變體:兩個(gè)1之間間隔1個(gè)位置,然后同步移動(dòng)) |
int test_bitflip_comparison(bufa, bufb, count); | (√ )也是32bit里面的一個(gè)bit=1不斷移動(dòng)生成data pattern然后,每個(gè)pattern均執(zhí)行:{取反交替寫(xiě)入a、b緩沖區(qū),寫(xiě)完之后檢查一遍,然后不斷重復(fù)以下步驟八次{用八個(gè)DMA從a緩沖區(qū)搬數(shù)據(jù)到b緩沖區(qū),并行搬,模擬短時(shí)間內(nèi)反復(fù)讀寫(xiě)同一位置看是否有數(shù)據(jù)丟失異常}}核心思想:短時(shí)間內(nèi)反復(fù)讀寫(xiě)同一位置。 |
int test_8bit_wide_random(bufa, bufb, count); | (√ )以char指針存值,也就是每次存8bit,粒度更細(xì); |
int test_16bit_wide_random(bufa, bufb, count); | (√ )以u(píng)nsigned short指針存值,也就是每次存16bit,不同粒度檢測(cè); |
× | int test_crosstalk_comparison(bufa, bufb, count):[32個(gè)0,接著32bit里面1個(gè)0移動(dòng)]以這樣的模型疊加寫(xiě)入內(nèi)存;(只有上行,沒(méi)像有moving inversions algorithm一樣進(jìn)行反轉(zhuǎn)) |
詳解函數(shù)
memtester-4.3.0 版本
方法test_stuck_address
函數(shù)名:int test_stuck_address(ulv *bufa, size_t count)
基本pattern按照下圖所示,j=0時(shí),先把P1的地址值寫(xiě)入對(duì)應(yīng)的內(nèi)存位置處,然后P2取反放入對(duì)應(yīng)位置處,如此反復(fù);
然后下一輪開(kāi)始,即j=1,把上述步驟反過(guò)來(lái)再進(jìn)行一遍即可;
直到16輪結(jié)束,假若發(fā)生異常就把異常的地址直接返回即可!
目的(原理)
為了驗(yàn)證是否有地址無(wú)法訪問(wèn),驗(yàn)證的是地址線。
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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
函數(shù)名:int test_random_value(ulv *bufa, ulv *bufb, size_t count)
開(kāi)了兩個(gè)Buffer區(qū)域,然后同時(shí)寫(xiě)入隨機(jī)值,寫(xiě)完count個(gè)之后,用compare_regions(bufa, bufb, count)函數(shù)來(lái)對(duì)比驗(yàn)證。
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;
}
目的(原理)
目的是測(cè)試data bus,以及某種數(shù)據(jù)pattern是否會(huì)導(dǎo)致cell無(wú)法讀寫(xiě),類似于軟件測(cè)試?yán)锩娴腗onkey test;
其中有幾個(gè)注意點(diǎn):
這里開(kāi)源版本是沒(méi)有底層加速優(yōu)化的,一個(gè)個(gè)地往內(nèi)存地址寫(xiě)數(shù)據(jù),每寫(xiě)一個(gè)就要fflush操作一些,免得數(shù)據(jù)在stdout緩沖區(qū)內(nèi)堆積而不會(huì)立即寫(xiě)入DRAM,因此我們底層優(yōu)化的時(shí)候要考慮cache的影響;
上述的對(duì)比函數(shù)就是一個(gè)一個(gè)值地對(duì)比,要是底層不做優(yōu)化地話時(shí)間花銷基本上是neon加速后的四倍;
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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移植版本
在公版的基礎(chǔ)上融合進(jìn)來(lái)與或的操作,但是還是一個(gè)一個(gè)寫(xiě),驗(yàn)證了一下全空間寫(xiě)0的時(shí)間是neon寫(xiě)的4倍。
arm平臺(tái)(平臺(tái)參數(shù)見(jiàn)上述描述)跑了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);
}
讀出對(duì)比的時(shí)間,全1GB空間實(shí)測(cè)大概花了6s的樣子(A53平臺(tái)單核1.46GHz 32bit),時(shí)間大大減少。
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;
}
而減少的時(shí)間主要是利用了neon底層加速:注釋見(jiàn)代碼
由于穿進(jìn)來(lái)的參數(shù)是(bufa, bufb, count),因此:
- r0 = bufa
- r1 = bufb
- r2 = count
基本思想就是對(duì)比,比完之后異或出現(xiàn)非零值就是出異常了,報(bào)警!返回異常值。
mctl_neon_cmp
PUSH {r3-r12, lr}
ADD r2,r2,r0 ;把count的值轉(zhuǎn)成最終的地址值了
neon_cmp
VLDM r0!,{q0-q3} ;一次從bufa加載4*128bit數(shù)據(jù)到4個(gè)neon的Q寄存器
VLDM r1!,{q4-q7} ;一次從bufb加載4*128bit數(shù)據(jù)到4個(gè)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
;上面這一段就是上圖的一個(gè)實(shí)現(xiàn),為什么一次只操作2X4Q個(gè)數(shù)據(jù),
;是因?yàn)榭偣簿?6個(gè)Q,不夠用啊!
;要是支持VEOR q0, q0,q4的話這里還可以加速的喲!
BNE rw_detect
;不為0跳轉(zhuǎn)指令
;檢測(cè)是否出現(xiàn)異常了,出現(xiàn)異常則結(jié)果不為0
;檢測(cè)是否全部對(duì)比完了
CMP r0,r2
BNE neon_cmp
;這里應(yīng)為r0是返回值,因此測(cè)試正常則賦0
MOV r0,#0x0
POP {r3-r12, pc}
rw_detect
;這里是假如中間出錯(cuò)了要進(jìn)行的操作
SUB r0,r0,#0x40
SUB r1,r1,#0x40
;bufa和bufb地址回退至4X16個(gè)32bit,及16個(gè)Q之前。
;(這里是要對(duì)16個(gè)Q值均進(jìn)行清算)
VMOV r4,r5,d16 ;d16解開(kāi)
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
函數(shù)名:nt test_walkbits1_comparison(bufa, bufb, count);
首先設(shè)定一個(gè)初始值(以walk1為例)為0x00000001,然后左移一位之后寫(xiě)入下一個(gè)地址,依此類推。
目的(原理)
This test is intended to uncover data or address bus problems both internal to the memory device as well as external.
同時(shí)也覆蓋測(cè)試臨近耦合缺陷。
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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
函數(shù)名:int test_seqinc_comparison(ulv *bufa, ulv *bufb, size_t count)
/
目的(原理)
驗(yàn)證連續(xù)按順序?qū)懯欠窆δ苷#?/p>
block模式則加上了壓力部分;
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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
函數(shù)名:int test_solidbits_comparison(ulv *bufa, ulv *bufb, size_t count)
取一個(gè)pattern(全1)然后取反交替寫(xiě)入buffer區(qū)間,然后再檢測(cè)時(shí)候有問(wèn)題,反復(fù)64次;
移植版本里面假如了hammer操作,也即短時(shí)間內(nèi)不斷快速讀寫(xiě)同一個(gè)位置,看功能是否正常。
目的(原理)
hammer異常檢測(cè);
全空間scan測(cè)試;
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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移植版本
增加了并行讀寫(xiě)操作(DMA部分)
DMA_TRAN(1,(s32)bufa,(s32)bufb,0,count << 2)參數(shù)解釋:
- “1”:是從sdram到sdram
- src_addr = bufa
- dst_addr = bufb
- 0~7八個(gè)DMA來(lái)并行搬運(yùn)數(shù)據(jù),搬運(yùn)四分之一,那這里模擬的就是對(duì)同一個(gè)位置反復(fù)不斷地讀寫(xiě)8次,最后再檢查一下有沒(méi)有出錯(cuò);
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;
}
方法
函數(shù)名:int test_bitflip_comparison(ulv *bufa, ulv *bufb, size_t count)
也是32bit里面的一個(gè)bit=1不斷移動(dòng)生成data pattern然后,每個(gè)pattern均執(zhí)行:{
取反交替寫(xiě)入a、b緩沖區(qū),寫(xiě)完之后檢查一遍,然后不斷重復(fù)以下步驟八次{
用八個(gè)DMA從a緩沖區(qū)搬數(shù)據(jù)到b緩沖區(qū),并行搬,模擬短時(shí)間內(nèi)反復(fù)讀寫(xiě)同一位置看是否有數(shù)據(jù)丟失異常}}
核心思想:短時(shí)間內(nèi)反復(fù)讀寫(xiě)同一位置。
目的(原理)
對(duì)比上面的 test_solidbits_comparison可以發(fā)現(xiàn)不同之處就在于data pattern的設(shè)計(jì),上面是固定的兩個(gè)值,這里是walking bit 1,因此這個(gè)用例是 test_solidbits_comparison和test_walkbits1_comparison的組合技能。
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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八個(gè)DMA來(lái)并行搬運(yùn)數(shù)據(jù),搬運(yùn)四分之一,那這里模擬的就是對(duì)同一個(gè)位置反復(fù)不斷地讀寫(xiě)8次,最后再檢查一下有沒(méi)有出錯(cuò);
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
函數(shù)名:int test_checkerboard_comparison(ulv *bufa, ulv *bufb, size_t count)
測(cè)64輪,每輪都是從兩個(gè)表格中取出一個(gè)data pattern來(lái)寫(xiě)入內(nèi)存,最后讀出對(duì)比即可;
目的(原理)
數(shù)據(jù)敏感型功能缺陷檢測(cè),也就是說(shuō)有可能memory就是無(wú)法存取某個(gè)值的情況,這也是從用戶視角出發(fā)的。
注:這里并沒(méi)有給出checkboard的值。
注2: 雖然這里有點(diǎn)類似于底層的NPSF(neighborhood pattern sensitive fault),但是這里的錨點(diǎn)卻不是這個(gè),而是:比如說(shuō)我的客戶在把內(nèi)存插入電腦后,使用過(guò)程中有這種pattern的數(shù)據(jù)寫(xiě)入內(nèi)存,會(huì)不會(huì)存在數(shù)據(jù)互相影響從而丟失的問(wèn)題呢?這搞不好就是藍(lán)屏了啊!也就是說(shuō)我們關(guān)注的是表層的狀態(tài)而不是底層的缺陷。
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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交替寫(xiě), 檢測(cè)stuck bit cases and many adjacent cell dependency cases.
標(biāo)準(zhǔn)算法描述如下:
然后這個(gè)地方的移植······
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;
}
方法
函數(shù)名:int test_bitspread_comparison(ulv *bufa, ulv *bufb, size_t count)
跟walkbits1比起就是data pattern變了一點(diǎn)點(diǎn)而已,其余不變,因此可以看作是walkbit1的一個(gè)擴(kuò)展測(cè)試;
walkbit1: 00000001 -> 00000010
bitspread: 00000101 -> 00001010
目的(原理)
也是主要為了檢測(cè)臨近耦合缺陷;
時(shí)間花銷
條件:
全空間1G Byte ,DDR帶寬1600M*32bit,CPU: ARM A53 (1460~1800)M* 32bit單核跑。
時(shí)間成本:
___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;
}
總結(jié)
整個(gè)memtester測(cè)試的視角就是從用戶的角度來(lái)看的,從用戶角度設(shè)立不同的測(cè)試場(chǎng)景即測(cè)試用例,然后針對(duì)性地進(jìn)行功能測(cè)試,注意是從系統(tǒng)級(jí)來(lái)測(cè)試,也就是說(shuō)關(guān)注的不單單是內(nèi)存顆粒了,還有系統(tǒng)板級(jí)的連線、IO性能、PCB等等相關(guān)的因素,在這些因素的影響下,你的memory是否還能正常工作;
注2: checkboard這里雖然有點(diǎn)類似于底層的NPSF(neighborhood pattern sensitive fault),但是這里的錨點(diǎn)卻不是這個(gè),而是:比如說(shuō)我的客戶在把內(nèi)存插入電腦后,使用過(guò)程中有這種pattern的數(shù)據(jù)寫(xiě)入內(nèi)存,會(huì)不會(huì)存在數(shù)據(jù)互相影響從而丟失的問(wèn)題呢?這搞不好就是藍(lán)屏了啊!也就是說(shuō)我們關(guān)注的是表層的狀態(tài)而不是底層的缺陷。