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
13 changes: 9 additions & 4 deletions include/common_symbol_errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ using namespace std::string_view_literals;

namespace ddprof {

inline constexpr std::array<std::string_view, 6> k_common_frame_names = {
"[truncated]"sv, "[unknown mapping]"sv,
"[unwind failure]"sv, "[incomplete]"sv,
"[lost]"sv, "[maximum pids]"sv};
inline constexpr std::array<std::string_view, 7> k_common_frame_names = {
"[truncated]"sv,
"[unknown mapping]"sv,
"[unwind failure]"sv,
"[incomplete]"sv,
"[lost]"sv,
"[maximum pids]"sv,
"[unsampled mapping]"sv};

enum SymbolErrors : std::uint8_t {
truncated_stack = 0,
Expand All @@ -26,6 +30,7 @@ enum SymbolErrors : std::uint8_t {
incomplete_stack,
lost_event,
max_pids,
unsampled_mapping,
};

} // namespace ddprof
78 changes: 56 additions & 22 deletions include/live_allocation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#include "unwind_output_hash.hpp"

#include <cstddef>
#include <set>
#include <sys/types.h>
#include <unordered_map>
#include <vector>

namespace ddprof {

Expand All @@ -26,48 +28,74 @@ T &access_resize(std::vector<T> &v, size_t index,

class LiveAllocation {
public:
// For allocations Value is the size
// This is the cumulative value and count for a given stack
struct SmapsEntry {
ProcessAddress_t start;
ProcessAddress_t end;
size_t rss_kb;
size_t accounted_size{};
};

struct ValueAndCount {
int64_t _value = 0;
int64_t _count = 0;
};

struct StackAndMapping {
const UnwindOutput *uw_output_ptr; // Pointer to an UnwindOutput in a set
ProcessAddress_t start_mmap; // Start of associated mapping

bool operator==(const StackAndMapping &other) const {
return uw_output_ptr == other.uw_output_ptr &&
start_mmap == other.start_mmap;
}
};

struct StackAndMappingHash {
std::size_t operator()(const StackAndMapping &s) const {
size_t seed = std::hash<const UnwindOutput *>{}(s.uw_output_ptr);
hash_combine(seed, std::hash<ProcessAddress_t>{}(s.start_mmap));
return seed;
}
};

using PprofStacks =
std::unordered_map<UnwindOutput, ValueAndCount, UnwindOutputHash>;
std::unordered_map<StackAndMapping, ValueAndCount, StackAndMappingHash>;
using MappingValuesMap = std::unordered_map<ProcessAddress_t, ValueAndCount>;

struct ValuePerAddress {
int64_t _value = 0;
PprofStacks::value_type *_unique_stack = nullptr;
};

using AddressMap = std::unordered_map<uintptr_t, ValuePerAddress>;

struct PidStacks {
AddressMap _address_map;
PprofStacks _unique_stacks;
std::set<UnwindOutput>
unwind_output_set; // Set to store all unique UnwindOutput objects
std::vector<SmapsEntry> entries;
MappingValuesMap
mapping_values; // New map to track memory usage per mapping
};

using PidMap = std::unordered_map<pid_t, PidStacks>;
using WatcherVector = std::vector<PidMap>;
// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
WatcherVector _watcher_vector;

// Allocation should be aggregated per stack trace
// instead of a stack, we would have a total size for this unique stack trace
// and a count.
void register_allocation(const UnwindOutput &uo, uintptr_t addr, size_t size,
int watcher_pos, pid_t pid) {
PidMap &pid_map = access_resize(_watcher_vector, watcher_pos);
PidStacks &pid_stacks = pid_map[pid];
register_allocation(uo, addr, size, pid_stacks._unique_stacks,
pid_stacks._address_map);
if (pid_stacks.entries.empty()) {
pid_stacks.entries = parse_smaps(pid);
}
register_allocation_internal(uo, addr, size, pid_stacks);
}

void register_deallocation(uintptr_t addr, int watcher_pos, pid_t pid) {
PidMap &pid_map = access_resize(_watcher_vector, watcher_pos);
PidStacks &pid_stacks = pid_map[pid];
if (!register_deallocation(addr, pid_stacks._unique_stacks,
pid_stacks._address_map)) {
if (!register_deallocation_internal(addr, pid_stacks)) {
++_stats._unmatched_deallocations;
}
}
Expand All @@ -83,24 +111,30 @@ class LiveAllocation {
}
}

[[nodiscard]] [[nodiscard]] unsigned get_nb_unmatched_deallocations() const {
[[nodiscard]] unsigned get_nb_unmatched_deallocations() const {
return _stats._unmatched_deallocations;
}

static std::vector<SmapsEntry> parse_smaps(pid_t pid);

static int64_t upscale_with_mapping(const PprofStacks::value_type &stack,
PidStacks &pid_stacks);

void cycle() { _stats = {}; }

// no lint to avoid warning about member being public (should be refactored)
WatcherVector _watcher_vector; // NOLINT
private:
// returns true if the deallocation was registered
static bool register_deallocation(uintptr_t address, PprofStacks &stacks,
AddressMap &address_map);

// returns true if the allocation was registerd
static bool register_allocation(const UnwindOutput &uo, uintptr_t address,
int64_t value, PprofStacks &stacks,
AddressMap &address_map);
static bool register_deallocation_internal(uintptr_t address,
PidStacks &pid_stacks);

static bool register_allocation_internal(const UnwindOutput &uo,
uintptr_t address, int64_t value,
PidStacks &pid_stacks);

struct {
unsigned _unmatched_deallocations = {};
} _stats;
};

} // namespace ddprof
} // namespace ddprof
14 changes: 10 additions & 4 deletions include/pprof/ddprof_pprof.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ namespace ddprof {
class Symbolizer;
struct SymbolHdr;

using NumToStrCache = std::unordered_map<ProcessAddress_t, std::string>;

struct DDProfPProf {
/* single profile gathering several value types */
ddog_prof_Profile _profile{};
unsigned _nb_values = 0;
Tags _tags;
bool use_process_adresses{true};
// avoid re-creating strings for all pid numbers
std::unordered_map<pid_t, std::string> _pid_str;
NumToStrCache _pid_str;
};

struct DDProfValuePack {
Expand All @@ -39,6 +41,11 @@ struct DDProfValuePack {

DDRes pprof_create_profile(DDProfPProf *pprof, DDProfContext &ctx);

struct AggregationConfig {
EventAggregationModePos value_pos{kSumPos};
bool show_samples{false};
bool adjust_locations{true};
};
/**
* Aggregate to the existing profile the provided unwinding output.
* @param uw_output
Expand All @@ -49,9 +56,8 @@ DDRes pprof_create_profile(DDProfPProf *pprof, DDProfContext &ctx);
DDRes pprof_aggregate(const UnwindOutput *uw_output,
const SymbolHdr &symbol_hdr, const DDProfValuePack &pack,
const PerfWatcher *watcher,
const FileInfoVector &file_infos, bool show_samples,
EventAggregationModePos value_pos, Symbolizer *symbolizer,
DDProfPProf *pprof);
const FileInfoVector &file_infos, AggregationConfig conf,
Symbolizer *symbolizer, DDProfPProf *pprof);

DDRes pprof_reset(DDProfPProf *pprof);

Expand Down
2 changes: 2 additions & 0 deletions include/unwind_output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ struct FunLoc {
struct UnwindOutput {
void clear() {
locs.clear();
labels.clear();
container_id = k_container_id_unknown;
exe_name = {};
thread_name = {};
}
std::vector<FunLoc> locs;
std::vector<std::pair<std::string, std::string>> labels;
std::string_view container_id;
std::string_view exe_name;
std::string_view thread_name;
Expand Down
Loading