1#include <errno.h>
2#include <fcntl.h>
3#include <stdbool.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/mman.h>
8#include <sys/time.h>
9
10#include "pagingtest.h"
11
12int pageinout_test(int test_runs, bool cache, unsigned long long file_size) {
13    int fd;
14    char tmpname[] = "pageinoutXXXXXX";
15    unsigned char *vec;
16    int i;
17    unsigned long long j;
18    volatile char *buf;
19    int ret = -1;
20    int rc;
21    struct timeval begin_time, end_time, elapsed_time, total_time_in, total_time_out;
22    long pagesize = sysconf(_SC_PAGE_SIZE);
23
24    timerclear(&total_time_in);
25    timerclear(&total_time_out);
26
27    fd = create_tmp_file(tmpname, file_size);
28    if (fd < 0) {
29        return -1;
30    }
31
32    vec = alloc_mincore_vec(file_size);
33    if (vec == NULL) {
34        goto err_alloc;
35    }
36
37    buf = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
38    if (buf == ((void *)-1)) {
39        fprintf(stderr, "Failed to mmap file: %s\n", strerror(errno));
40        goto err_mmap;
41    }
42
43    if (!check_caching((void *)buf, vec, file_size, false)) {
44        goto err;
45    }
46
47    if (!cache) {
48        //madvise and fadvise as random to prevent prefetching
49        rc = madvise((void *)buf, file_size, MADV_RANDOM) ||
50               posix_fadvise(fd, 0, file_size, POSIX_FADV_RANDOM);
51        if (rc) {
52            goto err;
53        }
54    }
55
56    for (i = 0; i < test_runs; i++) {
57        gettimeofday(&begin_time, NULL);
58        //read every page into the page cache
59        for (j = 0; j < file_size; j += pagesize) {
60            buf[j];
61        }
62        gettimeofday(&end_time, NULL);
63
64        timersub(&end_time, &begin_time, &elapsed_time);
65        timeradd(&total_time_in, &elapsed_time, &total_time_in);
66
67        if (!check_caching((void *)buf, vec, file_size, true)) {
68            goto err;
69        }
70
71        gettimeofday(&begin_time, NULL);
72        rc = madvise((void *)buf, file_size, MADV_DONTNEED) ||
73               posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED);
74        gettimeofday(&end_time, NULL);
75        if (rc) {
76            fprintf(stderr, "posix_fadvise/madvise DONTNEED failed\n");
77            goto err;
78        }
79
80        timersub(&end_time, &begin_time, &elapsed_time);
81        timeradd(&total_time_out, &elapsed_time, &total_time_out);
82
83        if (!check_caching((void *)buf, vec, file_size, false)) {
84            goto err;
85        }
86    }
87
88    printf("%scached page-in: %llu MB/s\n", cache ? "" : "un",
89             (file_size * test_runs * USEC_PER_SEC) /
90             (1024 * 1024 * (total_time_in.tv_sec * USEC_PER_SEC + total_time_in.tv_usec)));
91    printf("%scached page-out (clean): %llu MB/s\n", cache ? "" : "un",
92             (file_size * test_runs * USEC_PER_SEC) /
93             (1024 * 1024 * (total_time_out.tv_sec * USEC_PER_SEC + total_time_out.tv_usec)));
94
95    ret = 0;
96
97err:
98    munmap((void *)buf, file_size);
99err_mmap:
100    free(vec);
101err_alloc:
102    close(fd);
103    return ret;
104}
105