summaryrefslogtreecommitdiffstats
path: root/paging_speed.c
diff options
context:
space:
mode:
Diffstat (limited to 'paging_speed.c')
-rw-r--r--paging_speed.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/paging_speed.c b/paging_speed.c
new file mode 100644
index 0000000..4ad56e2
--- /dev/null
+++ b/paging_speed.c
@@ -0,0 +1,137 @@
1#define _GNU_SOURCE
2
3#include <sys/mman.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <stdio.h>
8#include <stdint.h>
9#include <time.h>
10#include <unistd.h>
11#include <stdlib.h>
12#include <string.h> // strlen()
13
14#define GiB 1024l*1024l*1024l
15#define s2ns(s) ((s)*1000l*1000l*1000l)
16
17
18int seq_walk(char* mem, int len, char to_find) {
19 int num_42 = 0;
20 // Stride of 4096 bytes (one 4k page)
21 for (int i = 4096; i < len; i += 4096)
22 if (mem[i] == to_find)
23 num_42++;
24 return num_42;
25}
26
27long time_diff_ns(struct timespec start, struct timespec stop) {
28 return (s2ns(stop.tv_sec) + stop.tv_nsec) - (s2ns(start.tv_sec) + start.tv_nsec);
29}
30// TODO: take *num_42, return time
31
32//#define PAGED_FILE "/home/jbakita/1gib_random_f"
33#define PAGED_FILE "/dev/nvme0n1"
34
35int main(int argc, char **argv) {
36 int iters = 1;
37 int no_seq = 0;
38 if (argc > 1)
39 iters = atoi(argv[1]);
40 if (argc > 2) {
41 no_seq = strncmp(argv[2], "--no-seq", strlen(argv[2])) ? 1 : 0;
42 fprintf(stderr, "Skipping seq, but using no-seq emulation with demand paging\n");
43 }
44 struct timespec start, stop, seq_stop;
45 int clear_fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
46 if (clear_fd == -1) {
47 perror("Unable to open /proc/sys/vm/drop_caches");
48 return 1;
49 }
50
51 char clear_cmd = '3';
52 for (int i = 0; i < iters; i++) {
53 int fd = open(PAGED_FILE, O_RDWR);
54 if (fd == -1) {
55 perror("Unable to open " PAGED_FILE);
56 return 1;
57 }
58 // Clear page cache
59 write(clear_fd, &clear_cmd, 1);
60 // VIA MMAP
61 clock_gettime(CLOCK_MONOTONIC_RAW, &start);
62 char* mem = mmap(NULL, GiB, PROT_READ, MAP_PRIVATE, fd, 0);
63 if (mem == MAP_FAILED) {
64 perror("Unable to mmap " PAGED_FILE);
65 return 1;
66 }
67 // Fault on all the pages via a sequential walk
68 int num_42 = seq_walk(mem, GiB, 42);
69 clock_gettime(CLOCK_MONOTONIC_RAW, &stop);
70 int num_52 = 0;
71 if (no_seq)
72 num_52 = seq_walk(mem, GiB, 52);
73 clock_gettime(CLOCK_MONOTONIC_RAW, &seq_stop);
74 if (num_52)
75 fprintf(stderr, "Something is seriously wrong! Found a 52 in a buffer that should be only 42s\n");
76 long duration = (s2ns(stop.tv_sec) + stop.tv_nsec) - (s2ns(start.tv_sec) + start.tv_nsec);
77 // Emulate the time demand paging would take if we didn't have to walk
78 if (no_seq) {
79 long seq_time = time_diff_ns(stop, seq_stop);
80 duration -= seq_time;
81 }
82 if (iters == 1) {
83 printf("Took %ldus via mmap\n", duration / 1000);
84 printf("Read %d 42s of %ld expected\n", num_42, GiB/4096);
85 } else {
86 printf("%ld, ", duration / 1000);
87 }
88 munmap(mem, GiB);
89 close(fd);
90 }
91 if (iters > 1)
92 printf("\n");
93
94 for (int i = 0; i < iters; i++) {
95 char* mem;
96 int fd = open(PAGED_FILE, O_RDWR | O_DIRECT);
97 if (fd == -1) {
98 perror("Unable to open " PAGED_FILE);
99 return 1;
100 }
101 // Clear page cache
102 write(clear_fd, &clear_cmd, 1);
103 // VIA READ
104 clock_gettime(CLOCK_MONOTONIC_RAW, &start);
105 // Aligned malloc(GiB) basicially
106 int res = posix_memalign((void**)&mem, 4096, GiB);
107 if (res) {
108 fprintf(stderr, "posix_memalign() failure. Error %d.", res);
109 return 1;
110 }
111 res = read(fd, mem, GiB);
112 if (res == -1) {
113 perror("Unable to read 1GiB from /dev/nvme0n1");
114 return 1;
115 }
116 if (res < GiB) {
117 fprintf(stderr, "Unable to read the buffer all at once!");
118 return 2;
119 }
120 int num_42 = 0;
121 if (!no_seq)
122 num_42 = seq_walk(mem, GiB, 42); // Not strictly necessary, but to match mmap path overheads
123 clock_gettime(CLOCK_MONOTONIC_RAW, &stop);
124 if (iters == 1) {
125 printf("Took %ldus via read\n", ((s2ns(stop.tv_sec) + stop.tv_nsec) - (s2ns(start.tv_sec) + start.tv_nsec)) / 1000);
126 if (!no_seq)
127 printf("Read %d 42s of %ld expected\n", num_42, GiB/4096);
128 } else {
129 printf("%ld, ", ((s2ns(stop.tv_sec) + stop.tv_nsec) - (s2ns(start.tv_sec) + start.tv_nsec)) / 1000);
130 }
131 close(fd);
132 free(mem);
133 }
134 if (iters > 1)
135 printf("\n");
136 return 0;
137}