You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.4 KiB
157 lines
4.4 KiB
#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();
|