blob: d7627e2851559461cc2c558db28d8f8975cc3142 [file] [log] [blame]
Elliott Hughes38cf3112017-07-21 16:19:55 -07001#include <benchmark/benchmark.h>
2
Riley Andrews6e61ea92015-09-03 17:25:14 -07003#include <string>
4#include <cstring>
5#include <cstdlib>
6#include <cstdio>
7#include <iostream>
8#include <vector>
9#include <tuple>
10
11#include <unistd.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <sys/mman.h>
15
16using namespace std;
Julien Desprezdf7cd652016-04-05 18:29:52 +010017static const size_t pageSize = PAGE_SIZE;
18static size_t fsize = 1024 * (1ull << 20);
19static size_t pagesTotal = fsize / pageSize;
Riley Andrews6e61ea92015-09-03 17:25:14 -070020
21class Fd {
22 int m_fd = -1;
23public:
24 int get() { return m_fd; }
25 void set(int fd) { m_fd = fd; }
26 Fd() {}
Chih-Hung Hsieh6fbd1a92016-05-06 10:41:04 -070027 explicit Fd(int fd) : m_fd{fd} {}
Riley Andrews6e61ea92015-09-03 17:25:14 -070028 ~Fd() {
29 if (m_fd >= 0)
30 close(m_fd);
31 }
32};
33
34int dummy = 0;
35
36void fillPageJunk(void *ptr)
37{
38 uint64_t seed = (unsigned long long)rand() | ((unsigned long long)rand() << 32);
39 uint64_t *target = (uint64_t*)ptr;
40 for (int i = 0; i < pageSize / sizeof(uint64_t); i++) {
41 *target = seed ^ (uint64_t)(uintptr_t)target;
42 seed = (seed << 1) | ((seed >> 63) & 1);
43 target++;
44 }
45}
46
47class FileMap {
48 string m_name;
49 size_t m_size;
50 void *m_ptr = nullptr;
51 Fd m_fileFd;
52public:
53 enum Hint {
54 FILE_MAP_HINT_NONE,
55 FILE_MAP_HINT_RAND,
56 FILE_MAP_HINT_LINEAR,
57 };
58 FileMap(const string &name, size_t size, Hint hint = FILE_MAP_HINT_NONE) : m_name{name}, m_size{size} {
59 int fd = open(name.c_str(), O_CREAT | O_RDWR, S_IRWXU);
60 if (fd < 0) {
Todd Kjos7d20a662015-12-09 15:37:54 -080061 cout << "Error: open failed for " << name << ": " << strerror(errno) << endl;
62 exit(1);
Riley Andrews6e61ea92015-09-03 17:25:14 -070063 }
64 m_fileFd.set(fd);
65 fallocate(m_fileFd.get(), 0, 0, size);
66 unlink(name.c_str());
67 m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fileFd.get(), 0);
68 if ((int)(uintptr_t)m_ptr == -1) {
Todd Kjos7d20a662015-12-09 15:37:54 -080069 cout << "Error: mmap failed: " << (int)(uintptr_t)m_ptr << ": " << strerror(errno) << endl;
70 exit(1);
Riley Andrews6e61ea92015-09-03 17:25:14 -070071 }
72 switch (hint) {
73 case FILE_MAP_HINT_NONE: break;
74 case FILE_MAP_HINT_RAND:
75 madvise(m_ptr, m_size, MADV_RANDOM);
76 break;
77 case FILE_MAP_HINT_LINEAR:
78 madvise(m_ptr, m_size, MADV_SEQUENTIAL);
79 break;
80 }
81 for (int i = 0; i < m_size / pageSize; i++) {
82 uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * i;
83 fillPageJunk(targetPtr);
84 }
85 }
Julien Desprezdf7cd652016-04-05 18:29:52 +010086 void benchRandomRead(unsigned int targetPage) {
87 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage;
88 dummy += *targetPtr;
Riley Andrews6e61ea92015-09-03 17:25:14 -070089 }
Julien Desprezdf7cd652016-04-05 18:29:52 +010090 void benchRandomWrite(unsigned int targetPage) {
91 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage;
92 *targetPtr = dummy;
93 }
94 void benchLinearRead(unsigned int j) {
95 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j;
96 dummy += *targetPtr;
97 }
98 void benchLinearWrite(unsigned int j) {
99 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j;
100 *targetPtr = dummy;
Riley Andrews6e61ea92015-09-03 17:25:14 -0700101 }
102 void dropCache() {
103 int ret1 = msync(m_ptr, m_size, MS_SYNC | MS_INVALIDATE);
104 madvise(m_ptr, m_size, MADV_DONTNEED);
105 (void)ret1;
106 }
107 ~FileMap() {
108 if (m_ptr)
109 munmap(m_ptr, m_size);
110 }
111
112};
113
Julien Desprezdf7cd652016-04-05 18:29:52 +0100114static void benchRandomRead(benchmark::State& state) {
115 FileMap file{"/data/local/tmp/mmap_test", fsize};
116 while (state.KeepRunning()) {
117 unsigned int targetPage = rand() % pagesTotal;
118 file.benchRandomRead(targetPage);
Todd Kjos7d20a662015-12-09 15:37:54 -0800119 }
Julien Desprezdf7cd652016-04-05 18:29:52 +0100120 state.SetBytesProcessed(state.iterations() * pageSize);
Riley Andrews6e61ea92015-09-03 17:25:14 -0700121}
Julien Desprezdf7cd652016-04-05 18:29:52 +0100122BENCHMARK(benchRandomRead);
123
124static void benchRandomWrite(benchmark::State& state) {
125 FileMap file{"/data/local/tmp/mmap_test", fsize};
126 while (state.KeepRunning()) {
127 unsigned int targetPage = rand() % pagesTotal;
128 file.benchRandomWrite(targetPage);
129 }
130 state.SetBytesProcessed(state.iterations() * pageSize);
131}
132BENCHMARK(benchRandomWrite);
133
134static void benchLinearRead(benchmark::State& state) {
135 FileMap file{"/data/local/tmp/mmap_test", fsize};
136 unsigned int j = 0;
137 while (state.KeepRunning()) {
138 file.benchLinearRead(j);
139 j = (j + 1) % pagesTotal;
140 }
141 state.SetBytesProcessed(state.iterations() * pageSize);
142}
143BENCHMARK(benchLinearRead);
144
145static void benchLinearWrite(benchmark::State& state) {
146 FileMap file{"/data/local/tmp/mmap_test", fsize};
147 unsigned int j = 0;
148 while (state.KeepRunning()) {
149 file.benchLinearWrite(j);
150 j = (j + 1) % pagesTotal;
151 }
152 state.SetBytesProcessed(state.iterations() * pageSize);
153}
154BENCHMARK(benchLinearWrite);
155
Elliott Hughes3a40c922017-12-13 18:18:05 -0800156BENCHMARK_MAIN();