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