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)