Skip to content

Commit

Permalink
[record & replay] Create virtual base classes for wrapped maps & arra…
Browse files Browse the repository at this point in the history
…ys. (#1662)

Summary: In preparation for introducing record & replay, we create a
virtual base classes for wrapped BCC maps & arrays. In a future PR, we
will introduce two new implementations, one for recording and one for
replaying.

Relevant Issues: #1163

Type of change: /kind feature

Test Plan: fully covered by existing tests.

---------

Signed-off-by: Pete Stevenson <[email protected]>
  • Loading branch information
Pete Stevenson authored Aug 10, 2023
1 parent b76a352 commit 5edc488
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 42 deletions.
5 changes: 5 additions & 0 deletions src/stirling/bpf_tools/bcc_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,11 @@ void BCCWrapperImpl::Close() {

std::unique_ptr<BCCWrapper> CreateBCC() { return std::make_unique<BCCWrapperImpl>(); }

std::unique_ptr<WrappedBCCStackTable> WrappedBCCStackTable::Create(bpf_tools::BCCWrapper* bcc,
const std::string& name) {
return std::make_unique<WrappedBCCStackTableImpl>(bcc, name);
}

} // namespace bpf_tools
} // namespace stirling
} // namespace px
140 changes: 98 additions & 42 deletions src/stirling/bpf_tools/bcc_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,17 +332,23 @@ class BCCWrapperImpl : public BCCWrapper {

std::unique_ptr<BCCWrapper> CreateBCC();

// Wrapped maps & arrays.
template <typename T>
class WrappedBCCArrayTable {
public:
using U = ebpf::BPFArrayTable<T>;
virtual ~WrappedBCCArrayTable() {}
static std::unique_ptr<WrappedBCCArrayTable> Create(BCCWrapper* bcc, const std::string& name);

static std::unique_ptr<WrappedBCCArrayTable> Create(bpf_tools::BCCWrapper* bcc,
const std::string& name) {
return std::unique_ptr<WrappedBCCArrayTable>(new WrappedBCCArrayTable(bcc, name));
}
virtual StatusOr<T> GetValue(const uint32_t idx) = 0;
virtual Status SetValue(const uint32_t idx, const T& value) = 0;
};

template <typename T>
class WrappedBCCArrayTableImpl : public WrappedBCCArrayTable<T> {
public:
using U = ebpf::BPFArrayTable<T>;

StatusOr<T> GetValue(const uint32_t idx) {
StatusOr<T> GetValue(const uint32_t idx) override {
T value;
ebpf::StatusTuple s = underlying_->get_value(idx, value);
if (!s.ok()) {
Expand All @@ -351,39 +357,47 @@ class WrappedBCCArrayTable {
return value;
}

Status SetValue(const uint32_t idx, const T& value) {
Status SetValue(const uint32_t idx, const T& value) override {
ebpf::StatusTuple s = underlying_->update_value(idx, value);
if (!s.ok()) {
return error::Internal(absl::Substitute(err_msg_, "set", name_, idx, s.msg()));
}
return Status::OK();
}

private:
WrappedBCCArrayTable(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
WrappedBCCArrayTableImpl(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
underlying_ = std::make_unique<U>(bcc->BPF().get_array_table<T>(name_));
}

private:
const std::string name_;
char const* const err_msg_ = "BPF failed to $0 value for array table: $1, index: $2. $3.";
std::unique_ptr<U> underlying_;
};

template <typename K, typename V, bool kUserSpaceManaged = false>
class WrappedBCCMap {
public:
static std::unique_ptr<WrappedBCCMap> Create(bpf_tools::BCCWrapper* bcc, const std::string& name);
virtual ~WrappedBCCMap() {}

virtual size_t capacity() const = 0;
virtual StatusOr<V> GetValue(const K& key) const = 0;
virtual Status SetValue(const K& key, const V& value) = 0;
virtual Status RemoveValue(const K& key) = 0;
virtual std::vector<std::pair<K, V>> GetTableOffline(const bool clear_table = false) = 0;
};

// Template parameter kUserSpaceManaged enables the "shadow keys" optimization.
// Set to true iff the map is modified/updated from user space only.
template <typename K, typename V, bool kUserSpaceManaged = false>
class WrappedBCCMap {
class WrappedBCCMapImpl : public WrappedBCCMap<K, V, kUserSpaceManaged> {
public:
using U = ebpf::BPFHashTable<K, V>;

static std::unique_ptr<WrappedBCCMap> Create(bpf_tools::BCCWrapper* bcc,
const std::string& name) {
return std::unique_ptr<WrappedBCCMap>(new WrappedBCCMap(bcc, name));
}

size_t capacity() const { return underlying_->capacity(); }
size_t capacity() const override { return underlying_->capacity(); }

StatusOr<V> GetValue(const K& key) const {
StatusOr<V> GetValue(const K& key) const override {
V value;
ebpf::StatusTuple s = underlying_->get_value(key, value);
if (!s.ok()) {
Expand All @@ -392,7 +406,7 @@ class WrappedBCCMap {
return value;
}

Status SetValue(const K& key, const V& value) {
Status SetValue(const K& key, const V& value) override {
ebpf::StatusTuple s = underlying_->update_value(key, value);
if (!s.ok()) {
return error::Internal(absl::Substitute(err_msg_, "set", name_, s.msg()));
Expand All @@ -403,7 +417,7 @@ class WrappedBCCMap {
return Status::OK();
}

Status RemoveValue(const K& key) {
Status RemoveValue(const K& key) override {
if constexpr (kUserSpaceManaged) {
if (!shadow_keys_.contains(key)) {
return Status::OK();
Expand All @@ -420,7 +434,7 @@ class WrappedBCCMap {
return Status::OK();
}

std::vector<std::pair<K, V>> GetTableOffline(const bool clear_table = false) {
std::vector<std::pair<K, V>> GetTableOffline(const bool clear_table = false) override {
if constexpr (!kUserSpaceManaged) {
return underlying_->get_table_offline(clear_table);
}
Expand All @@ -443,11 +457,11 @@ class WrappedBCCMap {
return r;
}

private:
WrappedBCCMap(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
WrappedBCCMapImpl(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
underlying_ = std::make_unique<U>(bcc->BPF().get_hash_table<K, V>(name_));
}

private:
const std::string name_;
char const* const err_msg_ = "BPF failed to $0 value for map: $1. $2.";
std::unique_ptr<U> underlying_;
Expand All @@ -457,14 +471,19 @@ class WrappedBCCMap {
template <typename T>
class WrappedBCCPerCPUArrayTable {
public:
using U = ebpf::BPFPercpuArrayTable<T>;

static std::unique_ptr<WrappedBCCPerCPUArrayTable> Create(bpf_tools::BCCWrapper* bcc,
const std::string& name) {
return std::unique_ptr<WrappedBCCPerCPUArrayTable>(new WrappedBCCPerCPUArrayTable(bcc, name));
}
const std::string& name);
virtual ~WrappedBCCPerCPUArrayTable() {}

virtual Status SetValues(const int idx, const T& value) = 0;
};

Status SetValues(const int idx, const T& value) {
template <typename T>
class WrappedBCCPerCPUArrayTableImpl : public WrappedBCCPerCPUArrayTable<T> {
public:
using U = ebpf::BPFPercpuArrayTable<T>;

Status SetValues(const int idx, const T& value) override {
std::vector<T> values(bpf_tools::BCCWrapper::kCPUCount, value);
ebpf::StatusTuple s = underlying_->update_value(idx, values);
if (!s.ok()) {
Expand All @@ -474,45 +493,82 @@ class WrappedBCCPerCPUArrayTable {
return Status::OK();
}

private:
WrappedBCCPerCPUArrayTable(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
WrappedBCCPerCPUArrayTableImpl(bpf_tools::BCCWrapper* bcc, const std::string& name)
: name_(name) {
underlying_ = std::make_unique<U>(bcc->BPF().get_percpu_array_table<T>(name_));
}

private:
const std::string name_;
std::unique_ptr<U> underlying_;
};

class WrappedBCCStackTable {
public:
using U = ebpf::BPFStackTable;

static std::unique_ptr<WrappedBCCStackTable> Create(bpf_tools::BCCWrapper* bcc,
const std::string& name) {
return std::unique_ptr<WrappedBCCStackTable>(new WrappedBCCStackTable(bcc, name));
}
const std::string& name);
virtual ~WrappedBCCStackTable() {}

std::vector<uintptr_t> GetStackAddr(const int stack_id, const bool clear_stack_id) {
virtual std::vector<uintptr_t> GetStackAddr(const int stack_id, const bool clear_stack_id) = 0;
virtual std::string GetAddrSymbol(const uintptr_t addr, const int pid) = 0;
virtual void ClearStackID(const int stack_id) = 0;
};

class WrappedBCCStackTableImpl : public WrappedBCCStackTable {
public:
using U = ebpf::BPFStackTable;

std::vector<uintptr_t> GetStackAddr(const int stack_id, const bool clear_stack_id) override {
return underlying_->get_stack_addr(stack_id, clear_stack_id);
}

std::string GetAddrSymbol(const uintptr_t addr, const int pid) {
std::string GetAddrSymbol(const uintptr_t addr, const int pid) override {
return underlying_->get_addr_symbol(addr, pid);
}

void ClearStackID(const int stack_id) { underlying_->clear_stack_id(stack_id); }

U* RawPtr() { return underlying_.get(); }
void ClearStackID(const int stack_id) override { underlying_->clear_stack_id(stack_id); }

private:
WrappedBCCStackTable(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
WrappedBCCStackTableImpl(bpf_tools::BCCWrapper* bcc, const std::string& name) : name_(name) {
underlying_ = std::make_unique<U>(bcc->BPF().get_stack_table(name_));
}

private:
const std::string name_;
std::unique_ptr<U> underlying_;
};

// Creators fns for wrapped maps & arrays:
template <typename BaseT, typename ImplT>
std::unique_ptr<BaseT> CreateBCCWrappedMapOrArray(BCCWrapper* bcc, const std::string& name) {
// The decision logic for "normal" vs. "recording" vs. "replaying" impl. will be inserted
// here in a future PR.
return std::make_unique<ImplT>(bcc, name);
}

template <typename T>
std::unique_ptr<WrappedBCCArrayTable<T>> WrappedBCCArrayTable<T>::Create(BCCWrapper* bcc,
const std::string& name) {
using BaseT = WrappedBCCArrayTable<T>;
using ImplT = WrappedBCCArrayTableImpl<T>;
return CreateBCCWrappedMapOrArray<BaseT, ImplT>(bcc, name);
}

template <typename K, typename V, bool U>
std::unique_ptr<WrappedBCCMap<K, V, U>> WrappedBCCMap<K, V, U>::Create(BCCWrapper* bcc,
const std::string& name) {
using BaseT = WrappedBCCMap<K, V, U>;
using ImplT = WrappedBCCMapImpl<K, V, U>;
return CreateBCCWrappedMapOrArray<BaseT, ImplT>(bcc, name);
}

template <typename T>
std::unique_ptr<WrappedBCCPerCPUArrayTable<T>> WrappedBCCPerCPUArrayTable<T>::Create(
BCCWrapper* bcc, const std::string& name) {
using BaseT = WrappedBCCPerCPUArrayTable<T>;
using ImplT = WrappedBCCPerCPUArrayTableImpl<T>;
return CreateBCCWrappedMapOrArray<BaseT, ImplT>(bcc, name);
}

} // namespace bpf_tools
} // namespace stirling
} // namespace px

0 comments on commit 5edc488

Please sign in to comment.