Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Using the build image will guarantee this.
```bash
CXX=clang++-17 CC=clang-17 source ./setup_env.sh
MkBuildDir ClangDeb
DebCMake -DENABLE_CLANG_TIDY=ON ../
DebCMake -DENABLE_CLANG_TIDY=ON ../
```

### Updating libdatadog
Expand Down
1 change: 1 addition & 0 deletions include/ddprof_cli.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct DDProfCLI {
// Profiling options
int pid{0};
bool global{false};
bool inlining{true};
std::chrono::seconds upload_period;
unsigned worker_period; // worker_period
std::vector<std::string> events;
Expand Down
1 change: 1 addition & 0 deletions include/ddprof_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace ddprof {
struct DDProfContext {
struct {
bool enable{true};
bool inlining{true};
std::chrono::seconds upload_period{};
bool fault_info{true};
int nice{-1};
Expand Down
1 change: 1 addition & 0 deletions include/ddres_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum { DD_COMMON_START_RANGE = 1000, DD_NATIVE_START_RANGE = 2000 };

#define NATIVE_ERROR_TABLE(X) \
X(DWFL_LIB_ERROR, "error withing dwfl library") \
X(NO_DWARF, "No dwarf information available") \
X(UW_CACHE_ERROR, "error from unwinding cache") \
X(UW_ERROR, "error from unwinding code") \
X(UW_MAX_DEPTH, "max depth reached in unwinding") \
Expand Down
30 changes: 30 additions & 0 deletions include/dwarf_helpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "ddprof_defs.hpp"
#include "ddres_def.hpp"
#include "dwfl_internals.hpp"

#include <vector>

namespace ddprof {
struct DieInformation {
struct Function {
ElfAddress_t start_addr{};
ElfAddress_t end_addr{};
const char *func_name{};
const char *file_name{};
int decl_line_number{0};
int call_line_number{0};
int parent_pos{-1}; // position within the die vector
SymbolIdx_t symbol_idx = -1;
};
std::vector<Function> die_mem_vec{};
};

// debug attribute functions
const char *get_attribute_name(int attrCode);
int print_attribute(Dwarf_Attribute *attr, void *arg);

DDRes parse_die_information(Dwarf_Die *cudie, ElfAddress_t elf_addr,
DieInformation &die_information);
} // namespace ddprof
1 change: 1 addition & 0 deletions include/dwfl_internals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@

#pragma once

#include <dwarf.h>
#include <elfutils/libdw.h>
#include <elfutils/libdwfl.h>
1 change: 1 addition & 0 deletions include/dwfl_symbol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ bool symbol_get_from_dwfl(Dwfl_Module *mod, ProcessAddress_t process_pc,

bool compute_elf_range(ElfAddress_t file_pc, const GElf_Sym &elf_sym,
ElfAddress_t &start_sym, ElfAddress_t &end_sym);

} // namespace ddprof
59 changes: 46 additions & 13 deletions include/dwfl_symbol_lookup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
#include "ddprof_defs.hpp"
#include "ddprof_file_info-i.hpp"
#include "ddprof_module.hpp"
#include "ddres.hpp"
#include "dso.hpp"
#include "dso_symbol_lookup.hpp"
#include "hash_helper.hpp"
#include "symbol_map.hpp"
#include "symbol_table.hpp"
#include "unwind_output.hpp"

#include <iostream>
#include <unordered_map>
Expand Down Expand Up @@ -42,22 +44,33 @@ struct DwflSymbolLookupStats {

class DwflSymbolLookup {
public:
using SymbolRange = std::pair<ElfAddress_t, ElfAddress_t>;
// build and check env var to know check setting
DwflSymbolLookup();
DwflSymbolLookup(bool inlining = true);

// Get symbol from internal cache or fetch through dwarf
SymbolIdx_t get_or_insert(const DDProfMod &ddprof_mod, SymbolTable &table,
DsoSymbolLookup &dso_symbol_lookup,
FileInfoId_t file_info_id,
ProcessAddress_t process_pc, const Dso &dso);
void get_or_insert(Dwfl *dwfl, const DDProfMod &ddprof_mod,
SymbolTable &table, DsoSymbolLookup &dso_symbol_lookup,
FileInfoId_t file_info_id, ProcessAddress_t process_pc,
const Dso &dso, std::vector<FunLoc> &func_locs);

void erase(FileInfoId_t file_info_id) { _file_info_map.erase(file_info_id); }
void erase(FileInfoId_t file_info_id) {
_file_info_function_map.erase(file_info_id);
}

unsigned size() const;

const DwflSymbolLookupStats &stats() const { return _stats; }
DwflSymbolLookupStats &stats() { return _stats; }

// todo: we can have a better type than symbol idx for the line
using InlineMap = NestedSymbolMap;
struct SymbolWrapper {
LineMap _line_map;
SymbolMap _symbol_map;
InlineMap _inline_map;
};

private:
/// Set through env var (DDPROF_CACHE_SETTING) in case of doubts on cache
enum SymbolLookupSetting {
Expand All @@ -67,24 +80,44 @@ class DwflSymbolLookup {

SymbolLookupSetting _lookup_setting{K_CACHE_ON};

SymbolIdx_t insert(const DDProfMod &ddprof_mod, SymbolTable &table,
DsoSymbolLookup &dso_symbol_lookup,
ProcessAddress_t process_pc, const Dso &dso,
SymbolMap &map);
SymbolMap::ValueType &insert(Dwfl *dwfl, const DDProfMod &ddprof_mod,
SymbolTable &table,
DsoSymbolLookup &dso_symbol_lookup,
ProcessAddress_t process_pc, const Dso &dso,
SymbolWrapper &symbol_wrapper);

void add_fun_loc(DwflSymbolLookup::SymbolWrapper &symbol_wrapper,
const SymbolMap::ValueType &parent_sym, ElfAddress_t elf_pc,
ProcessAddress_t process_pc, std::vector<FunLoc> &func_locs);

static DDRes insert_inlining_info(Dwfl *dwfl, const DDProfMod &ddprof_mod,
SymbolTable &table,
ProcessAddress_t process_pc, const Dso &dso,
SymbolWrapper &symbol_wrapper,
SymbolMap::ValueType &parent_func);

static NestedSymbolMap::FindRes
get_inlined(SymbolWrapper &symbol_wrapper, ElfAddress_t process_pc,
ElfAddress_t elf_pc, const SymbolMap::ValueType &parent_sym,
std::vector<FunLoc> &func_locs);

// Symbols are ordered by file.
// The assumption is that the elf addresses are the same across processes
// The unordered map stores symbols per file,
// The map stores symbols per address range
using FileInfo2SymbolMap = std::unordered_map<FileInfoId_t, SymbolMap>;
using FileInfo2SymbolVT = FileInfo2SymbolMap::value_type;
using FileInfo2SymbolWrapper =
std::unordered_map<FileInfoId_t, SymbolWrapper>;
using FileInfo2LineMap = std::unordered_map<FileInfoId_t, LineMap>;
using FileInfo2SymbolVT = FileInfo2SymbolWrapper::value_type;

static bool symbol_lookup_check(Dwfl_Module *mod, ElfAddress_t process_pc,
const Symbol &symbol);

// unordered map of DSO elements
FileInfo2SymbolMap _file_info_map;
FileInfo2SymbolWrapper _file_info_function_map;
FileInfo2LineMap _file_info_inlining_map;
DwflSymbolLookupStats _stats;
bool _inlining;
};

} // namespace ddprof
8 changes: 4 additions & 4 deletions include/symbol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ namespace ddprof {

class Symbol {
public:
Symbol() : _lineno(0) {}
Symbol() : _func_start_lineno(0) {}

// Warning : Generates some string copies (these are not rvalues)
Symbol(std::string symname, std::string demangle_name, uint32_t lineno,
std::string srcpath)
std::string srcpath, int parent_idx = -1)
: _symname(std::move(symname)), _demangle_name(std::move(demangle_name)),
_lineno(lineno), _srcpath(std::move(srcpath)) {}
_func_start_lineno(lineno), _srcpath(std::move(srcpath)) {}

// OUTPUT OF ADDRINFO
std::string _symname;
Expand All @@ -30,7 +30,7 @@ class Symbol {
std::string _demangle_name;

// OUTPUT OF LINE INFO
uint32_t _lineno;
uint32_t _func_start_lineno;
std::string _srcpath;
};
} // namespace ddprof
4 changes: 2 additions & 2 deletions include/symbol_hdr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

namespace ddprof {
struct SymbolHdr {
explicit SymbolHdr(std::string_view path_to_proc = "")
: _runtime_symbol_lookup(path_to_proc) {}
explicit SymbolHdr(std::string_view path_to_proc = "", bool inlining = true)
: _dwfl_symbol_lookup(inlining), _runtime_symbol_lookup(path_to_proc) {}
void display_stats() const {
_dwfl_symbol_lookup.stats().display(_dwfl_symbol_lookup.size());
_dso_symbol_lookup.stats_display();
Expand Down
115 changes: 103 additions & 12 deletions include/symbol_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
#include <map>

#include "ddprof_defs.hpp"
#include <logger.hpp>

namespace ddprof {

class SymbolSpan {
template <typename T, T DefaultValue = T()> class TSpan {
public:
SymbolSpan() : _end(0), _symbol_idx(-1) {}
SymbolSpan(Offset_t end, SymbolIdx_t symbol_idx)
: _end(end), _symbol_idx(symbol_idx) {}
TSpan() : _end(0), _value(DefaultValue) {}
TSpan(Offset_t end, T value) : _end(end), _value(value) {}
// push end further
void set_end(Offset_t end) {
if (end > _end) {
Expand All @@ -23,23 +23,27 @@ class SymbolSpan {
}
[[nodiscard]] Offset_t get_end() const { return _end; }

[[nodiscard]] SymbolIdx_t get_symbol_idx() const { return _symbol_idx; }
[[nodiscard]] T get_value() const { return _value; }

private:
// symbol end within the segment (considering file offset)
Offset_t _end;
// element inside internal symbol cache
SymbolIdx_t _symbol_idx;
T _value;
};

class SymbolMap : private std::map<ElfAddress_t, SymbolSpan> {
using SymbolSpan = TSpan<SymbolIdx_t, -1>;
using LineSpan = TSpan<uint32_t, 0>;

template <typename TSpan>
class SpanMap : private std::map<ElfAddress_t, TSpan> {
public:
using Map = std::map<ElfAddress_t, SymbolSpan>;
using It = Map::iterator;
using ConstIt = Map::const_iterator;
using Map = std::map<ElfAddress_t, TSpan>;
using It = typename Map::iterator;
using ConstIt = typename Map::const_iterator;
using FindRes = std::pair<It, bool>;
using ValueType =
Map::value_type; // key value pair ElfAddress_t, SymbolSpanMap
typename Map::value_type; // key value pair ElfAddress_t, SymbolSpanMap
// Functions we forward from underlying map type

using Map::begin;
Expand All @@ -51,8 +55,95 @@ class SymbolMap : private std::map<ElfAddress_t, SymbolSpan> {
using Map::erase;
using Map::size;

bool is_within(const Offset_t &norm_pc, const SpanMap::ValueType &kv) {
if (norm_pc < kv.first) {
return false;
}
if (norm_pc > kv.second.get_end()) {
return false;
}
return true;
}

FindRes find_closest(Offset_t norm_pc) {
// First element not less than (can match exactly a start addr)
auto it = Map::lower_bound(norm_pc);
if (it != end()) { // map is empty
if (SpanMap::is_within(norm_pc, *it)) {
return {it, true};
}
}

// previous element is more likely to contain our addr
if (it != begin()) {
--it;
} else { // map is empty
return {end(), false};
}
// element can not be end (as we reversed or exit)
return {it, is_within(norm_pc, *it)};
}
};

using SymbolMap = SpanMap<SymbolSpan>;
using LineMap = SpanMap<LineSpan>;

class NestedSymbolValue {
public:
NestedSymbolValue() : _symbol_idx(-1), _call_line_number(0) {}
NestedSymbolValue(SymbolIdx_t symbol_idx, int call_line_number = 0)
: _symbol_idx(symbol_idx), _call_line_number(call_line_number) {}
[[nodiscard]] SymbolIdx_t get_symbol_idx() const { return _symbol_idx; }
[[nodiscard]] int get_call_line_number() const { return _call_line_number; }

private:
SymbolIdx_t _symbol_idx;
int _call_line_number;
};

struct NestedSymbolKey {
ElfAddress_t start;
ElfAddress_t end;
NestedSymbolKey(ElfAddress_t s, ElfAddress_t e) : start(s), end(e) {}
bool operator<(const NestedSymbolKey &other) const {
if (start != other.start) {
return start < other.start;
}
// Sort by end address in descending order if start addresses are equal
return end > other.end;
}
};

class NestedSymbolMap : private std::map<NestedSymbolKey, NestedSymbolValue> {
public:
using Map = std::map<NestedSymbolKey, NestedSymbolValue>;
using It = Map::iterator;
using ConstIt = Map::const_iterator;
using FindRes = std::pair<ConstIt, bool>;
using ValueType = Map::value_type;
using Map::begin;
using Map::clear;
using Map::emplace;
using Map::emplace_hint;
using Map::empty;
using Map::end;
using Map::erase;
using Map::size;

// todo: possible improvement to return a table of all elements matching

FindRes find_parent(ConstIt it, const NestedSymbolKey &parent_bound,
Offset_t norm_pc) const;

// returns the element that is the most leaf
FindRes find_closest(Offset_t norm_pc,
const NestedSymbolKey &parent_bound) const;

FindRes find_closest_hint(Offset_t norm_pc,
const NestedSymbolKey &parent_bound,
ConstIt hint) const;

static bool is_within(const Offset_t &norm_pc, const ValueType &kv);
FindRes find_closest(Offset_t norm_pc);
};

} // namespace ddprof
5 changes: 5 additions & 0 deletions include/unwind_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ struct UnwindState;

bool is_max_stack_depth_reached(const UnwindState &us);

DDRes add_frame(const std::vector<FunLoc> &fun_locs, UnwindState *us);

DDRes add_frame(std::vector<SymbolIdx_t> symbol_indices, MapInfoIdx_t map_idx,
ElfAddress_t pc, UnwindState *us);

DDRes add_frame(SymbolIdx_t symbol_idx, MapInfoIdx_t map_idx, ElfAddress_t pc,
UnwindState *us);

Expand Down
8 changes: 4 additions & 4 deletions include/unwind_output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
namespace ddprof {

struct FunLoc {
uint64_t ip; // Relative to file, not VMA
SymbolIdx_t _symbol_idx;
MapInfoIdx_t _map_info_idx;

uint64_t _ip{};
uint32_t _lineno{};
SymbolIdx_t _symbol_idx{-1};
MapInfoIdx_t _map_info_idx{-1};
friend auto operator<=>(const FunLoc &, const FunLoc &) = default;
};

Expand Down
Loading