? ? ?今天我們繼續redis源碼test測試包下的其他文件,今天看完的是memtest文件,翻譯器起來,就是memory test 內存檢測的意思,這個文件雖然說代碼量不是很多,但是里面的提及了很多東西,也給我漲了很多見識,網上關于memtest這種類似的redis內部邊緣的文件解析基本沒有,所以自己從頭開始學習。機器的內存檢測會和機器的CPU位數有關,32位或64位會影響后面的一些宏定義參數。首先亮出memtest中的API:
~~~
/* 內存檢測API */
void memtest_progress_start(char *title, int pass) /* 內存檢測加載開始,輸出開始的一些圖線顯示 */
void memtest_progress_end(void) /* progress bar加載完再次清屏操作 */
void memtest_progress_step(size_t curr, size_t size, char c) /* progress填充自己設置的字符串 */
void memtest_addressing(unsigned long *l, size_t bytes) /* 地址檢測方法 */
void memtest_fill_random(unsigned long *l, size_t bytes) /* 隨機填充內存 */
void memtest_fill_value(unsigned long *l, size_t bytes, unsigned long v1, unsigned long v2, char sym) /* 像上面的方法,只不過這是特定2種值的填充v1,v2 */
void memtest_compare(unsigned long *l, size_t bytes) /* 內存比較方法 */
void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int times) /* 進行多次內存compare比較操作 */
void memtest_test(size_t megabytes, int passes) /* 整個內存檢測類操作的測試方法,passes為目標的循環數 */
void memtest_non_destructive_invert(void *addr, size_t size) /* 將內存地址,進行了按位取反操作,不具有對數據的破壞性 */
void memtest_non_destructive_swap(void *addr, size_t size) /* 將內存地址,2個,2個內部之間做交換,同樣不對數據具有破壞性 */
void memtest(size_t megabytes, int passes) /* 開發給整個系統使用的內存檢測方法 */
~~~
里面主要的方法就幾個,每當一個內存檢測的開始,都會出現progress bar的圖線輸出:
~~~
/* 內存檢測加載開始,輸出開始的一些圖線顯示 */
void memtest_progress_start(char *title, int pass) {
int j;
/*這里其實包含2個命令,"\xlb[H","xlb[2j",后面的命令是主要的操作
*"\x1b" 是ESC的16進制ASCII碼值,這里也可經表示成八進制的\033,
*[是一個CSI(Control sequence introducer),轉義序列的作用由最后一個字符決定的,
*這里J表示刪除,默認情況下它刪除從當前光標處到行尾的內容,
*這里的2為參數,它表示刪除所有的顯示內容。也可以使用printf "\x1b[2J"。*/
//現定位home最開始的位置,然后實現請屏幕操作
printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
/* Fill with dots. */
/* 輸出.符號填充屏幕 */
for (j = 0; j < ws.ws_col*(ws.ws_row-2); j++) printf(".");
printf("Please keep the test running several minutes per GB of memory.\n");
printf("Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/");
//最后一個參數變了,為K,意義也不一樣了變成刪除當前行操作
printf("\x1b[H\x1b[2K"); /* Cursor home, clear current line. */
printf("%s [%d]\n", title, pass); /* Print title. */
progress_printed = 0;
//求出填滿progress bar所需點的個數
progress_full = ws.ws_col*(ws.ws_row-3);
fflush(stdout);
}
~~~
我在里面解釋了一下清屏操作的,printf輸出形式。內存地址有效性的核心方法;
~~~
/* Test that addressing is fine. Every location is populated with its own
* address, and finally verified. This test is very fast but may detect
* ASAP big issues with the memory subsystem. */
/* 此方法是測試內存地址是否有效,此種檢測的速度是非常快的,但可能會檢測出ASAP的巨大問題 */
/* ASAP網上查了下:(可能為)Automated Statistical Analysis Programme 自動統計分析程序 */
void memtest_addressing(unsigned long *l, size_t bytes) {
//算出地址的長度
unsigned long words = bytes/sizeof(unsigned long);
unsigned long j, *p;
/* Fill */
p = l;
for (j = 0; j < words; j++) {
//將(unsigned long)p強制類型轉換到此時的*p,后面以此來判斷,沒有轉換成功,說明存在內存地址的問題
*p = (unsigned long)p;
p++;
//用A字符填充部分progress bar
if ((j & 0xffff) == 0) memtest_progress_step(j,words*2,'A');
}
/* Test */
p = l;
for (j = 0; j < words; j++) {
//比較Address的關鍵在于
if (*p != (unsigned long)p) {
printf("\n***MEMORY ADDRESSING ERROR: %p contains %lu\n",
(void*) p, *p);
exit(1);
}
p++;
if ((j & 0xffff) == 0) memtest_progress_step(j+words,words*2,'A');
}
}
~~~
為什么這樣的方法去檢測,本人也是帶著比較疑惑的感覺。在內存檢測中,內存地址有效性的檢查只是其中的一個方法,還有一個是內存地址的填充測試,分為隨機填充,和給定值的填充。下面給出隨機填充的方法實現:
~~~
/* Fill words stepping a single page at every write, so we continue to
* touch all the pages in the smallest amount of time reducing the
* effectiveness of caches, and making it hard for the OS to transfer
* pages on the swap. */
/* 在每次寫操作的時候,在單頁上填滿整個字符,這樣可以做到最快速的觸及所有的頁面 */
/* 減少了低效率的緩存使用,但是會讓分區在轉移頁面時會比較困難 */
/* 隨機填充內存 */
void memtest_fill_random(unsigned long *l, size_t bytes) {
unsigned long step = 4096/sizeof(unsigned long);
unsigned long words = bytes/sizeof(unsigned long)/2;
unsigned long iwords = words/step; /* words per iteration */
unsigned long off, w, *l1, *l2;
assert((bytes & 4095) == 0);
for (off = 0; off < step; off++) {
l1 = l+off;
l2 = l1+words;
for (w = 0; w < iwords; w++) {
//下面的rand()達到了隨機存儲的目的
#ifdef MEMTEST_32BIT
*l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
(((unsigned long) (rand()&0xffff)) << 16);
#else
*l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
(((unsigned long) (rand()&0xffff)) << 16) |
(((unsigned long) (rand()&0xffff)) << 32) |
(((unsigned long) (rand()&0xffff)) << 48);
#endif
l1 += step;
l2 += step;
if ((w & 0xffff) == 0)
memtest_progress_step(w+iwords*off,words,'R');
}
}
}
~~~
填充內存的好處是訪問頁面速度更快,不會出現斷斷續續的內存片,但是做頁面交換的時候,由于沒有空間,效率恐怕會比較低下。給定數值的填充與上面的類似,不展開說了。那么,內存測試程序到底是測哪些東西的呢,也就是說,他這個文件開放給外部的一個最直接的test方法是什么呢?
~~~
/* 整個內存檢測類操作的測試方法,passes為目標的循環數 */
void memtest_test(size_t megabytes, int passes) {
size_t bytes = megabytes*1024*1024;
unsigned long *m = malloc(bytes);
int pass = 0;
if (m == NULL) {
fprintf(stderr,"Unable to allocate %zu megabytes: %s",
megabytes, strerror(errno));
exit(1);
}
//必須經過passes論循環測試
while (pass != passes) {
pass++;
//地址檢測
memtest_progress_start("Addressing test",pass);
memtest_addressing(m,bytes);
memtest_progress_end();
//隨機填充檢測
memtest_progress_start("Random fill",pass);
memtest_fill_random(m,bytes);
memtest_progress_end();
//填充后比較四次
memtest_compare_times(m,bytes,pass,4);
//給定數值填充,這里稱為Solid fill固態填充
memtest_progress_start("Solid fill",pass);
memtest_fill_value(m,bytes,0,(unsigned long)-1,'S');
memtest_progress_end();
//填充后比較四次
memtest_compare_times(m,bytes,pass,4);
//也是屬于給定數值填充,這里叫Checkerboard fill鍵盤填充
memtest_progress_start("Checkerboard fill",pass);
memtest_fill_value(m,bytes,ULONG_ONEZERO,ULONG_ZEROONE,'C');
memtest_progress_end();
//填充后比較四次
memtest_compare_times(m,bytes,pass,4);
}
free(m);
}
~~~
可以看見,分為4中情況,1內存地址測試,2,3,4都為填充測試,分為3種類型的填充Random fill, Solid fill, Checkboard fill 。填充之后再做內存比較,這里的內存比較是在內存內部做前半部分的內存和后半部分的內存比較操作。在memtest文件的最后,提到了一個這樣的方法:
~~~
/* 開發給整個系統使用的內存檢測方法 */
void memtest(size_t megabytes, int passes) {
if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
ws.ws_col = 80;
ws.ws_row = 20;
}
memtest_test(megabytes,passes);
printf("\nYour memory passed this test.\n");
printf("Please if you are still in doubt use the following two tools:\n");
printf("1) memtest86: http://www.memtest86.com/\n");
printf("2) memtester: http://pyropus.ca/software/memtester/\n");
exit(0);
}
~~~
這里提到了memtester和memtest86,上網查了一下,大體如下:
* * memtest和memtest86是2款內存檢測軟件?
* memtest不但可以徹底的檢測出內存的穩定度,還可同時測試記憶的儲存與檢索數據的能力,讓你可以確實掌控到目前你機器上正在使用的內存到底可不可信賴。?
* MemTest是一個綠色軟件,直接點擊執行文件即可運行?
* memtest86這是一款小巧而專業的內存測試程序,是在著名的內存測試軟件Memtest86基礎上開發的。?
* Memtest86+的安裝和使用和其它內存測試軟件有些不同,因為他不能在Windows下運行。
* 不過還是有四種方式可以運行此程序,分別為ISO引導盤、Linux下使用的bin文件、
* USB啟動盤使用的EXE文件和軟盤引導制作包。由于Memtest86+測試耗時較長,因此它不僅可以用于內存測試,還可以用于系統穩定性測試。Memtest86+測試完畢后,
* 按下“Esc”鍵退出并重新啟動系統。?
- 前言
- (一)--Redis結構解析
- (二)--結構體分析(1)
- (三)---dict哈希結構
- (四)-- sds字符串
- (五)--- sparkline微線圖
- (六)--- ziplist壓縮列表
- (七)--- zipmap壓縮圖
- (八)--- t_hash哈希轉換
- (九)--- t_list,t_string的分析
- (十)--- testhelp.h小型測試框架和redis-check-aof.c日志檢測
- (十一)--- memtest內存檢測
- (十二)--- redis-check-dump本地數據庫檢測
- (十三)--- redis-benchmark性能測試
- (十四)--- rdb.c本地數據庫操作
- (十五)--- aof-append only file解析
- (十六)--- config配置文件
- (十七)--- multi事務操作
- (十八)--- db.c內存數據庫操作
- (十九)--- replication主從數據復制的實現
- (二十)--- ae事件驅動
- (二十一)--- anet網絡通信的封裝
- (二十二)--- networking網絡協議傳輸
- (二十三)--- CRC循環冗余算法和RAND隨機數算法
- (二十四)--- tool工具類(2)
- (二十五)--- zmalloc內存分配實現
- (二十六)--- slowLog和hyperloglog
- (二十七)--- rio系統I/O的封裝
- (二十八)--- object創建和釋放redisObject對象
- (二十九)--- bio后臺I/O服務的實現
- (三十)--- pubsub發布訂閱模式
- (三十一)--- latency延遲分析處理
- (三十二)--- redis-cli.c客戶端命令行接口的實現(1)
- (三十三)--- redis-cli.c客戶端命令行接口的實現(2)
- (三十四)--- redis.h服務端的實現分析(1)
- (三十五)--- redis.c服務端的實現分析(2)
- (三十六)--- Redis中的11大優秀設計