美文网首页
Page Cache

Page Cache

作者: 欧阳_z | 来源:发表于2020-08-30 20:31 被阅读0次

    1、简洁
    Page Cache 存在于内核,目的是为了减少 I/O,提升应用的 I/O 速度。

    2、速度对比
    生成一个 200 MB 的文件用于测试:

    ~/tmp$ dd if=/dev/urandom of=~/tmp/200.bin bs=1M count=200
    

    因为有缓存,可以看到速度很快:

    ~/tmp$ dd if=200.bin of=/dev/null bs=1M count=200
    200+0 records in
    200+0 records out
    209715200 bytes (210 MB, 200 MiB) copied, 0.0363743 s, 5.8 GB/s
    

    清理缓存之后,速度比较慢:

    ~/tmp$ sync && sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
    ~/tmp$ dd if=200.bin of=/dev/null bs=1M count=200
    200+0 records in
    200+0 records out
    209715200 bytes (210 MB, 200 MiB) copied, 0.506025 s, 414 MB/s
    

    一个是 5.8 GB/s ,一个是 414 MB/s,对比十分明显。

    3、vmtouch

    sudo apt install vmtouch
    

    源码在 https://github.com/hoytech/vmtouch
    vmtouch 可以查询 文件或目录是否有缓存,开始是100%,清理缓存之后是0%

    ~/tmp$ vmtouch 200.bin 
               Files: 1
         Directories: 0
      Resident Pages: 51200/51200  200M/200M  100%
             Elapsed: 0.003029 seconds
    ~/tmp$ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
    ~/tmp$ vmtouch 200.bin 
               Files: 1
         Directories: 0
      Resident Pages: 0/51200  0/200M  0%
             Elapsed: 0.002153 seconds
    ~/tmp$ 
    

    -e 选项可以仅清除指定文件的缓存:

    ~/tmp$ vmtouch 200.bin 
               Files: 1
         Directories: 0
      Resident Pages: 51200/51200  200M/200M  100%
             Elapsed: 0.004441 seconds
    ~/tmp$ vmtouch -e 200.bin 
               Files: 1
         Directories: 0
       Evicted Pages: 51200 (200M)
             Elapsed: 0.01934 seconds
    ~/tmp$ vmtouch 200.bin 
               Files: 1
         Directories: 0
      Resident Pages: 0/51200  0/200M  0%
             Elapsed: 0.001222 seconds
    

    4、vmtouch 的实现原理
    下面写一个测试程序,主要由 mmapmincore 两个系统调用实现,mincore 描述文件的哪些页在内核中,最低有效位表示页面是否驻留在内核中:

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    #include <errno.h>
    #include <fcntl.h>
    
    unsigned long get_file_size(const char *path)
    {  
        unsigned long filesize = -1;      
        struct stat statbuff;  
        if(stat(path, &statbuff) < 0)
        {  
            return filesize;  
        }
        else
        {  
            filesize = statbuff.st_size;  
        }  
        return filesize;  
    }
    
    void vmtouch_file(char *path)
    {
        int fd = open(path, O_RDONLY, 0);
        if (fd == -1)
        {
            fprintf(stderr, "open(%s): %s\n", path, strerror(errno));
            return;
        }
    
        long PAGE_SIZE = sysconf(_SC_PAGESIZE); // 4096
        int64_t file_bytes = get_file_size(path);
        int64_t file_pages = (file_bytes + PAGE_SIZE -1) / PAGE_SIZE;
        char *mincore_array = malloc(file_pages);
        if (mincore_array == NULL)
        {
            fprintf(stderr, "malloc: FATAL: %s\n", strerror(errno));
            goto fail;
        }
    
        void *mem = mmap(NULL, file_bytes, PROT_READ, MAP_SHARED, fd, 0);
        if (mem == MAP_FAILED)
        {
            fprintf(stderr, "mmap(%s): %s\n", path, strerror(errno));
            goto fail;
        }
    
        if (mincore(mem, file_bytes, (void*)mincore_array))
        {
            fprintf(stderr, "mincore: FATAL: %s\n", strerror(errno));
            goto fail;
        }
    
        int i;
        int64_t total_pages_in_core = 0;
        for (i = 0; i< file_pages; i++)
        {
            if ( mincore_array[i] & 0x1 )
            {
                total_pages_in_core++;
            }
        }
    
        printf("Pages: %ld/%ld  ", total_pages_in_core, file_pages);
        printf("%.3g%% \n", 100.0*total_pages_in_core/file_pages);
    
    fail:
        if (mincore_array)
        {
            free(mincore_array);
        }
        if (mem)
        {
            if (munmap(mem, file_bytes)) 
            {
                fprintf(stderr, "munmap: %s\n", strerror(errno));
            }
        }
        if (fd != -1)
        {
            close(fd);
        }
    }
    
    int main(int argc, char* argv[])
    {
        if (argc != 2)
            return -1;
        vmtouch_file(argv[1]);
    
        return 0;
    }
    

    测试效果,清缓存之前是100%,清缓存之后是0%

    ~/tmp$ vmtouch 200.bin 
               Files: 1
         Directories: 0
      Resident Pages: 51200/51200  200M/200M  100%
             Elapsed: 0.004504 seconds
    ~/tmp$ ./a.out 200.bin 
    Pages: 51200/51200  100% 
    ~/tmp$ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
    ~/tmp$ ./a.out 200.bin 
    Pages: 0/51200  0% 
    ~/tmp$ vmtouch 200.bin 
               Files: 1
         Directories: 0
      Resident Pages: 0/51200  0/200M  0%
             Elapsed: 0.002726 seconds
    

    相关文章

      网友评论

          本文标题:Page Cache

          本文链接:https://www.haomeiwen.com/subject/qtoesktx.html