Skip to content

Commit

Permalink
Sync AFDO/Propeller with internal and enable Arm SPE support (#191)
Browse files Browse the repository at this point in the history
Sync AFDO/Propeller with internal

This change:
  1. Updates necessary dependencies
  2. Brings AutoFDO and Propeller core libraries up to date
  3. Adds library functionality for SPE-driven Propeller and AutoFDO
     profile generation
  4. Enables SPE-driven Propeller and AutoFDO profile generation in
     create_llvm_prof
  5. Reapplies PR #134 and #156, which weren't synced internally
  • Loading branch information
dhoekwater authored May 6, 2024
1 parent 1fe2d5f commit 623c777
Show file tree
Hide file tree
Showing 183 changed files with 16,118 additions and 5,495 deletions.
Empty file added .gitattributes
Empty file.
388 changes: 308 additions & 80 deletions CMakeLists.txt

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions addr2cu.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "addr2cu.h"

#include <cstdint>
#include <memory>
#include <optional>
#include <string>

#include "base/logging.h"
#include "third_party/abseil/absl/algorithm/container.h"
#include "third_party/abseil/absl/status/status.h"
#include "third_party/abseil/absl/status/statusor.h"
#include "third_party/abseil/absl/strings/str_format.h"
#include "third_party/abseil/absl/strings/string_view.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Object/ObjectFile.h"

namespace devtools_crosstool_autofdo {

absl::StatusOr<std::unique_ptr<llvm::DWARFContext>> CreateDWARFContext(
const llvm::object::ObjectFile &obj, absl::string_view dwp_file) {
std::unique_ptr<llvm::DWARFContext> dwarf_context =
llvm::DWARFContext::create(
obj, llvm::DWARFContext::ProcessDebugRelocations::Process,
/*const LoadedObjectInfo *L=*/ nullptr, std::string(dwp_file));
CHECK(dwarf_context != nullptr);
if (dwp_file.empty() &&
absl::c_any_of(dwarf_context->compile_units(),
[](std::unique_ptr<llvm::DWARFUnit> &cu) {
return cu->getUnitDIE().getTag() ==
llvm::dwarf::DW_TAG_skeleton_unit;
})) {
return absl::FailedPreconditionError(
"skeleton unit found without a corresponding dwp file");
}
if (!dwarf_context->getNumCompileUnits()) {
return absl::FailedPreconditionError(
"no compilation unit found, binary must be built with debuginfo");
}
return dwarf_context;
}

absl::StatusOr<absl::string_view> Addr2Cu::GetCompileUnitFileNameForCodeAddress(
uint64_t code_address) {
llvm::DWARFCompileUnit *unit =
dwarf_context_.getCompileUnitForCodeAddress(code_address);
if (unit == nullptr) {
return absl::FailedPreconditionError(absl::StrFormat(
"no compile unit found on address 0x%x", code_address));
}
llvm::DWARFDie die = unit->getNonSkeletonUnitDIE();
std::optional<llvm::DWARFFormValue> form_value =
die.findRecursively({llvm::dwarf::DW_AT_name});
llvm::StringRef name = llvm::dwarf::toStringRef(form_value, "");
return absl::string_view(name.data(), name.size());
}
} // namespace devtools_crosstool_autofdo
42 changes: 42 additions & 0 deletions addr2cu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef AUTOFDOADDR2CU_H_
#define AUTOFDOADDR2CU_H_

#include <cstdint>
#include <memory>

#include "third_party/abseil/absl/status/statusor.h"
#include "third_party/abseil/absl/strings/string_view.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Object/ObjectFile.h"

namespace devtools_crosstool_autofdo {

// Creates an `llvm::DWARFContext` instance, which can then be used to create
// an `Addr2Cu` instance.
absl::StatusOr<std::unique_ptr<llvm::DWARFContext>> CreateDWARFContext(
const llvm::object::ObjectFile &obj, absl::string_view dwp_file = "");

// Utility class that gets the module name for a code address with
// the help of debug information.
class Addr2Cu {
public:
explicit Addr2Cu(llvm::DWARFContext &dwarf_context)
: dwarf_context_(dwarf_context) {}

Addr2Cu(const Addr2Cu&) = delete;
Addr2Cu& operator=(const Addr2Cu&) = delete;

Addr2Cu(Addr2Cu &&) = delete;
Addr2Cu& operator=(Addr2Cu &&) = delete;

// Returns the file name for the compile unit that contains the given code
// address. Note: the returned string_view lives as long as `dwarf_context_`.
absl::StatusOr<absl::string_view> GetCompileUnitFileNameForCodeAddress(
uint64_t code_address);

private:
llvm::DWARFContext &dwarf_context_;
};
} // namespace devtools_crosstool_autofdo
#endif // AUTOFDOADDR2CU_H_
77 changes: 77 additions & 0 deletions addr2cu_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "addr2cu.h"

#include <fstream>
#include <ios>
#include <memory>
#include <string>
#include <utility>

#include "base/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "third_party/abseil/absl/status/statusor.h"
#include "third_party/abseil/absl/strings/str_cat.h"
#include "third_party/abseil/absl/strings/string_view.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "util/testing/status_matchers.h"

namespace {

using ::devtools_crosstool_autofdo::Addr2Cu;
using ::devtools_crosstool_autofdo::CreateDWARFContext;
using ::testing::HasSubstr;
using ::testing::status::IsOkAndHolds;
using ::testing::status::StatusIs;

uint64_t GetSymbolAddress(const std::string &symmap, absl::string_view symbol) {
std::ifstream fin(symmap.c_str());
int64_t addr;
std::string sym_type;
std::string sym_name;
while (fin >> std::dec >> addr >> sym_type >> sym_name)
if (sym_name == symbol) return addr;
return -1;
}

struct BinaryData {
std::unique_ptr<llvm::MemoryBuffer> mem_buf;
std::unique_ptr<llvm::object::ObjectFile> object_file;
};

// Primes `BinaryData` for test cases.
absl::StatusOr<BinaryData> SetupBinaryData(absl::string_view binary) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mem_buf =
llvm::MemoryBuffer::getFile(binary);
if (!mem_buf) {
return absl::FailedPreconditionError(absl::StrCat(
"failed creating MemoryBuffer: %s", mem_buf.getError().message()));
}

llvm::Expected<std::unique_ptr<llvm::object::ObjectFile>> object_file =
llvm::object::ObjectFile::createELFObjectFile(**mem_buf);
if (!object_file) {
return absl::FailedPreconditionError(
absl::StrFormat("failed creating ELFObjectFile: %s",
llvm::toString(object_file.takeError())));
}

return BinaryData{.mem_buf = std::move(*mem_buf),
.object_file = std::move(*object_file)};
}

TEST(Addr2CuTest, ComdatFuncHasNoDwp) {
const std::string binary =
absl::StrCat(::testing::SrcDir(),
"/testdata/"
"test_comdat_with_dwp.bin");

ASSERT_OK_AND_ASSIGN(BinaryData binary_data, SetupBinaryData(binary));

EXPECT_THAT(CreateDWARFContext(*binary_data.object_file),
StatusIs(absl::StatusCode::kFailedPrecondition,
HasSubstr("without a corresponding dwp file")));
}
} // namespace
34 changes: 19 additions & 15 deletions addr2line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,23 @@
#include <cstdint>
#include <map>
#include <string>
#include <utility>

#include "base/commandlineflags.h"
#include "base/logging.h"
#include "symbol_map.h"
#include "source_info.h"
#include "third_party/abseil/absl/container/node_hash_map.h"
#include "third_party/abseil/absl/flags/flag.h"
#include "third_party/abseil/absl/strings/string_view.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ObjectFile.h"

ABSL_RETIRED_FLAG(bool, use_legacy_symbolizer, false,
Expand All @@ -31,7 +40,7 @@ typedef absl::node_hash_map<std::string, std::pair<const char *, uint64_t>>
// OwningBinary object. If the file does not exist, the OwningBinary object will
// be empty.
llvm::object::OwningBinary<llvm::object::ObjectFile> GetOwningBinary(
const std::string &filename) {
absl::string_view filename) {
auto object_owning_binary_or_err =
llvm::object::ObjectFile::createObjectFile(llvm::StringRef(filename));
if (!object_owning_binary_or_err) {
Expand All @@ -43,13 +52,7 @@ llvm::object::OwningBinary<llvm::object::ObjectFile> GetOwningBinary(

namespace devtools_crosstool_autofdo {

Addr2line *Addr2line::Create(const std::string &binary_name) {
return CreateWithSampledFunctions(binary_name, nullptr);
}

Addr2line *Addr2line::CreateWithSampledFunctions(
const std::string &binary_name,
const std::map<uint64_t, uint64_t> *sampled_functions) {
Addr2line *Addr2line::Create(absl::string_view binary_name) {
Addr2line *addr2line = new LLVMAddr2line(binary_name);
if (!addr2line->Prepare()) {
delete addr2line;
Expand All @@ -59,7 +62,7 @@ Addr2line *Addr2line::CreateWithSampledFunctions(
}
}

LLVMAddr2line::LLVMAddr2line(const std::string &binary_name)
LLVMAddr2line::LLVMAddr2line(absl::string_view binary_name)
: Addr2line(binary_name), binary_(GetOwningBinary(binary_name)) {}

bool LLVMAddr2line::Prepare() {
Expand All @@ -74,12 +77,13 @@ bool LLVMAddr2line::Prepare() {
void LLVMAddr2line::GetInlineStack(uint64_t address, SourceStack *stack) const {
auto cu_iter =
unit_map_.find(dwarf_info_->getDebugAranges()->findAddress(address));
if (cu_iter == unit_map_.end())
return;
if (cu_iter == unit_map_.end()) return;
const llvm::DWARFDebugLine::LineTable *line_table =
dwarf_info_->getLineTableForUnit(cu_iter->second);
if (line_table == nullptr)
if (line_table == nullptr) {
LOG_EVERY_N(WARNING, 1000) << "Missed line table.";
return;
}
llvm::SmallVector<llvm::DWARFDie, 4> InlinedChain;
cu_iter->second->getInlinedChainForAddress(address, InlinedChain);

Expand All @@ -94,8 +98,8 @@ void LLVMAddr2line::GetInlineStack(uint64_t address, SourceStack *stack) const {
const char *function_name =
FunctionDIE.getSubroutineName(llvm::DINameKind::LinkageName);
uint32_t start_line = FunctionDIE.getDeclLine();
std::string file_name;
std::string dir_name;
llvm::StringRef file_name;
llvm::StringRef dir_name;
if (line_table->hasFileAtIndex(file)) {
const auto &entry = line_table->Prologue.getFileNameEntry(file);
file_name = llvm::dwarf::toString(entry.Name).value();
Expand Down
34 changes: 20 additions & 14 deletions addr2line.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

#include <cstdint>
#include <map>
#include <memory>
#include <string>

#include "base/integral_types.h"
#include "base/macros.h"
#include "source_info.h"
#include "third_party/abseil/absl/strings/string_view.h"

#if defined(HAVE_LLVM)
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/Binary.h"
Expand All @@ -22,16 +24,16 @@
namespace devtools_crosstool_autofdo {
class Addr2line {
public:
explicit Addr2line(const std::string &binary_name)
explicit Addr2line(absl::string_view binary_name)
: binary_name_(binary_name) {}

virtual ~Addr2line() {}
// This type is neither copyable nor movable.
Addr2line(const Addr2line &) = delete;
Addr2line &operator=(const Addr2line &) = delete;

static Addr2line *Create(const std::string &binary_name);
virtual ~Addr2line() {}

static Addr2line *CreateWithSampledFunctions(
const std::string &binary_name,
const std::map<uint64_t, uint64_t> *sampled_functions);
static Addr2line *Create(absl::string_view binary_name);

// Reads the binary to prepare necessary binary in data.
// Returns True on success.
Expand All @@ -40,26 +42,32 @@ class Addr2line {
// Stores the inline stack of ADDR in STACK.
virtual void GetInlineStack(uint64_t addr, SourceStack *stack) const = 0;

#if defined(HAVE_LLVM)
// Return the object file.
virtual const llvm::object::ObjectFile *getObject() const { return nullptr; }
#endif // HAVE_LLVM

protected:
std::string binary_name_;

private:
DISALLOW_COPY_AND_ASSIGN(Addr2line);
};

#if defined(HAVE_LLVM)
class LLVMAddr2line : public Addr2line {
public:
explicit LLVMAddr2line(const std::string &binary_name);
explicit LLVMAddr2line(absl::string_view binary_name);
bool Prepare() override;
void GetInlineStack(uint64_t address, SourceStack *stack) const override;
const llvm::object::ObjectFile *getObject() const override {
return binary_.getBinary();
}

private:
// map from cu_offset to the CompileUnit.
std::map<uint32_t, llvm::DWARFUnit *> unit_map_;
llvm::object::OwningBinary<llvm::object::ObjectFile> binary_;
std::unique_ptr<llvm::DWARFContext> dwarf_info_;
};

#else
class AddressQuery;
class InlineStackHandler;
Expand All @@ -69,8 +77,7 @@ class AddressToLineMap;

class Google3Addr2line : public Addr2line {
public:
explicit Google3Addr2line(const string &binary_name,
const std::map<uint64_t, uint64_t> *sampled_functions);
explicit Google3Addr2line(const string &binary_name);
virtual ~Google3Addr2line();
virtual bool Prepare();
virtual void GetInlineStack(uint64_t address, SourceStack *stack) const;
Expand All @@ -79,7 +86,6 @@ class Google3Addr2line : public Addr2line {
AddressToLineMap *line_map_;
InlineStackHandler *inline_stack_handler_;
ElfReader *elf_;
const std::map<uint64_t, uint64_t> *sampled_functions_;
DISALLOW_COPY_AND_ASSIGN(Google3Addr2line);
};
#endif
Expand Down
Loading

0 comments on commit 623c777

Please sign in to comment.