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.
160 lines
4.8 KiB
160 lines
4.8 KiB
#include <fcntl.h> |
|
#include <linux/fs.h> |
|
#include <sys/stat.h> |
|
#include <sys/swap.h> |
|
#include <sys/types.h> |
|
#include <unistd.h> |
|
#include <chrono> |
|
#include <iostream> |
|
#include <numeric> |
|
#include <vector> |
|
|
|
using namespace std; |
|
|
|
static const size_t kPageSize = sysconf(_SC_PAGESIZE); |
|
static constexpr char kZramBlkdevPath[] = "/dev/block/zram0"; |
|
static constexpr size_t kPatternSize = 4; |
|
static constexpr size_t kSectorSize = 512; |
|
|
|
void fillPageRand(uint32_t *page) { |
|
uint32_t start = rand(); |
|
for (int i = 0; i < kPageSize / sizeof(start); i++) { |
|
page[i] = start+i; |
|
} |
|
} |
|
void fillPageCompressible(void* page) { |
|
uint32_t val = rand() & 0xfff; |
|
auto page_ptr = reinterpret_cast<typeof(val)*>(page); |
|
std::vector<typeof(val)> pattern(kPatternSize, 0); |
|
|
|
for (auto i = 0u; i < kPatternSize; i++) { |
|
pattern[i] = val + i; |
|
} |
|
// fill in ABCD... pattern |
|
for (int i = 0; i < kPageSize / sizeof(val); i += kPatternSize) { |
|
std::copy_n(pattern.data(), kPatternSize, (page_ptr + i)); |
|
} |
|
} |
|
|
|
class AlignedAlloc { |
|
void *m_ptr; |
|
public: |
|
AlignedAlloc(size_t size, size_t align) { |
|
posix_memalign(&m_ptr, align, size); |
|
} |
|
~AlignedAlloc() { |
|
free(m_ptr); |
|
} |
|
void *ptr() { |
|
return m_ptr; |
|
} |
|
}; |
|
|
|
class BlockFd { |
|
int m_fd = -1; |
|
public: |
|
BlockFd(const char *path, bool direct) { |
|
m_fd = open(path, O_RDWR | (direct ? O_DIRECT : 0)); |
|
} |
|
size_t getSize() { |
|
size_t blockSize = 0; |
|
int result = ioctl(m_fd, BLKGETSIZE, &blockSize); |
|
if (result < 0) { |
|
cout << "ioctl block size failed" << endl; |
|
} |
|
return blockSize * kSectorSize; |
|
} |
|
~BlockFd() { |
|
if (m_fd >= 0) { |
|
close(m_fd); |
|
} |
|
} |
|
void fillWithCompressible() { |
|
size_t devSize = getSize(); |
|
AlignedAlloc page(kPageSize, kPageSize); |
|
for (uint64_t offset = 0; offset < devSize; offset += kPageSize) { |
|
fillPageCompressible((uint32_t*)page.ptr()); |
|
ssize_t ret = write(m_fd, page.ptr(), kPageSize); |
|
if (ret != kPageSize) { |
|
cout << "write() failed" << endl; |
|
} |
|
} |
|
} |
|
void benchSequentialRead() { |
|
chrono::time_point<chrono::high_resolution_clock> start, end; |
|
size_t devSize = getSize(); |
|
size_t passes = 4; |
|
AlignedAlloc page(kPageSize, kPageSize); |
|
|
|
start = chrono::high_resolution_clock::now(); |
|
for (int i = 0; i < passes; i++) { |
|
for (uint64_t offset = 0; offset < devSize; offset += kPageSize) { |
|
if (offset == 0) |
|
lseek(m_fd, offset, SEEK_SET); |
|
ssize_t ret = read(m_fd, page.ptr(), kPageSize); |
|
if (ret != kPageSize) { |
|
cout << "read() failed" << endl; |
|
} |
|
} |
|
} |
|
end = chrono::high_resolution_clock::now(); |
|
size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count(); |
|
cout << "read: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl; |
|
} |
|
void benchSequentialWrite() { |
|
chrono::time_point<chrono::high_resolution_clock> start, end; |
|
size_t devSize = getSize(); |
|
size_t passes = 4; |
|
AlignedAlloc page(kPageSize, kPageSize); |
|
|
|
start = chrono::high_resolution_clock::now(); |
|
for (int i = 0; i < passes; i++) { |
|
for (uint64_t offset = 0; offset < devSize; offset += kPageSize) { |
|
fillPageCompressible((uint32_t*)page.ptr()); |
|
if (offset == 0) |
|
lseek(m_fd, offset, SEEK_SET); |
|
ssize_t ret = write(m_fd, page.ptr(), kPageSize); |
|
if (ret != kPageSize) { |
|
cout << "write() failed" << endl; |
|
} |
|
} |
|
} |
|
end = chrono::high_resolution_clock::now(); |
|
size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count(); |
|
cout << "write: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl; |
|
|
|
} |
|
}; |
|
|
|
int bench(bool direct) |
|
{ |
|
BlockFd zramDev{kZramBlkdevPath, direct}; |
|
|
|
zramDev.fillWithCompressible(); |
|
zramDev.benchSequentialRead(); |
|
zramDev.benchSequentialWrite(); |
|
return 0; |
|
} |
|
|
|
int main(int argc, char *argv[]) |
|
{ |
|
int result = swapoff(kZramBlkdevPath); |
|
if (result < 0) { |
|
cout << "swapoff failed: " << strerror(errno) << endl; |
|
} |
|
|
|
bench(1); |
|
|
|
result = system((string("mkswap ") + string(kZramBlkdevPath)).c_str()); |
|
if (result < 0) { |
|
cout << "mkswap failed: " << strerror(errno) << endl; |
|
return -1; |
|
} |
|
|
|
result = swapon(kZramBlkdevPath, 0); |
|
if (result < 0) { |
|
cout << "swapon failed: " << strerror(errno) << endl; |
|
return -1; |
|
} |
|
return 0; |
|
}
|
|
|