Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PROF-9088] Ensure DSO objects are cleared #400

Merged
merged 7 commits into from
Apr 9, 2024
Merged
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: 7 additions & 6 deletions include/common_symbol_errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ using namespace std::string_view_literals;
namespace ddprof {

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

enum SymbolErrors {
truncated_stack,
unknown_dso,
dwfl_frame,
truncated_stack = 0,
unknown_mapping,
unwind_failure,
incomplete_stack,
max_pids,
lost_event,
max_pids,
};

} // namespace ddprof
1 change: 1 addition & 0 deletions include/ddprof_cli.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct DDProfCLI {
bool remote_symbolization{false};
bool disable_symbolization{false};
bool reorder_events{false}; // reorder events by timestamp
int maximum_pids{};

std::string socket_path;
int pipefd_to_library{-1};
Expand Down
1 change: 1 addition & 0 deletions include/ddprof_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct DDProfContext {
bool remote_symbolization{false};
bool disable_symbolization{false};
bool reorder_events{false}; // reorder events by timestamp
int maximum_pids{0};
r1viollet marked this conversation as resolved.
Show resolved Hide resolved

cpu_set_t cpu_affinity{};
std::string switch_user;
Expand Down
3 changes: 2 additions & 1 deletion include/ddprof_defs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ inline constexpr int k_size_api_key = 32;

// Maximum number of profiled pids
// Exceeding a number of PIDs overloads file descriptors and memory
inline constexpr unsigned kMaxProfiledPids{100};
inline constexpr int k_default_max_profiled_pids{100};
inline constexpr int k_unlimited_max_profiled_pids{-1};

// Linux Inode type
using inode_t = uint64_t;
Expand Down
27 changes: 23 additions & 4 deletions include/ddprof_process.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
#include "container_id.hpp"
#include "ddprof_defs.hpp"
#include "ddres_def.hpp"
#include "dwfl_wrapper.hpp"
#include "logger.hpp"

#include <limits>
#include <memory>
#include <sys/types.h>
#include <unordered_map>
#include <unordered_set>

namespace ddprof {

Expand All @@ -35,28 +38,44 @@ class Process {

uint64_t increment_counter() { return ++_sample_counter; }

[[nodiscard]] DwflWrapper *get_or_insert_dwfl();
[[nodiscard]] DwflWrapper *get_dwfl();
[[nodiscard]] const DwflWrapper *get_dwfl() const;

private:
static std::string format_cgroup_file(pid_t pid,
std::string_view path_to_proc);

static DDRes read_cgroup_ns(pid_t pid, std::string_view path_to_proc,
CGroupId_t &cgroup);

std::unique_ptr<DwflWrapper> _dwfl_wrapper{};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::unique_ptr<DwflWrapper> _dwfl_wrapper{};
std::unique_ptr<DwflWrapper> _dwfl_wrapper;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not have an opinion on this. Leaving as is unless we push for a different guideline. Feel free to challenge me further if this is important.

ContainerId _container_id;
pid_t _pid;
CGroupId_t _cgroup_ns;
ContainerId _container_id;
uint64_t _sample_counter = {};
uint64_t _sample_counter{};
};

class ProcessHdr {
public:
explicit ProcessHdr(std::string_view path_to_proc = "")
: _path_to_proc(path_to_proc) {}
const ContainerId &get_container_id(pid_t pid, bool force = false);
void flag_visited(pid_t pid);
Process &get(pid_t pid);
const ContainerId &get_container_id(pid_t pid);
void clear(pid_t pid) { _process_map.erase(pid); }

std::vector<pid_t> get_unvisited() const;
const std::unordered_set<pid_t> &get_visited() const { return _visited_pid; }
void reset_unvisited();

unsigned process_count() const { return _process_map.size(); }
void display_stats() const;

private:
constexpr static auto k_nb_samples_container_id_lookup = 100;
int get_nb_mod() const;

std::unordered_set<pid_t> _visited_pid;
using ProcessMap = std::unordered_map<pid_t, Process>;
ProcessMap _process_map;
std::string _path_to_proc = {};
Expand Down
3 changes: 3 additions & 0 deletions include/dso_hdr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>

#include "ddprof_file_info.hpp"
#include "ddprof_module.hpp"
Expand Down Expand Up @@ -201,6 +202,8 @@ class DsoHdr {

bool check_invariants() const;

int clear_unvisited(const std::unordered_set<pid_t> &visited_pids);

private:
// erase range of elements
static void erase_range(DsoMap &map, DsoRange range, const Dso &new_mapping);
Expand Down
27 changes: 5 additions & 22 deletions include/dwfl_hdr.hpp → include/dwfl_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@

#pragma once

#include "create_elf.hpp"
#include "ddprof_defs.hpp"
#include "ddprof_file_info.hpp"
#include "ddprof_module.hpp"
#include "ddres.hpp"
#include "dso.hpp"
#include "dso_hdr.hpp"
#include "dwfl_internals.hpp"

#include <sys/types.h>
#include <unordered_map>
#include <unordered_set>

extern "C" {
struct Dwfl;
}
namespace ddprof {

struct UnwindState;
Expand All @@ -34,8 +35,7 @@ struct DwflWrapper {
DwflWrapper(const DwflWrapper &other) = delete; // avoid copy
DwflWrapper &operator=(const DwflWrapper &other) = delete; // avoid copy

DDRes attach(pid_t pid, const Dwfl_Thread_Callbacks *callbacks,
UnwindState *us);
DDRes attach(pid_t pid, const UniqueElf &ref_elf, UnwindState *us);

// unsafe get don't check ranges
DDProfMod *unsafe_get(FileInfoId_t file_info_id);
Expand All @@ -59,21 +59,4 @@ struct DwflWrapper {
std::unordered_map<FileInfoId_t, DDProfMod> _ddprof_mods;
};

class DwflHdr {
public:
// checks against maximum number of PIDs
DwflWrapper *get_or_insert(pid_t pid);
std::vector<pid_t> get_unvisited() const;
void reset_unvisited();
void clear_pid(pid_t pid);

// get number of accessed modules
int get_nb_mod() const;
void display_stats() const;

private:
std::unordered_map<pid_t, DwflWrapper> _dwfl_map;
std::unordered_set<pid_t> _visited_pid;
};

} // namespace ddprof
9 changes: 8 additions & 1 deletion include/common_frames.hpp → include/stack_helper.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0. This product includes software
// developed at Datadog (https://www.datadoghq.com/). Copyright 2021-Present
// developed at Datadog (https://www.datadoghq.com/). Copyright 2024-Present
// Datadog, Inc.

#pragma once

#include "ddprof_defs.hpp"

namespace ddprof {
bool memory_read(ProcessAddress_t addr, ElfWord_t *result, int regno,
void *arg);
}
5 changes: 3 additions & 2 deletions include/unwind_dwfl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

#pragma once

#include "ddprof_process.hpp"
#include "ddres_def.hpp"

namespace ddprof {

struct UnwindState;

DDRes unwind_init_dwfl(UnwindState *us);
DDRes unwind_init_dwfl(Process &process, UnwindState *us);

DDRes unwind_dwfl(UnwindState *us);
DDRes unwind_dwfl(Process &process, bool avoid_new_attach, UnwindState *us);

} // namespace ddprof
5 changes: 1 addition & 4 deletions include/unwind_helpers.hpp → include/unwind_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ void add_dso_frame(UnwindState *us, const Dso &dso,

void add_virtual_base_frame(UnwindState *us);

bool memory_read(ProcessAddress_t addr, ElfWord_t *result, int regno,
void *arg);

void add_error_frame(const Dso *dso, UnwindState *us, ProcessAddress_t pc,
SymbolErrors error_case = SymbolErrors::unknown_dso);
SymbolErrors error_case = SymbolErrors::unknown_mapping);

} // namespace ddprof
16 changes: 9 additions & 7 deletions include/unwind_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#include "ddprof_process.hpp"
#include "ddres_def.hpp"
#include "dso_hdr.hpp"
#include "dwfl_hdr.hpp"
#include "dwfl_thread_callbacks.hpp"
#include "dwfl_wrapper.hpp"
#include "perf.hpp"
#include "perf_archmap.hpp"
#include "symbol_hdr.hpp"
Expand Down Expand Up @@ -41,15 +41,14 @@ struct UnwindRegisters {
/// Single structure with everything necessary in unwinding. The structure is
/// given through callbacks
struct UnwindState {
explicit UnwindState(UniqueElf ref_elf, int dd_profiling_fd = -1)
: dso_hdr("", dd_profiling_fd), ref_elf(std::move(ref_elf)) {
explicit UnwindState(UniqueElf ref_elf, int dd_profiling_fd = -1,
int nb_max_pids = k_default_max_profiled_pids)
: dso_hdr("", dd_profiling_fd), ref_elf(std::move(ref_elf)),
maximum_pids(nb_max_pids) {
output.clear();
output.locs.reserve(kMaxStackDepth);
}

DwflHdr dwfl_hdr;
DwflWrapper *_dwfl_wrapper{nullptr}; // pointer to current dwfl element

DsoHdr dso_hdr;
SymbolHdr symbol_hdr;
ProcessHdr process_hdr;
Expand All @@ -63,9 +62,12 @@ struct UnwindState {

UnwindOutput output;
UniqueElf ref_elf; // reference elf object used to initialize dwfl
int maximum_pids;
};

std::optional<UnwindState> create_unwind_state(int dd_profiling_fd = -1);
std::optional<UnwindState>
create_unwind_state(int dd_profiling_fd = -1,
int maximum_pids = k_default_max_profiled_pids);

static inline bool unwind_registers_equal(const UnwindRegisters *lhs,
const UnwindRegisters *rhs) {
Expand Down
26 changes: 25 additions & 1 deletion src/ddprof_cli.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

#include "CLI/CLI11.hpp"
#include "constants.hpp"
#include "ddprof_cmdline.hpp"
#include "ddprof_cmdline_watcher.hpp"
#include "ddprof_defs.hpp"
#include "ddres.hpp"
Expand Down Expand Up @@ -92,6 +91,22 @@ struct SampleStackSizeValidator : public Validator {
};
}
};

using Validator = CLI::Validator;
struct MaximumPidsValidator : public Validator {
MaximumPidsValidator() {
name_ = "MAXIMUM_PIDS";
func_ = [](const std::string &str) {
int const value = std::stoi(str);
if (value <= 0 && value != -1) {
return static_cast<std::string>(
"Invalid value for maximum pids."
"The value should be -1 for unlimited or positive.");
}
return std::string();
};
}
};
} // namespace

int DDProfCLI::parse(int argc, const char *argv[]) {
Expand Down Expand Up @@ -374,6 +389,15 @@ int DDProfCLI::parse(int argc, const char *argv[]) {
->default_val(false)
->envname("DD_PROFILING_REORDER_EVENTS")
->group(""));

extended_options.push_back(app.add_flag("--maximum-pids,--maximum_pids",
r1viollet marked this conversation as resolved.
Show resolved Hide resolved
maximum_pids,
"Maximum number of profiled PIDs."
"Setting -1 means no limit.")
->check(MaximumPidsValidator())
->default_val(k_default_max_profiled_pids)
->envname("DD_PROFILING_MAXIMUM_PIDS")
->group(""));
// Parse
CLI11_PARSE(app, argc, argv);

Expand Down
1 change: 1 addition & 0 deletions src/ddprof_context_lib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ void copy_cli_values(const DDProfCLI &ddprof_cli, DDProfContext &ctx) {
ctx.params.remote_symbolization = ddprof_cli.remote_symbolization;
ctx.params.disable_symbolization = ddprof_cli.disable_symbolization;
ctx.params.reorder_events = ddprof_cli.reorder_events;
ctx.params.maximum_pids = ddprof_cli.maximum_pids;

ctx.params.initial_loaded_libs_check_delay =
ddprof_cli.initial_loaded_libs_check_delay;
Expand Down
Loading