blob: 93a2cc150efe05421871b46bc9e3afc147b2315b [file] [log] [blame]
Riley Andrews1199c512015-11-20 15:40:09 -08001#include <fcntl.h>
2#include <linux/fs.h>
Martin Liu2b076cd2018-11-19 15:02:46 +08003#include <sys/stat.h>
Riley Andrews1199c512015-11-20 15:40:09 -08004#include <sys/swap.h>
Martin Liu2b076cd2018-11-19 15:02:46 +08005#include <sys/types.h>
6#include <unistd.h>
7#include <chrono>
8#include <iostream>
9#include <numeric>
10#include <vector>
Riley Andrews1199c512015-11-20 15:40:09 -080011
12using namespace std;
13
Martin Liu2b076cd2018-11-19 15:02:46 +080014static const size_t kPageSize = sysconf(_SC_PAGESIZE);
15static constexpr char kZramBlkdevPath[] = "/dev/block/zram0";
16static constexpr size_t kPatternSize = 4;
17static constexpr size_t kSectorSize = 512;
Riley Andrews1199c512015-11-20 15:40:09 -080018
19void fillPageRand(uint32_t *page) {
Martin Liu2b076cd2018-11-19 15:02:46 +080020 uint32_t start = rand();
21 for (int i = 0; i < kPageSize / sizeof(start); i++) {
Riley Andrews1199c512015-11-20 15:40:09 -080022 page[i] = start+i;
23 }
24}
Martin Liu2b076cd2018-11-19 15:02:46 +080025void fillPageCompressible(void* page) {
26 uint32_t val = rand() & 0xfff;
27 auto page_ptr = reinterpret_cast<typeof(val)*>(page);
28 std::vector<typeof(val)> pattern(kPatternSize, 0);
29
30 for (auto i = 0u; i < kPatternSize; i++) {
31 pattern[i] = val + i;
32 }
33 // fill in ABCD... pattern
34 for (int i = 0; i < kPageSize / sizeof(val); i += kPatternSize) {
35 std::copy_n(pattern.data(), kPatternSize, (page_ptr + i));
Riley Andrews1199c512015-11-20 15:40:09 -080036 }
37}
38
39class AlignedAlloc {
40 void *m_ptr;
41public:
42 AlignedAlloc(size_t size, size_t align) {
43 posix_memalign(&m_ptr, align, size);
44 }
45 ~AlignedAlloc() {
46 free(m_ptr);
47 }
48 void *ptr() {
49 return m_ptr;
50 }
51};
52
53class BlockFd {
54 int m_fd = -1;
55public:
56 BlockFd(const char *path, bool direct) {
57 m_fd = open(path, O_RDWR | (direct ? O_DIRECT : 0));
58 }
59 size_t getSize() {
60 size_t blockSize = 0;
61 int result = ioctl(m_fd, BLKGETSIZE, &blockSize);
62 if (result < 0) {
Martin Liu2b076cd2018-11-19 15:02:46 +080063 cout << "ioctl block size failed" << endl;
Riley Andrews1199c512015-11-20 15:40:09 -080064 }
Martin Liu2b076cd2018-11-19 15:02:46 +080065 return blockSize * kSectorSize;
Riley Andrews1199c512015-11-20 15:40:09 -080066 }
67 ~BlockFd() {
68 if (m_fd >= 0) {
69 close(m_fd);
70 }
71 }
72 void fillWithCompressible() {
73 size_t devSize = getSize();
Martin Liu2b076cd2018-11-19 15:02:46 +080074 AlignedAlloc page(kPageSize, kPageSize);
75 for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
Riley Andrews1199c512015-11-20 15:40:09 -080076 fillPageCompressible((uint32_t*)page.ptr());
Martin Liu2b076cd2018-11-19 15:02:46 +080077 ssize_t ret = write(m_fd, page.ptr(), kPageSize);
78 if (ret != kPageSize) {
Riley Andrews1199c512015-11-20 15:40:09 -080079 cout << "write() failed" << endl;
80 }
81 }
82 }
83 void benchSequentialRead() {
84 chrono::time_point<chrono::high_resolution_clock> start, end;
85 size_t devSize = getSize();
86 size_t passes = 4;
Martin Liu2b076cd2018-11-19 15:02:46 +080087 AlignedAlloc page(kPageSize, kPageSize);
Riley Andrews1199c512015-11-20 15:40:09 -080088
89 start = chrono::high_resolution_clock::now();
90 for (int i = 0; i < passes; i++) {
Martin Liu2b076cd2018-11-19 15:02:46 +080091 for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
Riley Andrews1199c512015-11-20 15:40:09 -080092 if (offset == 0)
93 lseek(m_fd, offset, SEEK_SET);
Martin Liu2b076cd2018-11-19 15:02:46 +080094 ssize_t ret = read(m_fd, page.ptr(), kPageSize);
95 if (ret != kPageSize) {
Riley Andrews1199c512015-11-20 15:40:09 -080096 cout << "read() failed" << endl;
97 }
98 }
99 }
100 end = chrono::high_resolution_clock::now();
101 size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count();
102 cout << "read: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl;
103 }
104 void benchSequentialWrite() {
105 chrono::time_point<chrono::high_resolution_clock> start, end;
106 size_t devSize = getSize();
107 size_t passes = 4;
Martin Liu2b076cd2018-11-19 15:02:46 +0800108 AlignedAlloc page(kPageSize, kPageSize);
Riley Andrews1199c512015-11-20 15:40:09 -0800109
110 start = chrono::high_resolution_clock::now();
111 for (int i = 0; i < passes; i++) {
Martin Liu2b076cd2018-11-19 15:02:46 +0800112 for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
Riley Andrews1199c512015-11-20 15:40:09 -0800113 fillPageCompressible((uint32_t*)page.ptr());
114 if (offset == 0)
115 lseek(m_fd, offset, SEEK_SET);
Martin Liu2b076cd2018-11-19 15:02:46 +0800116 ssize_t ret = write(m_fd, page.ptr(), kPageSize);
117 if (ret != kPageSize) {
Riley Andrews1199c512015-11-20 15:40:09 -0800118 cout << "write() failed" << endl;
119 }
120 }
121 }
122 end = chrono::high_resolution_clock::now();
123 size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count();
124 cout << "write: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl;
125
126 }
127};
128
129int bench(bool direct)
130{
Martin Liu2b076cd2018-11-19 15:02:46 +0800131 BlockFd zramDev{kZramBlkdevPath, direct};
Riley Andrews1199c512015-11-20 15:40:09 -0800132
133 zramDev.fillWithCompressible();
134 zramDev.benchSequentialRead();
135 zramDev.benchSequentialWrite();
136 return 0;
137}
138
139int main(int argc, char *argv[])
140{
Martin Liu2b076cd2018-11-19 15:02:46 +0800141 int result = swapoff(kZramBlkdevPath);
Riley Andrews1199c512015-11-20 15:40:09 -0800142 if (result < 0) {
143 cout << "swapoff failed: " << strerror(errno) << endl;
144 }
145
146 bench(1);
147
Martin Liu2b076cd2018-11-19 15:02:46 +0800148 result = system((string("mkswap ") + string(kZramBlkdevPath)).c_str());
Riley Andrews1199c512015-11-20 15:40:09 -0800149 if (result < 0) {
150 cout << "mkswap failed: " << strerror(errno) << endl;
151 return -1;
152 }
153
Martin Liu2b076cd2018-11-19 15:02:46 +0800154 result = swapon(kZramBlkdevPath, 0);
Riley Andrews1199c512015-11-20 15:40:09 -0800155 if (result < 0) {
156 cout << "swapon failed: " << strerror(errno) << endl;
157 return -1;
158 }
159 return 0;
160}