Moved common tracepoint support into tracepoint.py
diff --git a/tools/trace.py b/tools/trace.py
index 8f1ce89..b159510 100755
--- a/tools/trace.py
+++ b/tools/trace.py
@@ -9,12 +9,11 @@
# 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
@@ -44,122 +43,6 @@
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
@@ -190,47 +73,6 @@
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))
@@ -290,8 +132,8 @@
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:
@@ -457,8 +299,8 @@
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)