summaryrefslogtreecommitdiff
path: root/simpleperf/dso.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-10-24 13:38:38 -0700
committerYabin Cui <yabinc@google.com>2016-10-31 10:40:03 -0700
commitc5b4a3106a0845d1bd8fd2c1b1c724eeb719ec62 (patch)
tree8d045224b547f708cadcd4c7c23476b0a78e262e /simpleperf/dso.cpp
parentd2fcab88ef855a9a415159b669f7ea7e00f5a575 (diff)
downloadextras-c5b4a3106a0845d1bd8fd2c1b1c724eeb719ec62.tar.gz
simpleperf: dump file feature section.
For `record --dump-symbols` option, change from dumping DsoRecord and SymbolRecord to dumping file feature section. It is to avoid reading symbols from elf files during recording, which takes a lot of time. And we don't want to mix optional data (the symbol tables) with necessary data (the profiling records). Bug: http://b/32340274 Test: run simpleperf_unit_test. Test: run simpleperf runtest.py. Change-Id: I0a387de243afac93486fc885f223a58060ec07f4
Diffstat (limited to 'simpleperf/dso.cpp')
-rw-r--r--simpleperf/dso.cpp114
1 files changed, 67 insertions, 47 deletions
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index b22ebbf2..2950939c 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -127,18 +127,15 @@ BuildId Dso::GetExpectedBuildId() {
std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type,
const std::string& dso_path) {
- static uint64_t id = 0;
- return std::unique_ptr<Dso>(new Dso(dso_type, ++id, dso_path));
+ return std::unique_ptr<Dso>(new Dso(dso_type, dso_path));
}
-Dso::Dso(DsoType type, uint64_t id, const std::string& path)
+Dso::Dso(DsoType type, const std::string& path)
: type_(type),
- id_(id),
path_(path),
debug_file_path_(path),
min_vaddr_(std::numeric_limits<uint64_t>::max()),
is_loaded_(false),
- has_dumped_(false),
hit_flag_(false) {
// Check if file matching path_ exists in symfs directory before using it as
// debug_file_path_.
@@ -173,35 +170,48 @@ Dso::~Dso() {
}
}
+static bool CompareSymbol(const Symbol& symbol1, const Symbol& symbol2) {
+ return symbol1.addr < symbol2.addr;
+}
+
const Symbol* Dso::FindSymbol(uint64_t vaddr_in_dso) {
if (!is_loaded_) {
- is_loaded_ = true;
- // If symbols has been read from SymbolRecords, no need to load them from
- // dso.
- if (symbols_.empty()) {
- if (!Load()) {
- LOG(DEBUG) << "failed to load dso: " << path_;
- return nullptr;
+ Load();
+ }
+ if (!symbols_.empty()) {
+ auto it = std::upper_bound(symbols_.begin(), symbols_.end(), Symbol("", vaddr_in_dso, 0), CompareSymbol);
+ if (it != symbols_.begin()) {
+ --it;
+ if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso)) {
+ return &*it;
}
}
}
- if (symbols_.empty()) {
- return nullptr;
- }
-
- auto it = symbols_.upper_bound(Symbol("", vaddr_in_dso, 0));
- if (it != symbols_.begin()) {
- --it;
- // If vaddr_in_dso is ULLONG_MAX, then it->addr + it->len overflows,
- // and we allow this situation.
- if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso ||
- it->addr + it->len < it->addr)) {
- return &*it;
+ if (!unknown_symbols_.empty()) {
+ auto it = unknown_symbols_.find(vaddr_in_dso);
+ if (it != unknown_symbols_.end()) {
+ return &it->second;
}
}
return nullptr;
}
+const std::vector<Symbol>& Dso::GetSymbols() {
+ if (!is_loaded_) {
+ Load();
+ }
+ return symbols_;
+}
+
+void Dso::SetSymbols(std::vector<Symbol>* symbols) {
+ symbols_ = std::move(*symbols);
+ symbols->clear();
+}
+
+void Dso::AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name) {
+ unknown_symbols_.insert(std::make_pair(vaddr_in_dso, Symbol(name, vaddr_in_dso, 1)));
+}
+
uint64_t Dso::MinVirtualAddress() {
if (min_vaddr_ == std::numeric_limits<uint64_t>::max()) {
min_vaddr_ = 0;
@@ -222,7 +232,14 @@ uint64_t Dso::MinVirtualAddress() {
return min_vaddr_;
}
-bool Dso::Load() {
+void Dso::Load() {
+ is_loaded_ = true;
+ if (!symbols_.empty()) {
+ // If symbols has been read from file feature section of perf.data, no
+ // need to load them from file system.
+ // TODO: combine symbols in file feature section and in file system.
+ return;
+ }
bool result = false;
switch (type_) {
case DSO_KERNEL:
@@ -241,11 +258,12 @@ bool Dso::Load() {
}
}
if (result) {
+ std::sort(symbols_.begin(), symbols_.end(), CompareSymbol);
FixupSymbolLength();
} else {
symbols_.clear();
+ LOG(DEBUG) << "failed to load dso: " << path_;
}
- return result;
}
static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
@@ -253,16 +271,18 @@ static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
symbol.type == 'w');
}
-static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol, Dso* dso) {
+static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol,
+ std::vector<Symbol>* symbols) {
if (IsKernelFunctionSymbol(kernel_symbol)) {
- dso->InsertSymbol(Symbol(kernel_symbol.name, kernel_symbol.addr, 0));
+ symbols->emplace_back(Symbol(kernel_symbol.name, kernel_symbol.addr, 0));
}
return false;
}
-static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol, Dso* dso) {
+static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol,
+ std::vector<Symbol>* symbols) {
if (elf_symbol.is_func) {
- dso->InsertSymbol(
+ symbols->emplace_back(
Symbol(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len));
}
}
@@ -286,11 +306,11 @@ bool Dso::LoadKernel() {
BuildId build_id = GetExpectedBuildId();
if (!vmlinux_.empty()) {
ElfStatus result = ParseSymbolsFromElfFile(vmlinux_, build_id,
- std::bind(VmlinuxSymbolCallback, std::placeholders::_1, this));
+ std::bind(VmlinuxSymbolCallback, std::placeholders::_1, &symbols_));
return CheckReadSymbolResult(result, vmlinux_);
} else if (!kallsyms_.empty()) {
ProcessKernelSymbols(kallsyms_, std::bind(&KernelSymbolCallback,
- std::placeholders::_1, this));
+ std::placeholders::_1, &symbols_));
bool all_zero = true;
for (const auto& symbol : symbols_) {
if (symbol.addr != 0) {
@@ -325,7 +345,7 @@ bool Dso::LoadKernel() {
return false;
}
ProcessKernelSymbols(kallsyms, std::bind(&KernelSymbolCallback,
- std::placeholders::_1, this));
+ std::placeholders::_1, &symbols_));
bool all_zero = true;
for (const auto& symbol : symbols_) {
if (symbol.addr != 0) {
@@ -343,11 +363,11 @@ bool Dso::LoadKernel() {
return true;
}
-static void ElfFileSymbolCallback(const ElfFileSymbol& elf_symbol, Dso* dso,
- bool (*filter)(const ElfFileSymbol&)) {
+static void ElfFileSymbolCallback(const ElfFileSymbol& elf_symbol,
+ bool (*filter)(const ElfFileSymbol&),
+ std::vector<Symbol>* symbols) {
if (filter(elf_symbol)) {
- dso->InsertSymbol(
- Symbol(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len));
+ symbols->emplace_back(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len);
}
}
@@ -359,8 +379,8 @@ static bool SymbolFilterForKernelModule(const ElfFileSymbol& elf_symbol) {
bool Dso::LoadKernelModule() {
BuildId build_id = GetExpectedBuildId();
ElfStatus result = ParseSymbolsFromElfFile(GetDebugFilePath(), build_id,
- std::bind(ElfFileSymbolCallback, std::placeholders::_1, this,
- SymbolFilterForKernelModule));
+ std::bind(ElfFileSymbolCallback, std::placeholders::_1,
+ SymbolFilterForKernelModule, &symbols_));
return CheckReadSymbolResult(result, GetDebugFilePath());
}
@@ -376,16 +396,18 @@ bool Dso::LoadElfFile() {
// Linux host can store debug shared libraries in /usr/lib/debug.
ElfStatus result = ParseSymbolsFromElfFile(
"/usr/lib/debug" + path_, build_id,
- std::bind(ElfFileSymbolCallback, std::placeholders::_1, this,
- SymbolFilterForDso));
+ std::bind(ElfFileSymbolCallback, std::placeholders::_1,
+ SymbolFilterForDso, &symbols_));
if (result == ElfStatus::NO_ERROR) {
return CheckReadSymbolResult(result, "/usr/lib/debug" + path_);
}
}
+ // TODO: load std::vector<Symbol> directly from ParseSymbolsFromElfFile
+ // instead of needing to call a callback function for each symbol.
ElfStatus result = ParseSymbolsFromElfFile(
GetDebugFilePath(), build_id,
- std::bind(ElfFileSymbolCallback, std::placeholders::_1, this,
- SymbolFilterForDso));
+ std::bind(ElfFileSymbolCallback, std::placeholders::_1,
+ SymbolFilterForDso, &symbols_));
return CheckReadSymbolResult(result, GetDebugFilePath());
}
@@ -395,13 +417,11 @@ bool Dso::LoadEmbeddedElfFile() {
CHECK(std::get<0>(tuple));
ElfStatus result = ParseSymbolsFromApkFile(
std::get<1>(tuple), std::get<2>(tuple), build_id,
- std::bind(ElfFileSymbolCallback, std::placeholders::_1, this,
- SymbolFilterForDso));
+ std::bind(ElfFileSymbolCallback, std::placeholders::_1,
+ SymbolFilterForDso, &symbols_));
return CheckReadSymbolResult(result, GetDebugFilePath());
}
-void Dso::InsertSymbol(const Symbol& symbol) { symbols_.insert(symbol); }
-
void Dso::FixupSymbolLength() {
Symbol* prev_symbol = nullptr;
for (auto& symbol : symbols_) {