struct event_t {
int pid;
char comm[16];
+ int cpu;
int got_bits;
};
struct event_t event = {};
event.pid = bpf_get_current_pid_tgid();
bpf_get_current_comm(&event.comm, sizeof(event.comm));
+ event.cpu = bpf_get_smp_processor_id();
event.got_bits = attr->got_bits;
events.perf_submit(attr, &event, sizeof(event));
struct event_t {
int pid;
char comm[16];
+ int cpu;
int got_bits;
};
void handle_output(void* cb_cookie, void* data, int data_size) {
auto event = static_cast<event_t*>(data);
- std::cout << "PID: " << event->pid << " (" << event->comm << ") "
- << "Read " << event->got_bits << " bits" << std::endl;
+ std::cout << "PID: " << event->pid << " (" << event->comm << ") on CPU "
+ << event->cpu << " read " << event->got_bits << " bits"
+ << std::endl;
}
ebpf::BPF* bpf;
}
for (auto it : perf_buffers_) {
- auto res = it.second->close();
+ auto res = it.second->close_all_cpu();
if (res.code() != 0) {
error_msg += "Failed to close perf buffer " + it.first + ": ";
error_msg += res.msg() + "\n";
if (perf_buffers_.find(name) == perf_buffers_.end())
perf_buffers_[name] = new BPFPerfBuffer(bpf_module_.get(), name);
auto table = perf_buffers_[name];
- TRY2(table->open(cb, cb_cookie));
+ TRY2(table->open_all_cpu(cb, cb_cookie));
return StatusTuple(0);
}
auto it = perf_buffers_.find(name);
if (it == perf_buffers_.end())
return StatusTuple(-1, "Perf buffer for %s not open", name.c_str());
- TRY2(it->second->close());
+ TRY2(it->second->close_all_cpu());
return StatusTuple(0);
}
return StatusTuple(-1, "Unable to open perf buffer on CPU %d: %s", cpu,
strerror(errno));
}
- cpu_readers_[cpu] = static_cast<perf_reader*>(reader);
+ cpu_readers_[cpu] = reader;
+ readers_.push_back(reader);
return StatusTuple(0);
}
-StatusTuple BPFPerfBuffer::open(perf_reader_raw_cb cb, void* cb_cookie) {
- for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); i++)
- TRY2(open_on_cpu(cb, i, cb_cookie));
+StatusTuple BPFPerfBuffer::open_all_cpu(perf_reader_raw_cb cb,
+ void* cb_cookie) {
+ if (cpu_readers_.size() != 0 || readers_.size() != 0)
+ return StatusTuple(-1, "Previously opened perf buffer not cleaned");
+
+ for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); i++) {
+ auto res = open_on_cpu(cb, i, cb_cookie);
+ if (res.code() != 0) {
+ TRY2(close_all_cpu());
+ return res;
+ }
+ }
return StatusTuple(0);
}
return StatusTuple(0);
}
-StatusTuple BPFPerfBuffer::close() {
+StatusTuple BPFPerfBuffer::close_all_cpu() {
std::string errors;
bool has_error = false;
for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); i++) {
has_error = true;
}
}
+ readers_.clear();
if (has_error)
return StatusTuple(-1, errors);
return StatusTuple(0);
}
void BPFPerfBuffer::poll(int timeout) {
- perf_reader* readers[cpu_readers_.size()];
- int i = 0;
- for (auto it : cpu_readers_)
- readers[i++] = it.second;
- perf_reader_poll(cpu_readers_.size(), readers, timeout);
+ if (readers_.empty())
+ return;
+ perf_reader_poll(readers_.size(), readers_.data(), timeout);
}
BPFPerfBuffer::~BPFPerfBuffer() {
- auto res = close();
+ auto res = close_all_cpu();
if (res.code() != 0)
std::cerr << "Failed to close all perf buffer on destruction: "
<< res.msg() << std::endl;
: BPFTableBase<int, int>(bpf_module, name) {}
~BPFPerfBuffer();
- StatusTuple open(perf_reader_raw_cb cb, void* cb_cookie);
- StatusTuple close();
+ StatusTuple open_all_cpu(perf_reader_raw_cb cb, void* cb_cookie);
+ StatusTuple close_all_cpu();
void poll(int timeout);
private:
StatusTuple close_on_cpu(int cpu);
std::map<int, perf_reader*> cpu_readers_;
+ std::vector<perf_reader*> readers_;
};
} // namespace ebpf