OSDN Git Service

Merge "Test SIOCKILLADDR on non-empty addresses too."
[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             cerr << "open failed: " << fd << endl;
58             return;
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             cerr << "mmap failed: " << (int)(uintptr_t)m_ptr << endl;
66             m_ptr = nullptr;
67             return;
68         }
69         switch (hint) {
70         case FILE_MAP_HINT_NONE: break;
71         case FILE_MAP_HINT_RAND:
72             madvise(m_ptr, m_size, MADV_RANDOM);
73             break;
74         case FILE_MAP_HINT_LINEAR:
75             madvise(m_ptr, m_size, MADV_SEQUENTIAL);
76             break;
77         }
78         for (int i = 0; i < m_size / pageSize; i++) {
79             uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * i;
80             fillPageJunk(targetPtr);
81         }
82     }
83     void benchRandom(bool write) {
84         size_t pagesTotal = m_size / pageSize;
85         size_t pagesToHit = pagesTotal / 128;
86         uint64_t nsTotal = 0;
87
88         chrono::time_point<chrono::high_resolution_clock> start, end;
89         start = chrono::high_resolution_clock::now();
90         for (int j = 0; j < pagesToHit; j++) {
91             int targetPage = rand() % pagesTotal;
92             uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * targetPage;
93             if (write) {
94                 *targetPtr = dummy;
95             }
96             else {
97                 dummy += *targetPtr;
98             }
99         }
100         end = chrono::high_resolution_clock::now();
101         nsTotal += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
102         //cout << "random: " << nsTotal / 1000.0 / (pagesToHit) << "us/page" << endl;
103         cout << "random " << (write ? "write" : "read") << ": " << ((4096.0 * pagesToHit) / (1 << 20)) / (nsTotal / 1.0E9) << "MB/s" << endl;
104     }
105     void benchLinear(bool write) {
106         int pagesTotal = m_size / pageSize;
107         int iterations = 4;
108         uint64_t nsTotal = 0;
109
110         chrono::time_point<chrono::high_resolution_clock> start, end;
111         start = chrono::high_resolution_clock::now();
112         for (int i = 0; i < iterations; i++) {
113             for (int j = 0; j < pagesTotal; j++) {
114                 uint8_t *targetPtr = (uint8_t*)m_ptr + 4096ull * j;
115                 if (write) {
116                     *targetPtr = dummy;
117                 }
118                 else {
119                     dummy += *targetPtr;
120                 }
121             }
122         }
123         end = chrono::high_resolution_clock::now();
124         nsTotal += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
125         //cout << "linear: " << nsTotal / 1000.0 / (pagesTotal * iterations) << "us/page" << endl;
126         cout << "linear " << (write ? "write" : "read") << ": " << ((4096.0 * pagesTotal * iterations) / (1 << 20)) / (nsTotal / 1.0E9 ) << "MB/s" << endl;
127     }
128     void dropCache() {
129         int ret1 = msync(m_ptr, m_size, MS_SYNC | MS_INVALIDATE);
130         madvise(m_ptr, m_size, MADV_DONTNEED);
131         (void)ret1;
132     }
133     ~FileMap() {
134         if (m_ptr)
135             munmap(m_ptr, m_size);
136     }
137
138 };
139
140 int main(int argc, char *argv[])
141 {
142     (void)argc;
143     (void)argv;
144     srand(0);
145
146     {
147         FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
148         file.benchRandom(false);
149     }
150     {
151         FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
152         file.benchLinear(false);
153     }
154     {
155         FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
156         file.benchRandom(true);
157     }
158     {
159         FileMap file{"/data/local/tmp/mmap_test", 16000 * (1ull << 20)};
160         file.benchLinear(true);
161     }
162     return 0;
163 }