Skip to content

Commit

Permalink
[record & replay] Add rr for per-cpu array table and for stack tabl…
Browse files Browse the repository at this point in the history
…e. (#1729)

Summary: We add the record & replay capability for per-cpu array tables
and for stack tables.

Type of change: /kind feature

Test Plan: We extend the test case: `rr_bpf_test`.

Signed-off-by: Pete Stevenson <[email protected]>
  • Loading branch information
Pete Stevenson authored Jan 23, 2024
1 parent ccf0a9b commit 892cfc6
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 14 deletions.
6 changes: 3 additions & 3 deletions src/stirling/bpf_tools/bcc_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,9 @@ std::unique_ptr<WrappedBCCStackTable> WrappedBCCStackTable::Create(bpf_tools::BC
const std::string& name) {
using BaseT = WrappedBCCStackTable;
using ImplT = WrappedBCCStackTableImpl;

// TODO(jps): Impl. rr for stack table.
return CreateBCCWrappedMapOrArray<BaseT, ImplT, ImplT, ImplT>(bcc, name);
using RecordingT = RecordingWrappedBCCStackTableImpl;
using ReplayingT = ReplayingWrappedBCCStackTableImpl;
return CreateBCCWrappedMapOrArray<BaseT, ImplT, RecordingT, ReplayingT>(bcc, name);
}

} // namespace bpf_tools
Expand Down
65 changes: 62 additions & 3 deletions src/stirling/bpf_tools/bcc_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,22 @@ class WrappedBCCPerCPUArrayTableImpl : public WrappedBCCPerCPUArrayTable<T> {
std::unique_ptr<U> underlying_;
};

template <typename T>
class RecordingWrappedBCCPerCPUArrayTableImpl : public WrappedBCCPerCPUArrayTableImpl<T> {
public:
using Super = WrappedBCCPerCPUArrayTableImpl<T>;
RecordingWrappedBCCPerCPUArrayTableImpl(bpf_tools::BCCWrapper* bcc, const std::string& name)
: Super(bcc, name) {}
};

template <typename T>
class ReplayingWrappedBCCPerCPUArrayTableImpl : public WrappedBCCPerCPUArrayTable<T> {
public:
Status SetValues(const int, const T&) override { return Status::OK(); }

ReplayingWrappedBCCPerCPUArrayTableImpl(bpf_tools::BCCWrapper*, const std::string&) {}
};

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Stack Table
Expand Down Expand Up @@ -797,6 +813,49 @@ class WrappedBCCStackTableImpl : public WrappedBCCStackTable {
std::unique_ptr<U> underlying_;
};

class RecordingWrappedBCCStackTableImpl : public WrappedBCCStackTableImpl {
public:
using Super = WrappedBCCStackTableImpl;

std::vector<uintptr_t> GetStackAddr(const int stack_id, const bool clear_stack_id) override {
const auto stack_addrs = Super::GetStackAddr(stack_id, clear_stack_id);
recorder_.RecordBPFStackTableGetStackAddrEvent(this->name_, stack_id, stack_addrs);
return stack_addrs;
}

std::string GetAddrSymbol(const uintptr_t addr, const int pid) override {
const auto symbol = Super::GetAddrSymbol(addr, pid);
recorder_.RecordBPFStackTableGetAddrSymbolEvent(this->name_, addr, pid, symbol);
return symbol;
}

RecordingWrappedBCCStackTableImpl(bpf_tools::BCCWrapper* bcc, const std::string& name)
: Super(bcc, name), recorder_(*bcc->GetBPFRecorder().ConsumeValueOrDie()) {}

private:
BPFRecorder& recorder_;
};

class ReplayingWrappedBCCStackTableImpl : public WrappedBCCStackTable {
public:
std::vector<uintptr_t> GetStackAddr(const int stack_id, const bool) override {
return replayer_.ReplayBPFStackTableGetStackAddrEvent(name_, stack_id).ConsumeValueOr({0});
}

std::string GetAddrSymbol(const uintptr_t addr, const int pid) override {
return replayer_.ReplayBPFStackTableGetAddrSymbolEvent(name_, addr, pid).ConsumeValueOr("");
}

void ClearStackID(const int) override {}

ReplayingWrappedBCCStackTableImpl(bpf_tools::BCCWrapper* bcc, const std::string& name)
: name_(name), replayer_(*bcc->GetBPFReplayer().ConsumeValueOrDie()) {}

private:
const std::string name_;
BPFReplayer& replayer_;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Creators fns for wrapped maps & arrays:
Expand Down Expand Up @@ -843,9 +902,9 @@ std::unique_ptr<WrappedBCCPerCPUArrayTable<T>> WrappedBCCPerCPUArrayTable<T>::Cr
BCCWrapper* bcc, const std::string& name) {
using BaseT = WrappedBCCPerCPUArrayTable<T>;
using ImplT = WrappedBCCPerCPUArrayTableImpl<T>;

// TODO(jps): Impl. rr for per cpu array.
return CreateBCCWrappedMapOrArray<BaseT, ImplT, ImplT, ImplT>(bcc, name);
using RecordingT = RecordingWrappedBCCPerCPUArrayTableImpl<T>;
using ReplayingT = ReplayingWrappedBCCPerCPUArrayTableImpl<T>;
return CreateBCCWrappedMapOrArray<BaseT, ImplT, RecordingT, ReplayingT>(bcc, name);
}

} // namespace bpf_tools
Expand Down
99 changes: 93 additions & 6 deletions src/stirling/bpf_tools/rr/rr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ void BPFRecorder::RecordBPFMapCapacityEvent(const std::string& name, const int32
*event_name = name;
}

void BPFRecorder::RecordBPFStackTableGetStackAddrEvent(const std::string& name,
const int32_t stack_id,
const std::vector<uintptr_t>& addrs) {
auto event = events_proto_.add_event()->mutable_get_stack_addr_event();
event->set_stack_id(stack_id);
for (const auto& a : addrs) {
event->add_addr(a);
}
auto event_name = event->mutable_name();
*event_name = name;
}

void BPFRecorder::RecordBPFStackTableGetAddrSymbolEvent(const std::string& name,
const uint64_t addr, const uint32_t pid,
const std::string symbol) {
auto event = events_proto_.add_event()->mutable_get_addr_symbol_event();
auto event_name = event->mutable_name();
auto event_symbol = event->mutable_symbol();
event->set_addr(addr);
event->set_pid(pid);
*event_name = name;
*event_symbol = symbol;
}

void BPFRecorder::WriteProto(const std::string& proto_buf_file_path) {
if (!recording_written_) {
LOG(INFO) << "Writing BPF events pb to file: " << proto_buf_file_path;
Expand Down Expand Up @@ -116,7 +140,7 @@ void RecordPerfBufferLoss(void* cb_cookie, uint64_t lost) {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Replay.
void BPFReplayer::ReplayPerfBufferEvents(const PerfBufferSpec& perf_buffer_spec) {
if (PlabackComplete()) {
if (PlaybackComplete()) {
LOG_FIRST_N(INFO, 1) << "BPFReplayer::ReplayPerfBufferEvents(), plaback complete.";
return;
}
Expand Down Expand Up @@ -147,7 +171,7 @@ void BPFReplayer::ReplayPerfBufferEvents(const PerfBufferSpec& perf_buffer_spec)

Status BPFReplayer::ReplayArrayGetValue(const std::string& name, const int32_t idx,
const uint32_t data_size, void* value) {
if (PlabackComplete()) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

Expand Down Expand Up @@ -179,7 +203,7 @@ Status BPFReplayer::ReplayArrayGetValue(const std::string& name, const int32_t i

Status BPFReplayer::ReplayMapGetValue(const std::string& name, const uint32_t key_size,
void const* const key, const uint32_t val_size, void* value) {
if (PlabackComplete()) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

Expand Down Expand Up @@ -214,7 +238,7 @@ Status BPFReplayer::ReplayMapGetValue(const std::string& name, const uint32_t ke

Status BPFReplayer::ReplayMapGetKeyAndValue(const std::string& name, const uint32_t key_size,
void* key, const uint32_t val_size, void* val) {
if (PlabackComplete()) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

Expand Down Expand Up @@ -245,7 +269,7 @@ Status BPFReplayer::ReplayMapGetKeyAndValue(const std::string& name, const uint3
}

StatusOr<int32_t> BPFReplayer::ReplayBPFMapCapacityEvent(const std::string& name) {
if (PlabackComplete()) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

Expand All @@ -266,7 +290,7 @@ StatusOr<int32_t> BPFReplayer::ReplayBPFMapCapacityEvent(const std::string& name
}

StatusOr<int32_t> BPFReplayer::ReplayBPFMapGetTableOfflineEvent(const std::string& name) {
if (PlabackComplete()) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

Expand All @@ -286,6 +310,69 @@ StatusOr<int32_t> BPFReplayer::ReplayBPFMapGetTableOfflineEvent(const std::strin
return event.size();
}

StatusOr<std::vector<uintptr_t>> BPFReplayer::ReplayBPFStackTableGetStackAddrEvent(
const std::string& name, const int32_t stack_id) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

const auto event_wrapper = events_proto_.event(playback_event_idx_);
if (!event_wrapper.has_get_stack_addr_event()) {
return error::Internal("Map event not available.");
}

const auto event = event_wrapper.get_stack_addr_event();

if (name != event.name()) {
const char* const msg = "Mismatched eBPF stack table name. Expected: $0, requested: $1.";
return error::Internal(absl::Substitute(msg, event.name(), name));
}
if (stack_id != event.stack_id()) {
const char* const msg = "Mismatched stack id. Expected: $0, requested: $1.";
return error::Internal(absl::Substitute(msg, event.stack_id(), stack_id));
}
++playback_event_idx_;

std::vector<uintptr_t> addrs;

for (int i = 0; i < event.addr_size(); ++i) {
const uint64_t addr = event.addr(i);
addrs.push_back(addr);
}
return addrs;
}

StatusOr<std::string> BPFReplayer::ReplayBPFStackTableGetAddrSymbolEvent(const std::string& name,
const uint64_t addr,
const uint32_t pid) {
if (PlaybackComplete()) {
return error::Internal("Playback complete.");
}

const auto event_wrapper = events_proto_.event(playback_event_idx_);
if (!event_wrapper.has_get_addr_symbol_event()) {
return error::Internal("Stack table get addr symbol event not available.");
}

const auto event = event_wrapper.get_addr_symbol_event();

if (name != event.name()) {
const char* const msg = "Mismatched stack table name. Expected: $0, requested: $1.";
return error::Internal(absl::Substitute(msg, event.name(), name));
}
if (addr != event.addr()) {
const char* const msg = "Mismatched addr. Expected: $0, requested: $1.";
return error::Internal(absl::Substitute(msg, event.addr(), addr));
}
if (pid != event.pid()) {
const char* const msg = "Mismatched pid. Expected: $0, requested: $1.";
return error::Internal(absl::Substitute(msg, event.pid(), pid));
}
++playback_event_idx_;

return event.symbol();
}

Status BPFReplayer::OpenReplayProtobuf(const std::string& replay_events_pb_file_path) {
LOG(INFO) << absl::Substitute("replay_events_pb_file_path: $0.", replay_events_pb_file_path);
std::fstream input(replay_events_pb_file_path, std::ios::in | std::ios::binary);
Expand Down
11 changes: 10 additions & 1 deletion src/stirling/bpf_tools/rr/rr.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class BPFRecorder : public NotCopyMoveable {
void const* const value);
void RecordBPFMapGetTableOfflineEvent(const std::string& name, const uint32_t size);
void RecordBPFMapCapacityEvent(const std::string& name, const int32_t n);
void RecordBPFStackTableGetStackAddrEvent(const std::string& name, const int32_t stack_id,
const std::vector<uintptr_t>& addrs);
void RecordBPFStackTableGetAddrSymbolEvent(const std::string& name, const uint64_t addr,
const uint32_t pid, const std::string symbol);
void RecordPerfBufferEvent(PerfBufferSpec* pb_spec, void const* const data, const int data_size);
void WriteProto(const std::string& proto_buf_file_path);

Expand All @@ -57,8 +61,13 @@ class BPFReplayer : public NotCopyMoveable {
const uint32_t val_size, void* value);
StatusOr<int32_t> ReplayBPFMapCapacityEvent(const std::string& name);
StatusOr<int32_t> ReplayBPFMapGetTableOfflineEvent(const std::string& name);
StatusOr<std::vector<uintptr_t>> ReplayBPFStackTableGetStackAddrEvent(const std::string& name,
const int32_t stack_id);
StatusOr<std::string> ReplayBPFStackTableGetAddrSymbolEvent(const std::string& name,
const uint64_t addr,
const uint32_t pid);
Status OpenReplayProtobuf(const std::string& replay_events_pb_file_path);
bool PlabackComplete() const { return playback_event_idx_ >= events_proto_.event_size(); }
bool PlaybackComplete() const { return playback_event_idx_ >= events_proto_.event_size(); }

::px::stirling::rr::BPFEvents& events_proto() { return events_proto_; }

Expand Down
Loading

0 comments on commit 892cfc6

Please sign in to comment.