simpleperf: use callback API to read dex symbols.
In experiment, it saves about 20% time reading dex symbols.
Bug: none
Test: run simpleperf_unit_test
Change-Id: I0e6bfd1f51f99f57175fece77c2ee3518e676a71
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 77a8b15..d3b7ffb 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -463,9 +463,12 @@
std::vector<Symbol> LoadSymbolsImpl() override {
std::vector<Symbol> symbols;
- std::vector<DexFileSymbol> dex_file_symbols;
auto tuple = SplitUrlInApk(debug_file_path_);
bool status = false;
+ auto symbol_callback = [&](DexFileSymbol* dex_symbol) {
+ symbols.emplace_back(std::string_view(dex_symbol->name, dex_symbol->name_size),
+ dex_symbol->addr, dex_symbol->size);
+ };
if (std::get<0>(tuple)) {
std::unique_ptr<ArchiveHelper> ahelper = ArchiveHelper::CreateInstance(std::get<1>(tuple));
ZipEntry entry;
@@ -473,10 +476,10 @@
if (ahelper && ahelper->FindEntry(std::get<2>(tuple), &entry) &&
ahelper->GetEntryData(entry, &data)) {
status = ReadSymbolsFromDexFileInMemory(data.data(), data.size(), dex_file_offsets_,
- &dex_file_symbols);
+ symbol_callback);
}
} else {
- status = ReadSymbolsFromDexFile(debug_file_path_, dex_file_offsets_, &dex_file_symbols);
+ status = ReadSymbolsFromDexFile(debug_file_path_, dex_file_offsets_, symbol_callback);
}
if (!status) {
android::base::LogSeverity level =
@@ -485,9 +488,6 @@
return symbols;
}
LOG(VERBOSE) << "Read symbols from " << debug_file_path_ << " successfully";
- for (auto& symbol : dex_file_symbols) {
- symbols.emplace_back(symbol.name, symbol.offset, symbol.len);
- }
SortAndFixSymbols(symbols);
return symbols;
}
diff --git a/simpleperf/nonlinux_support/nonlinux_support.cpp b/simpleperf/nonlinux_support/nonlinux_support.cpp
index 823b6e5..2268e30 100644
--- a/simpleperf/nonlinux_support/nonlinux_support.cpp
+++ b/simpleperf/nonlinux_support/nonlinux_support.cpp
@@ -32,12 +32,12 @@
}
bool ReadSymbolsFromDexFileInMemory(void*, uint64_t, const std::vector<uint64_t>&,
- std::vector<DexFileSymbol>*) {
+ const std::function<void(DexFileSymbol*)>&) {
return true;
}
bool ReadSymbolsFromDexFile(const std::string&, const std::vector<uint64_t>&,
- std::vector<DexFileSymbol>*) {
+ const std::function<void(DexFileSymbol*)>&) {
return true;
}
diff --git a/simpleperf/read_dex_file.cpp b/simpleperf/read_dex_file.cpp
index 055a408..d4d50e0 100644
--- a/simpleperf/read_dex_file.cpp
+++ b/simpleperf/read_dex_file.cpp
@@ -31,27 +31,20 @@
namespace simpleperf {
static bool ReadSymbols(
- const std::vector<uint64_t>& dex_file_offsets, std::vector<DexFileSymbol>* symbols,
- const std::function<std::unique_ptr<art_api::dex::DexFile>(uint64_t offset)>& open_file_cb) {
+ const std::vector<uint64_t>& dex_file_offsets,
+ const std::function<std::unique_ptr<art_api::dex::DexFile>(uint64_t offset)>& open_file_cb,
+ const std::function<void(DexFileSymbol*)>& symbol_cb) {
for (uint64_t offset : dex_file_offsets) {
std::unique_ptr<art_api::dex::DexFile> dex_file = open_file_cb(offset);
if (dex_file == nullptr) {
return false;
}
- std::vector<art_api::dex::MethodInfo> file_syms = dex_file->GetAllMethodInfos(false);
-
- // Adjust offsets to be from the start of the combined file.
- for (art_api::dex::MethodInfo& sym : file_syms) {
- sym.offset += offset;
- }
-
- if (symbols->empty()) {
- *symbols = std::move(file_syms);
- } else {
- symbols->reserve(symbols->size() + file_syms.size());
- std::move(std::begin(file_syms), std::end(file_syms), std::back_inserter(*symbols));
- }
+ auto callback = [&](DexFileSymbol* symbol) {
+ symbol->addr += offset;
+ symbol_cb(symbol);
+ };
+ dex_file->GetAllMethodInfos(callback);
}
return true;
@@ -59,9 +52,10 @@
bool ReadSymbolsFromDexFileInMemory(void* addr, uint64_t size,
const std::vector<uint64_t>& dex_file_offsets,
- std::vector<DexFileSymbol>* symbols) {
+ const std::function<void(DexFileSymbol*)>& symbol_callback) {
return ReadSymbols(
- dex_file_offsets, symbols, [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
+ dex_file_offsets,
+ [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
size_t max_file_size;
if (__builtin_sub_overflow(size, offset, &max_file_size)) {
return nullptr;
@@ -75,28 +69,31 @@
return nullptr;
}
return dex_file;
- });
+ },
+ symbol_callback);
}
bool ReadSymbolsFromDexFile(const std::string& file_path,
const std::vector<uint64_t>& dex_file_offsets,
- std::vector<DexFileSymbol>* symbols) {
+ const std::function<void(DexFileSymbol*)>& symbol_callback) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
return false;
}
- return ReadSymbols(dex_file_offsets, symbols,
- [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
- std::string error_msg;
- std::unique_ptr<art_api::dex::DexFile> dex_file =
- art_api::dex::DexFile::OpenFromFd(fd, offset, file_path, &error_msg);
- if (dex_file == nullptr) {
- LOG(WARNING) << "Failed to read dex file symbols from '" << file_path
- << "': " << error_msg;
- return nullptr;
- }
- return dex_file;
- });
+ return ReadSymbols(
+ dex_file_offsets,
+ [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
+ std::string error_msg;
+ std::unique_ptr<art_api::dex::DexFile> dex_file =
+ art_api::dex::DexFile::OpenFromFd(fd, offset, file_path, &error_msg);
+ if (dex_file == nullptr) {
+ LOG(WARNING) << "Failed to read dex file symbols from '" << file_path
+ << "': " << error_msg;
+ return nullptr;
+ }
+ return dex_file;
+ },
+ symbol_callback);
}
} // namespace simpleperf
diff --git a/simpleperf/read_dex_file.h b/simpleperf/read_dex_file.h
index ebddc87..e5b9790 100644
--- a/simpleperf/read_dex_file.h
+++ b/simpleperf/read_dex_file.h
@@ -28,22 +28,24 @@
namespace simpleperf {
-#ifndef NO_LIBDEXFILE_SUPPORT
-using DexFileSymbol = art_api::dex::MethodInfo;
-#else
+#ifdef NO_LIBDEXFILE_SUPPORT
struct DexFileSymbol {
- uint64_t offset;
- uint64_t len;
- std::string name;
+ size_t sizeof_struct;
+ uint32_t addr;
+ uint32_t size;
+ const char* name;
+ size_t name_size;
};
+#else
+using DexFileSymbol = ExtDexFileMethodInfo;
#endif
bool ReadSymbolsFromDexFileInMemory(void* addr, uint64_t size,
const std::vector<uint64_t>& dex_file_offsets,
- std::vector<DexFileSymbol>* symbols);
+ const std::function<void(DexFileSymbol*)>& symbol_callback);
bool ReadSymbolsFromDexFile(const std::string& file_path,
const std::vector<uint64_t>& dex_file_offsets,
- std::vector<DexFileSymbol>* symbols);
+ const std::function<void(DexFileSymbol*)>& symbol_callback);
} // namespace simpleperf
diff --git a/simpleperf/read_dex_file_test.cpp b/simpleperf/read_dex_file_test.cpp
index 3d0e900..5d71bc3 100644
--- a/simpleperf/read_dex_file_test.cpp
+++ b/simpleperf/read_dex_file_test.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
+#include "dso.h"
#include "get_test_data.h"
#include "test_util.h"
#include "utils.h"
@@ -27,13 +28,17 @@
using namespace simpleperf;
TEST(read_dex_file, smoke) {
- std::vector<DexFileSymbol> symbols;
- ASSERT_TRUE(ReadSymbolsFromDexFile(GetTestData("base.vdex"), {0x28}, &symbols));
+ std::vector<Symbol> symbols;
+ auto symbol_callback = [&](DexFileSymbol* symbol) {
+ symbols.emplace_back(std::string_view(symbol->name, symbol->name_size), symbol->addr,
+ symbol->size);
+ };
+ ASSERT_TRUE(ReadSymbolsFromDexFile(GetTestData("base.vdex"), {0x28}, symbol_callback));
ASSERT_EQ(12435u, symbols.size());
- DexFileSymbol target;
- target.offset = 0x6c77e;
- target.len = 0x16;
- target.name = art_api::dex::DexString(
- "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run");
- ASSERT_NE(std::find(symbols.begin(), symbols.end(), target), symbols.end());
+ auto it = std::find_if(symbols.begin(), symbols.end(),
+ [](const Symbol& symbol) { return symbol.addr == 0x6c77e; });
+ ASSERT_NE(it, symbols.end());
+ ASSERT_EQ(it->addr, 0x6c77e);
+ ASSERT_EQ(it->len, 0x16);
+ ASSERT_STREQ(it->Name(), "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run");
}