linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/10] trace-cruncher: Synthetic events
@ 2022-01-24  8:56 Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 01/10] trace-cruncher: Define Python type for synthetic events Yordan Karadzhov (VMware)
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Adding support for synthetic events. Only the low level wrapper of
the libtracefs APIs is added here.

Yordan Karadzhov (VMware) (10):
  trace-cruncher: Define Python type for synthetic events
  trace-cruncher: APIs for adding start/end fields to synth. event
  trace-cruncher: APIs for adding arithmetic fields to synth. events
  trace-cruncher: APIs for registering/unregistering synth. events
  trace-cruncher: APIs for enabling synth. events
  trace-cryncher: Add static methods for manipulating filters
  trace-cruncher: APIs for filtering synth. events
  trace-cruncher: API to show descriptor of the synth. event
  trace-cruncher: Add synthetic event example
  trace-cruncher: Add synth. events tests

 examples/synth.py                             |  43 ++
 src/ftracepy-utils.c                          | 513 ++++++++++++++++--
 src/ftracepy-utils.h                          |  47 ++
 src/ftracepy.c                                |  92 ++++
 .../tests/1_unit/test_01_ftracepy_unit.py     |  86 +++
 5 files changed, 735 insertions(+), 46 deletions(-)
 create mode 100755 examples/synth.py

-- 
2.32.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 01/10] trace-cruncher: Define Python type for synthetic events
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 02/10] trace-cruncher: APIs for adding start/end fields to synth. event Yordan Karadzhov (VMware)
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Addind new Python type and constructor for it:
synth()

The new type 'PySynthEvent will be used to implement APIs for working
with synthetic events.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 58 ++++++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h |  5 ++++
 src/ftracepy.c       | 17 +++++++++++++
 3 files changed, 80 insertions(+)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index cecb180..1fcf2f8 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -2426,6 +2426,64 @@ PyObject *PyFtrace_hist(PyObject *self, PyObject *args,
 	return NULL;
 }
 
+PyObject *PyFtrace_synth(PyObject *self, PyObject *args,
+					 PyObject *kwargs)
+{
+	const char *name, *start_match, *end_match, *match_name=NULL;
+	const char *start_sys, *start_evt, *end_sys, *end_evt;
+	static char *kwlist[] = {"name",
+				 "start_sys",
+				 "start_evt",
+				 "end_sys",
+				 "end_evt",
+				 "start_match",
+				 "end_match",
+				 "match_name",
+				 NULL};
+	static struct tracefs_synth *synth;
+	struct tep_handle *tep;
+	PyObject *py_synth;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "sssssss|s",
+					 kwlist,
+					 &name,
+					 &start_sys,
+					 &start_evt,
+					 &end_sys,
+					 &end_evt,
+					 &start_match,
+					 &end_match,
+					 &match_name)) {
+		return NULL;
+	}
+
+	tep = get_tep(NULL, NULL);
+	if (!tep)
+		return NULL;
+
+	synth = tracefs_synth_alloc(tep, name,
+				    start_sys, start_evt,
+				    end_sys, end_evt,
+				    start_match, end_match,
+				    match_name);
+	tep_free(tep);
+	if (!synth) {
+		MEM_ERROR;
+		return NULL;
+	}
+
+	py_synth = PySynthEvent_New(synth);
+	/*
+	 * Here we only allocated and initializes a synthetic event object.
+	 * However, no synthetic event is added to the system yet. Hence,
+	 * there is no need to 'destroy' this event at exit.
+	 */
+	set_destroy_flag(py_synth, false);
+	return py_synth;
+}
+
 PyObject *PyFtrace_set_ftrace_loglevel(PyObject *self, PyObject *args,
 						       PyObject *kwargs)
 {
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index fc5016c..e8db811 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -30,6 +30,8 @@ C_OBJECT_WRAPPER_DECLARE(tracefs_dynevent, PyDynevent);
 
 C_OBJECT_WRAPPER_DECLARE(tracefs_hist, PyTraceHist)
 
+C_OBJECT_WRAPPER_DECLARE(tracefs_synth, PySynthEvent)
+
 PyObject *PyTepRecord_time(PyTepRecord* self);
 
 PyObject *PyTepRecord_cpu(PyTepRecord* self);
@@ -210,6 +212,9 @@ PyObject *PyFtrace_register_kretprobe(PyObject *self, PyObject *args,
 PyObject *PyFtrace_hist(PyObject *self, PyObject *args,
 					PyObject *kwargs);
 
+PyObject *PyFtrace_synth(PyObject *self, PyObject *args,
+					 PyObject *kwargs);
+
 PyObject *PyFtrace_set_ftrace_loglevel(PyObject *self, PyObject *args,
 						       PyObject *kwargs);
 
diff --git a/src/ftracepy.c b/src/ftracepy.c
index f59bd4c..f8b8b36 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -221,6 +221,14 @@ C_OBJECT_WRAPPER(tracefs_hist, PyTraceHist,
 		 NO_DESTROY,
 		 tracefs_hist_free)
 
+static PyMethodDef PySynthEvent_methods[] = {
+	{NULL, NULL, 0, NULL}
+};
+
+C_OBJECT_WRAPPER(tracefs_synth, PySynthEvent,
+		 tracefs_synth_destroy,
+		 tracefs_synth_free)
+
 static PyMethodDef ftracepy_methods[] = {
 	{"dir",
 	 (PyCFunction) PyFtrace_dir,
@@ -382,6 +390,11 @@ static PyMethodDef ftracepy_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Define a histogram."
 	},
+	{"synth",
+	 (PyCFunction) PyFtrace_synth,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Define a synthetic event."
+	},
 	{"set_ftrace_loglevel",
 	 (PyCFunction) PyFtrace_set_ftrace_loglevel,
 	 METH_VARARGS | METH_KEYWORDS,
@@ -453,6 +466,9 @@ PyMODINIT_FUNC PyInit_ftracepy(void)
 	if (!PyTraceHistTypeInit())
 		return NULL;
 
+	if (!PySynthEventTypeInit())
+		return NULL;
+
 	TFS_ERROR = PyErr_NewException("tracecruncher.ftracepy.tfs_error",
 				       NULL, NULL);
 
@@ -470,6 +486,7 @@ PyMODINIT_FUNC PyInit_ftracepy(void)
 	PyModule_AddObject(module, "tracefs_instance", (PyObject *) &PyTfsInstanceType);
 	PyModule_AddObject(module, "tracefs_dynevent", (PyObject *) &PyDyneventType);
 	PyModule_AddObject(module, "tracefs_hist", (PyObject *) &PyTraceHistType);
+	PyModule_AddObject(module, "tracefs_synth", (PyObject *) &PySynthEventType);
 
 	PyModule_AddObject(module, "tfs_error", TFS_ERROR);
 	PyModule_AddObject(module, "tep_error", TEP_ERROR);
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 02/10] trace-cruncher: APIs for adding start/end fields to synth. event
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 01/10] trace-cruncher: Define Python type for synthetic events Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 03/10] trace-cruncher: APIs for adding arithmetic fields to synth. events Yordan Karadzhov (VMware)
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Here we add the following methods to the Python type for synthetic
events:
add_start_fields()
add_end_fields()

The new APIs allows for adding fields from the original 'start' and
'end' events to the new synthetic event.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h |  6 +++++
 src/ftracepy.c       | 10 +++++++
 3 files changed, 80 insertions(+)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 1fcf2f8..42bd9d0 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -1009,6 +1009,70 @@ PyObject *PyTraceHist_close(PyTraceHist *self, PyObject *args,
 	Py_RETURN_NONE;
 }
 
+typedef int (*add_field_ptr)(struct tracefs_synth *,
+			     const char *,
+			     const char *);
+
+PyObject *synth_add_fields(PySynthEvent *self, PyObject *args,
+					       PyObject *kwargs,
+					       bool to_start)
+{
+	static char *kwlist[] = {"fields", "names", NULL};
+	PyObject *py_fields, *py_names = NULL;
+	PyObject *item_field, *item_name;
+	add_field_ptr add_field_func;
+	const char *field, *name;
+	int ret, n, i;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "O|O",
+					 kwlist,
+					 &py_fields,
+					 &py_names)) {
+		return NULL;
+	}
+
+	add_field_func = to_start ? tracefs_synth_add_start_field:
+				    tracefs_synth_add_end_field;
+
+	n = PyList_Size(py_fields);
+	for (i = 0; i < n; ++i) {
+		item_field = PyList_GetItem(py_fields, i);
+		field = PyUnicode_DATA(item_field);
+
+		name = NULL;
+		if (py_names) {
+			item_name = PyList_GetItem(py_names, i);
+			if (item_name && item_name != Py_None)
+				name = PyUnicode_DATA(item_name);
+		}
+
+		ret = add_field_func(self->ptrObj, field, name);
+		if (ret < 0) {
+			TfsError_fmt(NULL,
+				     "Failed to add %s field '%s' to synth. event %s",
+				     to_start ? "start" : "end", field,
+				     tracefs_synth_get_name(self->ptrObj));
+			return NULL;
+		}
+	}
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PySynthEvent_add_start_fields(PySynthEvent *self, PyObject *args,
+							    PyObject *kwargs)
+{
+	return synth_add_fields(self, args, kwargs, true);
+}
+
+PyObject *PySynthEvent_add_end_fields(PySynthEvent *self, PyObject *args,
+							  PyObject *kwargs)
+{
+	return synth_add_fields(self, args, kwargs, false);
+}
+
 PyObject *PyFtrace_dir(PyObject *self)
 {
 	return PyUnicode_FromString(tracefs_tracing_dir());
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index e8db811..3c6c0f3 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -121,6 +121,12 @@ PyObject *PyTraceHist_read(PyTraceHist *self, PyObject *args,
 PyObject *PyTraceHist_close(PyTraceHist *self, PyObject *args,
 					       PyObject *kwargs);
 
+PyObject *PySynthEvent_add_start_fields(PySynthEvent *self, PyObject *args,
+							    PyObject *kwargs);
+
+PyObject *PySynthEvent_add_end_fields(PySynthEvent *self, PyObject *args,
+							  PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_detach(PyObject *self, PyObject *args, PyObject *kwargs);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index f8b8b36..44114f0 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -222,6 +222,16 @@ C_OBJECT_WRAPPER(tracefs_hist, PyTraceHist,
 		 tracefs_hist_free)
 
 static PyMethodDef PySynthEvent_methods[] = {
+	{"add_start_fields",
+	 (PyCFunction) PySynthEvent_add_start_fields,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add fields from the start event to save."
+	},
+	{"add_end_fields",
+	 (PyCFunction) PySynthEvent_add_end_fields,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add fields from the end event to save."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 03/10] trace-cruncher: APIs for adding arithmetic fields to synth. events
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 01/10] trace-cruncher: Define Python type for synthetic events Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 02/10] trace-cruncher: APIs for adding start/end fields to synth. event Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 04/10] trace-cruncher: APIs for registering/unregistering " Yordan Karadzhov (VMware)
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Here we add the following methods to the Python type for synthetic
events:
add_delta_start(),
add_delta_end(),
add_delta_T(),
add_sum()

The new APIs allows for adding to the new synthetic event, fields that
are calculated from the fields of the original 'start' and 'end' events
by using simple addition or subtraction.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h | 12 +++++++
 src/ftracepy.c       | 20 +++++++++++
 3 files changed, 113 insertions(+)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 42bd9d0..9245b07 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -1073,6 +1073,87 @@ PyObject *PySynthEvent_add_end_fields(PySynthEvent *self, PyObject *args,
 	return synth_add_fields(self, args, kwargs, false);
 }
 
+static inline void add_synth_field_err(const char *field, const char *event)
+{
+	TfsError_fmt(NULL, "Failed to add field '%s' to synth. event %s",
+		     field, event);
+}
+
+static inline PyObject *
+add_synth_field(PySynthEvent *self, PyObject *args, PyObject *kwargs,
+		enum tracefs_synth_calc calc)
+{
+	static char *kwlist[] = {"name", "start_field", "end_field", NULL};
+	const char *start_field, *end_field, *name;
+	int ret;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "sss",
+					 kwlist,
+					 &name,
+					 &start_field,
+					 &end_field)) {
+		return NULL;
+	}
+
+	ret = tracefs_synth_add_compare_field(self->ptrObj,
+					      start_field, end_field, calc,
+					      name);
+	if (ret < 0) {
+		add_synth_field_err(name, tracefs_synth_get_name(self->ptrObj));
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PySynthEvent_add_delta_start(PySynthEvent *self, PyObject *args,
+							   PyObject *kwargs)
+{
+	return add_synth_field(self, args, kwargs, TRACEFS_SYNTH_DELTA_START);
+}
+
+PyObject *PySynthEvent_add_delta_end(PySynthEvent *self, PyObject *args,
+							 PyObject *kwargs)
+{
+	return add_synth_field(self, args, kwargs, TRACEFS_SYNTH_DELTA_END);
+}
+
+PyObject *PySynthEvent_add_sum(PySynthEvent *self, PyObject *args,
+						   PyObject *kwargs)
+{
+	return add_synth_field(self, args, kwargs, TRACEFS_SYNTH_ADD);
+}
+
+PyObject *PySynthEvent_add_delta_T(PySynthEvent *self, PyObject *args,
+						       PyObject *kwargs)
+{
+	static char *kwlist[] = {"name", "hd", NULL};
+	const char *name = "delta_T";
+	const char* time_rez;
+	int ret, hd = 0;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "|sp",
+					 kwlist,
+					 &name,
+					 &hd)) {
+		return NULL;
+	}
+
+	time_rez = hd ? TRACEFS_TIMESTAMP : TRACEFS_TIMESTAMP_USECS;
+	ret = tracefs_synth_add_compare_field(self->ptrObj, time_rez, time_rez,
+					      TRACEFS_SYNTH_DELTA_END, name);
+	if (ret < 0) {
+		add_synth_field_err(name, tracefs_synth_get_name(self->ptrObj));
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
 PyObject *PyFtrace_dir(PyObject *self)
 {
 	return PyUnicode_FromString(tracefs_tracing_dir());
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index 3c6c0f3..7b798fc 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -127,6 +127,18 @@ PyObject *PySynthEvent_add_start_fields(PySynthEvent *self, PyObject *args,
 PyObject *PySynthEvent_add_end_fields(PySynthEvent *self, PyObject *args,
 							  PyObject *kwargs);
 
+PyObject *PySynthEvent_add_delta_start(PySynthEvent *self, PyObject *args,
+							   PyObject *kwargs);
+
+PyObject *PySynthEvent_add_delta_end(PySynthEvent *self, PyObject *args,
+							 PyObject *kwargs);
+
+PyObject *PySynthEvent_add_delta_T(PySynthEvent *self, PyObject *args,
+						       PyObject *kwargs);
+
+PyObject *PySynthEvent_add_sum(PySynthEvent *self, PyObject *args,
+						   PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_detach(PyObject *self, PyObject *args, PyObject *kwargs);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index 44114f0..066fc65 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -232,6 +232,26 @@ static PyMethodDef PySynthEvent_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Add fields from the end event to save."
 	},
+	{"add_delta_start",
+	 (PyCFunction) PySynthEvent_add_delta_start,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add 'start - end' field."
+	},
+	{"add_delta_end",
+	 (PyCFunction) PySynthEvent_add_delta_end,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add 'end - start' field."
+	},
+	{"add_delta_T",
+	 (PyCFunction) PySynthEvent_add_delta_T,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add time-difference field."
+	},
+	{"add_sum",
+	 (PyCFunction) PySynthEvent_add_delta_T,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add 'start + end' field."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 04/10] trace-cruncher: APIs for registering/unregistering synth. events
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (2 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 03/10] trace-cruncher: APIs for adding arithmetic fields to synth. events Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 05/10] trace-cruncher: APIs for enabling " Yordan Karadzhov (VMware)
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Here we add the following methods to the Python type for synthetic events:
register()
unregister()

The constructor only creates the objects that describe the new synthetic
event. We need to use those new APIs in order to actually create/destroy
the event into the system.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 42 +++++++++++++++++++++++++++++++++++++-----
 src/ftracepy-utils.h |  4 ++++
 src/ftracepy.c       | 10 ++++++++++
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 9245b07..244bff9 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -1154,17 +1154,49 @@ PyObject *PySynthEvent_add_delta_T(PySynthEvent *self, PyObject *args,
 	Py_RETURN_NONE;
 }
 
-PyObject *PyFtrace_dir(PyObject *self)
-{
-	return PyUnicode_FromString(tracefs_tracing_dir());
-}
-
 static void set_destroy_flag(PyObject *py_obj, bool val)
 {
 	PyFtrace_Object_HEAD *obj_head = (PyFtrace_Object_HEAD *)py_obj;
 	obj_head->destroy = val;
 }
 
+PyObject *PySynthEvent_register(PySynthEvent *self)
+{
+	if (tracefs_synth_create(self->ptrObj) < 0) {
+		TfsError_fmt(NULL, "Failed to register synth. event %s",
+			     tracefs_synth_get_name(self->ptrObj));
+		return NULL;
+	}
+
+	/*
+	 * Here the synthetic 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 *PySynthEvent_unregister(PySynthEvent *self)
+{
+	if (tracefs_synth_destroy(self->ptrObj) < 0) {
+		TfsError_fmt(NULL, "Failed to unregister synth. event %s",
+			     tracefs_synth_get_name(self->ptrObj));
+		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_dir(PyObject *self)
+{
+	return PyUnicode_FromString(tracefs_tracing_dir());
+}
+
 static PyObject *set_destroy(PyObject *args, PyObject *kwargs, bool destroy)
 {
 	static char *kwlist[] = {"object", NULL};
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index 7b798fc..40b41d8 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -139,6 +139,10 @@ PyObject *PySynthEvent_add_delta_T(PySynthEvent *self, PyObject *args,
 PyObject *PySynthEvent_add_sum(PySynthEvent *self, PyObject *args,
 						   PyObject *kwargs);
 
+PyObject *PySynthEvent_register(PySynthEvent *self);
+
+PyObject *PySynthEvent_unregister(PySynthEvent *self);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_detach(PyObject *self, PyObject *args, PyObject *kwargs);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index 066fc65..0314aa1 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -252,6 +252,16 @@ static PyMethodDef PySynthEvent_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Add 'start + end' field."
 	},
+	{"register",
+	 (PyCFunction) PySynthEvent_register,
+	 METH_NOARGS,
+	 "Register synth. event to a trace instance."
+	},
+	{"unregister",
+	 (PyCFunction) PySynthEvent_unregister,
+	 METH_NOARGS,
+	 "Unregister synth. event from a trace instance."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 05/10] trace-cruncher: APIs for enabling synth. events
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (3 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 04/10] trace-cruncher: APIs for registering/unregistering " Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 06/10] trace-cryncher: Add static methods for manipulating filters Yordan Karadzhov (VMware)
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Here we add the following methods to the Python type for synthetic
events:

enable()
disable()
is_enabled()

The 3 new APIs replicate the APIs available for kpobes.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h |  9 +++++++++
 src/ftracepy.c       | 15 +++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 244bff9..8a0c3c3 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -2661,6 +2661,51 @@ PyObject *PyFtrace_synth(PyObject *self, PyObject *args,
 	return py_synth;
 }
 
+#define SYNTH_SYS "synthetic"
+
+static bool enable_synth(PySynthEvent *self, PyObject *args, PyObject *kwargs,
+			 bool enable)
+{
+	struct tracefs_instance *instance;
+
+	if (!get_instance_from_arg(args, kwargs, &instance))
+		return NULL;
+
+	return event_enable_disable(instance, SYNTH_SYS,
+				    tracefs_synth_get_name(self->ptrObj),
+				    enable);
+}
+
+PyObject *PySynthEvent_enable(PySynthEvent *self, PyObject *args,
+						  PyObject *kwargs)
+{
+	if (!enable_synth(self, args, kwargs, true))
+		return NULL;
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PySynthEvent_disable(PySynthEvent *self, PyObject *args,
+						   PyObject *kwargs)
+{
+	if (!enable_synth(self, args, kwargs, false))
+		return NULL;
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PySynthEvent_is_enabled(PySynthEvent *self, PyObject *args,
+						      PyObject *kwargs)
+{
+	struct tracefs_instance *instance;
+
+	if (!get_instance_from_arg(args, kwargs, &instance))
+		return NULL;
+
+	return event_is_enabled(instance, SYNTH_SYS,
+				tracefs_synth_get_name(self->ptrObj));
+}
+
 PyObject *PyFtrace_set_ftrace_loglevel(PyObject *self, PyObject *args,
 						       PyObject *kwargs)
 {
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index 40b41d8..daf1a19 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -143,6 +143,15 @@ PyObject *PySynthEvent_register(PySynthEvent *self);
 
 PyObject *PySynthEvent_unregister(PySynthEvent *self);
 
+PyObject *PySynthEvent_enable(PySynthEvent *self, PyObject *args,
+						  PyObject *kwargs);
+
+PyObject *PySynthEvent_disable(PySynthEvent *self, PyObject *args,
+						   PyObject *kwargs);
+
+PyObject *PySynthEvent_is_enabled(PySynthEvent *self, PyObject *args,
+						      PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_detach(PyObject *self, PyObject *args, PyObject *kwargs);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index 0314aa1..62c6de0 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -262,6 +262,21 @@ static PyMethodDef PySynthEvent_methods[] = {
 	 METH_NOARGS,
 	 "Unregister synth. event from a trace instance."
 	},
+	{"enable",
+	 (PyCFunction) PySynthEvent_enable,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Enable synth. event."
+	},
+	{"disable",
+	 (PyCFunction) PySynthEvent_disable,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Disable synth. event."
+	},
+	{"is_enabled",
+	 (PyCFunction) PySynthEvent_is_enabled,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Check if synth. event is enabled."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 06/10] trace-cryncher: Add static methods for manipulating filters
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (4 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 05/10] trace-cruncher: APIs for enabling " Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 07/10] trace-cruncher: APIs for filtering synth. events Yordan Karadzhov (VMware)
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

All the code that can have a general use is extracted from the
implementation of the APIs for dealing with filters of dynamic
events and gets isolated in static methods. This is a preparation
for the implementation of the APIs for dealing with filters of
synthetic events. The new APIs for filtering synthetic events
will be implemented in a following patch.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 121 +++++++++++++++++++++++++++----------------
 1 file changed, 77 insertions(+), 44 deletions(-)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 8a0c3c3..af73784 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -2241,13 +2241,34 @@ PyObject *PyFtrace_register_kretprobe(PyObject *self, PyObject *args,
 	return PyDynevent_New(kprobe);
 }
 
-PyObject *PyDynevent_set_filter(PyDynevent *self, PyObject *args,
-						  PyObject *kwargs)
+struct tep_event *dynevent_get_event(PyDynevent *event,
+				     struct tep_handle **tep_ptr)
+{
+	struct tep_event *tep_evt;
+	struct tep_handle *tep;
+
+	tep = get_tep(NULL, NULL);
+	if (!tep)
+		return NULL;
+
+	tep_evt = tracefs_dynevent_get_event(tep, event->ptrObj);
+	if (!tep_evt) {
+		TfsError_setstr(NULL, "Failed to get dynevent.");
+		return NULL;
+	}
+
+	if (tep_ptr)
+		*tep_ptr = tep;
+
+	return tep_evt;
+}
+
+static PyObject *set_filter(PyObject *args, PyObject *kwargs,
+			    struct tep_handle *tep,
+			    struct tep_event *event)
 {
 	struct tracefs_instance *instance;
 	PyObject *py_inst = NULL;
-	struct tep_handle * tep;
-	struct tep_event *event;
 	const char *filter;
 
 	static char *kwlist[] = {"filter", "instance", NULL};
@@ -2263,16 +2284,6 @@ PyObject *PyDynevent_set_filter(PyDynevent *self, PyObject *args,
 	if (!get_optional_instance(py_inst, &instance))
 		return NULL;
 
-	tep = get_tep(NULL, NULL);
-	if (!tep)
-		return NULL;
-
-	event = tracefs_dynevent_get_event(tep, self->ptrObj);
-	if (!event) {
-		TfsError_setstr(NULL, "Failed to get event.");
-		return NULL;
-	}
-
 	if (tracefs_event_filter_apply(instance, event, filter) < 0) {
 		TfsError_fmt(NULL, "Failed to apply filter '%s' to event '%s'.",
 			     filter, event->name);
@@ -2282,59 +2293,36 @@ PyObject *PyDynevent_set_filter(PyDynevent *self, PyObject *args,
 	Py_RETURN_NONE;
 }
 
-PyObject *PyDynevent_get_filter(PyDynevent *self, PyObject *args,
-						  PyObject *kwargs)
+static PyObject *get_filter(PyObject *args, PyObject *kwargs,
+			    const char *system, const char* event )
 {
-	char *evt_name, *evt_system, *filter = NULL;
 	struct tracefs_instance *instance;
 	PyObject *ret = NULL;
+	char *filter = NULL;
 	char path[PATH_MAX];
-	int type;
 
 	if (!get_instance_from_arg(args, kwargs, &instance))
 		return NULL;
 
-	type = tracefs_dynevent_info(self->ptrObj, &evt_system, &evt_name,
-				     NULL, NULL, NULL);
-	if (type == TRACEFS_DYNEVENT_UNKNOWN) {
-		PyErr_SetString(TFS_ERROR, "Failed to get dynevent info.");
-		return NULL;
-	}
-
-	sprintf(path, "events/%s/%s/filter", evt_system, evt_name);
+	sprintf(path, "events/%s/%s/filter", system, event);
 	if (read_from_file(instance, path, &filter) <= 0)
-		goto free;
+		return NULL;
 
 	trim_new_line(filter);
 	ret = PyUnicode_FromString(filter);
- free:
-	free(evt_system);
-	free(evt_name);
 	free(filter);
 
 	return ret;
 }
 
-PyObject *PyDynevent_clear_filter(PyDynevent *self, PyObject *args,
-						    PyObject *kwargs)
+static PyObject *clear_filter(PyObject *args, PyObject *kwargs,
+			      struct tep_event *event)
 {
 	struct tracefs_instance *instance;
-	struct tep_handle * tep;
-	struct tep_event *event;
 
 	if (!get_instance_from_arg(args, kwargs, &instance))
 		return NULL;
 
-	tep = get_tep(NULL, NULL);
-	if (!tep)
-		return NULL;
-
-	event = tracefs_dynevent_get_event(tep, self->ptrObj);
-	if (!event) {
-		TfsError_setstr(NULL, "Failed to get event.");
-		return NULL;
-	}
-
 	if (tracefs_event_filter_clear(instance, event) < 0) {
 		TfsError_fmt(NULL, "Failed to clear filter for event '%s'.",
 			     event->name);
@@ -2344,6 +2332,51 @@ PyObject *PyDynevent_clear_filter(PyDynevent *self, PyObject *args,
 	Py_RETURN_NONE;
 }
 
+PyObject *PyDynevent_set_filter(PyDynevent *self, PyObject *args,
+						  PyObject *kwargs)
+{
+	struct tep_handle *tep;
+	struct tep_event *evt;
+
+	evt = dynevent_get_event(self, &tep);
+	if (!evt)
+		return NULL;
+
+	return set_filter(args, kwargs, tep, evt);
+}
+
+PyObject *PyDynevent_get_filter(PyDynevent *self, PyObject *args,
+						  PyObject *kwargs)
+{
+	struct tep_event *evt = dynevent_get_event(self, NULL);
+	char *evt_name, *evt_system;
+	int type;
+
+	if (!evt)
+		return NULL;
+
+	type = tracefs_dynevent_info(self->ptrObj, &evt_system, &evt_name,
+				     NULL, NULL, NULL);
+
+	if (type == TRACEFS_DYNEVENT_UNKNOWN) {
+		PyErr_SetString(TFS_ERROR, "Failed to get dynevent info.");
+		return NULL;
+	}
+
+	return get_filter(args, kwargs, evt_system, evt_name);
+}
+
+PyObject *PyDynevent_clear_filter(PyDynevent *self, PyObject *args,
+						    PyObject *kwargs)
+{
+	struct tep_event *evt = dynevent_get_event(self, NULL);
+
+	if (!evt)
+		return NULL;
+
+	return clear_filter(args, kwargs, evt);
+}
+
 static bool enable_dynevent(PyDynevent *self, PyObject *args, PyObject *kwargs,
 			  bool enable)
 {
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 07/10] trace-cruncher: APIs for filtering synth. events
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (5 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 06/10] trace-cryncher: Add static methods for manipulating filters Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 08/10] trace-cruncher: API to show descriptor of the synth. event Yordan Karadzhov (VMware)
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Here we add the following methods to the Python type for synthetic
events:
set_filter()
get_filter()
clear_filter()

The new APIs allow for easy manipulation of the filters associated
with a given synthetic event.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h |  9 +++++++
 src/ftracepy.c       | 15 ++++++++++++
 3 files changed, 80 insertions(+)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index af73784..43c0f07 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -2739,6 +2739,62 @@ PyObject *PySynthEvent_is_enabled(PySynthEvent *self, PyObject *args,
 				tracefs_synth_get_name(self->ptrObj));
 }
 
+struct tep_event *synth_get_event(PySynthEvent *event, struct tep_handle **tep_ptr)
+{
+	struct tep_event *tep_evt;
+	struct tep_handle *tep;
+
+	tep = get_tep(NULL, NULL);
+	if (!tep)
+		return NULL;
+
+	tep_evt = tracefs_synth_get_event(tep, event->ptrObj);
+	if (!tep_evt) {
+		TfsError_setstr(NULL, "Failed to get synth. event.");
+		return NULL;
+	}
+
+	if (tep_ptr)
+		*tep_ptr = tep;
+
+	return tep_evt;
+}
+
+PyObject *PySynthEvent_set_filter(PySynthEvent *self, PyObject *args,
+						      PyObject *kwargs)
+{
+	struct tep_handle *tep;
+	struct tep_event *evt;
+
+	evt = synth_get_event(self, &tep);
+	if (!evt)
+		return NULL;
+
+	return set_filter(args, kwargs, tep, evt);
+}
+
+PyObject *PySynthEvent_get_filter(PySynthEvent *self, PyObject *args,
+						      PyObject *kwargs)
+{
+	struct tep_event *evt = synth_get_event(self, NULL);
+
+	if (!evt)
+		return NULL;
+
+	return get_filter(args, kwargs, SYNTH_SYS, evt->name);
+}
+
+PyObject *PySynthEvent_clear_filter(PySynthEvent *self, PyObject *args,
+							PyObject *kwargs)
+{
+	struct tep_event *evt = synth_get_event(self, NULL);
+
+	if (!evt)
+		return NULL;
+
+	return clear_filter(args, kwargs, evt);
+}
+
 PyObject *PyFtrace_set_ftrace_loglevel(PyObject *self, PyObject *args,
 						       PyObject *kwargs)
 {
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index daf1a19..f31b330 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -152,6 +152,15 @@ PyObject *PySynthEvent_disable(PySynthEvent *self, PyObject *args,
 PyObject *PySynthEvent_is_enabled(PySynthEvent *self, PyObject *args,
 						      PyObject *kwargs);
 
+PyObject *PySynthEvent_set_filter(PySynthEvent *self, PyObject *args,
+						      PyObject *kwargs);
+
+PyObject *PySynthEvent_get_filter(PySynthEvent *self, PyObject *args,
+						      PyObject *kwargs);
+
+PyObject *PySynthEvent_clear_filter(PySynthEvent *self, PyObject *args,
+							PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_detach(PyObject *self, PyObject *args, PyObject *kwargs);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index 62c6de0..50675c0 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -277,6 +277,21 @@ static PyMethodDef PySynthEvent_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Check if synth. event is enabled."
 	},
+	{"set_filter",
+	 (PyCFunction) PySynthEvent_set_filter,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Define a filter for a synthetic event."
+	},
+	{"get_filter",
+	 (PyCFunction) PySynthEvent_get_filter,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Get the filter of a synthetic event."
+	},
+	{"clear_filter",
+	 (PyCFunction) PySynthEvent_clear_filter,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Clear the filter of a synthetic event."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 08/10] trace-cruncher: API to show descriptor of the synth. event
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (6 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 07/10] trace-cruncher: APIs for filtering synth. events Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 09/10] trace-cruncher: Add synthetic event example Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 10/10] trace-cruncher: Add synth. events tests Yordan Karadzhov (VMware)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Here we add the following method to the Python type for synthetic
events:
repr()

The new APIs provides a representative descriptor of the synth. event,
including the dynamic event and the two histograms. It can be useful
in the case where the user wants to check what exactly gets passed to
the kernel as definition of a synth event.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h |  2 ++
 src/ftracepy.c       |  5 +++++
 3 files changed, 59 insertions(+)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 43c0f07..8c46590 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -1192,6 +1192,58 @@ PyObject *PySynthEvent_unregister(PySynthEvent *self)
 	Py_RETURN_NONE;
 }
 
+PyObject *PySynthEvent_repr(PySynthEvent *self, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = {"event", "hist_start", "hist_end", NULL};
+	int event, hist_start, hist_end;
+	char buff[2048] = {0};
+	bool new_line = false;
+	const char *str = NULL;
+
+	event = hist_start = hist_end = true;
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "|ppp",
+					 kwlist,
+					 &event,
+					 &hist_start,
+					 &hist_end)) {
+		return NULL;
+	}
+
+	if (event) {
+		strcat(buff, "synth. event: ");
+		str = tracefs_synth_show_event(self->ptrObj);
+		if (str)
+			strcat(buff, str);
+		new_line = true;
+	}
+
+	if (hist_start) {
+		if (new_line)
+			strcat(buff, "\n");
+		else
+			new_line = true;
+
+		strcat(buff, "hist. start: ");
+		str = tracefs_synth_show_start_hist(self->ptrObj);
+		if (str)
+			strcat(buff, str);
+	}
+
+	if (hist_end) {
+		if (new_line)
+			strcat(buff, "\n");
+
+		strcat(buff, "hist. end: ");
+		str = tracefs_synth_show_end_hist(self->ptrObj);
+		if (str)
+			strcat(buff, str);
+	}
+
+	return PyUnicode_FromString(strdup(buff));
+}
+
 PyObject *PyFtrace_dir(PyObject *self)
 {
 	return PyUnicode_FromString(tracefs_tracing_dir());
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index f31b330..7612df6 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -161,6 +161,8 @@ PyObject *PySynthEvent_get_filter(PySynthEvent *self, PyObject *args,
 PyObject *PySynthEvent_clear_filter(PySynthEvent *self, PyObject *args,
 							PyObject *kwargs);
 
+PyObject *PySynthEvent_repr(PySynthEvent *self, PyObject *args, PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_detach(PyObject *self, PyObject *args, PyObject *kwargs);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index 50675c0..3f71b5e 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -292,6 +292,11 @@ static PyMethodDef PySynthEvent_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Clear the filter of a synthetic event."
 	},
+	{"repr",
+	 (PyCFunction) PySynthEvent_repr,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Show a representative descriptor of the synth. event."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 09/10] trace-cruncher: Add synthetic event example
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (7 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 08/10] trace-cruncher: API to show descriptor of the synth. event Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  2022-01-24  8:56 ` [PATCH 10/10] trace-cruncher: Add synth. events tests Yordan Karadzhov (VMware)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

This is a very basic example, demonsting the usage of the new APIs
for kernel synth. events.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 examples/synth.py | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100755 examples/synth.py

diff --git a/examples/synth.py b/examples/synth.py
new file mode 100755
index 0000000..ec9427b
--- /dev/null
+++ b/examples/synth.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+"""
+SPDX-License-Identifier: CC-BY-4.0
+
+Copyright 2021 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
+"""
+
+import tracecruncher.ftracepy as ft
+
+# Define a synthetic event that combines 'sched_waking' and 'sched_switch'.
+# A synth. event will be recorded every time a 'start' event (sched_waking)
+# is followed by an 'end' event (sched_switch) and both events have the same
+# value of the fields 'pid' and 'next_pid' (belong to the same process).
+synth = ft.synth(name='synth_wakeup',
+                 start_sys='sched', start_evt='sched_waking',
+                 end_sys='sched',   end_evt='sched_switch',
+                 start_match='pid', end_match='next_pid',
+                 match_name='pid')
+
+# Add to the synth. event two fields from the 'start' event. In the synth. event,
+# the field 'target_cpu' will be renamed to 'cpu'.
+synth.add_start_fields(fields=['target_cpu', 'prio'],
+                       names=['cpu', None])
+
+# Add to the synth. event one field from the 'end' event.
+synth.add_end_fields(fields=['next_prio'])
+
+# 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)
+
+# Register the synth. event on the system.
+synth.register()
+
+inst = ft.create_instance()
+
+# Apply a filter and enable the synth. event.
+synth.set_filter(instance=inst, filter='prio<100')
+synth.enable(instance=inst)
+
+# Print the stream of trace events. "Ctrl+c" to stop tracing.
+ft.read_trace(instance=inst)
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 10/10] trace-cruncher: Add synth. events tests
  2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
                   ` (8 preceding siblings ...)
  2022-01-24  8:56 ` [PATCH 09/10] trace-cruncher: Add synthetic event example Yordan Karadzhov (VMware)
@ 2022-01-24  8:56 ` Yordan Karadzhov (VMware)
  9 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-24  8:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

APIs for kernel synthetic events have been added.
Here we add the corresponding test cases.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 .../tests/1_unit/test_01_ftracepy_unit.py     | 86 +++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
index 51970d3..2de3d89 100644
--- a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
+++ b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
@@ -691,5 +691,91 @@ class HistOopTestCase(unittest.TestCase):
         self.assertTrue(err in str(context.exception))
 
 
+class SyntTestCase(unittest.TestCase):
+    def test_synt_create(self):
+        synth = ft.synth(name='wakeup_lat',
+                         start_sys='sched', start_evt='sched_waking',
+                         end_sys='sched',   end_evt='sched_switch',
+                         start_match='pid', end_match='next_pid',
+                         match_name='pid')
+
+        synth.add_start_fields(fields=['target_cpu', 'prio'],
+                               names=['cpu', None])
+        synth.add_end_fields(fields=['prev_prio', 'next_prio'],
+                             names=[None, 'nxt_p'])
+        synth.register()
+
+        event = synth.repr(event=True, hist_start=False, hist_end=False)
+        hist_s = synth.repr(event=False, hist_start=True, hist_end=False)
+        hist_e = synth.repr(event=False, hist_start=False, hist_end=True)
+
+        self.assertTrue('keys=pid'in hist_s)
+        self.assertTrue('keys=next_pid' in hist_e)
+        self.assertTrue('pid=next_pid' in hist_e)
+        self.assertTrue('onmatch(sched.sched_waking).trace(wakeup_lat,$pid' in hist_e)
+
+        self.assertTrue('s32 cpu;' in event)
+        self.assertTrue('s32 prio;' in event)
+        hist_s = synth.repr(event=False, hist_start=True, hist_end=False)
+        split_1 = hist_s.split('__arg_')
+        arg1 = '__arg_' + split_1[1].split('=')[0]
+        arg2 = '__arg_' + split_1[2].split('=')[0]
+        self.assertTrue(arg1 + '=target_cpu' in hist_s)
+        self.assertTrue(arg2 + '=prio' in hist_s)
+        hist_e = synth.repr(event=False, hist_start=False, hist_end=True)
+        self.assertTrue('cpu=$' + arg1 in hist_e)
+        self.assertTrue('prio=$' + arg2 in hist_e)
+        split_2 = hist_e.split('trace(')
+        self.assertTrue('$pid' in split_2[1])
+        self.assertTrue('$prio' in split_2[1])
+
+        event = synth.repr(event=True, hist_start=False, hist_end=False)
+        self.assertTrue('s32 prev_prio;' in event)
+        self.assertTrue('s32 nxt_p;' in event)
+        hist_e = synth.repr(event=False, hist_start=False, hist_end=True)
+        self.assertTrue('nxt_p=next_prio' in hist_e)
+        split_3 = hist_e.split('__arg_')
+        arg3 = '__arg_' + split_3[3].split('=')[0]
+        self.assertTrue(arg3 + '=prev_prio' in hist_e)
+        split_4 = hist_e.split('trace(')
+        self.assertTrue('$nxt_p' in split_4[1])
+        self.assertTrue('$' + arg3 in split_4[1])
+
+        synth.unregister()
+
+    def test_synt_enable(self):
+        synth = ft.synth(name='wakeup_lat',
+                         start_sys='sched', start_evt='sched_waking',
+                         end_sys='sched',   end_evt='sched_switch',
+                         start_match='pid', end_match='next_pid',
+                         match_name='pid')
+        synth.register()
+        ret = synth.is_enabled()
+        self.assertEqual(ret, '0')
+        synth.enable()
+        ret = synth.is_enabled()
+        self.assertEqual(ret, '1')
+        synth.disable()
+        ret = synth.is_enabled()
+        self.assertEqual(ret, '0')
+        synth.unregister()
+
+    def test_synt_enable(self):
+        evt_filter = 'prio<100'
+        synth = ft.synth(name='wakeup_lat',
+                         start_sys='sched', start_evt='sched_waking',
+                         end_sys='sched',   end_evt='sched_switch',
+                         start_match='pid', end_match='next_pid',
+                         match_name='pid')
+        synth.add_start_fields(fields=['prio'])
+        synth.register()
+        self.assertEqual('none', synth.get_filter())
+        synth.set_filter(filter=evt_filter)
+        self.assertEqual(evt_filter, synth.get_filter())
+        synth.clear_filter()
+        self.assertEqual('none', synth.get_filter())
+        synth.unregister()
+
+
 if __name__ == '__main__':
     unittest.main()
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2022-01-24  8:56 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-01-24  8:56 [PATCH 00/10] trace-cruncher: Synthetic events Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 01/10] trace-cruncher: Define Python type for synthetic events Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 02/10] trace-cruncher: APIs for adding start/end fields to synth. event Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 03/10] trace-cruncher: APIs for adding arithmetic fields to synth. events Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 04/10] trace-cruncher: APIs for registering/unregistering " Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 05/10] trace-cruncher: APIs for enabling " Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 06/10] trace-cryncher: Add static methods for manipulating filters Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 07/10] trace-cruncher: APIs for filtering synth. events Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 08/10] trace-cruncher: API to show descriptor of the synth. event Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 09/10] trace-cruncher: Add synthetic event example Yordan Karadzhov (VMware)
2022-01-24  8:56 ` [PATCH 10/10] trace-cruncher: Add synth. events tests Yordan Karadzhov (VMware)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).