• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <benchmark/benchmark.h>
2 
3 #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 
16 using namespace std;
17 static const size_t pageSize = PAGE_SIZE;
18 static size_t fsize = 1024 * (1ull << 20);
19 static size_t pagesTotal = fsize / pageSize;
20 
21 class Fd {
22     int m_fd = -1;
23 public:
get()24     int get() { return m_fd; }
set(int fd)25     void set(int fd) { m_fd = fd; }
Fd()26     Fd() {}
Fd(int fd)27     explicit Fd(int fd) : m_fd{fd} {}
~Fd()28     ~Fd() {
29         if (m_fd >= 0)
30             close(m_fd);
31     }
32 };
33 
34 int dummy = 0;
35 
fillPageJunk(void * ptr)36 void 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 
47 class FileMap {
48     string m_name;
49     size_t m_size;
50     void *m_ptr = nullptr;
51     Fd m_fileFd;
52 public:
53     enum Hint {
54        FILE_MAP_HINT_NONE,
55        FILE_MAP_HINT_RAND,
56        FILE_MAP_HINT_LINEAR,
57     };
FileMap(const string & name,size_t size,Hint hint=FILE_MAP_HINT_NONE)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) {
61             cout << "Error: open failed for " << name << ": " << strerror(errno) << endl;
62             exit(1);
63         }
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) {
69             cout << "Error: mmap failed: " << (int)(uintptr_t)m_ptr << ": " << strerror(errno) << endl;
70             exit(1);
71         }
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     }
benchRandomRead(unsigned int targetPage)86     void benchRandomRead(unsigned int targetPage) {
87         uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage;
88         dummy += *targetPtr;
89     }
benchRandomWrite(unsigned int targetPage)90     void benchRandomWrite(unsigned int targetPage) {
91         uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage;
92         *targetPtr = dummy;
93     }
benchLinearRead(unsigned int j)94     void benchLinearRead(unsigned int j) {
95         uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j;
96         dummy += *targetPtr;
97     }
benchLinearWrite(unsigned int j)98     void benchLinearWrite(unsigned int j) {
99         uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j;
100         *targetPtr = dummy;
101     }
dropCache()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     }
~FileMap()107     ~FileMap() {
108         if (m_ptr)
109             munmap(m_ptr, m_size);
110     }
111 
112 };
113 
benchRandomRead(benchmark::State & state)114 static 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);
119     }
120     state.SetBytesProcessed(state.iterations() * pageSize);
121 }
122 BENCHMARK(benchRandomRead);
123 
benchRandomWrite(benchmark::State & state)124 static 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 }
132 BENCHMARK(benchRandomWrite);
133 
benchLinearRead(benchmark::State & state)134 static 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 }
143 BENCHMARK(benchLinearRead);
144 
benchLinearWrite(benchmark::State & state)145 static 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 }
154 BENCHMARK(benchLinearWrite);
155 
156 BENCHMARK_MAIN();
157