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 <err.h>
18 #include <stdint.h>
19 
20 #include <string>
21 
22 #include <android-base/file.h>
23 #include <android-base/stringprintf.h>
24 
25 #include <benchmark/benchmark.h>
26 
27 #include <unwindstack/Maps.h>
28 
29 class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
30  public:
BenchmarkLocalUpdatableMaps()31   BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
32   virtual ~BenchmarkLocalUpdatableMaps() = default;
33 
GetMapsFile() const34   const std::string GetMapsFile() const override { return maps_file_; }
35 
BenchmarkSetMapsFile(const std::string & maps_file)36   void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
37 
38  private:
39   std::string maps_file_;
40 };
41 
42 static constexpr size_t kNumSmallMaps = 100;
43 static constexpr size_t kNumLargeMaps = 10000;
44 
CreateMap(const char * filename,size_t num_maps,size_t increment=1)45 static void CreateMap(const char* filename, size_t num_maps, size_t increment = 1) {
46   std::string maps;
47   for (size_t i = 0; i < num_maps; i += increment) {
48     maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
49                                         (i + 1) * 1000 * increment, i * increment);
50   }
51   if (!android::base::WriteStringToFile(maps, filename)) {
52     errx(1, "WriteStringToFile failed");
53   }
54 }
55 
ReparseBenchmark(benchmark::State & state,const char * maps1,size_t maps1_total,const char * maps2,size_t maps2_total)56 static void ReparseBenchmark(benchmark::State& state, const char* maps1, size_t maps1_total,
57                              const char* maps2, size_t maps2_total) {
58   for (const auto& _ : state) {
59     BenchmarkLocalUpdatableMaps maps;
60     maps.BenchmarkSetMapsFile(maps1);
61     if (!maps.Reparse()) {
62       errx(1, "Internal Error: reparse of initial maps filed.");
63     }
64     if (maps.Total() != maps1_total) {
65       errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
66            maps1_total);
67     }
68     maps.BenchmarkSetMapsFile(maps2);
69     if (!maps.Reparse()) {
70       errx(1, "Internal Error: reparse of second set of maps filed.");
71     }
72     if (maps.Total() != maps2_total) {
73       errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
74            maps2_total);
75     }
76   }
77 }
78 
BM_local_updatable_maps_reparse_double_initial_small(benchmark::State & state)79 void BM_local_updatable_maps_reparse_double_initial_small(benchmark::State& state) {
80   TemporaryFile initial_maps;
81   CreateMap(initial_maps.path, kNumSmallMaps, 2);
82 
83   TemporaryFile reparse_maps;
84   CreateMap(reparse_maps.path, kNumSmallMaps);
85 
86   ReparseBenchmark(state, initial_maps.path, kNumSmallMaps / 2, reparse_maps.path, kNumSmallMaps);
87 }
88 BENCHMARK(BM_local_updatable_maps_reparse_double_initial_small);
89 
BM_local_updatable_maps_reparse_double_initial_large(benchmark::State & state)90 void BM_local_updatable_maps_reparse_double_initial_large(benchmark::State& state) {
91   TemporaryFile initial_maps;
92   CreateMap(initial_maps.path, kNumLargeMaps, 2);
93 
94   TemporaryFile reparse_maps;
95   CreateMap(reparse_maps.path, kNumLargeMaps);
96 
97   ReparseBenchmark(state, initial_maps.path, kNumLargeMaps / 2, reparse_maps.path, kNumLargeMaps);
98 }
99 BENCHMARK(BM_local_updatable_maps_reparse_double_initial_large);
100 
BM_local_updatable_maps_reparse_same_maps_small(benchmark::State & state)101 void BM_local_updatable_maps_reparse_same_maps_small(benchmark::State& state) {
102   static constexpr size_t kNumSmallMaps = 100;
103   TemporaryFile maps;
104   CreateMap(maps.path, kNumSmallMaps);
105 
106   ReparseBenchmark(state, maps.path, kNumSmallMaps, maps.path, kNumSmallMaps);
107 }
108 BENCHMARK(BM_local_updatable_maps_reparse_same_maps_small);
109 
BM_local_updatable_maps_reparse_same_maps_large(benchmark::State & state)110 void BM_local_updatable_maps_reparse_same_maps_large(benchmark::State& state) {
111   TemporaryFile maps;
112   CreateMap(maps.path, kNumLargeMaps);
113 
114   ReparseBenchmark(state, maps.path, kNumLargeMaps, maps.path, kNumLargeMaps);
115 }
116 BENCHMARK(BM_local_updatable_maps_reparse_same_maps_large);
117 
BM_local_updatable_maps_reparse_few_extra_small(benchmark::State & state)118 void BM_local_updatable_maps_reparse_few_extra_small(benchmark::State& state) {
119   TemporaryFile maps1;
120   CreateMap(maps1.path, kNumSmallMaps - 4);
121 
122   TemporaryFile maps2;
123   CreateMap(maps2.path, kNumSmallMaps);
124 
125   ReparseBenchmark(state, maps1.path, kNumSmallMaps - 4, maps2.path, kNumSmallMaps);
126 }
127 BENCHMARK(BM_local_updatable_maps_reparse_few_extra_small);
128 
BM_local_updatable_maps_reparse_few_extra_large(benchmark::State & state)129 void BM_local_updatable_maps_reparse_few_extra_large(benchmark::State& state) {
130   TemporaryFile maps1;
131   CreateMap(maps1.path, kNumLargeMaps - 4);
132 
133   TemporaryFile maps2;
134   CreateMap(maps2.path, kNumLargeMaps);
135 
136   ReparseBenchmark(state, maps1.path, kNumLargeMaps - 4, maps2.path, kNumLargeMaps);
137 }
138 BENCHMARK(BM_local_updatable_maps_reparse_few_extra_large);
139 
BM_local_updatable_maps_reparse_few_less_small(benchmark::State & state)140 void BM_local_updatable_maps_reparse_few_less_small(benchmark::State& state) {
141   TemporaryFile maps1;
142   CreateMap(maps1.path, kNumSmallMaps);
143 
144   TemporaryFile maps2;
145   CreateMap(maps2.path, kNumSmallMaps - 4);
146 
147   ReparseBenchmark(state, maps1.path, kNumSmallMaps, maps2.path, kNumSmallMaps - 4);
148 }
149 BENCHMARK(BM_local_updatable_maps_reparse_few_less_small);
150 
BM_local_updatable_maps_reparse_few_less_large(benchmark::State & state)151 void BM_local_updatable_maps_reparse_few_less_large(benchmark::State& state) {
152   TemporaryFile maps1;
153   CreateMap(maps1.path, kNumLargeMaps);
154 
155   TemporaryFile maps2;
156   CreateMap(maps2.path, kNumLargeMaps - 4);
157 
158   ReparseBenchmark(state, maps1.path, kNumLargeMaps, maps2.path, kNumLargeMaps - 4);
159 }
160 BENCHMARK(BM_local_updatable_maps_reparse_few_less_large);
161