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