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