From patchwork Fri Jan 28 18:21:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12728913 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 64A00C433EF for ; Fri, 28 Jan 2022 18:21:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233898AbiA1SVR (ORCPT ); Fri, 28 Jan 2022 13:21:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40888 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244651AbiA1SVQ (ORCPT ); Fri, 28 Jan 2022 13:21:16 -0500 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5579CC06173B for ; Fri, 28 Jan 2022 10:21:16 -0800 (PST) Received: by mail-wr1-x42b.google.com with SMTP id f17so12514804wrx.1 for ; Fri, 28 Jan 2022 10:21:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HHetTWONN+R98r08NI7jIE8wyollHS0rlDTpu/zUFIQ=; b=Q3IS+8L2LjsiqKRfchkfHPUpJYPUoPCDjcV2kJq8YcEq9lYavduhzDxKUaF8PCP4J4 aZZilZYn6rgVjlCwgLNUOJszIRoi51jfD0CMrwYkzK9P+/XoSdz/F7dtk8banJCaU5t8 o0t+l3NyBu6XETLs8yfP1XFui2gxPYfapZaXqzJP2/gWlInssINYkQrl7fVgHPiRNQhQ f2LmnLmix55Elbr5USA5gIdm/CZTME8Z9FCqlxcrnwOpvmW+7PmouYq3XcxgiZmNM2UF MivYEdYHHTjj9XZINMQxrBz29DwseUbcjoF4Pz2t7l2nGFQy4NpcuOUeCmtybAePxKlk mTUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HHetTWONN+R98r08NI7jIE8wyollHS0rlDTpu/zUFIQ=; b=Gf207Ipyr2zcyM1jJgCVqVE7qJYFDqW/tI3Tb7NZway9EtZJCxWwCNKvq65Co14lFI EWfszQgAu+Zq7ipvfQHydTcOMB/5Je4h8mQiLoJme+oTDH24AOh//+UNoturKB4lnseb +lbw1OYhKvLChi/DtGgOqpQECCRvvLN8esHBF404nyKLcRO+8Ix6vY8i3f+CdWLH4am9 AsGe7FkeaVclw2Pb19guz7eintmNKkqukySOXIL4A6Mj3mnnhhNqx4Y5GjtBDzchVegk OKl5nf+evFIXDOoG3qB7kryxxh0cP62qvzMrAWSIkt+X/8qfzhRWSSfF/6hIfK6CWEPO 4kHg== X-Gm-Message-State: AOAM533f+VGC0KPAxyxYTLh3hbav+qs+q5Ak7cbgJwlxrA8v7TKiKp5n CWjbWo8qe7CtLMwtwDXDHGhBWnQ//Q0= X-Google-Smtp-Source: ABdhPJwvBALCSy5mxgW3X0475EpWHYfbmRRWDDf+fBEi97xwj0OAeMYaSdt/Eu9KvXODqrKmR73vxw== X-Received: by 2002:a05:6000:1acc:: with SMTP id i12mr8098836wry.482.1643394074599; Fri, 28 Jan 2022 10:21:14 -0800 (PST) Received: from crow.. ([95.87.219.163]) by smtp.gmail.com with ESMTPSA id o14sm6220698wry.104.2022.01.28.10.21.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Jan 2022 10:21:14 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: linux-trace-devel@vger.kernel.org Cc: "Yordan Karadzhov (VMware)" Subject: [PATCH 1/2] trace-cruncher: Add (un)register methods for dynamic events Date: Fri, 28 Jan 2022 20:21:01 +0200 Message-Id: <20220128182102.8672-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220128182102.8672-1-y.karadz@gmail.com> References: <20220128182102.8672-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Currently the allocation of the Python object and the registration of the new dynamic event are both done in the corresponding constructor for kprobe, kretprobe or eprobe. Originally, this was done with the idea to simplify the usage, however it turns that this can be an issue in the case when these events are used in conjuction with synthetic events. In such a case, the order in which the events are registered cannot be arbitrary, because of the intrinsic dependencies between those events. And the order used to create the events must be reverced when destroying them. However, this requirement collides with way the Python automatic garbage collection works, where the objects are destroyed in the same order of there creation. The problem gets solved by decoupling the allocation of the Python objects from the registration of the corresponding events on the system. With this, we can create the objects in one order and register in another. Signed-off-by: Yordan Karadzhov (VMware) --- src/ftracepy-utils.c | 90 ++++++++++++++----- src/ftracepy-utils.h | 4 + src/ftracepy.c | 15 +++- tracecruncher/ft_utils.py | 2 + .../tests/1_unit/test_01_ftracepy_unit.py | 7 +- 5 files changed, 93 insertions(+), 25 deletions(-) diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c index 19e237b..888e29b 100644 --- a/src/ftracepy-utils.c +++ b/src/ftracepy-utils.c @@ -2234,11 +2234,54 @@ PyObject *PyDynevent_probe(PyDynevent *self) return dynevent_info2py(buff, type); } +PyObject *PyDynevent_register(PyDynevent *self) +{ + if (tracefs_dynevent_create(self->ptrObj) < 0) { + char *evt; + int type; + + type = tracefs_dynevent_info(self->ptrObj, NULL, &evt, NULL, NULL, NULL); + TfsError_fmt(NULL, "Failed to register dynamic event '%s'.", + type != TRACEFS_DYNEVENT_UNKNOWN ? evt : "UNKNOWN"); + free(evt); + return NULL; + } + + /* + * Here the dynamic event gets added to the system. + * Hence we need to 'destroy' this event at exit. + */ + set_destroy_flag((PyObject *)self, true); + Py_RETURN_NONE; +} + +PyObject *PyDynevent_unregister(PyDynevent *self) +{ + if (tracefs_dynevent_destroy(self->ptrObj, true) < 0) { + char *evt; + int type; + + type = tracefs_dynevent_info(self->ptrObj, NULL, &evt, NULL, NULL, NULL); + TfsError_fmt(NULL, "Failed to unregister dynamic event '%s'.", + type != TRACEFS_DYNEVENT_UNKNOWN ? evt : "UNKNOWN"); + free(evt); + return NULL; + } + + /* + * Here the synthetic event gets removed from the system. + * Hence we no loger need to 'destroy' this event at exit. + */ + set_destroy_flag((PyObject *)self, false); + Py_RETURN_NONE; +} + PyObject *PyFtrace_kprobe(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"event", "function", "probe", NULL}; const char *event, *function, *probe; struct tracefs_dynevent *kprobe; + PyObject *py_dyn; if (!PyArg_ParseTupleAndKeywords(args, kwargs, @@ -2256,13 +2299,14 @@ PyObject *PyFtrace_kprobe(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; } - if (tracefs_dynevent_create(kprobe) < 0) { - TfsError_fmt(NULL, "Failed to create kprobe '%s'", event); - tracefs_dynevent_free(kprobe); - return NULL; - } - - return PyDynevent_New(kprobe); + py_dyn = PyDynevent_New(kprobe); + /* + * Here we only allocated and initializes a dynamic event object. + * However, no dynamic event is added to the system yet. Hence, + * there is no need to 'destroy' this event at exit. + */ + set_destroy_flag(py_dyn, false); + return py_dyn; } PyObject *PyFtrace_kretprobe(PyObject *self, PyObject *args, PyObject *kwargs) @@ -2270,6 +2314,7 @@ PyObject *PyFtrace_kretprobe(PyObject *self, PyObject *args, PyObject *kwargs) static char *kwlist[] = {"event", "function", "probe", NULL}; const char *event, *function, *probe = "$retval"; struct tracefs_dynevent *kprobe; + PyObject *py_dyn; if (!PyArg_ParseTupleAndKeywords(args, kwargs, @@ -2287,13 +2332,14 @@ PyObject *PyFtrace_kretprobe(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; } - if (tracefs_dynevent_create(kprobe) < 0) { - TfsError_fmt(NULL, "Failed to create kretprobe '%s'", event); - tracefs_dynevent_free(kprobe); - return NULL; - } - - return PyDynevent_New(kprobe); + py_dyn = PyDynevent_New(kprobe); + /* + * Here we only allocated and initializes a dynamic event object. + * However, no dynamic event is added to the system yet. Hence, + * there is no need to 'destroy' this event at exit. + */ + set_destroy_flag(py_dyn, false); + return py_dyn; } struct tep_event *dynevent_get_event(PyDynevent *event, @@ -2323,6 +2369,7 @@ PyObject *PyFtrace_eprobe(PyObject *self, PyObject *args, PyObject *kwargs) static char *kwlist[] = {"event", "target_system", "target_event", "fetchargs", NULL}; const char *event, *target_system, *target_event, *fetchargs; struct tracefs_dynevent *eprobe; + PyObject *py_dyn; if (!PyArg_ParseTupleAndKeywords(args, kwargs, @@ -2341,13 +2388,14 @@ PyObject *PyFtrace_eprobe(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; } - if (tracefs_dynevent_create(eprobe) < 0) { - TfsError_fmt(NULL, "Failed to create eprobe '%s'", event); - tracefs_dynevent_free(eprobe); - return NULL; - } - - return PyDynevent_New(eprobe); + py_dyn = PyDynevent_New(eprobe); + /* + * Here we only allocated and initializes a dynamic event object. + * However, no dynamic event is added to the system yet. Hence, + * there is no need to 'destroy' this event at exit. + */ + set_destroy_flag(py_dyn, false); + return py_dyn;; } static PyObject *set_filter(PyObject *args, PyObject *kwargs, diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h index 13b4c91..9491b18 100644 --- a/src/ftracepy-utils.h +++ b/src/ftracepy-utils.h @@ -76,6 +76,10 @@ PyObject *PyDynevent_address(PyDynevent *self); PyObject *PyDynevent_probe(PyDynevent *self); +PyObject *PyDynevent_register(PyDynevent *self); + +PyObject *PyDynevent_unregister(PyDynevent *self); + PyObject *PyDynevent_set_filter(PyDynevent *self, PyObject *args, PyObject *kwargs); diff --git a/src/ftracepy.c b/src/ftracepy.c index 354c6d1..574bf38 100644 --- a/src/ftracepy.c +++ b/src/ftracepy.c @@ -127,6 +127,16 @@ static PyMethodDef PyDynevent_methods[] = { METH_NOARGS, "Get the event definition." }, + {"register", + (PyCFunction) PyDynevent_register, + METH_NOARGS, + "Register dynamic event." + }, + {"unregister", + (PyCFunction) PyDynevent_unregister, + METH_NOARGS, + "Unregister dynamic event." + }, {"set_filter", (PyCFunction) PyDynevent_set_filter, METH_VARARGS | METH_KEYWORDS, @@ -164,6 +174,7 @@ static int dynevent_destroy(struct tracefs_dynevent *devt) { return tracefs_dynevent_destroy(devt, true); } + C_OBJECT_WRAPPER(tracefs_dynevent, PyDynevent, dynevent_destroy, tracefs_dynevent_free) @@ -255,12 +266,12 @@ static PyMethodDef PySynthEvent_methods[] = { {"register", (PyCFunction) PySynthEvent_register, METH_NOARGS, - "Register synth. event to a trace instance." + "Register synth. event." }, {"unregister", (PyCFunction) PySynthEvent_unregister, METH_NOARGS, - "Unregister synth. event from a trace instance." + "Unregister synth. event." }, {"enable", (PyCFunction) PySynthEvent_enable, diff --git a/tracecruncher/ft_utils.py b/tracecruncher/ft_utils.py index b7e2e73..26c06ec 100644 --- a/tracecruncher/ft_utils.py +++ b/tracecruncher/ft_utils.py @@ -157,6 +157,7 @@ class kprobe(kprobe_base): probe = ' '.join('{!s}={!s}'.format(key,val) for (key, val) in self.fields.items()) self.kp = ft.kprobe(event=self.name, function=self.func, probe=probe); + self.kp.register(); self.evt_id = find_event_id(system=ft.tc_event_system(), event=self.name) @@ -187,6 +188,7 @@ class kretval_probe(kprobe_base): """ Register this probe to Ftrace. """ self.kp = ft.kprobe(event=self.name, function=self.func); + self.kp.register(); self.evt_id = find_event_id(system=ft.tc_event_system(), event=self.name) diff --git a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py index 1ef8951..f51bcc1 100644 --- a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py +++ b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py @@ -414,11 +414,13 @@ class KprobeTestCase(unittest.TestCase): evt2_prove = 'file=+u0($arg2):ustring' kp1 = ft.kprobe(event=evt1, function=evt1_func, probe=evt1_prove) + kp1.register() self.assertEqual(evt1, kp1.event()) self.assertEqual(evt1_func, kp1.address()) self.assertEqual(evt1_prove, kp1.probe()) kp2 = ft.kprobe(event=evt2, function=evt2_func, probe=evt2_prove) + kp2.register() self.assertEqual(evt2, kp2.event()) self.assertEqual(evt2_func, kp2.address()) self.assertEqual(evt2_prove, kp2.probe()) @@ -430,6 +432,7 @@ class KprobeTestCase(unittest.TestCase): flt = 'path~\'/sys/fs/cgroup/*\'' kp1 = ft.kprobe(event=evt1, function=evt1_func, probe=evt1_prove) + kp1.register() inst = ft.create_instance(instance_name) kp1.set_filter(instance=inst, filter=flt) @@ -445,6 +448,7 @@ class KprobeTestCase(unittest.TestCase): evt1_prove = 'path=+u0($arg2):ustring' kp1 = ft.kprobe(event=evt1, function=evt1_func, probe=evt1_prove) + kp1.register() inst = ft.create_instance(instance_name) kp1.enable(instance=inst) ret = kp1.is_enabled(instance=inst) @@ -458,8 +462,6 @@ class EprobeTestCase(unittest.TestCase): def test_eprobe(self): """ Event probes are introduced in Linux kernel 5.15 """ - if kernel_version < (5, 15): - return evt1 = 'sopen_in' evt1_tsys = 'syscalls' @@ -495,6 +497,7 @@ class EprobeTestCase(unittest.TestCase): ep1 = ft.eprobe(event=evt1, target_system=evt1_tsys, target_event=evt1_tevent, fetchargs=evt1_args) + ep1.register() inst = ft.create_instance(instance_name) ep1.enable(instance=inst) ret = ep1.is_enabled(instance=inst) From patchwork Fri Jan 28 18:21:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12728914 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8727BC433F5 for ; Fri, 28 Jan 2022 18:21:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345547AbiA1SVS (ORCPT ); Fri, 28 Jan 2022 13:21:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40894 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244651AbiA1SVR (ORCPT ); Fri, 28 Jan 2022 13:21:17 -0500 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 50AC0C061714 for ; Fri, 28 Jan 2022 10:21:17 -0800 (PST) Received: by mail-wr1-x42b.google.com with SMTP id l25so12396337wrb.13 for ; Fri, 28 Jan 2022 10:21:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2AitvGUNRIMmDNvFTtfRqZkeAbdUNhueLWGjCIB3t8Y=; b=S8rV1O5hyVohvar7M3NahA6bcZT18XQqKpt2X5YCY0wxqZcU9Ys+fKEU3hQGIhHCgY cgE5XDv1rO7ZPWCNYiFBNRUsxrCh4qnTvVHdD7zECFP/T4i+MdN5SYJj9orjH3rHQpCZ vF6W+LcpNHZe4JgF+CYpNpeinWnsKHmdSDF6goaTXxkLibxJPBj3PrZ6tHzGFR/mGJXJ GqKLEbzRX9X4EYxylnNddXrqbRgll9B3EyZ5sXTbTCOR3iUXJFQjeZjVLDciypP5TROO IgQZr7Fwrz5zHXttmxwoeZc5WkuvqNZ4V4nBDNtyFgzNAk1L5iphXcFWfRVBHPcSL/I0 A3Zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2AitvGUNRIMmDNvFTtfRqZkeAbdUNhueLWGjCIB3t8Y=; b=VHhd6cQt/3OTOa6GIzunqh320YDYMOrgva4a9dGB8iK/kJjPZRS9Yx73vLNXO3xdCF 526k6c2zYpDRBFiLWHka423JX9955cC4Ca4vNCQhslNpwG+mn8OdFL3k/axrEgKEqITr qKdtm5QTgDyH1Jxc44qKZXMbThrKRJosxCE+DexDpiEfbNJsr2pzwe8gaksfRJpBN44W Ef4UqCvw4aZZAGSTFKKVMI2gI4r1zoMBd2NsovH2F4hoe8E7FCkuNXS83cA0BT3/IQkJ XTJ1jFXKb3oeKvUrHVBXCECv56RmKp2oe+geUEZCndTiDhTdstbymDQ/QThH0mo58l8z JvGA== X-Gm-Message-State: AOAM533Y8EGpKo3DjiCGWjC0jDO+IORLlIPK2xEXEV1LmI3wlWCK0NWm VMoU4oItb+uNgi8vxhSgmt6ZgYfUvd4= X-Google-Smtp-Source: ABdhPJz6tiUPg5Ggw/Q+P0tDm5Cn7ZdgMwdrj9WSXz/qsLy4RkG93rTsMaC1nJbzx5NKON/UMLj+Ow== X-Received: by 2002:a05:6000:178d:: with SMTP id e13mr7914587wrg.183.1643394075495; Fri, 28 Jan 2022 10:21:15 -0800 (PST) Received: from crow.. ([95.87.219.163]) by smtp.gmail.com with ESMTPSA id o14sm6220698wry.104.2022.01.28.10.21.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Jan 2022 10:21:15 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: linux-trace-devel@vger.kernel.org Cc: "Yordan Karadzhov (VMware)" Subject: [PATCH 2/2] trace-cruncher: Add example of tracing systemcalls Date: Fri, 28 Jan 2022 20:21:02 +0200 Message-Id: <20220128182102.8672-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220128182102.8672-1-y.karadz@gmail.com> References: <20220128182102.8672-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org This is a very basic example, demonstrating how the low-level APIs can be used to trace system calls. Signed-off-by: Yordan Karadzhov (VMware) --- examples/syscall_trace.py | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100755 examples/syscall_trace.py diff --git a/examples/syscall_trace.py b/examples/syscall_trace.py new file mode 100755 index 0000000..7d6f399 --- /dev/null +++ b/examples/syscall_trace.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +""" +SPDX-License-Identifier: CC-BY-4.0 + +Copyright 2022 VMware Inc, Yordan Karadzhov (VMware) +""" + +import sys + +import tracecruncher.ftracepy as ft +import tracecruncher.ft_utils as tc + +eprobe_evt = 'eprobe_open' +synth_evt = 'synth_open' +syscall = 'openat' +args = 'file=+0($file):ustring delta_T=$delta_T:s64' + +# In order to trace a system call, we will create a synthetic event that +# combines the 'sys_enter_XXX' and 'sys_exit_XXX' static events. A dynamic +# 'eprobe' will be attached to this synthetic event in order to decode the +# pointer argument of the system and to calculate the time spend between +# 'sys_enter_XXX' and 'sys_exit_XXX' (syscall duration). + +eprobe = ft.eprobe(event=eprobe_evt, + target_system='synthetic', target_event=synth_evt, + fetchargs=args) + +synth = ft.synth(name=synth_evt, + start_sys='syscalls', start_evt='sys_enter_' + syscall, + end_sys='syscalls', end_evt='sys_exit_' + syscall, + start_match='common_pid', end_match='common_pid') + +# Add to the synth. event one field from the 'start' event. In the synth. event, +# the field 'filename' will be renamed to 'file'. +synth.add_start_fields(fields=['filename'], names=['file']) + +# Add to the synth. event a field that measures the time-difference between +# the 'start' and 'end' events. Use 'hd' time resolution (nanoseconds). +synth.add_delta_T(hd=True) + +# The synthetic event must be registered first (and destroyed last), because the +# eprobe depends on it. Note that the order in which the events are allocated +# will be the order in which Python will destroy them at exit. +synth.register() +eprobe.register() + +tep = tc.local_tep() +eprobe_id = tep.get_event(system=ft.tc_event_system(), name=eprobe_evt).id() + +def callback(event, record): + if event.id() == eprobe_id: + # Print only the dynamic eprobe. + print(tep.info(event, record)) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print('Usage: ', sys.argv[0], ' [PROCESS]') + sys.exit(1) + + inst = ft.create_instance(tracing_on=False) + + # Enable the two events and trace the user process. + synth.enable(instance=inst) + eprobe.enable(instance=inst) + ft.trace_process(instance=inst, argv=sys.argv[1:])