Commit 0dd24416 authored by Brenden Blanco's avatar Brenden Blanco

Fix breakage in open_perf_buffer

The previous commit for splitting table.py into a separate file lost
some required imports. Add those back.

In addition, add a test for open_perf_buffer, and take out the
compile-time check in libbpf.c for this feature.

I couldn't think of a good way to fix the PERF_COUNT_SW_BPF_OUTPUT
literal, so for now left it as a comment. A #define wouldn't work since
the eventual value comes from an enum (no #ifndef/#define/#endif
pattern).

Fixes: #391 #363
Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent fe036068
...@@ -349,7 +349,6 @@ int bpf_detach_uprobe(const char *event_desc) { ...@@ -349,7 +349,6 @@ int bpf_detach_uprobe(const char *event_desc) {
} }
void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void *cb_cookie, int pid, int cpu) { void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void *cb_cookie, int pid, int cpu) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
int pfd; int pfd;
struct perf_event_attr attr = {}; struct perf_event_attr attr = {};
struct perf_reader *reader = NULL; struct perf_reader *reader = NULL;
...@@ -358,14 +357,15 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void *cb_cookie, int pid, ...@@ -358,14 +357,15 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void *cb_cookie, int pid,
if (!reader) if (!reader)
goto error; goto error;
attr.config = PERF_COUNT_SW_BPF_OUTPUT; attr.config = 10;//PERF_COUNT_SW_BPF_OUTPUT;
attr.type = PERF_TYPE_SOFTWARE; attr.type = PERF_TYPE_SOFTWARE;
attr.sample_type = PERF_SAMPLE_RAW; attr.sample_type = PERF_SAMPLE_RAW;
attr.sample_period = 1; attr.sample_period = 1;
attr.wakeup_events = 1; attr.wakeup_events = 1;
pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, -1, PERF_FLAG_FD_CLOEXEC); pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, -1, PERF_FLAG_FD_CLOEXEC);
if (pfd < 0) { if (pfd < 0) {
perror("perf_event_open"); fprintf(stderr, "perf_event_open: %s\n", strerror(errno));
fprintf(stderr, " (check your kernel for PERF_COUNT_SW_BPF_OUTPUT support, 4.4 or newer)\n");
goto error; goto error;
} }
perf_reader_set_fd(reader, pfd); perf_reader_set_fd(reader, pfd);
...@@ -385,8 +385,4 @@ error: ...@@ -385,8 +385,4 @@ error:
perf_reader_free(reader); perf_reader_free(reader);
return NULL; return NULL;
#else
fprintf(stderr, "PERF_COUNT_SW_BPF_OUTPUT feature unsupported\n");
return NULL;
#endif
} }
...@@ -310,6 +310,11 @@ class BPF(object): ...@@ -310,6 +310,11 @@ class BPF(object):
open_kprobes[ev_name] = res open_kprobes[ev_name] = res
return self return self
@staticmethod
def open_kprobes():
global open_kprobes
return open_kprobes
@staticmethod @staticmethod
def detach_kprobe(event): def detach_kprobe(event):
ev_name = "p_" + event.replace("+", "_").replace(".", "_") ev_name = "p_" + event.replace("+", "_").replace(".", "_")
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
from collections import MutableMapping from collections import MutableMapping
import ctypes as ct import ctypes as ct
import multiprocessing
from .libbcc import lib, _RAW_CB_TYPE from .libbcc import lib, _RAW_CB_TYPE
...@@ -378,13 +379,13 @@ class PerfEventArray(ArrayBase): ...@@ -378,13 +379,13 @@ class PerfEventArray(ArrayBase):
raise Exception("Could not open perf buffer") raise Exception("Could not open perf buffer")
fd = lib.perf_reader_fd(reader) fd = lib.perf_reader_fd(reader)
self[self.Key(cpu)] = self.Leaf(fd) self[self.Key(cpu)] = self.Leaf(fd)
open_kprobes[(id(self), cpu)] = reader self.bpf.open_kprobes()[(id(self), cpu)] = reader
# keep a refcnt # keep a refcnt
self._cbs[cpu] = fn self._cbs[cpu] = fn
def close_perf_buffer(self, key): def close_perf_buffer(self, key):
reader = open_kprobes.get((id(self), key)) reader = self.bpf.open_kprobes().get((id(self), key))
if reader: if reader:
lib.perf_reader_free(reader) lib.perf_reader_free(reader)
del(open_kprobes[(id(self), key)]) del(self.bpf.open_kprobes()[(id(self), key)])
del self._cbs[key] del self._cbs[key]
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
from bcc import BPF from bcc import BPF
from ctypes import c_int, c_ulonglong import ctypes as ct
import random import random
import time import time
from unittest import main, TestCase from unittest import main, TestCase
...@@ -12,8 +12,8 @@ class TestArray(TestCase): ...@@ -12,8 +12,8 @@ class TestArray(TestCase):
def test_simple(self): def test_simple(self):
b = BPF(text="""BPF_TABLE("array", int, u64, table1, 128);""") b = BPF(text="""BPF_TABLE("array", int, u64, table1, 128);""")
t1 = b["table1"] t1 = b["table1"]
t1[c_int(0)] = c_ulonglong(100) t1[ct.c_int(0)] = ct.c_ulonglong(100)
t1[c_int(127)] = c_ulonglong(1000) t1[ct.c_int(127)] = ct.c_ulonglong(1000)
for i, v in t1.items(): for i, v in t1.items():
if i.value == 0: if i.value == 0:
self.assertEqual(v.value, 100) self.assertEqual(v.value, 100)
...@@ -24,9 +24,9 @@ class TestArray(TestCase): ...@@ -24,9 +24,9 @@ class TestArray(TestCase):
def test_native_type(self): def test_native_type(self):
b = BPF(text="""BPF_TABLE("array", int, u64, table1, 128);""") b = BPF(text="""BPF_TABLE("array", int, u64, table1, 128);""")
t1 = b["table1"] t1 = b["table1"]
t1[0] = c_ulonglong(100) t1[0] = ct.c_ulonglong(100)
t1[-2] = c_ulonglong(37) t1[-2] = ct.c_ulonglong(37)
t1[127] = c_ulonglong(1000) t1[127] = ct.c_ulonglong(1000)
for i, v in t1.items(): for i, v in t1.items():
if i.value == 0: if i.value == 0:
self.assertEqual(v.value, 100) self.assertEqual(v.value, 100)
...@@ -36,5 +36,32 @@ class TestArray(TestCase): ...@@ -36,5 +36,32 @@ class TestArray(TestCase):
self.assertEqual(t1[-2].value, 37) self.assertEqual(t1[-2].value, 37)
self.assertEqual(t1[-1].value, t1[127].value) self.assertEqual(t1[-1].value, t1[127].value)
def test_perf_buffer(self):
self.counter = 0
class Data(ct.Structure):
_fields_ = [("ts", ct.c_ulonglong)]
def cb(cpu, data, size):
self.assertGreater(size, ct.sizeof(Data))
event = ct.cast(data, ct.POINTER(Data)).contents
self.counter += 1
text = """
BPF_PERF_OUTPUT(events);
int kprobe__sys_nanosleep(void *ctx) {
struct {
u64 ts;
} data = {bpf_ktime_get_ns()};
events.perf_submit(ctx, &data, sizeof(data));
return 0;
}
"""
b = BPF(text=text)
b["events"].open_perf_buffer(cb)
time.sleep(0.1)
b.kprobe_poll()
self.assertGreater(self.counter, 0)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment