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: 23 int get() { return m_fd; } 24 void set(int fd) { m_fd = fd; } 25 Fd() {} 26 Fd(int fd) : m_fd{fd} {} 27 ~Fd() { 28 if (m_fd >= 0) 29 close(m_fd); 30 } 31 }; 32 33 int dummy = 0; 34 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 }; 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 } 85 void benchRandomRead(unsigned int targetPage) { 86 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage; 87 dummy += *targetPtr; 88 } 89 void benchRandomWrite(unsigned int targetPage) { 90 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage; 91 *targetPtr = dummy; 92 } 93 void benchLinearRead(unsigned int j) { 94 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j; 95 dummy += *targetPtr; 96 } 97 void benchLinearWrite(unsigned int j) { 98 uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j; 99 *targetPtr = dummy; 100 } 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 } 106 ~FileMap() { 107 if (m_ptr) 108 munmap(m_ptr, m_size); 109 } 110 111 }; 112 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 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 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 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