Skip to content

Commit

Permalink
Support ringbuf_query method for Ring buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
andreyviktorov2 authored and yonghong-song committed Apr 29, 2023
1 parent 59a2a43 commit 4e09e97
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
17 changes: 17 additions & 0 deletions docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,23 @@ ignores the data associated with the discarded event. Must be preceded by a call
Examples in situ: <!-- TODO -->
[search /examples](https://github.com/iovisor/bcc/search?q=ringbuf_submit+path%3Aexamples&type=Code),

### 10. ringbuf_query()

Syntax: ```u64 ringbuf_query(u64 flags)```

Return: Requested value, or 0, if flags are not recognized

Flags:
- ```BPF_RB_AVAIL_DATA```: Amount of data not yet consumed
- ```BPF_RB_RING_SIZE```: The size of ring buffer
- ```BPF_RB_CONS_POS```: Consumer position
- ```BPF_RB_PROD_POS```: Producer(s) position

A method of the BPF_RINGBUF_OUTPUT table, for getting various properties of ring buffer. Returned values are momentarily snapshots of ring buffer state and could be off by the time helper returns, so this should be used only for debugging/reporting reasons or for implementing various heuristics, that take into account highly-changeable nature of some of those characteristics.

Examples in situ: <!-- TODO -->
[search /examples](https://github.com/iovisor/bcc/search?q=ringbuf_query+path%3Aexamples&type=Code),

## Maps

Maps are BPF data stores, and are the basis for higher level object types including tables, hashes, and histograms.
Expand Down
2 changes: 2 additions & 0 deletions src/cc/export/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ struct _name##_table_t { \
void (*ringbuf_discard) (void *, u64); \
/* map.ringbuf_submit(data, flags) */ \
void (*ringbuf_submit) (void *, u64); \
/* map.ringbuf_query(flags) */ \
u64 (*ringbuf_query) (u64); \
u32 max_entries; \
}; \
__attribute__((section("maps/ringbuf"))) \
Expand Down
5 changes: 5 additions & 0 deletions src/cc/frontends/clang/b_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,11 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
string args = rewriter_.getRewrittenText(expansionRange(SourceRange(GET_BEGINLOC(Call->getArg(0)),
GET_ENDLOC(Call->getArg(1)))));
txt = "bpf_ringbuf_discard(" + args + ")";
} else if (memb_name == "ringbuf_query") {
string name = string(Ref->getDecl()->getName());
string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
txt = "bpf_ringbuf_query((void *)bpf_pseudo_fd(1, " + fd + ")";
txt += ", " + arg0 + ")";
} else if (memb_name == "ringbuf_submit") {
string name = string(Ref->getDecl()->getName());
string args = rewriter_.getRewrittenText(expansionRange(SourceRange(GET_BEGINLOC(Call->getArg(0)),
Expand Down
43 changes: 43 additions & 0 deletions tests/python/test_ringbuf.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,48 @@ def cb(ctx, data, size):
self.assertEqual(self.counter, 0)
b.cleanup()

@skipUnless(kernel_version_ge(5,8), "requires kernel >= 5.8")
def test_ringbuf_query(self):
PAGE_SIZE = 8
self.counter = 0
self.page_counts = 0

class Data(ct.Structure):
_fields_ = [("page_cnt", ct.c_ulonglong)]

def cb(ctx, data, size):
self.assertEqual(size, ct.sizeof(Data))
event = ct.cast(data, ct.POINTER(Data)).contents
self.page_counts += event.page_cnt
self.counter += 1

text = b"""
BPF_RINGBUF_OUTPUT(events, %i);
struct data_t {
u64 page_cnt;
};
int do_sys_nanosleep(void *ctx) {
u64 res = 0;
res = events.ringbuf_query(BPF_RB_RING_SIZE);
if(res == 0) {
return 1;
}
struct data_t data = {res / PAGE_SIZE};
events.ringbuf_output(&data, sizeof(data), 0);
return 0;
}
"""
text = text % PAGE_SIZE
b = BPF(text=text)
b.attach_kprobe(event=b.get_syscall_fnname(b"nanosleep"),
fn_name=b"do_sys_nanosleep")
b.attach_kprobe(event=b.get_syscall_fnname(b"clock_nanosleep"),
fn_name=b"do_sys_nanosleep")
b[b"events"].open_ring_buffer(cb)
subprocess.call(['sleep', '0.1'])
b.ring_buffer_poll()
self.assertEqual(self.page_counts / self.counter, PAGE_SIZE)
b.cleanup()

if __name__ == "__main__":
main()

0 comments on commit 4e09e97

Please sign in to comment.