LibELF: Use binary search when looking up symbols :^)

For whatever reason, symbolication was doing an O(n) walk of all the
symbols, despite having sorted them beforehand.

Changing this to a binary_search() makes symbolication noticeably
faster and improves Profiler startup time.
This commit is contained in:
Andreas Kling 2021-05-15 00:51:23 +02:00
parent ef09f9c825
commit b31602367e
Notes: sideshowbarker 2024-07-18 18:08:09 +09:00
2 changed files with 49 additions and 56 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/BinarySearch.h>
#include <AK/Debug.h>
#include <AK/Demangle.h>
#include <AK/Memory.h>
@ -309,36 +310,45 @@ Optional<Image::Symbol> Image::find_demangled_function(const String& name) const
return found;
}
Image::SortedSymbol* Image::find_sorted_symbol(FlatPtr address) const
{
if (m_sorted_symbols.is_empty())
sort_symbols();
size_t index = 0;
binary_search(m_sorted_symbols, nullptr, &index, [&address](auto, auto& candidate) {
return address - candidate.address;
});
// FIXME: The error path here feels strange, index == 0 means error but what about symbol #0?
if (index == 0)
return nullptr;
return &m_sorted_symbols[index];
}
Optional<Image::Symbol> Image::find_symbol(u32 address, u32* out_offset) const
{
auto symbol_count = this->symbol_count();
if (!symbol_count)
return {};
SortedSymbol* sorted_symbols = nullptr;
if (m_sorted_symbols.is_empty()) {
m_sorted_symbols.ensure_capacity(symbol_count);
for_each_symbol([this](const auto& symbol) {
m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol });
return IterationDecision::Continue;
});
quick_sort(m_sorted_symbols, [](auto& a, auto& b) {
return a.address < b.address;
});
}
sorted_symbols = m_sorted_symbols.data();
auto* symbol = find_sorted_symbol(address);
if (!symbol)
return {};
if (out_offset)
*out_offset = address - symbol->address;
return symbol->symbol;
}
for (size_t i = 0; i < symbol_count; ++i) {
if (sorted_symbols[i].address > address) {
if (i == 0)
return {};
auto& symbol = sorted_symbols[i - 1];
if (out_offset)
*out_offset = address - symbol.address;
return symbol.symbol;
}
}
return {};
NEVER_INLINE void Image::sort_symbols() const
{
m_sorted_symbols.ensure_capacity(symbol_count());
for_each_symbol([this](const auto& symbol) {
m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol });
return IterationDecision::Continue;
});
quick_sort(m_sorted_symbols, [](auto& a, auto& b) {
return a.address < b.address;
});
}
String Image::symbolicate(u32 address, u32* out_offset) const
@ -349,43 +359,23 @@ String Image::symbolicate(u32 address, u32* out_offset) const
*out_offset = 0;
return "??";
}
SortedSymbol* sorted_symbols = nullptr;
if (m_sorted_symbols.is_empty()) {
m_sorted_symbols.ensure_capacity(symbol_count);
for_each_symbol([this](const auto& symbol) {
m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol });
return IterationDecision::Continue;
});
quick_sort(m_sorted_symbols, [](auto& a, auto& b) {
return a.address < b.address;
});
auto* symbol = find_sorted_symbol(address);
if (!symbol) {
if (out_offset)
*out_offset = 0;
return "??";
}
sorted_symbols = m_sorted_symbols.data();
for (size_t i = 0; i < symbol_count; ++i) {
if (sorted_symbols[i].address > address) {
if (i == 0) {
if (out_offset)
*out_offset = 0;
return "!!";
}
auto& symbol = sorted_symbols[i - 1];
auto& demangled_name = symbol->demangled_name;
if (demangled_name.is_null())
demangled_name = demangle(symbol->name);
auto& demangled_name = symbol.demangled_name;
if (demangled_name.is_null()) {
demangled_name = demangle(symbol.name);
}
if (out_offset) {
*out_offset = address - symbol.address;
return demangled_name;
}
return String::formatted("{} +{:#x}", demangled_name, address - symbol.address);
}
if (out_offset) {
*out_offset = address - symbol->address;
return demangled_name;
}
if (out_offset)
*out_offset = 0;
return "??";
return String::formatted("{} +{:#x}", demangled_name, address - symbol->address);
}
} // end namespace ELF

View file

@ -216,6 +216,9 @@ private:
Optional<Image::Symbol> symbol;
};
void sort_symbols() const;
SortedSymbol* find_sorted_symbol(FlatPtr) const;
mutable Vector<SortedSymbol> m_sorted_symbols;
};