• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <fcntl.h>
2 #include <linux/fs.h>
3 #include <sys/stat.h>
4 #include <sys/swap.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <chrono>
8 #include <iostream>
9 #include <numeric>
10 #include <vector>
11 
12 using namespace std;
13 
14 static const size_t kPageSize = sysconf(_SC_PAGESIZE);
15 static constexpr char kZramBlkdevPath[] = "/dev/block/zram0";
16 static constexpr size_t kPatternSize = 4;
17 static constexpr size_t kSectorSize = 512;
18 
fillPageRand(uint32_t * page)19 void fillPageRand(uint32_t *page) {
20     uint32_t start = rand();
21     for (int i = 0; i < kPageSize / sizeof(start); i++) {
22         page[i] = start+i;
23     }
24 }
fillPageCompressible(void * page)25 void 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));
36     }
37 }
38 
39 class AlignedAlloc {
40     void *m_ptr;
41 public:
AlignedAlloc(size_t size,size_t align)42     AlignedAlloc(size_t size, size_t align) {
43         posix_memalign(&m_ptr, align, size);
44     }
~AlignedAlloc()45     ~AlignedAlloc() {
46         free(m_ptr);
47     }
ptr()48     void *ptr() {
49         return m_ptr;
50     }
51 };
52 
53 class BlockFd {
54     int m_fd = -1;
55 public:
BlockFd(const char * path,bool direct)56     BlockFd(const char *path, bool direct) {
57         m_fd = open(path, O_RDWR | (direct ? O_DIRECT : 0));
58     }
getSize()59     size_t getSize() {
60         size_t blockSize = 0;
61         int result = ioctl(m_fd, BLKGETSIZE, &blockSize);
62         if (result < 0) {
63             cout << "ioctl block size failed" << endl;
64         }
65         return blockSize * kSectorSize;
66     }
~BlockFd()67     ~BlockFd() {
68         if (m_fd >= 0) {
69             close(m_fd);
70         }
71     }
fillWithCompressible()72     void fillWithCompressible() {
73         size_t devSize = getSize();
74         AlignedAlloc page(kPageSize, kPageSize);
75         for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
76             fillPageCompressible((uint32_t*)page.ptr());
77             ssize_t ret = write(m_fd, page.ptr(), kPageSize);
78             if (ret != kPageSize) {
79                 cout << "write() failed" << endl;
80             }
81         }
82     }
benchSequentialRead()83     void benchSequentialRead() {
84         chrono::time_point<chrono::high_resolution_clock> start, end;
85         size_t devSize = getSize();
86         size_t passes = 4;
87         AlignedAlloc page(kPageSize, kPageSize);
88 
89         start = chrono::high_resolution_clock::now();
90         for (int i = 0; i < passes; i++) {
91             for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
92                 if (offset == 0)
93                     lseek(m_fd, offset, SEEK_SET);
94                 ssize_t ret = read(m_fd, page.ptr(), kPageSize);
95                 if (ret != kPageSize) {
96                     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     }
benchSequentialWrite()104     void benchSequentialWrite() {
105         chrono::time_point<chrono::high_resolution_clock> start, end;
106         size_t devSize = getSize();
107         size_t passes = 4;
108         AlignedAlloc page(kPageSize, kPageSize);
109 
110         start = chrono::high_resolution_clock::now();
111         for (int i = 0; i < passes; i++) {
112             for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
113                 fillPageCompressible((uint32_t*)page.ptr());
114                 if (offset == 0)
115                     lseek(m_fd, offset, SEEK_SET);
116                 ssize_t ret = write(m_fd, page.ptr(), kPageSize);
117                 if (ret != kPageSize) {
118                     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 
bench(bool direct)129 int bench(bool direct)
130 {
131     BlockFd zramDev{kZramBlkdevPath, direct};
132 
133     zramDev.fillWithCompressible();
134     zramDev.benchSequentialRead();
135     zramDev.benchSequentialWrite();
136     return 0;
137 }
138 
main(int argc,char * argv[])139 int main(int argc, char *argv[])
140 {
141     int result = swapoff(kZramBlkdevPath);
142     if (result < 0) {
143         cout << "swapoff failed: " << strerror(errno) << endl;
144     }
145 
146     bench(1);
147 
148     result = system((string("mkswap ") + string(kZramBlkdevPath)).c_str());
149     if (result < 0) {
150         cout << "mkswap failed: " <<  strerror(errno) << endl;
151         return -1;
152     }
153 
154     result = swapon(kZramBlkdevPath, 0);
155     if (result < 0) {
156         cout << "swapon failed: " <<  strerror(errno) << endl;
157         return -1;
158     }
159     return 0;
160 }
161