diff options
Diffstat (limited to 'directio_paging_speed.c')
-rw-r--r-- | directio_paging_speed.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/directio_paging_speed.c b/directio_paging_speed.c index b0a01d3..9dd6598 100644 --- a/directio_paging_speed.c +++ b/directio_paging_speed.c | |||
@@ -1,19 +1,34 @@ | |||
1 | /** | ||
2 | * Copyright 2022 Joshua Bakita | ||
3 | * This program clocks how long it takes to read, and write, a 1GiB buffer via | ||
4 | * Linux direct I/O. | ||
5 | * | ||
6 | * More precisely, this program clocks: | ||
7 | * write(random_buffer); | ||
8 | * free(random_buffer); | ||
9 | * for writing data via direct I/O, and | ||
10 | * malloc(big_buffer); | ||
11 | * read(big_buffer); | ||
12 | * for reading in data via direct I/O. `random_buffer` is a preinitialized 1GiB | ||
13 | * buffer of random non-zero bytes. | ||
14 | */ | ||
1 | #define _GNU_SOURCE | 15 | #define _GNU_SOURCE |
2 | 16 | ||
3 | #include <sys/mman.h> | ||
4 | #include <sys/types.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <fcntl.h> | 17 | #include <fcntl.h> |
7 | #include <stdio.h> | ||
8 | #include <stdint.h> | 18 | #include <stdint.h> |
19 | #include <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <sys/mman.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <sys/types.h> | ||
9 | #include <time.h> | 24 | #include <time.h> |
10 | #include <unistd.h> | 25 | #include <unistd.h> |
11 | #include <stdlib.h> | ||
12 | 26 | ||
13 | #define GiB 1024l*1024l*1024l | 27 | #define GiB 1024l*1024l*1024l |
14 | #define s2ns(s) ((s)*1000l*1000l*1000l) | 28 | #define s2ns(s) ((s)*1000l*1000l*1000l) |
15 | #define ns2us(ns) ((ns)/1000l) | 29 | #define ns2us(ns) ((ns)/1000l) |
16 | #define PAGED_FILE "/dev/nvme0n1" | 30 | #define PAGED_FILE "/dev/nvme0n1" |
31 | #define CLEAR_PAGECACHE_DENTRIES_INODES "3" | ||
17 | int max(int x, int y) {return x > y ? x : y;} | 32 | int max(int x, int y) {return x > y ? x : y;} |
18 | 33 | ||
19 | // Original function from copy_only.cu | 34 | // Original function from copy_only.cu |
@@ -31,16 +46,24 @@ uint64_t count_zero(char* buf, uint64_t buf_len) { | |||
31 | return num_zeros; | 46 | return num_zeros; |
32 | } | 47 | } |
33 | 48 | ||
49 | // Subtract first parameter from second parameter. Return as nanoseconds. | ||
34 | long time_diff_ns(struct timespec start, struct timespec stop) { | 50 | long time_diff_ns(struct timespec start, struct timespec stop) { |
35 | return (s2ns(stop.tv_sec) + stop.tv_nsec) - (s2ns(start.tv_sec) + start.tv_nsec); | 51 | return (s2ns(stop.tv_sec) + stop.tv_nsec) - (s2ns(start.tv_sec) + start.tv_nsec); |
36 | } | 52 | } |
37 | 53 | ||
38 | int main(int argc, char **argv) { | 54 | int main(int argc, char **argv) { |
39 | struct timespec out_start, out_stop, in_start, in_stop; | 55 | struct timespec out_start, out_stop, in_start, in_stop; |
40 | int iters = 1; | 56 | int iters, res; |
41 | int res; | 57 | |
42 | if (argc > 1) | 58 | if (argc != 2 || argv[1][0] == '-') { |
43 | iters = atoi(argv[1]); | 59 | fprintf(stderr, "Usage: %s <number of iterations>\n", argv[0]); |
60 | return 1; | ||
61 | } | ||
62 | iters = atoi(argv[1]); | ||
63 | |||
64 | // If output is redirected, add comment with source details | ||
65 | if (!isatty(fileno(stdout))) | ||
66 | fprintf(stdout, "# Generated by '%s %s'\n", argv[0], argv[1]); | ||
44 | 67 | ||
45 | // Needed to allow page cache clearing between iterations | 68 | // Needed to allow page cache clearing between iterations |
46 | // Note: Shouldn't be needed with O_DIRECT, but include it just in case | 69 | // Note: Shouldn't be needed with O_DIRECT, but include it just in case |
@@ -49,8 +72,8 @@ int main(int argc, char **argv) { | |||
49 | perror("Unable to open /proc/sys/vm/drop_caches"); | 72 | perror("Unable to open /proc/sys/vm/drop_caches"); |
50 | return 1; | 73 | return 1; |
51 | } | 74 | } |
52 | char clear_cmd = '3'; | ||
53 | 75 | ||
76 | // Print table header. One read, one write sample per following row | ||
54 | printf("out (us)\tin (us)\n"); | 77 | printf("out (us)\tin (us)\n"); |
55 | for (int i = 0; i < iters; i++) { | 78 | for (int i = 0; i < iters; i++) { |
56 | char *mem_in, *mem_out; | 79 | char *mem_in, *mem_out; |
@@ -60,7 +83,7 @@ int main(int argc, char **argv) { | |||
60 | return 1; | 83 | return 1; |
61 | } | 84 | } |
62 | // Clear page cache | 85 | // Clear page cache |
63 | write(clear_fd, &clear_cmd, 1); | 86 | write(clear_fd, CLEAR_PAGECACHE_DENTRIES_INODES, 1); |
64 | // Allocate and fill a buffer with random data | 87 | // Allocate and fill a buffer with random data |
65 | // Aligned malloc(GiB) basicially | 88 | // Aligned malloc(GiB) basicially |
66 | res = posix_memalign((void**)&mem_in, 4096, GiB); | 89 | res = posix_memalign((void**)&mem_in, 4096, GiB); |
@@ -81,7 +104,7 @@ int main(int argc, char **argv) { | |||
81 | } | 104 | } |
82 | 105 | ||
83 | sleep(1); // Supposedly some other work would happen here | 106 | sleep(1); // Supposedly some other work would happen here |
84 | write(clear_fd, &clear_cmd, 1); // Just in case O_DIRECT misbehaves | 107 | write(clear_fd, CLEAR_PAGECACHE_DENTRIES_INODES, 1); // Just in case O_DIRECT misbehaves |
85 | res = lseek(fd, 0, SEEK_SET); // Reposition offset | 108 | res = lseek(fd, 0, SEEK_SET); // Reposition offset |
86 | if (res == -1) { | 109 | if (res == -1) { |
87 | perror("Unable to seek to offset 0 in " PAGED_FILE); | 110 | perror("Unable to seek to offset 0 in " PAGED_FILE); |