Loading libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -395,7 +395,9 @@ cc_benchmark { srcs: [ "benchmarks/unwind_benchmarks.cpp", "benchmarks/ElfBenchmark.cpp", "benchmarks/SymbolBenchmark.cpp", "benchmarks/Utils.cpp", ], data: [ Loading libunwindstack/ElfInterface.cpp +7 −5 Original line number Diff line number Diff line Loading @@ -371,7 +371,7 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { // Look for the .debug_frame and .gnu_debugdata. if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) { if (name == ".debug_frame") { debug_frame_offset_ = shdr.sh_offset; debug_frame_size_ = shdr.sh_size; Loading Loading @@ -405,7 +405,7 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { } else if (shdr.sh_type == SHT_NOTE) { if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name) && if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) && name == ".note.gnu.build-id") { gnu_build_id_offset_ = shdr.sh_offset; gnu_build_id_size_ = shdr.sh_size; Loading Loading @@ -456,10 +456,11 @@ std::string ElfInterface::GetSonameWithTemplate() { for (const auto& entry : strtabs_) { if (entry.first == strtab_addr) { soname_offset = entry.second + soname_offset; if (soname_offset >= entry.second + strtab_size) { uint64_t soname_max = entry.second + strtab_size; if (soname_offset >= soname_max) { return ""; } if (!memory_->ReadString(soname_offset, &soname_)) { if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) { return ""; } soname_type_ = SONAME_VALID; Loading Loading @@ -608,7 +609,8 @@ bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_i } std::string name; if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size && memory->ReadString(sec_offset + shdr.sh_name, &name) && name == ".note.gnu.build-id") { memory->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) && name == ".note.gnu.build-id") { *build_id_offset = shdr.sh_offset; *build_id_size = shdr.sh_size; return true; Loading libunwindstack/Memory.cpp +22 −12 Original line number Diff line number Diff line Loading @@ -158,20 +158,30 @@ bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) { return rc == size; } bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) { string->clear(); uint64_t bytes_read = 0; while (bytes_read < max_read) { uint8_t value; if (!ReadFully(addr, &value, sizeof(value))) { return false; } if (value == '\0') { bool Memory::ReadString(uint64_t addr, std::string* dst, size_t max_read) { char buffer[256]; // Large enough for 99% of symbol names. size_t size = 0; // Number of bytes which were read into the buffer. for (size_t offset = 0; offset < max_read; offset += size) { // Look for null-terminator first, so we can allocate string of exact size. // If we know the end of valid memory range, do the reads in larger blocks. size_t read = std::min(sizeof(buffer), max_read - offset); size = Read(addr + offset, buffer, read); if (size == 0) { return false; // We have not found end of string yet and we can not read more data. } size_t length = strnlen(buffer, size); // Index of the null-terminator. if (length < size) { // We found the null-terminator. Allocate the string and set its content. if (offset == 0) { // We did just single read, so the buffer already contains the whole string. dst->assign(buffer, length); return true; } else { // The buffer contains only the last block. Read the whole string again. dst->assign(offset + length, '\0'); return ReadFully(addr, dst->data(), dst->size()); } } string->push_back(value); addr++; bytes_read++; } return false; } Loading libunwindstack/benchmarks/ElfBenchmark.cpp 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <err.h> #include <malloc.h> #include <stdint.h> #include <string> #include <benchmark/benchmark.h> #include <unwindstack/Elf.h> #include <unwindstack/Memory.h> #include "Utils.h" static void BenchmarkElfCreate(benchmark::State& state, const std::string& elf_file) { #if defined(__BIONIC__) uint64_t rss_bytes = 0; #endif uint64_t alloc_bytes = 0; for (auto _ : state) { state.PauseTiming(); #if defined(__BIONIC__) mallopt(M_PURGE, 0); uint64_t rss_bytes_before = 0; GatherRss(&rss_bytes_before); #endif uint64_t alloc_bytes_before = mallinfo().uordblks; auto file_memory = unwindstack::Memory::CreateFileMemory(elf_file, 0); state.ResumeTiming(); unwindstack::Elf elf(file_memory.release()); if (!elf.Init() || !elf.valid()) { errx(1, "Internal Error: Cannot open elf."); } state.PauseTiming(); #if defined(__BIONIC__) mallopt(M_PURGE, 0); #endif alloc_bytes += mallinfo().uordblks - alloc_bytes_before; #if defined(__BIONIC__) GatherRss(&rss_bytes); rss_bytes -= rss_bytes_before; #endif state.ResumeTiming(); } #if defined(__BIONIC__) state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations()); #endif state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations()); } void BM_elf_create(benchmark::State& state) { BenchmarkElfCreate(state, GetElfFile()); } BENCHMARK(BM_elf_create); void BM_elf_create_compressed(benchmark::State& state) { BenchmarkElfCreate(state, GetCompressedElfFile()); } BENCHMARK(BM_elf_create_compressed); libunwindstack/benchmarks/SymbolBenchmark.cpp +7 −36 Original line number Diff line number Diff line Loading @@ -22,33 +22,12 @@ #include <string> #include <vector> #include <android-base/file.h> #include <android-base/strings.h> #include <benchmark/benchmark.h> #include <unwindstack/Elf.h> #include <unwindstack/Memory.h> #if defined(__BIONIC__) #include <meminfo/procmeminfo.h> #include <procinfo/process_map.h> static void Gather(uint64_t* rss_bytes) { android::meminfo::ProcMemInfo proc_mem(getpid()); const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats(); for (auto& vma : maps) { if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") || android::base::StartsWith(vma.name, "[anon:GWP-ASan")) { android::meminfo::Vma update_vma(vma); if (!proc_mem.FillInVmaStats(update_vma)) { err(1, "FillInVmaStats failed\n"); } *rss_bytes += update_vma.usage.rss; } } } #endif #include "Utils.h" static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> offsets, std::string elf_file, bool expect_found) { Loading @@ -66,7 +45,7 @@ static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> #if defined(__BIONIC__) mallopt(M_PURGE, 0); uint64_t rss_bytes_before = 0; Gather(&rss_bytes_before); GatherRss(&rss_bytes_before); #endif uint64_t alloc_bytes_before = mallinfo().uordblks; state.ResumeTiming(); Loading @@ -88,7 +67,7 @@ static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> #endif alloc_bytes += mallinfo().uordblks - alloc_bytes_before; #if defined(__BIONIC__) Gather(&rss_bytes); GatherRss(&rss_bytes); rss_bytes -= rss_bytes_before; #endif state.ResumeTiming(); Loading @@ -105,14 +84,6 @@ static void BenchmarkSymbolLookup(benchmark::State& state, uint64_t pc, std::str BenchmarkSymbolLookup(state, std::vector<uint64_t>{pc}, elf_file, expect_found); } std::string GetElfFile() { return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so"; } std::string GetSortedElfFile() { return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat"; } void BM_symbol_not_present(benchmark::State& state) { BenchmarkSymbolLookup(state, 0, GetElfFile(), false); } Loading @@ -136,23 +107,23 @@ void BM_symbol_find_multiple(benchmark::State& state) { BENCHMARK(BM_symbol_find_multiple); void BM_symbol_not_present_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, 0, GetSortedElfFile(), false); BenchmarkSymbolLookup(state, 0, GetSymbolSortedElfFile(), false); } BENCHMARK(BM_symbol_not_present_from_sorted); void BM_symbol_find_single_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, 0x138638, GetSortedElfFile(), true); BenchmarkSymbolLookup(state, 0x138638, GetSymbolSortedElfFile(), true); } BENCHMARK(BM_symbol_find_single_from_sorted); void BM_symbol_find_single_many_times_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSortedElfFile(), true); BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSymbolSortedElfFile(), true); } BENCHMARK(BM_symbol_find_single_many_times_from_sorted); void BM_symbol_find_multiple_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, std::vector<uint64_t>{0x138638, 0x84350, 0x14df18, 0x1f3a38, 0x1f3ca8}, GetSortedElfFile(), true); GetSymbolSortedElfFile(), true); } BENCHMARK(BM_symbol_find_multiple_from_sorted); Loading
libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -395,7 +395,9 @@ cc_benchmark { srcs: [ "benchmarks/unwind_benchmarks.cpp", "benchmarks/ElfBenchmark.cpp", "benchmarks/SymbolBenchmark.cpp", "benchmarks/Utils.cpp", ], data: [ Loading
libunwindstack/ElfInterface.cpp +7 −5 Original line number Diff line number Diff line Loading @@ -371,7 +371,7 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { // Look for the .debug_frame and .gnu_debugdata. if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) { if (name == ".debug_frame") { debug_frame_offset_ = shdr.sh_offset; debug_frame_size_ = shdr.sh_size; Loading Loading @@ -405,7 +405,7 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { } else if (shdr.sh_type == SHT_NOTE) { if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name) && if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) && name == ".note.gnu.build-id") { gnu_build_id_offset_ = shdr.sh_offset; gnu_build_id_size_ = shdr.sh_size; Loading Loading @@ -456,10 +456,11 @@ std::string ElfInterface::GetSonameWithTemplate() { for (const auto& entry : strtabs_) { if (entry.first == strtab_addr) { soname_offset = entry.second + soname_offset; if (soname_offset >= entry.second + strtab_size) { uint64_t soname_max = entry.second + strtab_size; if (soname_offset >= soname_max) { return ""; } if (!memory_->ReadString(soname_offset, &soname_)) { if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) { return ""; } soname_type_ = SONAME_VALID; Loading Loading @@ -608,7 +609,8 @@ bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_i } std::string name; if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size && memory->ReadString(sec_offset + shdr.sh_name, &name) && name == ".note.gnu.build-id") { memory->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) && name == ".note.gnu.build-id") { *build_id_offset = shdr.sh_offset; *build_id_size = shdr.sh_size; return true; Loading
libunwindstack/Memory.cpp +22 −12 Original line number Diff line number Diff line Loading @@ -158,20 +158,30 @@ bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) { return rc == size; } bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) { string->clear(); uint64_t bytes_read = 0; while (bytes_read < max_read) { uint8_t value; if (!ReadFully(addr, &value, sizeof(value))) { return false; } if (value == '\0') { bool Memory::ReadString(uint64_t addr, std::string* dst, size_t max_read) { char buffer[256]; // Large enough for 99% of symbol names. size_t size = 0; // Number of bytes which were read into the buffer. for (size_t offset = 0; offset < max_read; offset += size) { // Look for null-terminator first, so we can allocate string of exact size. // If we know the end of valid memory range, do the reads in larger blocks. size_t read = std::min(sizeof(buffer), max_read - offset); size = Read(addr + offset, buffer, read); if (size == 0) { return false; // We have not found end of string yet and we can not read more data. } size_t length = strnlen(buffer, size); // Index of the null-terminator. if (length < size) { // We found the null-terminator. Allocate the string and set its content. if (offset == 0) { // We did just single read, so the buffer already contains the whole string. dst->assign(buffer, length); return true; } else { // The buffer contains only the last block. Read the whole string again. dst->assign(offset + length, '\0'); return ReadFully(addr, dst->data(), dst->size()); } } string->push_back(value); addr++; bytes_read++; } return false; } Loading
libunwindstack/benchmarks/ElfBenchmark.cpp 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <err.h> #include <malloc.h> #include <stdint.h> #include <string> #include <benchmark/benchmark.h> #include <unwindstack/Elf.h> #include <unwindstack/Memory.h> #include "Utils.h" static void BenchmarkElfCreate(benchmark::State& state, const std::string& elf_file) { #if defined(__BIONIC__) uint64_t rss_bytes = 0; #endif uint64_t alloc_bytes = 0; for (auto _ : state) { state.PauseTiming(); #if defined(__BIONIC__) mallopt(M_PURGE, 0); uint64_t rss_bytes_before = 0; GatherRss(&rss_bytes_before); #endif uint64_t alloc_bytes_before = mallinfo().uordblks; auto file_memory = unwindstack::Memory::CreateFileMemory(elf_file, 0); state.ResumeTiming(); unwindstack::Elf elf(file_memory.release()); if (!elf.Init() || !elf.valid()) { errx(1, "Internal Error: Cannot open elf."); } state.PauseTiming(); #if defined(__BIONIC__) mallopt(M_PURGE, 0); #endif alloc_bytes += mallinfo().uordblks - alloc_bytes_before; #if defined(__BIONIC__) GatherRss(&rss_bytes); rss_bytes -= rss_bytes_before; #endif state.ResumeTiming(); } #if defined(__BIONIC__) state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations()); #endif state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations()); } void BM_elf_create(benchmark::State& state) { BenchmarkElfCreate(state, GetElfFile()); } BENCHMARK(BM_elf_create); void BM_elf_create_compressed(benchmark::State& state) { BenchmarkElfCreate(state, GetCompressedElfFile()); } BENCHMARK(BM_elf_create_compressed);
libunwindstack/benchmarks/SymbolBenchmark.cpp +7 −36 Original line number Diff line number Diff line Loading @@ -22,33 +22,12 @@ #include <string> #include <vector> #include <android-base/file.h> #include <android-base/strings.h> #include <benchmark/benchmark.h> #include <unwindstack/Elf.h> #include <unwindstack/Memory.h> #if defined(__BIONIC__) #include <meminfo/procmeminfo.h> #include <procinfo/process_map.h> static void Gather(uint64_t* rss_bytes) { android::meminfo::ProcMemInfo proc_mem(getpid()); const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats(); for (auto& vma : maps) { if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") || android::base::StartsWith(vma.name, "[anon:GWP-ASan")) { android::meminfo::Vma update_vma(vma); if (!proc_mem.FillInVmaStats(update_vma)) { err(1, "FillInVmaStats failed\n"); } *rss_bytes += update_vma.usage.rss; } } } #endif #include "Utils.h" static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> offsets, std::string elf_file, bool expect_found) { Loading @@ -66,7 +45,7 @@ static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> #if defined(__BIONIC__) mallopt(M_PURGE, 0); uint64_t rss_bytes_before = 0; Gather(&rss_bytes_before); GatherRss(&rss_bytes_before); #endif uint64_t alloc_bytes_before = mallinfo().uordblks; state.ResumeTiming(); Loading @@ -88,7 +67,7 @@ static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> #endif alloc_bytes += mallinfo().uordblks - alloc_bytes_before; #if defined(__BIONIC__) Gather(&rss_bytes); GatherRss(&rss_bytes); rss_bytes -= rss_bytes_before; #endif state.ResumeTiming(); Loading @@ -105,14 +84,6 @@ static void BenchmarkSymbolLookup(benchmark::State& state, uint64_t pc, std::str BenchmarkSymbolLookup(state, std::vector<uint64_t>{pc}, elf_file, expect_found); } std::string GetElfFile() { return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so"; } std::string GetSortedElfFile() { return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat"; } void BM_symbol_not_present(benchmark::State& state) { BenchmarkSymbolLookup(state, 0, GetElfFile(), false); } Loading @@ -136,23 +107,23 @@ void BM_symbol_find_multiple(benchmark::State& state) { BENCHMARK(BM_symbol_find_multiple); void BM_symbol_not_present_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, 0, GetSortedElfFile(), false); BenchmarkSymbolLookup(state, 0, GetSymbolSortedElfFile(), false); } BENCHMARK(BM_symbol_not_present_from_sorted); void BM_symbol_find_single_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, 0x138638, GetSortedElfFile(), true); BenchmarkSymbolLookup(state, 0x138638, GetSymbolSortedElfFile(), true); } BENCHMARK(BM_symbol_find_single_from_sorted); void BM_symbol_find_single_many_times_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSortedElfFile(), true); BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSymbolSortedElfFile(), true); } BENCHMARK(BM_symbol_find_single_many_times_from_sorted); void BM_symbol_find_multiple_from_sorted(benchmark::State& state) { BenchmarkSymbolLookup(state, std::vector<uint64_t>{0x138638, 0x84350, 0x14df18, 0x1f3a38, 0x1f3ca8}, GetSortedElfFile(), true); GetSymbolSortedElfFile(), true); } BENCHMARK(BM_symbol_find_multiple_from_sorted);