Optimize Memory::ReadString
This function is responsible for majority of CPU time in prefetto.
Reduce the number of memory reads (don't read strings byte-by-byte).
Update all calls of ReadString to include the third parameter to have
a max read.
Add an Elf creation benchmark since this function is on the elf
creation path.
Test: libunwindstack_unit_test
Change-Id: Ia36e1f1a5ba76c9e9f13c43fb9e3691dde7897f2
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
new file mode 100644
index 0000000..c108a2a
--- /dev/null
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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);
diff --git a/libunwindstack/benchmarks/SymbolBenchmark.cpp b/libunwindstack/benchmarks/SymbolBenchmark.cpp
index a850ff0..73088da 100644
--- a/libunwindstack/benchmarks/SymbolBenchmark.cpp
+++ b/libunwindstack/benchmarks/SymbolBenchmark.cpp
@@ -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) {
@@ -66,7 +45,7 @@
#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();
@@ -88,7 +67,7 @@
#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();
@@ -105,14 +84,6 @@
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);
}
@@ -136,23 +107,23 @@
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);
diff --git a/libunwindstack/benchmarks/Utils.cpp b/libunwindstack/benchmarks/Utils.cpp
new file mode 100644
index 0000000..c92f109
--- /dev/null
+++ b/libunwindstack/benchmarks/Utils.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 <stdint.h>
+
+#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>
+
+std::string GetElfFile() {
+ return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so";
+}
+
+std::string GetSymbolSortedElfFile() {
+ return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat";
+}
+
+std::string GetCompressedElfFile() {
+ // Both are the same right now.
+ return GetSymbolSortedElfFile();
+}
+
+#if defined(__BIONIC__)
+
+#include <meminfo/procmeminfo.h>
+#include <procinfo/process_map.h>
+
+void GatherRss(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
diff --git a/libunwindstack/benchmarks/Utils.h b/libunwindstack/benchmarks/Utils.h
new file mode 100644
index 0000000..bee6efc
--- /dev/null
+++ b/libunwindstack/benchmarks/Utils.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_UTILS_H
+#define _LIBUNWINDSTACK_UTILS_H
+
+#include <stdint.h>
+
+#include <string>
+
+std::string GetElfFile();
+
+std::string GetSymbolSortedElfFile();
+
+std::string GetCompressedElfFile();
+
+#if defined(__BIONIC__)
+
+#include <meminfo/procmeminfo.h>
+#include <procinfo/process_map.h>
+
+void GatherRss(uint64_t* rss_bytes);
+
+#endif
+
+#endif // _LIBUNWINDSTACK_UTILS_h