Add a configurable cache size for the line tables cache, related to #193
This commit is contained in:
parent
8c7b1dc6aa
commit
1d79dbcf42
@ -121,6 +121,7 @@ target_sources(
|
|||||||
src/demangle/demangle_with_winapi.cpp
|
src/demangle/demangle_with_winapi.cpp
|
||||||
src/snippets/snippet.cpp
|
src/snippets/snippet.cpp
|
||||||
src/symbols/dwarf/debug_map_resolver.cpp
|
src/symbols/dwarf/debug_map_resolver.cpp
|
||||||
|
src/symbols/dwarf/dwarf_options.cpp
|
||||||
src/symbols/dwarf/dwarf_resolver.cpp
|
src/symbols/dwarf/dwarf_resolver.cpp
|
||||||
src/symbols/symbols_core.cpp
|
src/symbols/symbols_core.cpp
|
||||||
src/symbols/symbols_with_addr2line.cpp
|
src/symbols/symbols_with_addr2line.cpp
|
||||||
|
|||||||
@ -43,6 +43,11 @@ namespace cpptrace {
|
|||||||
namespace experimental {
|
namespace experimental {
|
||||||
CPPTRACE_EXPORT void set_cache_mode(cache_mode mode);
|
CPPTRACE_EXPORT void set_cache_mode(cache_mode mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dwarf options
|
||||||
|
namespace experimental {
|
||||||
|
CPPTRACE_EXPORT void set_dwarf_resolver_line_table_cache_size(nullable<std::size_t> max_entries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
22
src/symbols/dwarf/dwarf_options.cpp
Normal file
22
src/symbols/dwarf/dwarf_options.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "symbols/dwarf/dwarf_options.hpp"
|
||||||
|
|
||||||
|
#include <cpptrace/utils.hpp>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace cpptrace {
|
||||||
|
namespace detail {
|
||||||
|
std::atomic<nullable<std::size_t>> dwarf_resolver_line_table_cache_size{nullable<std::size_t>::null()};
|
||||||
|
|
||||||
|
optional<std::size_t> get_dwarf_resolver_line_table_cache_size() {
|
||||||
|
auto max_entries = dwarf_resolver_line_table_cache_size.load();
|
||||||
|
return max_entries.has_value() ? optional<std::size_t>(max_entries.value()) : nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace experimental {
|
||||||
|
void set_dwarf_resolver_line_table_cache_size(nullable<std::size_t> max_entries) {
|
||||||
|
detail::dwarf_resolver_line_table_cache_size.store(max_entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/symbols/dwarf/dwarf_options.hpp
Normal file
14
src/symbols/dwarf/dwarf_options.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef DWARF_OPTIONS_HPP
|
||||||
|
#define DWARF_OPTIONS_HPP
|
||||||
|
|
||||||
|
#include "utils/optional.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace cpptrace {
|
||||||
|
namespace detail {
|
||||||
|
optional<std::size_t> get_dwarf_resolver_line_table_cache_size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
#include <cpptrace/basic.hpp>
|
#include <cpptrace/basic.hpp>
|
||||||
#include "symbols/dwarf/dwarf.hpp" // has dwarf #includes
|
#include "symbols/dwarf/dwarf.hpp" // has dwarf #includes
|
||||||
|
#include "symbols/dwarf/dwarf_options.hpp"
|
||||||
#include "symbols/symbols.hpp"
|
#include "symbols/symbols.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/error.hpp"
|
#include "utils/error.hpp"
|
||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
#include "utils/lru_cache.hpp"
|
||||||
#include "platform/path.hpp"
|
#include "platform/path.hpp"
|
||||||
#include "platform/program_name.hpp" // For CPPTRACE_MAX_PATH
|
#include "platform/program_name.hpp" // For CPPTRACE_MAX_PATH
|
||||||
|
|
||||||
@ -109,7 +111,7 @@ namespace libdwarf {
|
|||||||
Dwarf_Arange* aranges = nullptr;
|
Dwarf_Arange* aranges = nullptr;
|
||||||
Dwarf_Signed arange_count = 0;
|
Dwarf_Signed arange_count = 0;
|
||||||
// Map from CU -> Line context
|
// Map from CU -> Line context
|
||||||
std::unordered_map<Dwarf_Off, line_table_info> line_tables;
|
lru_cache<Dwarf_Off, line_table_info> line_tables{get_dwarf_resolver_line_table_cache_size()};
|
||||||
// Map from CU -> Sorted subprograms vector
|
// Map from CU -> Sorted subprograms vector
|
||||||
std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache;
|
std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache;
|
||||||
// Vector of ranges and their corresponding CU offsets
|
// Vector of ranges and their corresponding CU offsets
|
||||||
@ -409,7 +411,7 @@ namespace libdwarf {
|
|||||||
if(file_i) {
|
if(file_i) {
|
||||||
// for dwarf 2, 3, 4, and experimental line table version 0xfe06 1-indexing is used
|
// for dwarf 2, 3, 4, and experimental line table version 0xfe06 1-indexing is used
|
||||||
// for dwarf 5 0-indexing is used
|
// for dwarf 5 0-indexing is used
|
||||||
optional<std::reference_wrapper<line_table_info>> line_table_opt;
|
optional<line_table_info&> line_table_opt;
|
||||||
if(skeleton) {
|
if(skeleton) {
|
||||||
line_table_opt = skeleton.unwrap().resolver.get_line_table(
|
line_table_opt = skeleton.unwrap().resolver.get_line_table(
|
||||||
skeleton.unwrap().cu_die
|
skeleton.unwrap().cu_die
|
||||||
@ -418,7 +420,7 @@ namespace libdwarf {
|
|||||||
line_table_opt = get_line_table(cu_die);
|
line_table_opt = get_line_table(cu_die);
|
||||||
}
|
}
|
||||||
if(line_table_opt) {
|
if(line_table_opt) {
|
||||||
auto& line_table = line_table_opt.unwrap().get();
|
auto& line_table = line_table_opt.unwrap();
|
||||||
if(line_table.version != 5) {
|
if(line_table.version != 5) {
|
||||||
if(file_i.unwrap() == 0) {
|
if(file_i.unwrap() == 0) {
|
||||||
file_i.reset(); // 0 means no name to be found
|
file_i.reset(); // 0 means no name to be found
|
||||||
@ -635,11 +637,11 @@ namespace libdwarf {
|
|||||||
|
|
||||||
// returns a reference to a CU's line table, may be invalidated if the line_tables map is modified
|
// returns a reference to a CU's line table, may be invalidated if the line_tables map is modified
|
||||||
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
||||||
optional<std::reference_wrapper<line_table_info>> get_line_table(const die_object& cu_die) {
|
optional<line_table_info&> get_line_table(const die_object& cu_die) {
|
||||||
auto off = cu_die.get_global_offset();
|
auto off = cu_die.get_global_offset();
|
||||||
auto it = line_tables.find(off);
|
auto res = line_tables.maybe_get(off);
|
||||||
if(it != line_tables.end()) {
|
if(res) {
|
||||||
return it->second;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
Dwarf_Unsigned version;
|
Dwarf_Unsigned version;
|
||||||
Dwarf_Small table_count;
|
Dwarf_Small table_count;
|
||||||
@ -706,8 +708,7 @@ namespace libdwarf {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
it = line_tables.insert({off, line_table_info{version, line_context, std::move(line_entries)}}).first;
|
return line_tables.insert(off, line_table_info{version, line_context, std::move(line_entries)});
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,7 +726,7 @@ namespace libdwarf {
|
|||||||
if(!table_info_opt) {
|
if(!table_info_opt) {
|
||||||
return; // failing silently for now
|
return; // failing silently for now
|
||||||
}
|
}
|
||||||
auto& table_info = table_info_opt.unwrap().get();
|
auto& table_info = table_info_opt.unwrap();
|
||||||
if(get_cache_mode() == cache_mode::prioritize_speed) {
|
if(get_cache_mode() == cache_mode::prioritize_speed) {
|
||||||
// Lookup in the table
|
// Lookup in the table
|
||||||
auto& line_entries = table_info.line_entries;
|
auto& line_entries = table_info.line_entries;
|
||||||
|
|||||||
107
src/utils/lru_cache.hpp
Normal file
107
src/utils/lru_cache.hpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#ifndef LRU_CACHE_HPP
|
||||||
|
#define LRU_CACHE_HPP
|
||||||
|
|
||||||
|
#include "utils/error.hpp"
|
||||||
|
#include "utils/optional.hpp"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace cpptrace {
|
||||||
|
namespace detail {
|
||||||
|
template<typename K, typename V>
|
||||||
|
class lru_cache {
|
||||||
|
struct kvp {
|
||||||
|
K key;
|
||||||
|
V value;
|
||||||
|
};
|
||||||
|
using list_type = std::list<kvp>;
|
||||||
|
using list_iterator = typename list_type::iterator;
|
||||||
|
mutable list_type lru;
|
||||||
|
std::unordered_map<K, list_iterator> map;
|
||||||
|
optional<std::size_t> max_size;
|
||||||
|
public:
|
||||||
|
lru_cache() = default;
|
||||||
|
lru_cache(optional<std::size_t> max_size) : max_size(max_size) {
|
||||||
|
VERIFY(!max_size || max_size.unwrap() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_max_size(optional<std::size_t> max_size) {
|
||||||
|
VERIFY(!max_size || max_size.unwrap() > 0);
|
||||||
|
this->max_size = max_size;
|
||||||
|
maybe_trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void maybe_touch(const K& key) {
|
||||||
|
auto it = map.find(key);
|
||||||
|
if(it == map.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto list_it = it->second;
|
||||||
|
touch(list_it);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<V&> maybe_get(const K& key) {
|
||||||
|
auto it = map.find(key);
|
||||||
|
if(it == map.end()) {
|
||||||
|
return nullopt;
|
||||||
|
} else {
|
||||||
|
touch(it->second);
|
||||||
|
return it->second->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<const V&> maybe_get(const K& key) const {
|
||||||
|
auto it = map.find(key);
|
||||||
|
if(it == map.end()) {
|
||||||
|
return nullopt;
|
||||||
|
} else {
|
||||||
|
touch(it->second);
|
||||||
|
return it->second->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const K& key, V value) {
|
||||||
|
auto it = map.find(key);
|
||||||
|
if(it == map.end()) {
|
||||||
|
insert(key, std::move(value));
|
||||||
|
} else {
|
||||||
|
touch(it->second);
|
||||||
|
it->second->value = std::move(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<V&> insert(const K& key, V value) {
|
||||||
|
auto pair = map.insert({key, lru.end()});
|
||||||
|
if(!pair.second) {
|
||||||
|
// didn't insert
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
auto map_it = pair.first;
|
||||||
|
lru.push_front({key, std::move(value)});
|
||||||
|
map_it->second = lru.begin();
|
||||||
|
maybe_trim();
|
||||||
|
return lru.front().value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const {
|
||||||
|
return lru.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void touch(list_iterator list_it) const {
|
||||||
|
lru.splice(lru.begin(), lru, list_it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void maybe_trim() {
|
||||||
|
while(max_size && lru.size() > max_size.unwrap()) {
|
||||||
|
const auto& to_remove = lru.back();
|
||||||
|
map.erase(to_remove.key);
|
||||||
|
lru.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user