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: %s", elf_file.c_str());
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_large_compressed(benchmark::State & state)76 void BM_elf_create_large_compressed(benchmark::State& state) {
77 BenchmarkElfCreate(state, GetLargeCompressedFrameElfFile());
78 }
79 BENCHMARK(BM_elf_create_large_compressed);
80
BM_elf_create_large_eh_frame(benchmark::State & state)81 void BM_elf_create_large_eh_frame(benchmark::State& state) {
82 BenchmarkElfCreate(state, GetLargeEhFrameElfFile());
83 }
84 BENCHMARK(BM_elf_create_large_eh_frame);
85
InitializeBuildId(benchmark::State & state,unwindstack::Maps & maps,unwindstack::MapInfo ** build_id_map_info)86 static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
87 unwindstack::MapInfo** build_id_map_info) {
88 if (!maps.Parse()) {
89 state.SkipWithError("Failed to parse local maps.");
90 return;
91 }
92
93 // Find the libc.so share library and use that for benchmark purposes.
94 *build_id_map_info = nullptr;
95 for (auto& map_info : maps) {
96 if (map_info->offset() == 0 && map_info->GetBuildID() != "") {
97 *build_id_map_info = map_info.get();
98 break;
99 }
100 }
101
102 if (*build_id_map_info == nullptr) {
103 state.SkipWithError("Failed to find a map with a BuildID.");
104 }
105 }
106
BM_elf_get_build_id_from_object(benchmark::State & state)107 static void BM_elf_get_build_id_from_object(benchmark::State& state) {
108 unwindstack::LocalMaps maps;
109 unwindstack::MapInfo* build_id_map_info;
110 InitializeBuildId(state, maps, &build_id_map_info);
111
112 unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
113 unwindstack::Regs::CurrentArch());
114 if (!elf->valid()) {
115 state.SkipWithError("Cannot get valid elf from map.");
116 }
117
118 for (auto _ : state) {
119 state.PauseTiming();
120 unwindstack::SharedString* id = build_id_map_info->build_id();
121 if (id != nullptr) {
122 delete id;
123 build_id_map_info->set_build_id(nullptr);
124 }
125 state.ResumeTiming();
126 benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
127 }
128 }
129 BENCHMARK(BM_elf_get_build_id_from_object);
130
BM_elf_get_build_id_from_file(benchmark::State & state)131 static void BM_elf_get_build_id_from_file(benchmark::State& state) {
132 unwindstack::LocalMaps maps;
133 unwindstack::MapInfo* build_id_map_info;
134 InitializeBuildId(state, maps, &build_id_map_info);
135
136 for (auto _ : state) {
137 state.PauseTiming();
138 unwindstack::SharedString* id = build_id_map_info->build_id();
139 if (id != nullptr) {
140 delete id;
141 build_id_map_info->set_build_id(nullptr);
142 }
143 state.ResumeTiming();
144 benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
145 }
146 }
147 BENCHMARK(BM_elf_get_build_id_from_file);
148