2012-07-06 30 views
5

我想知道在內存中緩存大文件的哪一部分。我使用的是fincore的一些代碼,它的工作方式如下:文件是mmaped,然後fincore遍歷地址空間並用mincore檢查頁面,但由於文件大小很長(幾分鐘) )。Linux:識別內存中的頁面

有沒有辦法循環使用的RAM頁面?它會更快,但這意味着我應該從某處獲得已使用頁面的列表......但是,我無法找到一個方便的系統調用來實現。

這裏談到的代碼:

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
/* } */ 

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/mman.h> 
#include <sys/sysinfo.h> 


void 
fincore(char *filename) { 
    int fd; 
    struct stat st; 

    struct sysinfo info; 
    if (sysinfo(& info)) { 
    perror("sysinfo"); 
    return; 
    } 

    void *pa = (char *)0; 
    char *vec = (char *)0; 
    size_t pageSize = getpagesize(); 
    register size_t pageIndex; 

    fd = open(filename, 0); 
    if (0 > fd) { 
     perror("open"); 
     return; 
    } 

    if (0 != fstat(fd, &st)) { 
     perror("fstat"); 
     close(fd); 
     return; 
    } 

    pa = mmap((void *)0, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); 
    if (MAP_FAILED == pa) { 
     perror("mmap"); 
     close(fd); 
     return; 
    } 

    /* vec = calloc(1, 1+st.st_size/pageSize); */ 
    /* 2.2 sec for 8 TB */ 
    vec = calloc(1, (st.st_size+pageSize-1)/pageSize); 
    if ((void *)0 == vec) { 
     perror("calloc"); 
     close(fd); 
     return; 
    } 

    /* 48 sec for 8 TB */ 
    if (0 != mincore(pa, st.st_size, vec)) { 
     fprintf(stderr, "mincore(%p, %lu, %p): %s\n", 
       pa, (unsigned long)st.st_size, vec, strerror(errno)); 
     free(vec); 
     close(fd); 
     return; 
    } 

    /* handle the results */ 
    /* 2m45s for 8 TB */ 
    for (pageIndex = 0; pageIndex <= st.st_size/pageSize; pageIndex++) { 
     if (vec[pageIndex]&1) { 
     printf("%zd\n", pageIndex); 
     } 
    } 

    free(vec); 
    vec = (char *)0; 

    munmap(pa, st.st_size); 
    close(fd); 

    return; 
} 

int main(int argc, char *argv[]) { 
    fincore(argv[1]); 

    return 0; 
} 
+2

映射一個8 TB文件需要20億4k頁面。 「mincore」的48秒運行時間表示正在檢查44.7 Mpages/sec。你認爲這可以走多快?用printf()打印數百或數十億行也不是世界上最快的事情。 – 2012-07-06 15:07:44

+0

我不希望讓mmap/mincore比這更快;我想要的是減少循環的長度,可能通過掃描較少的頁面... – wazoox 2012-07-06 15:42:29

+0

'printf'通常是非常慢的操作。將它替換爲'activePages ++'之類的東西,看看處理循環需要多少時間。注意'vec'仍然是2 GiB,甚至調用'mincore'可能會改變緩存的內容,因爲在分配給'vec'的虛擬地址空間內正在觸摸物理內存。 – 2012-07-06 15:50:29

回答

0

由誰緩存?

考慮引導後文件位於磁盤上。沒有任何部分是在記憶中。

現在打開文件並執行隨機讀取。

文件系統(例如內核)將被緩存。

C標準庫將被緩存。

內核將緩存在內核模式內存中,即用戶模式內存中的C標準庫。

如果您可以發出查詢,也可能是在查詢之後立即發出 - 在它返回給您之前 - 從緩存中刪除有問題的緩存數據。

+0

這是一個iscsi目標,所以它被內核緩存在磁盤緩存中。我想隨時監控緩存的使用情況和進化。 – wazoox 2012-07-06 15:44:11

1

對於悲觀的情況,當所有頁面或幾乎所有頁面都在RAM中時,比位圖高出許多 - 每個條目至少64比1比特。如果有這樣一個API,當查詢它關於你的20億頁時,你將不得不準備在答覆中獲得16 GB的數據。此外,處理可變長度結構(如列表)比處理固定長度數組更復雜,因此庫函數(尤其是低級系統函數)往往避免了麻煩。我也不是很確定實現(在這種情況下操作系統如何與TLB和Co進行交互),但很可能填充位圖的操作(甚至大小差異)可以比創建由於從中提取信息的操作系統和硬件級結構而產生的列表。

如果你不關心非常精細的粒度,你可以看看/proc/<PID>/smaps。對於每個映射區域,它顯示一些統計信息,包括裝入內存的多少(Rss字段)。如果出於調試的目的,用一個單獨的mmap()調用映射某個文件的某些區域(除用於執行實際任務的主映射外),您可能會在smaps中獲得單獨的條目,從而查看這些區域的單獨統計信息。你幾乎肯定無法在不殺死你的系統的情況下進行數十億次映射,但是如果文件結構合理,也許只有幾十個精心挑選的區域有單獨的統計數據可以幫助你找到你正在尋找的答案。

+0

我確實嘗試了smaps。但由於某些原因,它不會報告其他進程映射的內存頁面,所以在這種情況下它不會幫助我。我真正想要的是訪問MMU虛擬到物理地址表:) – wazoox 2012-07-06 22:03:41