zram-perf.cpp 4.8 KB

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