1#include "pagingtest.h"
2
3#include <errno.h>
4#include <fcntl.h>
5#include <stdbool.h>
6#include <stdio.h>
7#include <stdint.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/mman.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15#define TEST_RUNS 10
16#define ALLOC_SIZE (10 * 1024 * 1024)
17#define FILE_SIZE (10 * 1024 * 1024)
18
19int create_tmp_file(char *filename, off_t size) {
20    void *buf;
21    uint8_t *tmp_buf;
22    off_t tmp_size;
23    ssize_t rc;
24    int fd;
25    int urandom;
26
27    fd = mkstemp(filename);
28    if (fd < 0) {
29        fprintf(stderr, "unable to create temp file: %s\n", strerror(errno));
30        goto err_mkstemp;
31    }
32
33    urandom = open("/dev/urandom", O_RDONLY);
34    if (urandom < 0) {
35        fprintf(stderr, "unable to open urandom: %s\n", strerror(errno));
36        goto err_open;
37    }
38
39    if (unlink(filename)) {
40        fprintf(stderr, "unable to unlink temp file: %s\n", strerror(errno));
41        goto err_unlink;
42    }
43
44    if (ftruncate(fd, size)) {
45        fprintf(stderr, "unable to allocate temp file: %s\n", strerror(errno));
46        goto err_truncate;
47    }
48
49    buf = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
50    if (buf == (void *)-1) {
51        fprintf(stderr, "unable to mmap temp file: %s\n", strerror(errno));
52        goto err_mmap;
53    }
54
55    tmp_buf = buf;
56    tmp_size = size;
57    do {
58        rc = read(urandom, tmp_buf, tmp_size);
59
60        if (rc < 0) {
61            fprintf(stderr, "write random data failed: %s\n", strerror(errno));
62            goto err;
63        }
64
65        tmp_buf += rc;
66        tmp_size -= rc;
67    } while (tmp_size > 0);
68
69    if (madvise(buf, size, MADV_DONTNEED)) {
70        fprintf(stderr, "madvise DONTNEED failed: %s\n", strerror(errno));
71        goto err;
72    }
73
74    if (fsync(fd) < 0) {
75        fprintf(stderr, "fsync failed: %s\n", strerror(errno));
76        goto err;
77    }
78
79    rc = posix_fadvise(fd, 0, size, POSIX_FADV_DONTNEED);
80    if (rc) {
81        fprintf(stderr, "fadvise DONTNEED failed: %s\n", strerror(errno));
82        goto err;
83    }
84
85    munmap(buf, size);
86    close(urandom);
87    return fd;
88
89err:
90    munmap(buf, size);
91err_mmap:
92err_truncate:
93err_unlink:
94    close(urandom);
95err_open:
96    close(fd);
97err_mkstemp:
98    return -1;
99}
100
101unsigned char *alloc_mincore_vec(size_t size) {
102    unsigned char *vec;
103
104    vec = malloc(mincore_vec_len(size));
105    if (vec == NULL) {
106        fprintf(stderr, "malloc failed\n");
107    }
108
109    return vec;
110}
111
112bool check_caching(void *buf, unsigned char *vec, size_t size, bool is_cached) {
113    bool ret = true;
114    size_t i;
115
116    if (mincore(buf, size, vec)) {
117        fprintf(stderr, "mincore failed: %s\n", strerror(errno));
118        return false;
119    }
120
121    if (is_cached) {
122        for (i = 0; i < mincore_vec_len(size); i++) {
123            if (!(vec[i] & 0x1)) {
124                fprintf(stderr, "found an uncached page at page offset %zd\n", i);
125                ret = false;
126            }
127        }
128    } else {
129        for (i = 0; i < mincore_vec_len(size); i++) {
130            if (vec[i] & 0x1) {
131                fprintf(stderr, "found a cached page at page offset %zd\n", i);
132                ret = false;
133            }
134        }
135    }
136
137    return ret;
138}
139
140int main(int argc, char **argv) {
141    unsigned long long alloc_size = 0ULL;
142    unsigned long long file_size = 0ULL;
143    int test_runs = 0;
144    int rc;
145
146    //arguments: <program> [test_runs [alloc_size [file_size]]]
147    if (argc >= 2) {
148        test_runs = atoi(argv[1]);
149    }
150    if (test_runs <= 0) {
151        test_runs = TEST_RUNS;
152    }
153    if (argc >= 3) {
154        alloc_size = strtoull(argv[2], NULL, 10);
155    }
156    if (!alloc_size) {
157        alloc_size = ALLOC_SIZE;
158    }
159    if (argc >= 4) {
160        file_size = strtoull(argv[3], NULL, 10);
161    }
162    if (!file_size) {
163        file_size = FILE_SIZE;
164    }
165
166    rc = mmap_test(test_runs, alloc_size);
167    if (rc) {
168        return rc;
169    }
170    rc = pageinout_test(test_runs, true, file_size);
171    if (rc) {
172        return rc;
173    }
174    rc = pageinout_test(test_runs, false, file_size);
175    if (rc) {
176        return rc;
177    }
178    rc = thrashing_test(test_runs, true);
179    if (rc) {
180        return rc;
181    }
182    rc = thrashing_test(test_runs, false);
183
184    return rc;
185}
186