1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/file.h>
18 #include <android-base/mapped_file.h>
19 #include <benchmark/benchmark.h>
20 #include <unistd.h>
21 
22 #include "incfs_support/access.h"
23 #include "incfs_support/signal_handling.h"
24 #include "util/map_ptr.h"
25 
makeFile()26 static std::unique_ptr<TemporaryFile> makeFile() {
27     auto tmp = std::unique_ptr<TemporaryFile>(new TemporaryFile());
28     char c = 1;
29     write(tmp->fd, &c, sizeof(c));
30     return tmp;
31 }
32 
33 static std::pair<std::unique_ptr<TemporaryFile>, std::unique_ptr<android::base::MappedFile>>
makeEmptyFileMapping()34 makeEmptyFileMapping() {
35     auto tmp = makeFile();
36     // mmap() only works for non-empty files, but it's "ok" to resize it back to empty afterwards
37     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
38     ftruncate(tmp->fd, 0);
39     return {std::move(tmp), std::move(mapping)};
40 }
41 
TestEmpty(benchmark::State & state)42 static void TestEmpty(benchmark::State& state) {
43     int val = 0;
44     for (auto _ : state) {
45         benchmark::DoNotOptimize(val += 1);
46     }
47 }
48 BENCHMARK(TestEmpty);
49 
TestSignal(benchmark::State & state)50 static void TestSignal(benchmark::State& state) {
51     auto tmp = makeFile();
52     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
53 
54     int val = 0;
55     for (auto _ : state) {
56         SCOPED_SIGBUS_HANDLER({ break; });
57         val += *mapping->data();
58     }
59 }
60 BENCHMARK(TestSignal);
61 
TestRead(benchmark::State & state)62 static void TestRead(benchmark::State& state) {
63     auto tmp = makeFile();
64     int val = 0;
65     for (auto _ : state) {
66         char c;
67         pread(tmp->fd, &c, sizeof(c), 0);
68         val += c;
69     }
70 }
71 BENCHMARK(TestRead);
72 
TestMapPtrRaw(benchmark::State & state)73 static void TestMapPtrRaw(benchmark::State& state) {
74     auto tmp = makeFile();
75     android::incfs::IncFsFileMap map;
76     map.CreateForceVerification(tmp->fd, 0, 1, tmp->path, true);
77     int val = 0;
78     const uint8_t* prev_block = nullptr;
79     for (auto _ : state) {
80         auto start = static_cast<const uint8_t*>(map.unsafe_data());
81         auto end = start + map.length();
82         val += map.Verify(start, end, &prev_block);
83     }
84 }
85 BENCHMARK(TestMapPtrRaw);
86 
TestMapPtr(benchmark::State & state)87 static void TestMapPtr(benchmark::State& state) {
88     auto tmp = makeFile();
89     android::incfs::IncFsFileMap map;
90     map.CreateForceVerification(tmp->fd, 0, 1, tmp->path, true);
91     int val = 0;
92     for (auto _ : state) {
93         val += map.data<char>().verify();
94     }
95 }
96 BENCHMARK(TestMapPtr);
97 
TestAccess(benchmark::State & state)98 static void TestAccess(benchmark::State& state) {
99     auto tmp = makeFile();
100     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
101     int val = 0;
102     for (auto _ : state) {
103         incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
104     }
105 }
106 BENCHMARK(TestAccess);
107 
TestAccessFast(benchmark::State & state)108 static void TestAccessFast(benchmark::State& state) {
109     auto tmp = makeFile();
110     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
111     int val = 0;
112     incfs::access(mapping->data(), [&](auto ptr) {
113         for (auto _ : state) {
114             val += *ptr;
115         }
116     });
117 }
118 BENCHMARK(TestAccessFast);
119 
TestAccessVal(benchmark::State & state)120 static void TestAccessVal(benchmark::State& state) {
121     auto tmp = makeFile();
122     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
123     int val = 0;
124     for (auto _ : state) {
125         incfs::access(mapping->data(), [&](auto ptr) { return val += *ptr; });
126     }
127 }
128 BENCHMARK(TestAccessVal);
129 
TestAccessNested(benchmark::State & state)130 static void TestAccessNested(benchmark::State& state) {
131     auto tmp = makeFile();
132     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
133     int val = 0;
134     incfs::access(nullptr, [&](auto) {
135         for (auto _ : state) {
136             incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
137         }
138     });
139 }
140 BENCHMARK(TestAccessNested);
141 
TestAccessDoubleNested(benchmark::State & state)142 static void TestAccessDoubleNested(benchmark::State& state) {
143     auto tmp = makeFile();
144     auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
145     int val = 0;
146     incfs::access(nullptr, [&](auto) {
147         incfs::access(nullptr, [&](auto) {
148             for (auto _ : state) {
149                 incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
150             }
151         });
152     });
153 }
154 BENCHMARK(TestAccessDoubleNested);
155 
TestAccessError(benchmark::State & state)156 static void TestAccessError(benchmark::State& state) {
157     auto [tmp, mapping] = makeEmptyFileMapping();
158     int val = 0;
159     for (auto _ : state) {
160         incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
161     }
162 }
163 BENCHMARK(TestAccessError);
164 
165 BENCHMARK_MAIN();
166