有一天,我無意中發現了一位用戶試圖監控其虛擬機器中 RAM 效能的程式碼。 我不會給出這個代碼(那裡有一個“腳布”),我只會留下最重要的部分。 所以,貓咪在工作室裡!
#include <sys/time.h>
#include <string.h>
#include <iostream>
#define CNT 1024
#define SIZE (1024*1024)
int main() {
struct timeval start;
struct timeval end;
long millis;
double gbs;
char ** buffers;
buffers = new char*[CNT];
for (int i=0;i<CNT;i++) {
buffers[i] = new char[SIZE];
}
gettimeofday(&start, NULL);
for (int i=0;i<CNT;i++) {
memset(buffers[i], 0, SIZE);
}
gettimeofday(&end, NULL);
millis = (end.tv_sec - start.tv_sec) * 1000 +
(end.tv_usec - start.tv_usec) / 1000;
gbs = 1000.0 / millis;
std::cout << gbs << " GB/sn";
for (int i=0;i<CNT;i++) {
delete buffers[i];
}
delete buffers;
return 0;
}
很簡單 - 分配記憶體並向其中寫入 XNUMX GB。 這個測試顯示了什麼?
$ ./記憶體測試
4.06504 GB / s
大約 4GB/秒。
什麼?!?!
如何?!?!?
這是Core i7(雖然不是最新的),DDR4,處理器幾乎沒有加載 - 為什麼?!?!
答案一如既往地異常普通。
new 運算子(順便說一句,就像 malloc 函數)實際上並不會分配記憶體。 透過這個調用,分配器會查看記憶體池中的空閒位置列表,如果沒有,則調用 sbrk() 來增加資料段,然後將新位置的位址參考傳回給程式分配。
問題是分配的區域完全是虛擬的。 沒有分配實際記憶體頁。
當第一次訪問這個分配的段落中的每個頁面時,MMU「射擊」頁面錯誤,之後正在訪問的虛擬頁面被分配一個真實的頁面。
因此,實際上我們測試的不是匯流排和RAM模組的效能,而是作業系統的MMU和VMM的效能。 而為了測試RAM的真實效能,我們只需要對分配的區域進行一次初始化即可。 例如這樣:
#include <sys/time.h>
#include <string.h>
#include <iostream>
#define CNT 1024
#define SIZE (1024*1024)
int main() {
struct timeval start;
struct timeval end;
long millis;
double gbs;
char ** buffers;
buffers = new char*[CNT];
for (int i=0;i<CNT;i++) {
// FIXED HERE!!!
buffers[i] = new char[SIZE](); // Add brackets, &$# !!!
}
gettimeofday(&start, NULL);
for (int i=0;i<CNT;i++) {
memset(buffers[i], 0, SIZE);
}
gettimeofday(&end, NULL);
millis = (end.tv_sec - start.tv_sec) * 1000 +
(end.tv_usec - start.tv_usec) / 1000;
gbs = 1000.0 / millis;
std::cout << gbs << " GB/sn";
for (int i=0;i<CNT;i++) {
delete buffers[i];
}
delete buffers;
return 0;
}
也就是說,我們只需使用預設值(char 0)初始化分配的緩衝區。
我們檢查:
$ ./記憶體測試
28.5714 GB / s
另一件事。
這個故事的寓意是——如果您需要大緩衝區才能快速工作,請不要忘記初始化它們。
來源: www.habr.com