from .libbcc import lib, _CB_TYPE
from .table import Table
+from .tracepoint import Perf, Tracepoint
open_kprobes = {}
open_uprobes = {}
--- /dev/null
+# Copyright 2016 Sasha Goldshtein
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import ctypes as ct
+import multiprocessing
+import os
+import re
+
+class Perf(object):
+ class perf_event_attr(ct.Structure):
+ _fields_ = [
+ ('type', ct.c_uint),
+ ('size', ct.c_uint),
+ ('config', ct.c_ulong),
+ ('sample_period', ct.c_ulong),
+ ('sample_type', ct.c_ulong),
+ ('IGNORE1', ct.c_ulong),
+ ('IGNORE2', ct.c_ulong),
+ ('wakeup_events', ct.c_uint),
+ ('IGNORE3', ct.c_uint),
+ ('IGNORE4', ct.c_ulong),
+ ('IGNORE5', ct.c_ulong),
+ ('IGNORE6', ct.c_ulong),
+ ('IGNORE7', ct.c_uint),
+ ('IGNORE8', ct.c_int),
+ ('IGNORE9', ct.c_ulong),
+ ('IGNORE10', ct.c_uint),
+ ('IGNORE11', ct.c_uint)
+ ]
+
+ NR_PERF_EVENT_OPEN = 298
+ PERF_TYPE_TRACEPOINT = 2
+ PERF_SAMPLE_RAW = 1024
+ PERF_FLAG_FD_CLOEXEC = 8
+ PERF_EVENT_IOC_SET_FILTER = 1074275334
+ PERF_EVENT_IOC_ENABLE = 9216
+
+ libc = ct.CDLL('libc.so.6', use_errno=True)
+ syscall = libc.syscall # not declaring vararg types
+ ioctl = libc.ioctl # not declaring vararg types
+
+ @staticmethod
+ def _open_for_cpu(cpu, attr):
+ pfd = Perf.syscall(Perf.NR_PERF_EVENT_OPEN, ct.byref(attr),
+ -1, cpu, -1, Perf.PERF_FLAG_FD_CLOEXEC)
+ if pfd < 0:
+ errno_ = ct.get_errno()
+ raise OSError(errno_, os.strerror(errno_))
+ if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_SET_FILTER,
+ "common_pid == -17") < 0:
+ errno_ = ct.get_errno()
+ raise OSError(errno_, os.strerror(errno_))
+ if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_ENABLE, 0) < 0:
+ errno_ = ct.get_errno()
+ raise OSError(errno_, os.strerror(errno_))
+
+ @staticmethod
+ def perf_event_open(tpoint_id):
+ attr = Perf.perf_event_attr()
+ attr.config = tpoint_id
+ attr.type = Perf.PERF_TYPE_TRACEPOINT
+ attr.sample_type = Perf.PERF_SAMPLE_RAW
+ attr.sample_period = 1
+ attr.wakeup_events = 1
+ for cpu in range(0, multiprocessing.cpu_count()):
+ Perf._open_for_cpu(cpu, attr)
+
+class Tracepoint(object):
+ enabled_tracepoints = []
+ trace_root = "/sys/kernel/debug/tracing"
+ event_root = os.path.join(trace_root, "events")
+
+ @classmethod
+ def _any_tracepoints_enabled(cls):
+ return len(cls.enabled_tracepoints) > 0
+
+ @classmethod
+ def generate_decl(cls):
+ if not cls._any_tracepoints_enabled():
+ return ""
+ return "\nBPF_HASH(__trace_di, u64, u64);\n"
+
+ @classmethod
+ def generate_entry_probe(cls):
+ if not cls._any_tracepoints_enabled():
+ return ""
+ return """
+int __trace_entry_update(struct pt_regs *ctx)
+{
+ u64 tid = bpf_get_current_pid_tgid();
+ u64 val = ctx->di;
+ __trace_di.update(&tid, &val);
+ return 0;
+}
+"""
+
+ def __init__(self, category, event, tp_id):
+ self.category = category
+ self.event = event
+ self.tp_id = tp_id
+
+ def _generate_struct_fields(self):
+ format_lines = Tracepoint.get_tpoint_format(self.category,
+ self.event)
+ text = ""
+ for line in format_lines:
+ match = re.search(r'field:([^;]*);.*size:(\d+);', line)
+ if match is None:
+ continue
+ parts = match.group(1).split()
+ field_name = parts[-1:][0]
+ field_type = " ".join(parts[:-1])
+ field_size = int(match.group(2))
+ if "__data_loc" in field_type:
+ continue
+ if field_name.startswith("common_"):
+ continue
+ text += " %s %s;\n" % (field_type, field_name)
+ return text
+
+ def generate_struct(self):
+ self.struct_name = self.event + "_trace_entry"
+ return """
+struct %s {
+ u64 __do_not_use__;
+ %s
+};
+ """ % (self.struct_name, self._generate_struct_fields())
+
+ def generate_get_struct(self):
+ return """
+ u64 tid = bpf_get_current_pid_tgid();
+ u64 *di = __trace_di.lookup(&tid);
+ if (di == 0) { return 0; }
+ struct %s tp = {};
+ bpf_probe_read(&tp, sizeof(tp), (void *)*di);
+ """ % self.struct_name
+
+ @classmethod
+ def enable_tracepoint(cls, category, event):
+ tp_id = cls.get_tpoint_id(category, event)
+ if tp_id == -1:
+ raise ValueError("no such tracepoint found: %s:%s" %
+ (category, event))
+ Perf.perf_event_open(tp_id)
+ new_tp = Tracepoint(category, event, tp_id)
+ cls.enabled_tracepoints.append(new_tp)
+ return new_tp
+
+ @staticmethod
+ def get_tpoint_id(category, event):
+ evt_dir = os.path.join(Tracepoint.event_root, category, event)
+ try:
+ return int(
+ open(os.path.join(evt_dir, "id")).read().strip())
+ except:
+ return -1
+
+ @staticmethod
+ def get_tpoint_format(category, event):
+ evt_dir = os.path.join(Tracepoint.event_root, category, event)
+ try:
+ return open(os.path.join(evt_dir, "format")).readlines()
+ except:
+ return ""
+
+ @classmethod
+ def attach(cls, bpf):
+ if cls._any_tracepoints_enabled():
+ bpf.attach_kprobe(event="tracing_generic_entry_update",
+ fn_name="__trace_entry_update")
+
# Licensed under the Apache License, Version 2.0 (the "License")
# Copyright (C) 2016 Sasha Goldshtein.
-from bcc import BPF
+from bcc import BPF, Tracepoint, Perf
from time import sleep, strftime
import argparse
-import ctypes as ct
import re
import traceback
import os
-import multiprocessing
import sys
-class Perf(object):
- class perf_event_attr(ct.Structure):
- _fields_ = [
- ('type', ct.c_uint),
- ('size', ct.c_uint),
- ('config', ct.c_ulong),
- ('sample_period', ct.c_ulong),
- ('sample_type', ct.c_ulong),
- ('IGNORE1', ct.c_ulong),
- ('IGNORE2', ct.c_ulong),
- ('wakeup_events', ct.c_uint),
- ('IGNORE3', ct.c_uint),
- ('IGNORE4', ct.c_ulong),
- ('IGNORE5', ct.c_ulong),
- ('IGNORE6', ct.c_ulong),
- ('IGNORE7', ct.c_uint),
- ('IGNORE8', ct.c_int),
- ('IGNORE9', ct.c_ulong),
- ('IGNORE10', ct.c_uint),
- ('IGNORE11', ct.c_uint)
- ]
-
- NR_PERF_EVENT_OPEN = 298
- PERF_TYPE_TRACEPOINT = 2
- PERF_SAMPLE_RAW = 1024
- PERF_FLAG_FD_CLOEXEC = 8
- PERF_EVENT_IOC_SET_FILTER = 1074275334
- PERF_EVENT_IOC_ENABLE = 9216
-
- libc = ct.CDLL('libc.so.6', use_errno=True)
- syscall = libc.syscall # not declaring vararg types
- ioctl = libc.ioctl # not declaring vararg types
-
- @staticmethod
- def _open_for_cpu(cpu, attr):
- pfd = Perf.syscall(Perf.NR_PERF_EVENT_OPEN, ct.byref(attr),
- -1, cpu, -1, Perf.PERF_FLAG_FD_CLOEXEC)
- if pfd < 0:
- errno_ = ct.get_errno()
- raise OSError(errno_, os.strerror(errno_))
- if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_SET_FILTER,
- "common_pid == -17") < 0:
- errno_ = ct.get_errno()
- raise OSError(errno_, os.strerror(errno_))
- if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_ENABLE, 0) < 0:
- errno_ = ct.get_errno()
- raise OSError(errno_, os.strerror(errno_))
-
- @staticmethod
- def perf_event_open(tpoint_id):
- attr = Perf.perf_event_attr()
- attr.config = tpoint_id
- attr.type = Perf.PERF_TYPE_TRACEPOINT
- attr.sample_type = Perf.PERF_SAMPLE_RAW
- attr.sample_period = 1
- attr.wakeup_events = 1
- for cpu in range(0, multiprocessing.cpu_count()):
- Perf._open_for_cpu(cpu, attr)
-
-class Tracepoint(object):
- tracepoints_enabled = 0
- trace_root = "/sys/kernel/debug/tracing"
- event_root = os.path.join(trace_root, "events")
-
- @staticmethod
- def generate_decl():
- if Tracepoint.tracepoints_enabled == 0:
- return ""
- return "\nBPF_HASH(__trace_di, u64, u64);\n"
-
- @staticmethod
- def generate_entry_probe():
- if Tracepoint.tracepoints_enabled == 0:
- return ""
- return """
-int __trace_entry_update(struct pt_regs *ctx)
-{
- u64 tid = bpf_get_current_pid_tgid();
- u64 val = ctx->di;
- __trace_di.update(&tid, &val);
- return 0;
-}
-"""
-
- @staticmethod
- def enable_tracepoint(category, event):
- tp_id = Tracepoint.get_tpoint_id(category, event)
- if tp_id == -1:
- raise ValueError("no such tracepoint found: %s:%s" %
- (category, event))
- Perf.perf_event_open(tp_id)
- Tracepoint.tracepoints_enabled += 1
-
- @staticmethod
- def get_tpoint_id(category, event):
- evt_dir = os.path.join(Tracepoint.event_root, category, event)
- try:
- return int(
- open(os.path.join(evt_dir, "id")).read().strip())
- except:
- return -1
-
- @staticmethod
- def get_tpoint_format(category, event):
- evt_dir = os.path.join(Tracepoint.event_root, category, event)
- try:
- return open(os.path.join(evt_dir, "format")).readlines()
- except:
- return ""
-
- @staticmethod
- def attach(bpf):
- if Tracepoint.tracepoints_enabled > 0:
- bpf.attach_kprobe(event="tracing_generic_entry_update",
- fn_name="__trace_entry_update")
-
class Specifier(object):
probe_text = """
DATA_DECL
self.library = "" # kernel
self.tp_category = parts[1]
self.tp_event = self.function
- Tracepoint.enable_tracepoint(
+ self.tp = Tracepoint.enable_tracepoint(
self.tp_category, self.tp_event)
self.function = "perf_trace_" + self.function
else:
else:
return ""
- def _generate_tpoint_entry_struct_fields(self):
- format_lines = Tracepoint.get_tpoint_format(self.tp_category,
- self.tp_event)
- text = ""
- for line in format_lines:
- match = re.search(r'field:([^;]*);.*size:(\d+);', line)
- if match is None:
- continue
- parts = match.group(1).split()
- field_name = parts[-1:][0]
- field_type = " ".join(parts[:-1])
- field_size = int(match.group(2))
- if "__data_loc" in field_type:
- continue
- if field_name.startswith("common_"):
- continue
- text += " %s %s;\n" % (field_type, field_name)
- return text
-
- def _generate_tpoint_entry_struct(self):
- text = """
-struct %s {
- u64 __do_not_use__;
-%s
-};
- """
- self.tp_entry_struct_name = self.probe_func_name + \
- "_trace_entry"
- fields = self._generate_tpoint_entry_struct_fields()
- return text % (self.tp_entry_struct_name, fields)
-
- def _generate_tpoint_entry_prefix(self):
- text = """
- u64 tid = bpf_get_current_pid_tgid();
- u64 *di = __trace_di.lookup(&tid);
- if (di == 0) { return 0; }
- struct %s tp = {};
- bpf_probe_read(&tp, sizeof(tp), (void *)*di);
- """ % self.tp_entry_struct_name
- return text
-
def generate_text(self):
program = ""
# that enables access to the tracepoint structure and also
# the structure definition itself
if self.probe_type == "t":
- program += self._generate_tpoint_entry_struct()
- prefix += self._generate_tpoint_entry_prefix()
+ program += self.tp.generate_struct()
+ prefix += self.tp.generate_get_struct()
program += self.probe_text.replace("PROBENAME",
self.probe_func_name)
# Licensed under the Apache License, Version 2.0 (the "License")
# Copyright (C) 2016 Sasha Goldshtein.
-from bcc import BPF
+from bcc import BPF, Tracepoint, Perf
from time import sleep, strftime
import argparse
import re
import ctypes as ct
-import multiprocessing
import os
import traceback
import sys
raise OSError(errno_, os.strerror(errno_))
return t.tv_sec * 1e9 + t.tv_nsec
-class Perf(object):
- class perf_event_attr(ct.Structure):
- _fields_ = [
- ('type', ct.c_uint),
- ('size', ct.c_uint),
- ('config', ct.c_ulong),
- ('sample_period', ct.c_ulong),
- ('sample_type', ct.c_ulong),
- ('IGNORE1', ct.c_ulong),
- ('IGNORE2', ct.c_ulong),
- ('wakeup_events', ct.c_uint),
- ('IGNORE3', ct.c_uint),
- ('IGNORE4', ct.c_ulong),
- ('IGNORE5', ct.c_ulong),
- ('IGNORE6', ct.c_ulong),
- ('IGNORE7', ct.c_uint),
- ('IGNORE8', ct.c_int),
- ('IGNORE9', ct.c_ulong),
- ('IGNORE10', ct.c_uint),
- ('IGNORE11', ct.c_uint)
- ]
-
- NR_PERF_EVENT_OPEN = 298
- PERF_TYPE_TRACEPOINT = 2
- PERF_SAMPLE_RAW = 1024
- PERF_FLAG_FD_CLOEXEC = 8
- PERF_EVENT_IOC_SET_FILTER = 1074275334
- PERF_EVENT_IOC_ENABLE = 9216
-
- libc = ct.CDLL('libc.so.6', use_errno=True)
- syscall = libc.syscall # not declaring vararg types
- ioctl = libc.ioctl # not declaring vararg types
-
- @staticmethod
- def _open_for_cpu(cpu, attr):
- pfd = Perf.syscall(Perf.NR_PERF_EVENT_OPEN, ct.byref(attr),
- -1, cpu, -1, Perf.PERF_FLAG_FD_CLOEXEC)
- if pfd < 0:
- errno_ = ct.get_errno()
- raise OSError(errno_, os.strerror(errno_))
- if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_SET_FILTER,
- "common_pid == -17") < 0:
- errno_ = ct.get_errno()
- raise OSError(errno_, os.strerror(errno_))
- if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_ENABLE, 0) < 0:
- errno_ = ct.get_errno()
- raise OSError(errno_, os.strerror(errno_))
-
- @staticmethod
- def perf_event_open(tpoint_id):
- attr = Perf.perf_event_attr()
- attr.config = tpoint_id
- attr.type = Perf.PERF_TYPE_TRACEPOINT
- attr.sample_type = Perf.PERF_SAMPLE_RAW
- attr.sample_period = 1
- attr.wakeup_events = 1
- for cpu in range(0, multiprocessing.cpu_count()):
- Perf._open_for_cpu(cpu, attr)
-
-class Tracepoint(object):
- tracepoints_enabled = 0
- trace_root = "/sys/kernel/debug/tracing"
- event_root = os.path.join(trace_root, "events")
-
- @staticmethod
- def generate_decl():
- if Tracepoint.tracepoints_enabled == 0:
- return ""
- return "\nBPF_HASH(__trace_di, u64, u64);\n"
-
- @staticmethod
- def generate_entry_probe():
- if Tracepoint.tracepoints_enabled == 0:
- return ""
- return """
-int __trace_entry_update(struct pt_regs *ctx)
-{
- u64 tid = bpf_get_current_pid_tgid();
- u64 val = ctx->di;
- __trace_di.update(&tid, &val);
- return 0;
-}
-"""
-
- @staticmethod
- def enable_tracepoint(category, event):
- tp_id = Tracepoint.get_tpoint_id(category, event)
- if tp_id == -1:
- raise ValueError("no such tracepoint found: %s:%s" %
- (category, event))
- Perf.perf_event_open(tp_id)
- Tracepoint.tracepoints_enabled += 1
-
- @staticmethod
- def get_tpoint_id(category, event):
- evt_dir = os.path.join(Tracepoint.event_root, category, event)
- try:
- return int(
- open(os.path.join(evt_dir, "id")).read().strip())
- except:
- return -1
-
- @staticmethod
- def get_tpoint_format(category, event):
- evt_dir = os.path.join(Tracepoint.event_root, category, event)
- try:
- return open(os.path.join(evt_dir, "format")).readlines()
- except:
- return ""
-
- @staticmethod
- def attach(bpf):
- if Tracepoint.tracepoints_enabled > 0:
- bpf.attach_kprobe(event="tracing_generic_entry_update",
- fn_name="__trace_entry_update")
-
class Probe(object):
probe_count = 0
max_events = None
def is_default_action(self):
return self.python_format == ""
- def _generate_tpoint_entry_struct_fields(self):
- format_lines = Tracepoint.get_tpoint_format(self.tp_category,
- self.tp_event)
- text = ""
- for line in format_lines:
- match = re.search(r'field:([^;]*);.*size:(\d+);', line)
- if match is None:
- continue
- parts = match.group(1).split()
- field_name = parts[-1:][0]
- field_type = " ".join(parts[:-1])
- field_size = int(match.group(2))
- if "__data_loc" in field_type:
- continue
- if field_name.startswith("common_"):
- continue
- text += " %s %s;\n" % (field_type, field_name)
- return text
-
- def _generate_tpoint_entry_struct(self):
- text = """
-struct %s {
- u64 __do_not_use__;
-%s
-};
- """
- self.tp_entry_struct_name = self.probe_name + \
- "_trace_entry"
- fields = self._generate_tpoint_entry_struct_fields()
- return text % (self.tp_entry_struct_name, fields)
-
- def _generate_tpoint_entry_prefix(self):
- text = """
- u64 tid = bpf_get_current_pid_tgid();
- u64 *di = __trace_di.lookup(&tid);
- if (di == 0) { return 0; }
- struct %s tp = {};
- bpf_probe_read(&tp, sizeof(tp), (void *)*di);
- """ % self.tp_entry_struct_name
- return text
-
def _bail(self, error):
raise ValueError("error parsing probe '%s': %s" %
(self.raw_probe, error))
if self.probe_type == "t":
self.tp_category = parts[1]
self.tp_event = parts[2]
- Tracepoint.enable_tracepoint(self.tp_category,
- self.tp_event)
+ self.tp = Tracepoint.enable_tracepoint(
+ self.tp_category, self.tp_event)
self.library = "" # kernel
self.function = "perf_trace_%s" % self.tp_event
else:
prefix = ""
if self.probe_type == "t":
- data_decl += self._generate_tpoint_entry_struct()
- prefix = self._generate_tpoint_entry_prefix()
+ data_decl += self.tp.generate_struct()
+ prefix = self.tp.generate_get_struct()
text = """
int %s(struct pt_regs *ctx)