File: zram-perf.cpp

package info (click to toggle)
android-platform-tools 29.0.6-28
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 365,224 kB
  • sloc: cpp: 1,049,638; java: 460,532; ansic: 375,452; asm: 301,257; xml: 134,509; python: 92,731; perl: 62,008; sh: 26,753; makefile: 3,210; javascript: 3,172; yacc: 1,403; lex: 455; awk: 368; ruby: 183; sql: 140
file content (160 lines) | stat: -rw-r--r-- 4,892 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;

static const size_t kPageSize = sysconf(_SC_PAGESIZE);
static constexpr char kZramBlkdevPath[] = "/dev/block/zram0";
static constexpr size_t kPatternSize = 4;
static constexpr size_t kSectorSize = 512;

void fillPageRand(uint32_t *page) {
    uint32_t start = rand();
    for (int i = 0; i < kPageSize / sizeof(start); i++) {
        page[i] = start+i;
    }
}
void fillPageCompressible(void* page) {
    uint32_t val = rand() & 0xfff;
    auto page_ptr = reinterpret_cast<typeof(val)*>(page);
    std::vector<typeof(val)> pattern(kPatternSize, 0);

    for (auto i = 0u; i < kPatternSize; i++) {
        pattern[i] = val + i;
    }
    // fill in ABCD... pattern
    for (int i = 0; i < kPageSize / sizeof(val); i += kPatternSize) {
        std::copy_n(pattern.data(), kPatternSize, (page_ptr + i));
    }
}

class AlignedAlloc {
    void *m_ptr;
public:
    AlignedAlloc(size_t size, size_t align) {
        posix_memalign(&m_ptr, align, size);
    }
    ~AlignedAlloc() {
        free(m_ptr);
    }
    void *ptr() {
        return m_ptr;
    }
};

class BlockFd {
    int m_fd = -1;
public:
    BlockFd(const char *path, bool direct) {
        m_fd = open(path, O_RDWR | (direct ? O_DIRECT : 0));
    }
    size_t getSize() {
        size_t blockSize = 0;
        int result = ioctl(m_fd, BLKGETSIZE, &blockSize);
        if (result < 0) {
            cout << "ioctl block size failed" << endl;
        }
        return blockSize * kSectorSize;
    }
    ~BlockFd() {
        if (m_fd >= 0) {
            close(m_fd);
        }
    }
    void fillWithCompressible() {
        size_t devSize = getSize();
        AlignedAlloc page(kPageSize, kPageSize);
        for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
            fillPageCompressible((uint32_t*)page.ptr());
            ssize_t ret = write(m_fd, page.ptr(), kPageSize);
            if (ret != kPageSize) {
                cout << "write() failed" << endl;
            }
        }
    }
    void benchSequentialRead() {
        chrono::time_point<chrono::high_resolution_clock> start, end;
        size_t devSize = getSize();
        size_t passes = 4;
        AlignedAlloc page(kPageSize, kPageSize);

        start = chrono::high_resolution_clock::now();
        for (int i = 0; i < passes; i++) {
            for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
                if (offset == 0)
                    lseek(m_fd, offset, SEEK_SET);
                ssize_t ret = read(m_fd, page.ptr(), kPageSize);
                if (ret != kPageSize) {
                    cout << "read() failed" << endl;
                }
            }
        }
        end = chrono::high_resolution_clock::now();
        size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count();
        cout << "read: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl;
    }
    void benchSequentialWrite() {
        chrono::time_point<chrono::high_resolution_clock> start, end;
        size_t devSize = getSize();
        size_t passes = 4;
        AlignedAlloc page(kPageSize, kPageSize);

        start = chrono::high_resolution_clock::now();
        for (int i = 0; i < passes; i++) {
            for (uint64_t offset = 0; offset < devSize; offset += kPageSize) {
                fillPageCompressible((uint32_t*)page.ptr());
                if (offset == 0)
                    lseek(m_fd, offset, SEEK_SET);
                ssize_t ret = write(m_fd, page.ptr(), kPageSize);
                if (ret != kPageSize) {
                    cout << "write() failed" << endl;
                }
            }
        }
        end = chrono::high_resolution_clock::now();
        size_t duration = chrono::duration_cast<chrono::microseconds>(end - start).count();
        cout << "write: " << (double)devSize * passes / 1024.0 / 1024.0 / (duration / 1000.0 / 1000.0) << "MB/s" << endl;

    }
};

int bench(bool direct)
{
    BlockFd zramDev{kZramBlkdevPath, direct};

    zramDev.fillWithCompressible();
    zramDev.benchSequentialRead();
    zramDev.benchSequentialWrite();
    return 0;
}

int main(int argc, char *argv[])
{
    int result = swapoff(kZramBlkdevPath);
    if (result < 0) {
        cout << "swapoff failed: " << strerror(errno) << endl;
    }

    bench(1);

    result = system((string("mkswap ") + string(kZramBlkdevPath)).c_str());
    if (result < 0) {
        cout << "mkswap failed: " <<  strerror(errno) << endl;
        return -1;
    }

    result = swapon(kZramBlkdevPath, 0);
    if (result < 0) {
        cout << "swapon failed: " <<  strerror(errno) << endl;
        return -1;
    }
    return 0;
}