Home | History | Annotate | Download | only in zram-perf
      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 
     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 }
     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:
     33     AlignedAlloc(size_t size, size_t align) {
     34         posix_memalign(&m_ptr, align, size);
     35     }
     36     ~AlignedAlloc() {
     37         free(m_ptr);
     38     }
     39     void *ptr() {
     40         return m_ptr;
     41     }
     42 };
     43 
     44 class BlockFd {
     45     int m_fd = -1;
     46 public:
     47     BlockFd(const char *path, bool direct) {
     48         m_fd = open(path, O_RDWR | (direct ? O_DIRECT : 0));
     49     }
     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     }
     58     ~BlockFd() {
     59         if (m_fd >= 0) {
     60             close(m_fd);
     61         }
     62     }
     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     }
     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     }
     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 
    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 
    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