Refactor cu_cache to use die_cache abstraction and reduce cu die cloning

This commit is contained in:
Jeremy Rifkin 2025-02-17 21:13:08 -06:00
parent 83527947a2
commit a4faef7f1e
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4

View File

@ -101,7 +101,16 @@ namespace libdwarf {
std::size_t ranges_count() const { std::size_t ranges_count() const {
return range_entries.size(); return range_entries.size();
} }
optional<const die_object&> lookup(Dwarf_Addr pc) const { struct die_and_data {
const die_object& die;
const T& data;
};
using lookup_result = typename std::conditional<
std::is_same<T, monostate>::value,
const die_object&,
die_and_data
>::type;
optional<lookup_result> lookup(Dwarf_Addr pc) const {
auto vec_it = first_less_than_or_equal( auto vec_it = first_less_than_or_equal(
range_entries.begin(), range_entries.begin(),
range_entries.end(), range_entries.end(),
@ -113,7 +122,11 @@ namespace libdwarf {
if(vec_it == range_entries.end()) { if(vec_it == range_entries.end()) {
return nullopt; return nullopt;
} }
return dies.at(vec_it->die.die_index); if constexpr(std::is_same<T, monostate>::value) {
return dies.at(vec_it->die.die_index);
} else {
return die_and_data{dies.at(vec_it->die.die_index), vec_it->data};
}
} }
}; };
@ -180,7 +193,8 @@ namespace libdwarf {
// Map from CU -> Sorted subprograms vector // Map from CU -> Sorted subprograms vector
std::unordered_map<Dwarf_Off, die_cache<monostate>> subprograms_cache; std::unordered_map<Dwarf_Off, die_cache<monostate>> subprograms_cache;
// Vector of ranges and their corresponding CU offsets // Vector of ranges and their corresponding CU offsets
std::vector<cu_entry> cu_cache; // data stored for each cache entry is a Dwarf_Half dwversion
die_cache<Dwarf_Half> cu_cache;
bool generated_cu_cache = false; bool generated_cu_cache = false;
// Map from CU -> {srcfiles, count} // Map from CU -> {srcfiles, count}
std::unordered_map<Dwarf_Off, srcfiles> srcfiles_cache; std::unordered_map<Dwarf_Off, srcfiles> srcfiles_cache;
@ -365,23 +379,25 @@ namespace libdwarf {
// TODO: Also assuming same dwversion // TODO: Also assuming same dwversion
const auto& skeleton_cu = skeleton.unwrap().cu_die; const auto& skeleton_cu = skeleton.unwrap().cu_die;
auto ranges_vec = skeleton_cu.get_rangelist_entries(skeleton_cu, dwversion); auto ranges_vec = skeleton_cu.get_rangelist_entries(skeleton_cu, dwversion);
for(auto range : ranges_vec) { if(!ranges_vec.empty()) {
// TODO: Reduce cloning here auto cu_die_handle = cu_cache.add_die(cu_die.clone());
cu_cache.push_back({ cu_die.clone(), dwversion, range.first, range.second }); for(auto range : ranges_vec) {
cu_cache.insert(cu_die_handle, range.first, range.second, dwversion);
}
} }
return false; return false;
} else { } else {
auto ranges_vec = cu_die.get_rangelist_entries(cu_die, dwversion); auto ranges_vec = cu_die.get_rangelist_entries(cu_die, dwversion);
for(auto range : ranges_vec) { if(!ranges_vec.empty()) {
// TODO: Reduce cloning here auto cu_die_handle = cu_cache.add_die(cu_die.clone());
cu_cache.push_back({ cu_die.clone(), dwversion, range.first, range.second }); for(auto range : ranges_vec) {
cu_cache.insert(cu_die_handle, range.first, range.second, dwversion);
}
} }
return true; return true;
} }
}); });
std::sort(cu_cache.begin(), cu_cache.end(), [] (const cu_entry& a, const cu_entry& b) { cu_cache.finalize();
return a.low < b.low;
});
generated_cu_cache = true; generated_cu_cache = true;
} }
} }
@ -969,17 +985,13 @@ namespace libdwarf {
} else { } else {
lazy_generate_cu_cache(); lazy_generate_cu_cache();
// look up the cu // look up the cu
auto vec_it = first_less_than_or_equal( auto res = cu_cache.lookup(pc);
cu_cache.begin(), // res can be nullopt if the cu_cache vector is empty
cu_cache.end(), // It can also happen for something like _start, where there is a cached CU for the object but
pc, // _start is outside of the CU's PC range
[] (Dwarf_Addr pc, const cu_entry& entry) { if(res) {
return pc < entry.low; const auto& die = res.unwrap().die;
} const auto dwversion = res.unwrap().data;
);
// TODO: Vec-it is already range-based, this range check is redundant
// If the vector has been empty this can happen
if(vec_it != cu_cache.end()) {
// TODO: Cache the range list? // TODO: Cache the range list?
// NOTE: If we have a corresponding skeleton, we assume we have one CU matching the skeleton CU // NOTE: If we have a corresponding skeleton, we assume we have one CU matching the skeleton CU
if( if(
@ -990,14 +1002,10 @@ namespace libdwarf {
skeleton.unwrap().dwversion, skeleton.unwrap().dwversion,
pc pc
) )
) || vec_it->die.pc_in_die(vec_it->die, vec_it->dwversion, pc) ) || die.pc_in_die(die, dwversion, pc)
) { ) {
return cu_info{maybe_owned_die_object::ref(vec_it->die), vec_it->dwversion}; return cu_info{maybe_owned_die_object::ref(die), dwversion};
} }
} else {
// I've had this happen for _start, where there is a cached CU for the object but _start is outside
// of the CU's PC range
// ASSERT(cu_cache.size() == 0, "Vec should be empty?");
} }
return nullopt; return nullopt;
} }