Home | History | Annotate | Download | only in mmap-perf
      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