2013-12-09 32 views
3

我在讀向量爲:連續調用mmap,任何緩存?

int readBytes(string filename, vector<uint32_t> &v) 
{ 
    // fstat file, get filesize, etc. 

    uint32_t *filebuf = (uint32_t*)mmap(0,filesize,PROT_READ, 
             MAP_FILE|MAP_PRIVATE, 
             fhand,0); 
    v = std::vector<uint32_t>(filebuf,filebuf+numrecords); 
    munmap(filebuf, filesize); 
} 
在主

()我有兩個連續調用(純粹作爲測試):

vector<uint32_t> v(10000);  
readBytes(filename, v); 
readBytes(filename, v); 
// ... 

第二個電話幾乎總是給人一種更快的時鐘時間:

Profile time [1st call]: 0.000214141 sec 
Profile time [2nd call]: 0.000094109 sec 

一看系統調用指示塊被differend內存:

mmap(NULL, 40000, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe843ac8000 
mmap(NULL, 40000, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7fe843ac7000 

第二次調用爲什麼更快?巧合?什麼,如果有的話,被緩存?

回答

4

假設你正在談論的是* NIX-ish,那麼可能有一個頁面緩存,其工作就是緩存這種數據以獲得這種加速。除非在調用從緩存中清除這些頁面之間出現其他內容,否則它們仍然存在。

所以,在第一次調用可能有:

  1. 分配頁面
  2. 映射頁面插入進程的地址空間
  3. 從這些網頁中的數據複製到您的載體(可能是斷層從數據盤,因爲它去)

第二個電話可能發現的頁面仍然在緩存中,並且只需要:

  1. 映射頁面插入進程的地址空間
  2. 從這些頁面插入載體複製數據(它們是預故障這段時間,所以這是一個簡單的存儲操作)

實際上,我跳過了一個步驟:評論中的open/fstat步驟可能是,也可通過inode緩存加速

+0

是的 - linux - 我剛剛添加上面的標籤。所以這個過程爲第一個呼叫建立頁表,而不是第二個呼叫。我鬆散地將此與創建新的虛擬內存區域聯繫起來。這是否總是隻在這個過程中進行第一次調用,或者是因爲調用的相似性而在此處執行了一次? –

+0

進程擁有的頁表由每個mmap/munmap調用修改。插入/從表中插入的頁面由內核頁面緩存擁有,並保留在調用之間。 – Useless

3

請記住,您的程序看到虛擬內存。有一個映射表(「頁表」),將您的程序看到的虛擬地址映射到真實的物理內存。操作系統將確保這兩個mmap()調用將您的程序看到的兩個不同的虛擬地址映射到相同的物理內存。所以數據只需要從磁盤加載一次。

更多DETAL:

  • 首先mmap()的:OS只是記錄映射
  • 當你真正嘗試讀取數據:A「頁面錯誤」情況,因爲數據是不是在內存。操作系統捕捉到這一點,從磁盤讀取數據到磁盤緩存,並更新頁面表,以便程序可以直接從磁盤緩存中讀取數據,然後自動恢復程序。
  • 首先munmap():操作系統禁用映射,並更新您的頁面表,因此您不能再讀取該文件。請注意,該文件仍在操作系統的磁盤緩存中。
  • 第二個mmap():OS只記錄映射
  • 當您實際嘗試讀取數據時:發生「頁面錯誤」,因爲數據未映射。操作系統捕捉到這些數據,注意到數據已經存在於其磁盤緩存中,並更新頁表以便程序可以直接從磁盤緩存中讀取數據,然後自動恢復程序。
  • 第二個munmap():操作系統禁用映射,並更新您的頁面表,因此您無法再讀取該文件。請注意,該文件仍在操作系統的磁盤緩存中。