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 <malloc.h>
19 #include <stdint.h>
20 
21 #include <string>
22 
23 #include <benchmark/benchmark.h>
24 
25 #include <unwindstack/Elf.h>
26 #include <unwindstack/Maps.h>
27 #include <unwindstack/Memory.h>
28 #include <unwindstack/Regs.h>
29 
30 #include "Utils.h"
31 
BenchmarkElfCreate(benchmark::State & state,const std::string & elf_file)32 static void BenchmarkElfCreate(benchmark::State& state, const std::string& elf_file) {
33 #if defined(__BIONIC__)
34   uint64_t rss_bytes = 0;
35 #endif
36   uint64_t alloc_bytes = 0;
37   for (auto _ : state) {
38     state.PauseTiming();
39 #if defined(__BIONIC__)
40     mallopt(M_PURGE, 0);
41     uint64_t rss_bytes_before = 0;
42     GatherRss(&rss_bytes_before);
43 #endif
44     uint64_t alloc_bytes_before = mallinfo().uordblks;
45     auto file_memory = unwindstack::Memory::CreateFileMemory(elf_file, 0);
46     state.ResumeTiming();
47 
48     unwindstack::Elf elf(file_memory.release());
49     if (!elf.Init() || !elf.valid()) {
50       errx(1, "Internal Error: Cannot open elf.");
51     }
52 
53     state.PauseTiming();
54 #if defined(__BIONIC__)
55     mallopt(M_PURGE, 0);
56 #endif
57     alloc_bytes += mallinfo().uordblks - alloc_bytes_before;
58 #if defined(__BIONIC__)
59     GatherRss(&rss_bytes);
60     rss_bytes -= rss_bytes_before;
61 #endif
62     state.ResumeTiming();
63   }
64 
65 #if defined(__BIONIC__)
66   state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations());
67 #endif
68   state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations());
69 }
70 
BM_elf_create(benchmark::State & state)71 void BM_elf_create(benchmark::State& state) {
72   BenchmarkElfCreate(state, GetElfFile());
73 }
74 BENCHMARK(BM_elf_create);
75 
BM_elf_create_compressed(benchmark::State & state)76 void BM_elf_create_compressed(benchmark::State& state) {
77   BenchmarkElfCreate(state, GetCompressedElfFile());
78 }
79 BENCHMARK(BM_elf_create_compressed);
80 
InitializeBuildId(benchmark::State & state,unwindstack::Maps & maps,unwindstack::MapInfo ** build_id_map_info)81 static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
82                               unwindstack::MapInfo** build_id_map_info) {
83   if (!maps.Parse()) {
84     state.SkipWithError("Failed to parse local maps.");
85     return;
86   }
87 
88   // Find the libc.so share library and use that for benchmark purposes.
89   *build_id_map_info = nullptr;
90   for (auto& map_info : maps) {
91     if (map_info->offset() == 0 && map_info->GetBuildID() != "") {
92       *build_id_map_info = map_info.get();
93       break;
94     }
95   }
96 
97   if (*build_id_map_info == nullptr) {
98     state.SkipWithError("Failed to find a map with a BuildID.");
99   }
100 }
101 
BM_elf_get_build_id_from_object(benchmark::State & state)102 static void BM_elf_get_build_id_from_object(benchmark::State& state) {
103   unwindstack::LocalMaps maps;
104   unwindstack::MapInfo* build_id_map_info;
105   InitializeBuildId(state, maps, &build_id_map_info);
106 
107   unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
108                                                     unwindstack::Regs::CurrentArch());
109   if (!elf->valid()) {
110     state.SkipWithError("Cannot get valid elf from map.");
111   }
112 
113   for (auto _ : state) {
114     state.PauseTiming();
115     unwindstack::SharedString* id = build_id_map_info->build_id();
116     if (id != nullptr) {
117       delete id;
118       build_id_map_info->set_build_id(nullptr);
119     }
120     state.ResumeTiming();
121     benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
122   }
123 }
124 BENCHMARK(BM_elf_get_build_id_from_object);
125 
BM_elf_get_build_id_from_file(benchmark::State & state)126 static void BM_elf_get_build_id_from_file(benchmark::State& state) {
127   unwindstack::LocalMaps maps;
128   unwindstack::MapInfo* build_id_map_info;
129   InitializeBuildId(state, maps, &build_id_map_info);
130 
131   for (auto _ : state) {
132     state.PauseTiming();
133     unwindstack::SharedString* id = build_id_map_info->build_id();
134     if (id != nullptr) {
135       delete id;
136       build_id_map_info->set_build_id(nullptr);
137     }
138     state.ResumeTiming();
139     benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
140   }
141 }
142 BENCHMARK(BM_elf_get_build_id_from_file);
143