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