1 #include <iostream>
2 #include <chrono>
3 #include <numeric>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <linux/fs.h>
8 #include <unistd.h>
9 #include <sys/swap.h>
10
11 using namespace std;
12
13 const char zram_blkdev_path[] = "/dev/block/zram0";
14 const size_t sector_size = 512;
15 const size_t page_size = 4096;
16
fillPageRand(uint32_t * page)17 void fillPageRand(uint32_t *page) {
18 int start = rand();
19 for (int i = 0; i < page_size / sizeof(int); i++) {
20 page[i] = start+i;
21 }
22 }
fillPageCompressible(uint32_t * page)23 void fillPageCompressible(uint32_t *page) {
24 int val = rand() & 0xfff;
25 for (int i = 0; i < page_size / sizeof(int); i++) {
26 page[i] = val;
27 }
28 }
29
30 class AlignedAlloc {
31 void *m_ptr;
32 public:
AlignedAlloc(size_t size,size_t align)33 AlignedAlloc(size_t size, size_t align) {
34 posix_memalign(&m_ptr, align, size);
35 }
~AlignedAlloc()36 ~AlignedAlloc() {
37 free(m_ptr);
38 }
ptr()39 void *ptr() {
40 return m_ptr;
41 }
42 };
43
44 class BlockFd {
45 int m_fd = -1;
46 public:
BlockFd(const char * path,bool direct)47 BlockFd(const char *path, bool direct) {
48 m_fd = open(path, O_RDWR | (direct ? O_DIRECT : 0));
49 }
getSize()50 size_t getSize() {
51 size_t blockSize = 0;
52 int result = ioctl(m_fd, BLKGETSIZE, &blockSize);
53 if (result < 0) {
54 cout << "ioctl failed" << endl;
55 }
56 return blockSize * sector_size;
57 }
~BlockFd()58 ~BlockFd() {
59 if (m_fd >= 0) {
60 close(m_fd);
61 }
62 }
fillWithCompressible()63 void fillWithCompressible() {
64 size_t devSize = getSize();
65 AlignedAlloc page(page_size, page_size);
66 for (uint64_t offset = 0; offset < devSize; offset += page_size) {
67 fillPageCompressible((uint32_t*)page.ptr());
68 ssize_t ret = write(m_fd, page.ptr(), page_size);
69 if (ret != page_size) {
70 cout << "write() failed" << endl;
71 }
72 }
73 }
benchSequentialRead()74 void benchSequentialRead() {
75 chrono::time_point<chrono::high_resolution_clock> start, end;
76 size_t devSize = getSize();
77 size_t passes = 4;
78 AlignedAlloc page(page_size, page_size);
79
80 start = chrono::high_resolution_clock::now();
81 for (int i = 0; i < passes; i++) {
82 for (uint64_t offset = 0; offset < devSize; offset += page_size) {
83 if (offset == 0)
84 lseek(m_fd, offset, SEEK_SET);
85 ssize_t ret = read(m_fd, page.ptr(), page_size);
86 if (ret != page_size) {
87 cout << "read() failed" << endl;
88 }
89 }
90 }
91 end = chrono::high_resolution_clock::now();
92 size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count();
93 cout << "read: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl;
94 }
benchSequentialWrite()95 void benchSequentialWrite() {
96 chrono::time_point<chrono::high_resolution_clock> start, end;
97 size_t devSize = getSize();
98 size_t passes = 4;
99 AlignedAlloc page(page_size, page_size);
100
101 start = chrono::high_resolution_clock::now();
102 for (int i = 0; i < passes; i++) {
103 for (uint64_t offset = 0; offset < devSize; offset += page_size) {
104 fillPageCompressible((uint32_t*)page.ptr());
105 if (offset == 0)
106 lseek(m_fd, offset, SEEK_SET);
107 ssize_t ret = write(m_fd, page.ptr(), page_size);
108 if (ret != page_size) {
109 cout << "write() failed" << endl;
110 }
111 }
112 }
113 end = chrono::high_resolution_clock::now();
114 size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count();
115 cout << "write: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl;
116
117 }
118 };
119
bench(bool direct)120 int bench(bool direct)
121 {
122 BlockFd zramDev{zram_blkdev_path, direct};
123
124 zramDev.fillWithCompressible();
125 zramDev.benchSequentialRead();
126 zramDev.benchSequentialWrite();
127 return 0;
128 }
129
main(int argc,char * argv[])130 int main(int argc, char *argv[])
131 {
132 int result = swapoff(zram_blkdev_path);
133 if (result < 0) {
134 cout << "swapoff failed: " << strerror(errno) << endl;
135 }
136
137 bench(1);
138
139 result = system((string("mkswap ") + string(zram_blkdev_path)).c_str());
140 if (result < 0) {
141 cout << "mkswap failed: " << strerror(errno) << endl;
142 return -1;
143 }
144
145 result = swapon(zram_blkdev_path, 0);
146 if (result < 0) {
147 cout << "swapon failed: " << strerror(errno) << endl;
148 return -1;
149 }
150 return 0;
151 }
152