|  | #include <benchmark/benchmark.h> | 
|  |  | 
|  | #include <string> | 
|  | #include <cstring> | 
|  | #include <cstdlib> | 
|  | #include <cstdio> | 
|  | #include <iostream> | 
|  | #include <vector> | 
|  | #include <tuple> | 
|  |  | 
|  | #include <unistd.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <sys/mman.h> | 
|  |  | 
|  | using namespace std; | 
|  | static const size_t pageSize = PAGE_SIZE; | 
|  | static size_t fsize = 1024 * (1ull << 20); | 
|  | static size_t pagesTotal = fsize / pageSize; | 
|  |  | 
|  | class Fd { | 
|  | int m_fd = -1; | 
|  | public: | 
|  | int get() { return m_fd; } | 
|  | void set(int fd) { m_fd = fd; } | 
|  | Fd() {} | 
|  | explicit Fd(int fd) : m_fd{fd} {} | 
|  | ~Fd() { | 
|  | if (m_fd >= 0) | 
|  | close(m_fd); | 
|  | } | 
|  | }; | 
|  |  | 
|  | int dummy = 0; | 
|  |  | 
|  | void fillPageJunk(void *ptr) | 
|  | { | 
|  | uint64_t seed = (unsigned long long)rand() | ((unsigned long long)rand() << 32); | 
|  | uint64_t *target = (uint64_t*)ptr; | 
|  | for (int i = 0; i < pageSize / sizeof(uint64_t); i++) { | 
|  | *target = seed ^ (uint64_t)(uintptr_t)target; | 
|  | seed = (seed << 1) | ((seed >> 63) & 1); | 
|  | target++; | 
|  | } | 
|  | } | 
|  |  | 
|  | class FileMap { | 
|  | string m_name; | 
|  | size_t m_size; | 
|  | void *m_ptr = nullptr; | 
|  | Fd m_fileFd; | 
|  | public: | 
|  | enum Hint { | 
|  | FILE_MAP_HINT_NONE, | 
|  | FILE_MAP_HINT_RAND, | 
|  | FILE_MAP_HINT_LINEAR, | 
|  | }; | 
|  | FileMap(const string &name, size_t size, Hint hint = FILE_MAP_HINT_NONE) : m_name{name}, m_size{size} { | 
|  | int fd = open(name.c_str(), O_CREAT | O_RDWR, S_IRWXU); | 
|  | if (fd < 0) { | 
|  | cout << "Error: open failed for " << name << ": " << strerror(errno) << endl; | 
|  | exit(1); | 
|  | } | 
|  | m_fileFd.set(fd); | 
|  | fallocate(m_fileFd.get(), 0, 0, size); | 
|  | unlink(name.c_str()); | 
|  | m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fileFd.get(), 0); | 
|  | if ((int)(uintptr_t)m_ptr == -1) { | 
|  | cout << "Error: mmap failed: " << (int)(uintptr_t)m_ptr << ": " << strerror(errno) << endl; | 
|  | exit(1); | 
|  | } | 
|  | switch (hint) { | 
|  | case FILE_MAP_HINT_NONE: break; | 
|  | case FILE_MAP_HINT_RAND: | 
|  | madvise(m_ptr, m_size, MADV_RANDOM); | 
|  | break; | 
|  | case FILE_MAP_HINT_LINEAR: | 
|  | madvise(m_ptr, m_size, MADV_SEQUENTIAL); | 
|  | break; | 
|  | } | 
|  | for (int i = 0; i < m_size / pageSize; i++) { | 
|  | uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * i; | 
|  | fillPageJunk(targetPtr); | 
|  | } | 
|  | } | 
|  | void benchRandomRead(unsigned int targetPage) { | 
|  | uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage; | 
|  | dummy += *targetPtr; | 
|  | } | 
|  | void benchRandomWrite(unsigned int targetPage) { | 
|  | uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * targetPage; | 
|  | *targetPtr = dummy; | 
|  | } | 
|  | void benchLinearRead(unsigned int j) { | 
|  | uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j; | 
|  | dummy += *targetPtr; | 
|  | } | 
|  | void benchLinearWrite(unsigned int j) { | 
|  | uint8_t *targetPtr = (uint8_t*)m_ptr + pageSize * j; | 
|  | *targetPtr = dummy; | 
|  | } | 
|  | void dropCache() { | 
|  | int ret1 = msync(m_ptr, m_size, MS_SYNC | MS_INVALIDATE); | 
|  | madvise(m_ptr, m_size, MADV_DONTNEED); | 
|  | (void)ret1; | 
|  | } | 
|  | ~FileMap() { | 
|  | if (m_ptr) | 
|  | munmap(m_ptr, m_size); | 
|  | } | 
|  |  | 
|  | }; | 
|  |  | 
|  | static void benchRandomRead(benchmark::State& state) { | 
|  | FileMap file{"/data/local/tmp/mmap_test", fsize}; | 
|  | while (state.KeepRunning()) { | 
|  | unsigned int targetPage = rand() % pagesTotal; | 
|  | file.benchRandomRead(targetPage); | 
|  | } | 
|  | state.SetBytesProcessed(state.iterations() * pageSize); | 
|  | } | 
|  | BENCHMARK(benchRandomRead); | 
|  |  | 
|  | static void benchRandomWrite(benchmark::State& state) { | 
|  | FileMap file{"/data/local/tmp/mmap_test", fsize}; | 
|  | while (state.KeepRunning()) { | 
|  | unsigned int targetPage = rand() % pagesTotal; | 
|  | file.benchRandomWrite(targetPage); | 
|  | } | 
|  | state.SetBytesProcessed(state.iterations() * pageSize); | 
|  | } | 
|  | BENCHMARK(benchRandomWrite); | 
|  |  | 
|  | static void benchLinearRead(benchmark::State& state) { | 
|  | FileMap file{"/data/local/tmp/mmap_test", fsize}; | 
|  | unsigned int j = 0; | 
|  | while (state.KeepRunning()) { | 
|  | file.benchLinearRead(j); | 
|  | j = (j + 1) % pagesTotal; | 
|  | } | 
|  | state.SetBytesProcessed(state.iterations() * pageSize); | 
|  | } | 
|  | BENCHMARK(benchLinearRead); | 
|  |  | 
|  | static void benchLinearWrite(benchmark::State& state) { | 
|  | FileMap file{"/data/local/tmp/mmap_test", fsize}; | 
|  | unsigned int j = 0; | 
|  | while (state.KeepRunning()) { | 
|  | file.benchLinearWrite(j); | 
|  | j = (j + 1) % pagesTotal; | 
|  | } | 
|  | state.SetBytesProcessed(state.iterations() * pageSize); | 
|  | } | 
|  | BENCHMARK(benchLinearWrite); | 
|  |  | 
|  | BENCHMARK_MAIN(); |