File size: 2,295 Bytes
00d4f8c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Count how many pages of a file are resident in the page cache (mincore(2)).
// This is how we check "did the pager really bypass the page cache?": if the
// expert weights were served from cache, the model file would show up as resident.
//
// usage: pagecache_resident <file> [file...]
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char ** argv) {
    if (argc < 2) { fprintf(stderr, "usage: %s [--evict] <file> [file...]\n", argv[0]); return 1; }
    int argi = 1;
    int evict = 0;
    if (strcmp(argv[1], "--evict") == 0) { evict = 1; argi = 2; }
    const long page = sysconf(_SC_PAGESIZE);
    unsigned long long tot_r = 0, tot_s = 0;

    for (int i = argi; i < argc; i++) {
        const char * path = argv[i];
        int fd = open(path, O_RDONLY);
        if (fd < 0) { perror(path); return 1; }
        struct stat st;
        fstat(fd, &st);
        if (evict) {
            // per-file eviction of clean page-cache pages (no root needed)
            posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
        }
        const size_t size = (size_t) st.st_size;
        char * addr = (char *) mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
        if (addr == MAP_FAILED) { perror("mmap"); return 1; }

        const size_t npages = (size + page - 1) / page;
        unsigned char * vec = (unsigned char *) malloc(npages);
        if (mincore(addr, size, vec) != 0) { perror("mincore"); return 1; }
        unsigned long long res = 0;
        for (size_t p = 0; p < npages; p++) {
            res += (vec[p] & 1);
        }
        free(vec);
        munmap(addr, size);
        close(fd);

        const char * base = strrchr(path, '/');
        base = base ? base + 1 : path;
        printf("%-48s resident %8.3f GiB / %8.3f GiB  (%5.1f %%)\n",
               base, res * (double) page / 1073741824.0, size / 1073741824.0,
               100.0 * (double) res * (double) page / (double) size);
        tot_r += res * (unsigned long long) page;
        tot_s += size;
    }
    if (argc > argi + 1) {
        printf("%-48s resident %8.3f GiB / %8.3f GiB\n", "TOTAL",
               tot_r / 1073741824.0, tot_s / 1073741824.0);
    }
    return 0;
}