DWARFAttribute is used in 2 classes: DWARFAbbreviationDecl and DWARFAttributes. The former stores a std::vector of them and the latter has a small structure called AttributeValue that contains a DWARFAttribute. DWARFAttributes maintains a llvm::SmallVector of AttributeValues. My end goal is to have `DWARFAttributes` have a llvm::SmallVector specialized on DWARFAttribute. In order to do that, we'll have to move the other elements of AttributeValue into DWARFAttribute itself. But we don't want to do this while DWARFAbbreviationDecl is using DWARFAttribute because it will needlessly increase the size of DWARFAbbreviationDecl. So instead I will create a small type containing only what DWARFAbbreviationDecl needs and call it `AttributeSpec`. This is the exact same thing that LLVM does today. I've elected to swap std::vector for llvm::SmallVector here with a pre-allocated size of 8. I've collected time and memory measurements before this change and after it as well. Using a c++ project with 10,000 object files and no dSYM, I place a breakpoint by file + lineno and see how long it takes to resolve. Before this patch: Time (mean ± σ): 13.577 s ± 0.024 s [User: 12.418 s, System: 1.247 s] Total number of bytes allocated: 1.38 GiB Total number of allocations: 6.47 million allocations After this patch: Time (mean ± σ): 13.287 s ± 0.020 s [User: 12.128 s, System: 1.250 s] Total number of bytes allocated: 1.59 GiB Total number of allocations: 4.61 million allocations So we consume more memory than before, but we actually make less allocations on average. I also measured with an llvm::SmallVector with a pre-allocated size of 4 instead of 8 to measure how well it performs: Time (mean ± σ): 13.246 s ± 0.048 s [User: 12.074 s, System: 1.268 s] Total memory consumption: 1.50 GiB Total number of allocations: 5.74 million Of course this data may look very different depending on the actual program being debugged, but each of the object files had 100+ AbbreviationDeclarations each with between 0 and 10 Attributes, so I feel this was a fair example to consider. Differential Revision: https://reviews.llvm.org/D150418
82 lines
2.7 KiB
C++
82 lines
2.7 KiB
C++
//===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DWARFAbbreviationDeclaration.h"
|
|
|
|
#include "lldb/Core/dwarf.h"
|
|
#include "lldb/Utility/Stream.h"
|
|
|
|
#include "llvm/Object/Error.h"
|
|
|
|
#include "DWARFFormValue.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::dwarf;
|
|
|
|
DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() : m_attributes() {}
|
|
|
|
DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration(dw_tag_t tag,
|
|
uint8_t has_children)
|
|
: m_tag(tag), m_has_children(has_children), m_attributes() {}
|
|
|
|
llvm::Expected<DWARFEnumState>
|
|
DWARFAbbreviationDeclaration::extract(const DWARFDataExtractor &data,
|
|
lldb::offset_t *offset_ptr) {
|
|
m_code = data.GetULEB128(offset_ptr);
|
|
if (m_code == 0)
|
|
return DWARFEnumState::Complete;
|
|
|
|
m_attributes.clear();
|
|
m_tag = static_cast<dw_tag_t>(data.GetULEB128(offset_ptr));
|
|
if (m_tag == DW_TAG_null)
|
|
return llvm::make_error<llvm::object::GenericBinaryError>(
|
|
"abbrev decl requires non-null tag.");
|
|
|
|
m_has_children = data.GetU8(offset_ptr);
|
|
|
|
while (data.ValidOffset(*offset_ptr)) {
|
|
auto attr = static_cast<dw_attr_t>(data.GetULEB128(offset_ptr));
|
|
auto form = static_cast<dw_form_t>(data.GetULEB128(offset_ptr));
|
|
|
|
// This is the last attribute for this abbrev decl, but there may still be
|
|
// more abbrev decls, so return MoreItems to indicate to the caller that
|
|
// they should call this function again.
|
|
if (!attr && !form)
|
|
return DWARFEnumState::MoreItems;
|
|
|
|
if (!attr || !form)
|
|
return llvm::make_error<llvm::object::GenericBinaryError>(
|
|
"malformed abbreviation declaration attribute");
|
|
|
|
if (form == DW_FORM_implicit_const) {
|
|
int64_t value = data.GetSLEB128(offset_ptr);
|
|
m_attributes.emplace_back(attr, form, value);
|
|
continue;
|
|
}
|
|
|
|
m_attributes.emplace_back(attr, form);
|
|
}
|
|
|
|
return llvm::make_error<llvm::object::GenericBinaryError>(
|
|
"abbreviation declaration attribute list not terminated with a null "
|
|
"entry");
|
|
}
|
|
|
|
bool DWARFAbbreviationDeclaration::IsValid() {
|
|
return m_code != 0 && m_tag != llvm::dwarf::DW_TAG_null;
|
|
}
|
|
|
|
uint32_t
|
|
DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const {
|
|
for (size_t i = 0; i < m_attributes.size(); ++i) {
|
|
if (m_attributes[i].GetAttribute() == attr)
|
|
return i;
|
|
}
|
|
return DW_INVALID_INDEX;
|
|
}
|