Page Cache

2020-08-30  本文已影响0人  欧阳_z

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
上一篇 下一篇

猜你喜欢

热点阅读