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 <inttypes.h>
19 #include <malloc.h>
20 #include <stdint.h>
21 
22 #include <string>
23 #include <vector>
24 
25 #include <benchmark/benchmark.h>
26 
27 #include <unwindstack/Elf.h>
28 #include <unwindstack/Memory.h>
29 
30 #include "Utils.h"
31 
32 class SymbolLookupBenchmark : public benchmark::Fixture {
33  public:
RunBenchmark(benchmark::State & state,const std::vector<uint64_t> & offsets,const std::string & elf_file,bool expect_found,uint32_t runs=1)34   void RunBenchmark(benchmark::State& state, const std::vector<uint64_t>& offsets,
35                     const std::string& elf_file, bool expect_found, uint32_t runs = 1) {
36     MemoryTracker mem_tracker;
37     for (const auto& _ : state) {
38       state.PauseTiming();
39       mem_tracker.StartTrackingAllocations();
40       state.ResumeTiming();
41 
42       auto elf_memory = unwindstack::Memory::CreateFileMemory(elf_file, 0);
43       unwindstack::Elf elf(elf_memory);
44       if (!elf.Init() || !elf.valid()) {
45         errx(1, "Internal Error: Cannot open elf: %s", elf_file.c_str());
46       }
47 
48       unwindstack::SharedString name;
49       uint64_t offset;
50       for (size_t i = 0; i < runs; i++) {
51         for (auto pc : offsets) {
52           bool found = elf.GetFunctionName(pc, &name, &offset);
53           if (expect_found && !found) {
54             errx(1, "expected pc 0x%" PRIx64 " present, but not found.", pc);
55           } else if (!expect_found && found) {
56             errx(1, "expected pc 0x%" PRIx64 " not present, but found.", pc);
57           }
58         }
59       }
60 
61       state.PauseTiming();
62       mem_tracker.StopTrackingAllocations();
63       state.ResumeTiming();
64     }
65     mem_tracker.SetBenchmarkCounters(state);
66   }
67 
RunBenchmark(benchmark::State & state,uint64_t pc,const std::string & elf_file,bool expect_found,uint32_t runs=1)68   void RunBenchmark(benchmark::State& state, uint64_t pc, const std::string& elf_file,
69                     bool expect_found, uint32_t runs = 1) {
70     RunBenchmark(state, std::vector<uint64_t>{pc}, elf_file, expect_found, runs);
71   }
72 };
73 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_not_present)74 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_not_present)(benchmark::State& state) {
75   RunBenchmark(state, 0, GetElfFile(), false);
76 }
77 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_single)78 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_single)(benchmark::State& state) {
79   RunBenchmark(state, 0x22b2bc, GetElfFile(), true);
80 }
81 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_single_many_times)82 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_single_many_times)
83 (benchmark::State& state) {
84   RunBenchmark(state, 0x22b2bc, GetElfFile(), true, 4096);
85 }
86 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_multiple)87 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_multiple)(benchmark::State& state) {
88   RunBenchmark(state, std::vector<uint64_t>{0x22b2bc, 0xd5d30, 0x1312e8, 0x13582e, 0x1389c8},
89                GetElfFile(), true);
90 }
91 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_not_present_from_sorted)92 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_not_present_from_sorted)
93 (benchmark::State& state) {
94   RunBenchmark(state, 0, GetSymbolSortedElfFile(), false);
95 }
96 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_single_from_sorted)97 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_single_from_sorted)
98 (benchmark::State& state) {
99   RunBenchmark(state, 0x138638, GetSymbolSortedElfFile(), true);
100 }
101 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_single_many_times_from_sorted)102 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_single_many_times_from_sorted)
103 (benchmark::State& state) {
104   RunBenchmark(state, 0x138638, GetSymbolSortedElfFile(), true, 4096);
105 }
106 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_multiple_from_sorted)107 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_multiple_from_sorted)
108 (benchmark::State& state) {
109   RunBenchmark(state, std::vector<uint64_t>{0x138638, 0x84350, 0x14df18, 0x1f3a38, 0x1f3ca8},
110                GetSymbolSortedElfFile(), true);
111 }
112 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_not_present_from_large_compressed_frame)113 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_not_present_from_large_compressed_frame)
114 (benchmark::State& state) {
115   RunBenchmark(state, 0, GetLargeCompressedFrameElfFile(), false);
116 }
117 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_single_from_large_compressed_frame)118 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_single_from_large_compressed_frame)
119 (benchmark::State& state) {
120   RunBenchmark(state, 0x202aec, GetLargeCompressedFrameElfFile(), true);
121 }
122 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_single_many_times_from_large_compressed_frame)123 BENCHMARK_F(SymbolLookupBenchmark,
124             BM_symbol_lookup_find_single_many_times_from_large_compressed_frame)
125 (benchmark::State& state) {
126   RunBenchmark(state, 0x202aec, GetLargeCompressedFrameElfFile(), true, 4096);
127 }
128 
BENCHMARK_F(SymbolLookupBenchmark,BM_symbol_lookup_find_multiple_from_large_compressed_frame)129 BENCHMARK_F(SymbolLookupBenchmark, BM_symbol_lookup_find_multiple_from_large_compressed_frame)
130 (benchmark::State& state) {
131   RunBenchmark(state, std::vector<uint64_t>{0x202aec, 0x23e74c, 0xd000c, 0x201b10, 0x183060},
132                GetLargeCompressedFrameElfFile(), true);
133 }
134