Fix breakage in open_perf_buffer
authorBrenden Blanco <bblanco@plumgrid.com>
Wed, 17 Feb 2016 08:26:14 +0000 (00:26 -0800)
committerBrenden Blanco <bblanco@plumgrid.com>
Wed, 17 Feb 2016 08:28:58 +0000 (00:28 -0800)
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: Brenden Blanco <bblanco@plumgrid.com>
src/cc/libbpf.c
src/python/bcc/__init__.py
src/python/bcc/table.py
tests/cc/test_array.py

index 4a5c083..62bfea1 100644 (file)
@@ -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) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
   int pfd;
   struct perf_event_attr attr = {};
   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,
   if (!reader)
     goto error;
 
-  attr.config = PERF_COUNT_SW_BPF_OUTPUT;
+  attr.config = 10;//PERF_COUNT_SW_BPF_OUTPUT;
   attr.type = PERF_TYPE_SOFTWARE;
   attr.sample_type = PERF_SAMPLE_RAW;
   attr.sample_period = 1;
   attr.wakeup_events = 1;
   pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, -1, PERF_FLAG_FD_CLOEXEC);
   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;
   }
   perf_reader_set_fd(reader, pfd);
@@ -385,8 +385,4 @@ error:
     perf_reader_free(reader);
 
   return NULL;
-#else
-  fprintf(stderr, "PERF_COUNT_SW_BPF_OUTPUT feature unsupported\n");
-  return NULL;
-#endif
 }
index c7b67f9..6d9e33d 100644 (file)
@@ -311,6 +311,11 @@ class BPF(object):
         return self
 
     @staticmethod
+    def open_kprobes():
+        global open_kprobes
+        return open_kprobes
+
+    @staticmethod
     def detach_kprobe(event):
         ev_name = "p_" + event.replace("+", "_").replace(".", "_")
         if ev_name not in open_kprobes:
index 9b9e60c..a364e32 100644 (file)
@@ -14,6 +14,7 @@
 
 from collections import MutableMapping
 import ctypes as ct
+import multiprocessing
 
 from .libbcc import lib, _RAW_CB_TYPE
 
@@ -378,13 +379,13 @@ class PerfEventArray(ArrayBase):
             raise Exception("Could not open perf buffer")
         fd = lib.perf_reader_fd(reader)
         self[self.Key(cpu)] = self.Leaf(fd)
-        open_kprobes[(id(self), cpu)] = reader
+        self.bpf.open_kprobes()[(id(self), cpu)] = reader
         # keep a refcnt
         self._cbs[cpu] = fn
 
     def close_perf_buffer(self, key):
-        reader = open_kprobes.get((id(self), key))
+        reader = self.bpf.open_kprobes().get((id(self), key))
         if reader:
             lib.perf_reader_free(reader)
-            del(open_kprobes[(id(self), key)])
+            del(self.bpf.open_kprobes()[(id(self), key)])
         del self._cbs[key]
index 9dcb731..3fe1dce 100755 (executable)
@@ -3,7 +3,7 @@
 # Licensed under the Apache License, Version 2.0 (the "License")
 
 from bcc import BPF
-from ctypes import c_int, c_ulonglong
+import ctypes as ct
 import random
 import time
 from unittest import main, TestCase
@@ -12,8 +12,8 @@ class TestArray(TestCase):
     def test_simple(self):
         b = BPF(text="""BPF_TABLE("array", int, u64, table1, 128);""")
         t1 = b["table1"]
-        t1[c_int(0)] = c_ulonglong(100)
-        t1[c_int(127)] = c_ulonglong(1000)
+        t1[ct.c_int(0)] = ct.c_ulonglong(100)
+        t1[ct.c_int(127)] = ct.c_ulonglong(1000)
         for i, v in t1.items():
             if i.value == 0:
                 self.assertEqual(v.value, 100)
@@ -24,9 +24,9 @@ class TestArray(TestCase):
     def test_native_type(self):
         b = BPF(text="""BPF_TABLE("array", int, u64, table1, 128);""")
         t1 = b["table1"]
-        t1[0] = c_ulonglong(100)
-        t1[-2] = c_ulonglong(37)
-        t1[127] = c_ulonglong(1000)
+        t1[0] = ct.c_ulonglong(100)
+        t1[-2] = ct.c_ulonglong(37)
+        t1[127] = ct.c_ulonglong(1000)
         for i, v in t1.items():
             if i.value == 0:
                 self.assertEqual(v.value, 100)
@@ -36,5 +36,32 @@ class TestArray(TestCase):
         self.assertEqual(t1[-2].value, 37)
         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__":
     main()