fix iteration over CPUs
Since kernel version 4.9.0 BPF stopped working in a KVM guest.
The problem are calls to perf_event_open with CPU identifiers which do
not exist (ENODEV). The root cause for this is that the current code
assumes ascending numbered CPUs. However, this is not always the case
(e.g. CPU hotplugging).
This patch introduces the get_online_cpus() and get_possible_cpus()
helper functions and uses the appropriate function for iterations over
CPUs. The BPF_MAP_TYPE_PERF_EVENT_ARRAY map contains now an entry for
each possible CPU instead of for each online CPU.
Fixes: #893
Signed-off-by: Andreas Gerstmayr <andreas.gerstmayr@catalysts.cc>
diff --git a/tests/python/test_array.py b/tests/python/test_array.py
index 3fe1dce..a7c82a4 100755
--- a/tests/python/test_array.py
+++ b/tests/python/test_array.py
@@ -6,6 +6,8 @@
import ctypes as ct
import random
import time
+import subprocess
+from bcc.utils import get_online_cpus
from unittest import main, TestCase
class TestArray(TestCase):
@@ -62,6 +64,37 @@
time.sleep(0.1)
b.kprobe_poll()
self.assertGreater(self.counter, 0)
+ b.cleanup()
+
+ def test_perf_buffer_for_each_cpu(self):
+ self.events = []
+
+ class Data(ct.Structure):
+ _fields_ = [("cpu", ct.c_ulonglong)]
+
+ def cb(cpu, data, size):
+ self.assertGreater(size, ct.sizeof(Data))
+ event = ct.cast(data, ct.POINTER(Data)).contents
+ self.events.append(event)
+
+ text = """
+BPF_PERF_OUTPUT(events);
+int kprobe__sys_nanosleep(void *ctx) {
+ struct {
+ u64 cpu;
+ } data = {bpf_get_smp_processor_id()};
+ events.perf_submit(ctx, &data, sizeof(data));
+ return 0;
+}
+"""
+ b = BPF(text=text)
+ b["events"].open_perf_buffer(cb)
+ online_cpus = get_online_cpus()
+ for cpu in online_cpus:
+ subprocess.call(['taskset', '-c', str(cpu), 'sleep', '0.1'])
+ b.kprobe_poll()
+ b.cleanup()
+ self.assertGreaterEqual(len(self.events), len(online_cpus), 'Received only {}/{} events'.format(len(self.events), len(online_cpus)))
if __name__ == "__main__":
main()