OSDN Git Service

merge in nyc-release history after reset to nyc-dev
[android-x86/system-extras.git] / mmap-perf / mmapPerf.cpp
1 #include <string>
2 #include <cstring>
3 #include <cstdlib>
4 #include <cstdio>
5 #include <iostream>
6 #include <vector>
7 #include <tuple>
8
9 #include <unistd.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <sys/mman.h>
13
14 using namespace std;
15 static const size_t pageSize = 4096;
16
17 class Fd {
18     int m_fd = -1;
19 public:
20     int get() { return m_fd; }
21     void set(int fd) { m_fd = fd; }
22     Fd() {}
23     Fd(int fd) : m_fd{fd} {}
24     ~Fd() {
25         if (m_fd >= 0)
26             close(m_fd);
27     }
28 };
29
30 int dummy = 0;
31
32 void fillPageJunk(void *ptr)
33 {
34     uint64_t seed = (unsigned long long)rand() | ((unsigned long long)rand() << 32);
35     uint64_t *target = (uint64_t*)ptr;
36     for (int i = 0; i < pageSize / sizeof(uint64_t); i++) {
37         *target = seed ^ (uint64_t)(uintptr_t)target;
38         seed = (seed << 1) | ((seed >> 63) & 1);
39         target++;
40     }
41 }
42
43 class FileMap {
44     string m_name;
45     size_t m_size;
46     void *m_ptr = nullptr;
47     Fd m_fileFd;
48 public:
49     enum Hint {
50        FILE_MAP_HINT_NONE,
51        FILE_MAP_HINT_RAND,
52        FILE_MAP_HINT_LINEAR,
53     };
54     FileMap(const string &name, size_t size, Hint hint = FILE_MAP_HINT_NONE) : m_name{name}, m_size{size} {
55         int fd = open(name.c_str(), O_CREAT | O_RDWR, S_IRWXU);
56         if (fd < 0) {
57             cout << "Error: open failed for " << name << ": " << strerror(errno) << endl;
58             exit(1);
59         }
60         m_fileFd.set(fd);
61         fallocate(m_fileFd.get(), 0, 0, size);
62         unlink(name.c_str());
63         m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fileFd.get(), 0);
64         if ((int)(uintptr_t)m_ptr == -1) {
65             cout << "Error: mmap failed: " << (int)(uintptr_t)m_ptr << ": " << strerror(errno) << endl;
66             exit(1);
67         }
68         switch (hint) {
69         case FILE_MAP_HINT_NONE: break;
70         case FILE_MAP_HINT_RAND:
71             madvise(m_ptr, m_size, MADV_RANDOM);
72             break;
73         case FILE_MAP_HINT_LINEAR:
74             madvise(m_ptr, m_size, MADV_SEQUENTIAL);
75             break;
76         }
77         for (int i = 0; i < m_size / pageSize; i++) {
78             uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * i;
79             fillPageJunk(targetPtr);
80         }
81     }
82     double benchRandom(bool write) {
83         size_t pagesTotal = m_size / pageSize;
84         size_t pagesToHit = pagesTotal / 128;
85         uint64_t nsTotal = 0;
86
87         chrono::time_point<chrono::high_resolution_clock> start, end;
88         start = chrono::high_resolution_clock::now();
89         for (int j = 0; j < pagesToHit; j++) {
90             int targetPage = rand() % pagesTotal;
91             uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * targetPage;
92             if (write) {
93                 *targetPtr = dummy;
94             }
95             else {
96                 dummy += *targetPtr;
97             }
98         }
99         end = chrono::high_resolution_clock::now();
100         nsTotal += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
101         return ((4096.0 * pagesToHit) / (1 << 20)) / (nsTotal / 1.0E9);
102     }
103     double benchLinear(bool write) {
104         int pagesTotal = m_size / pageSize;
105         int iterations = 4;
106         uint64_t nsTotal = 0;
107
108         chrono::time_point<chrono::high_resolution_clock> start, end;
109         start = chrono::high_resolution_clock::now();
110         for (int i = 0; i < iterations; i++) {
111             for (int j = 0; j < pagesTotal; j++) {
112                 uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * j;
113                 if (write) {
114                     *targetPtr = dummy;
115                 }
116                 else {
117                     dummy += *targetPtr;
118                 }
119             }
120         }
121         end = chrono::high_resolution_clock::now();
122         nsTotal += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
123         return ((4096.0 * pagesTotal * iterations) / (1 << 20)) / (nsTotal / 1.0E9 );
124     }
125     void dropCache() {
126         int ret1 = msync(m_ptr, m_size, MS_SYNC | MS_INVALIDATE);
127         madvise(m_ptr, m_size, MADV_DONTNEED);
128         (void)ret1;
129     }
130     ~FileMap() {
131         if (m_ptr)
132             munmap(m_ptr, m_size);
133     }
134
135 };
136
137 int main(int argc, char *argv[])
138 {
139     double randomRead, randomWrite, linearRead, linearWrite;
140     size_t fsize = 0;
141     srand(0);
142
143     if (argc == 1)
144         fsize = 1024 * (1ull << 20);
145     else if (argc == 2) {
146         long long sz = atoll(argv[1]);
147         if (sz > 0 && (sz << 20) < SIZE_MAX)
148             fsize = atoll(argv[1]) * (1ull << 20);
149     }
150
151     if (fsize <= 0) {
152         cout << "Error: invalid argument" << endl;
153         cerr << "Usage: " << argv[0] << " [fsize_in_MB]" << endl;
154         exit(1);
155     }
156     cerr << "Using filesize=" << fsize << endl;
157
158     {
159         cerr << "Running random_read..." << endl;
160         FileMap file{"/data/local/tmp/mmap_test", fsize};
161         randomRead = file.benchRandom(false);
162     }
163     {
164         cerr << "Running linear_read..." << endl;
165         FileMap file{"/data/local/tmp/mmap_test", fsize};
166         linearRead = file.benchLinear(false);
167     }
168     {
169         cerr << "Running random_write..." << endl;
170         FileMap file{"/data/local/tmp/mmap_test", fsize};
171         randomWrite = file.benchRandom(true);
172     }
173     {
174         cerr << "Running linear_write..." << endl;
175         FileMap file{"/data/local/tmp/mmap_test", fsize};
176         linearWrite = file.benchLinear(true);
177     }
178     cout << "Success" << endl;
179     cout << "random_read : " << randomRead << " : MB/s" << endl;
180     cout << "linear_read : " << linearRead << " : MB/s" << endl;
181     cout << "random_write : " << randomWrite << " : MB/s" << endl;
182     cout << "linear_write : " << linearWrite << " : MB/s" << endl;
183     return 0;
184 }