linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] trace-cruncher: Kernel histograms
@ 2021-12-07 14:28 Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 1/5] trace-cruncher: Define Python type for trace histograms Yordan Karadzhov (VMware)
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-12-07 14:28 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Adding support for trace histograms. Only the low level wrapper of
the libtracefs APIs is added here.


Yordan Karadzhov (VMware) (5):
  trace-cruncher: Define Python type for trace histograms
  trace-cruncher: Define constructor for trace histograms
  trace-cruncher: Add APIs to setup a histogram
  trace-cruncher: Add APIs for histogram control
  trace-cruncher: Add kernel histogram example

 examples/hist.py     |  66 ++++++
 src/common.h         |  10 +-
 src/ftracepy-utils.c | 526 +++++++++++++++++++++++++++++++++++++++----
 src/ftracepy-utils.h |  32 +++
 src/ftracepy.c       |  63 +++++-
 5 files changed, 650 insertions(+), 47 deletions(-)
 create mode 100755 examples/hist.py

-- 
2.32.0


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

* [PATCH 1/5] trace-cruncher: Define Python type for trace histograms
  2021-12-07 14:28 [PATCH 0/5] trace-cruncher: Kernel histograms Yordan Karadzhov (VMware)
@ 2021-12-07 14:28 ` Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 2/5] trace-cruncher: Define constructor " Yordan Karadzhov (VMware)
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-12-07 14:28 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

The new Python type will be used to implement new APIs for working
with histograms.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.h |  2 ++
 src/ftracepy.c       | 13 ++++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index 70e86ff..da31998 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -28,6 +28,8 @@ struct tracefs_dynevent;
 
 C_OBJECT_WRAPPER_DECLARE(tracefs_dynevent, PyDynevent);
 
+C_OBJECT_WRAPPER_DECLARE(tracefs_hist, PyTraceHist)
+
 PyObject *PyTepRecord_time(PyTepRecord* self);
 
 PyObject *PyTepRecord_cpu(PyTepRecord* self);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index fcc69dd..0f06796 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -168,6 +168,14 @@ C_OBJECT_WRAPPER(tracefs_dynevent, PyDynevent,
 		 dynevent_destroy,
 		 tracefs_dynevent_free)
 
+static PyMethodDef PyTraceHist_methods[] = {
+	{NULL, NULL, 0, NULL}
+};
+
+C_OBJECT_WRAPPER(tracefs_hist, PyTraceHist,
+		 NO_DESTROY,
+		 tracefs_hist_free)
+
 static PyMethodDef ftracepy_methods[] = {
 	{"dir",
 	 (PyCFunction) PyFtrace_dir,
@@ -387,6 +395,9 @@ PyMODINIT_FUNC PyInit_ftracepy(void)
 	if (!PyDyneventTypeInit())
 		return NULL;
 
+	if (!PyTraceHistTypeInit())
+		return NULL;
+
 	TFS_ERROR = PyErr_NewException("tracecruncher.ftracepy.tfs_error",
 				       NULL, NULL);
 
@@ -403,7 +414,7 @@ PyMODINIT_FUNC PyInit_ftracepy(void)
 	PyModule_AddObject(module, "tep_record", (PyObject *) &PyTepRecordType);
 	PyModule_AddObject(module, "tracefs_instance", (PyObject *) &PyTfsInstanceType);
 	PyModule_AddObject(module, "tracefs_dynevent", (PyObject *) &PyDyneventType);
-
+	PyModule_AddObject(module, "tracefs_hist", (PyObject *) &PyTraceHistType);
 
 	PyModule_AddObject(module, "tfs_error", TFS_ERROR);
 	PyModule_AddObject(module, "tep_error", TEP_ERROR);
-- 
2.32.0


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

* [PATCH 2/5] trace-cruncher: Define constructor for trace histograms
  2021-12-07 14:28 [PATCH 0/5] trace-cruncher: Kernel histograms Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 1/5] trace-cruncher: Define Python type for trace histograms Yordan Karadzhov (VMware)
@ 2021-12-07 14:28 ` Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 3/5] trace-cruncher: Add APIs to setup a histogram Yordan Karadzhov (VMware)
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-12-07 14:28 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

A method for creating histogram objects is added. The optional arguments
of the method allows for variety of ways to create histograms.

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

diff --git a/src/common.h b/src/common.h
index 9eee563..eacea7d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -26,10 +26,9 @@ static const char *NO_ARG = "/NONE/";
 
 #define TC_NIL_MSG	"(nil)"
 
-static inline bool is_all(const char *arg)
+static inline bool lax_cmp(const char *arg, const char *model)
 {
-	const char all[] = "all";
-	const char *p = &all[0];
+	const char *p = &model[0];
 
 	for (; *arg; arg++, p++) {
 		if (tolower(*arg) != *p)
@@ -38,6 +37,11 @@ static inline bool is_all(const char *arg)
 	return !(*p);
 }
 
+static inline bool is_all(const char *arg)
+{
+	return lax_cmp(arg, "all");
+}
+
 static inline bool is_no_arg(const char *arg)
 {
 	return arg[0] == '\0' || arg == NO_ARG;
diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 7f3daca..65aca81 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -1954,6 +1954,201 @@ PyObject *PyDynevent_is_enabled(PyDynevent *self, PyObject *args,
 	return ret;
 }
 
+static enum tracefs_hist_key_type hist_key_type(PyObject * py_type)
+{
+	int type = -1;
+
+	if (PyUnicode_Check(py_type)) {
+		const char *type_str = PyUnicode_DATA(py_type);
+
+		if (lax_cmp(type_str, "normal") ||
+		    lax_cmp(type_str, "n") )
+			type = TRACEFS_HIST_KEY_NORMAL;
+		else if (lax_cmp(type_str, "hex") ||
+			 lax_cmp(type_str, "h") )
+			type = TRACEFS_HIST_KEY_HEX;
+		else if (lax_cmp(type_str, "sym"))
+			 type = TRACEFS_HIST_KEY_SYM;
+		else if (lax_cmp(type_str, "sym_offset") ||
+			 lax_cmp(type_str, "so"))
+			type = TRACEFS_HIST_KEY_SYM_OFFSET;
+		else if (lax_cmp(type_str, "syscall") ||
+			 lax_cmp(type_str, "sc"))
+			type = TRACEFS_HIST_KEY_SYSCALL;
+		else if (lax_cmp(type_str, "execname") ||
+			 lax_cmp(type_str, "e"))
+			 type = TRACEFS_HIST_KEY_EXECNAME;
+		else if (lax_cmp(type_str, "log") ||
+			 lax_cmp(type_str, "l"))
+			type = TRACEFS_HIST_KEY_LOG;
+		else if (lax_cmp(type_str, "users") ||
+			 lax_cmp(type_str, "u"))
+			type = TRACEFS_HIST_KEY_USECS;
+		else if (lax_cmp(type_str, "max") ||
+			 lax_cmp(type_str, "m"))
+			type = TRACEFS_HIST_KEY_MAX;
+		else {
+			TfsError_fmt(NULL, "Unknown axis type %s\n",
+				     type_str);
+		}
+	} else if (PyLong_CheckExact(py_type)) {
+		type = PyLong_AsLong(py_type);
+	} else {
+		TfsError_fmt(NULL, "Unknown axis type %s\n");
+	}
+
+	return type;
+}
+
+static struct tracefs_hist *hist_from_key(struct tep_handle *tep,
+					  const char *system, const char *event,
+					  PyObject *py_key, PyObject * py_type)
+{
+	struct tracefs_hist *hist = NULL;
+	int type = 0;
+
+	if (PyUnicode_Check(py_key)) {
+		if (py_type) {
+			type = hist_key_type(py_type);
+			if (type < 0)
+				return NULL;
+		}
+
+		hist = tracefs_hist_alloc(tep, system, event,
+					  PyUnicode_DATA(py_key), type);
+	} else if (PyList_CheckExact(py_key)) {
+		int i, n_keys = PyList_Size(py_key);
+		struct tracefs_hist_axis *axes;
+		PyObject *item_type;
+
+		if (py_type) {
+			/*
+			 * The format of the types have to match the format
+			 * of the keys.
+			 */
+			if (!PyList_CheckExact(py_key) ||
+			    PyList_Size(py_type) != n_keys)
+				return NULL;
+		}
+
+		axes = calloc(n_keys + 1, sizeof(*axes));
+		if (!axes) {
+			MEM_ERROR
+			return NULL;
+		}
+
+		for (i = 0; i < n_keys; ++i) {
+			axes[i].key = str_from_list(py_key, i);
+			if (!axes[i].key)
+				return NULL;
+
+			if (py_type) {
+				item_type = PyList_GetItem(py_type, i);
+				if (!PyLong_CheckExact(item_type))
+					return NULL;
+
+				type = hist_key_type(item_type);
+				if (type < 0)
+					return NULL;
+
+				axes[i].type = type;
+			}
+		}
+
+		hist = tracefs_hist_alloc_nd(tep, system, event, axes);
+		free(axes);
+	}
+
+	return hist;
+}
+
+static struct tracefs_hist *hist_from_axis(struct tep_handle *tep,
+					   const char *system, const char *event,
+					   PyObject *py_axes)
+{
+	struct tracefs_hist *hist = NULL;
+	struct tracefs_hist_axis *axes;
+	PyObject *key, *value;
+	Py_ssize_t i = 0;
+	int n_axes;
+
+	n_axes = PyDict_Size(py_axes);
+	if (PyErr_Occurred())
+		return NULL;
+
+	axes = calloc(n_axes + 1, sizeof(*axes));
+	if (!axes) {
+		MEM_ERROR
+		return NULL;
+	}
+
+	while (PyDict_Next(py_axes, &i, &key, &value)) {
+		axes[i - 1].key = PyUnicode_DATA(key);
+		axes[i - 1].type = hist_key_type(value);
+		if (PyErr_Occurred()) {
+			PyErr_Print();
+			free(axes);
+			return NULL;
+		}
+	}
+
+	hist = tracefs_hist_alloc_nd(tep, system, event, axes);
+	free(axes);
+
+	return hist;
+}
+
+PyObject *PyFtrace_hist(PyObject *self, PyObject *args,
+					PyObject *kwargs)
+{
+	static char *kwlist[] =
+		{"system", "event", "key", "type", "axes", "name", NULL};
+	PyObject *py_axes = NULL, *py_key = NULL, *py_type = NULL;
+	const char *system, *event, *name = NULL;
+	struct tracefs_hist *hist = NULL;
+	struct tep_handle *tep;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "ss|OOOs",
+					 kwlist,
+					 &system,
+					 &event,
+					 &py_key,
+					 &py_type,
+					 &py_axes,
+					 &name)) {
+		return NULL;
+	}
+
+	tep = tracefs_local_events(tracefs_tracing_dir());
+	if (!tep)
+		goto fail;
+
+	if (py_key && ! py_axes) {
+		hist = hist_from_key(tep, system, event, py_key, py_type);
+	} else if (!py_key && py_axes) {
+		hist = hist_from_axis(tep, system, event, py_axes);
+	} else {
+		TfsError_setstr(NULL, "'key' or 'axis' must be provided.");
+		return NULL;
+	}
+
+	if (!hist)
+		goto fail;
+
+	if (name && tracefs_hist_add_name(hist, name) < 0)
+		goto fail;
+
+	return PyTraceHist_New(hist);
+
+ fail:
+	TfsError_fmt(NULL, "Failed to create histogram for %s/%s",
+		     system, event);
+	tracefs_hist_free(hist);
+	return NULL;
+}
+
 PyObject *PyFtrace_set_ftrace_loglevel(PyObject *self, PyObject *args,
 						       PyObject *kwargs)
 {
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index da31998..f69a6d4 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -178,6 +178,9 @@ PyObject *PyFtrace_register_kprobe(PyObject *self, PyObject *args,
 PyObject *PyFtrace_register_kretprobe(PyObject *self, PyObject *args,
 						      PyObject *kwargs);
 
+PyObject *PyFtrace_hist(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 0f06796..7891b5e 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -327,6 +327,11 @@ static PyMethodDef ftracepy_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Define a kretprobe."
 	},
+	{"hist",
+	 (PyCFunction) PyFtrace_hist,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Define a histogram."
+	},
 	{"set_ftrace_loglevel",
 	 (PyCFunction) PyFtrace_set_ftrace_loglevel,
 	 METH_VARARGS | METH_KEYWORDS,
-- 
2.32.0


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

* [PATCH 3/5] trace-cruncher: Add APIs to setup a histogram
  2021-12-07 14:28 [PATCH 0/5] trace-cruncher: Kernel histograms Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 1/5] trace-cruncher: Define Python type for trace histograms Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 2/5] trace-cruncher: Define constructor " Yordan Karadzhov (VMware)
@ 2021-12-07 14:28 ` Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 4/5] trace-cruncher: Add APIs for histogram control Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 5/5] trace-cruncher: Add kernel histogram example Yordan Karadzhov (VMware)
  4 siblings, 0 replies; 6+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-12-07 14:28 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

More methods for controlling the data acquisition of the histogram
are added.

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

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 65aca81..d7e6d6a 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -707,6 +707,135 @@ PyObject *PyTfsInstance_dir(PyTfsInstance *self)
 	return PyUnicode_FromString(tracefs_instance_get_dir(self->ptrObj));
 }
 
+PyObject *PyTraceHist_add_value(PyTraceHist *self, PyObject *args,
+						   PyObject *kwargs)
+{
+	static char *kwlist[] = {"value", NULL};
+	const char *value;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "s",
+					 kwlist,
+					 &value)) {
+		return NULL;
+	}
+
+	if (tracefs_hist_add_value(self->ptrObj, value) < 0) {
+		MEM_ERROR
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
+const char *hist_noname = "unnamed";
+static inline const char *get_hist_name(struct tracefs_hist *hist)
+{
+	const char *name = tracefs_hist_get_name(hist);
+	return name ? name : hist_noname;
+}
+
+static bool add_sort_key(struct tracefs_hist *hist,
+			 const char *sort_key)
+{
+	if (tracefs_hist_add_sort_key(hist, sort_key) < 0) {
+		TfsError_fmt(NULL,
+			     "Failed to add sort key \'%s\'to histogram \'%s\'.",
+			     sort_key, get_hist_name(hist));
+		return false;
+	}
+
+	return true;
+}
+
+PyObject *PyTraceHist_sort_keys(PyTraceHist *self, PyObject *args,
+						   PyObject *kwargs)
+{
+	static char *kwlist[] = {"keys", NULL};
+	PyObject *py_obj;
+	const char *key;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "O",
+					 kwlist,
+					 &py_obj)) {
+		return NULL;
+	}
+
+	if (PyUnicode_Check(py_obj)) {
+		if (!add_sort_key(self->ptrObj, PyUnicode_DATA(py_obj)))
+			return NULL;
+	} else if (PyList_CheckExact(py_obj)) {
+		int i, n = PyList_Size(py_obj);
+
+		for (i = 0; i < n; ++i) {
+			key = str_from_list(py_obj, i);
+			if (!key ||
+			    !add_sort_key(self->ptrObj, key)) {
+				PyErr_SetString(TRACECRUNCHER_ERROR,
+						"Inconsistent \"keys\" argument.");
+				return NULL;
+			}
+		}
+	}
+
+	Py_RETURN_NONE;
+}
+
+static int sort_direction(PyObject *py_dir)
+{
+	int dir = -1;
+
+	if (PyLong_CheckExact(py_dir)) {
+		dir = PyLong_AsLong(py_dir);
+	} else if (PyUnicode_Check(py_dir)) {
+		const char *dir_str =  PyUnicode_DATA(py_dir);
+
+		if (lax_cmp(dir_str, "descending") ||
+		    lax_cmp(dir_str, "desc") ||
+		    lax_cmp(dir_str, "d"))
+			dir = 1;
+		else if (lax_cmp(dir_str, "ascending") ||
+			 lax_cmp(dir_str, "asc") ||
+			 lax_cmp(dir_str, "a"))
+			dir = 0;
+	}
+
+	return dir;
+}
+
+PyObject *PyTraceHist_sort_key_direction(PyTraceHist *self, PyObject *args,
+							    PyObject *kwargs)
+{
+	static char *kwlist[] = {"sort_key", "direction", NULL};
+	const char *sort_key;
+	PyObject *py_dir;
+	int dir;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "sO",
+					 kwlist,
+					 &sort_key,
+					 &py_dir)) {
+		return NULL;
+	}
+
+	dir = sort_direction(py_dir);
+
+	if (dir < 0 ||
+	    tracefs_hist_sort_key_direction(self->ptrObj, sort_key, dir) < 0) {
+		TfsError_fmt(NULL,
+			     "Failed to add sort direction to histogram \'%s\'.",
+			     get_hist_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 f69a6d4..07d2cac 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -92,6 +92,15 @@ PyObject *PyDynevent_disable(PyDynevent *self, PyObject *args,
 PyObject *PyDynevent_is_enabled(PyDynevent *self, PyObject *args,
 					      PyObject *kwargs);
 
+PyObject *PyTraceHist_add_value(PyTraceHist *self, PyObject *args,
+						   PyObject *kwargs);
+
+PyObject *PyTraceHist_sort_keys(PyTraceHist *self, PyObject *args,
+						   PyObject *kwargs);
+
+PyObject *PyTraceHist_sort_key_direction(PyTraceHist *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 7891b5e..b91cda9 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -169,6 +169,21 @@ C_OBJECT_WRAPPER(tracefs_dynevent, PyDynevent,
 		 tracefs_dynevent_free)
 
 static PyMethodDef PyTraceHist_methods[] = {
+	{"add_value",
+	 (PyCFunction) PyTraceHist_add_value,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Add value field."
+	},
+	{"sort_keys",
+	 (PyCFunction) PyTraceHist_sort_keys,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Set key felds or values to sort on."
+	},
+	{"sort_key_direction",
+	 (PyCFunction) PyTraceHist_sort_key_direction,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Set the direction of a sort key field."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


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

* [PATCH 4/5] trace-cruncher: Add APIs for histogram control
  2021-12-07 14:28 [PATCH 0/5] trace-cruncher: Kernel histograms Yordan Karadzhov (VMware)
                   ` (2 preceding siblings ...)
  2021-12-07 14:28 ` [PATCH 3/5] trace-cruncher: Add APIs to setup a histogram Yordan Karadzhov (VMware)
@ 2021-12-07 14:28 ` Yordan Karadzhov (VMware)
  2021-12-07 14:28 ` [PATCH 5/5] trace-cruncher: Add kernel histogram example Yordan Karadzhov (VMware)
  4 siblings, 0 replies; 6+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-12-07 14:28 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

This is an almost direct wrapping of the corresponding APIs defined in
libtracefs. The 'continue' API (tracefs_hist_continue()) gets renamed
to resume(), because 'continue' is a keyword in Python.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/ftracepy-utils.c | 202 ++++++++++++++++++++++++++++++++++---------
 src/ftracepy-utils.h |  18 ++++
 src/ftracepy.c       |  30 +++++++
 3 files changed, 207 insertions(+), 43 deletions(-)

diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index d7e6d6a..a735d88 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -836,6 +836,165 @@ PyObject *PyTraceHist_sort_key_direction(PyTraceHist *self, PyObject *args,
 	Py_RETURN_NONE;
 }
 
+static bool get_optional_instance(PyObject *py_obj,
+				  struct tracefs_instance **instance)
+{
+	PyTfsInstance *py_inst;
+
+	if (!py_obj) {
+		*instance = NULL;
+		return true;
+	}
+
+	if (!PyTfsInstance_Check(py_obj)) {
+		PyErr_SetString(TRACECRUNCHER_ERROR,
+				"Passing argument \'instance\' with incompatible type.");
+		return false;
+	}
+
+	py_inst = (PyTfsInstance *)py_obj;
+	*instance = py_inst->ptrObj;
+
+	return true;
+}
+
+bool get_instance_from_arg(PyObject *args, PyObject *kwargs,
+			   struct tracefs_instance **instance)
+{
+	static char *kwlist[] = {"instance", NULL};
+	PyObject *py_inst = NULL;
+	*instance = NULL;
+
+	if (!PyArg_ParseTupleAndKeywords(args,
+					 kwargs,
+					 "|O",
+					 kwlist,
+					 &py_inst)) {
+		return false;
+	}
+
+	if (!get_optional_instance(py_inst, instance))
+		return NULL;
+
+	return true;
+}
+
+static bool hist_cmd(PyTraceHist *self, PyObject *args, PyObject *kwargs,
+		     enum tracefs_hist_command cmd,
+		     const char *err_msg)
+{
+	struct tracefs_instance *instance;
+
+	if (!get_instance_from_arg(args, kwargs, &instance))
+		return NULL;
+
+	if (tracefs_hist_command(instance, self->ptrObj, cmd) < 0) {
+		char *buff;
+
+		if (asprintf(&buff, "%s %s",
+			     err_msg, get_hist_name(self->ptrObj)) <= 0) {
+			MEM_ERROR;
+			return false;
+		}
+
+		TfsError_setstr(instance, buff);
+		free(buff);
+
+		return false;
+	}
+
+	return true;
+}
+
+PyObject *PyTraceHist_start(PyTraceHist *self, PyObject *args,
+					       PyObject *kwargs)
+{
+	if (!hist_cmd(self, args, kwargs,
+		      TRACEFS_HIST_CMD_START,
+		      "Failed to start filling the histogram"))
+		return false;
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PyTraceHist_stop(PyTraceHist *self, PyObject *args,
+					      PyObject *kwargs)
+{
+	if (!hist_cmd(self, args, kwargs,
+		      TRACEFS_HIST_CMD_PAUSE,
+		      "Failed to stop filling the histogram"))
+		return false;
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PyTraceHist_resume(PyTraceHist *self, PyObject *args,
+						PyObject *kwargs)
+{
+	if (!hist_cmd(self, args, kwargs,
+		      TRACEFS_HIST_CMD_CONT,
+		      "Failed to resume filling the histogram"))
+		return false;
+
+	Py_RETURN_NONE;
+}
+
+PyObject *PyTraceHist_clear(PyTraceHist *self, PyObject *args,
+					       PyObject *kwargs)
+{
+	if (!hist_cmd(self, args, kwargs,
+		      TRACEFS_HIST_CMD_CLEAR,
+		      "Failed to clear the histogram"))
+		return false;
+
+	Py_RETURN_NONE;
+}
+
+static char *hist_read(PyTraceHist *self, PyObject *args,
+					  PyObject *kwargs)
+{
+	struct tracefs_instance *instance;
+	const char *hist_file = "hist";
+	char *data;
+
+	if (!get_instance_from_arg(args, kwargs, &instance))
+		return NULL;
+
+	data = tracefs_event_file_read(instance,
+				       tracefs_hist_get_system(self->ptrObj),
+				       tracefs_hist_get_event(self->ptrObj),
+				       hist_file,
+				       NULL);
+	if (!data) {
+		TfsError_fmt(instance,
+			     "Failed read data from histogram \'%s\'.",
+			     get_hist_name(self->ptrObj));
+	}
+
+	return data;
+}
+
+PyObject *PyTraceHist_read(PyTraceHist *self, PyObject *args,
+					      PyObject *kwargs)
+{
+	char *data = hist_read(self, args, kwargs);
+	PyObject *ret = PyUnicode_FromString(data);
+
+	free(data);
+	return ret;
+}
+
+PyObject *PyTraceHist_close(PyTraceHist *self, PyObject *args,
+					       PyObject *kwargs)
+{
+	if (!hist_cmd(self, args, kwargs,
+		      TRACEFS_HIST_CMD_DESTROY,
+		      "Failed to close the histogram"))
+		return false;
+
+	Py_RETURN_NONE;
+}
+
 PyObject *PyFtrace_dir(PyObject *self)
 {
 	return PyUnicode_FromString(tracefs_tracing_dir());
@@ -967,49 +1126,6 @@ PyObject *PyFtrace_find_instance(PyObject *self, PyObject *args,
 	return py_inst;
 }
 
-static bool get_optional_instance(PyObject *py_obj,
-				  struct tracefs_instance **instance)
-{
-	PyTfsInstance *py_inst;
-
-	if (!py_obj) {
-		*instance = NULL;
-		return true;
-	}
-
-	if (!PyTfsInstance_Check(py_obj)) {
-		PyErr_SetString(TRACECRUNCHER_ERROR,
-				"Passing argument \'instance\' with incompatible type.");
-		return false;
-	}
-
-	py_inst = (PyTfsInstance *)py_obj;
-	*instance = py_inst->ptrObj;
-
-	return true;
-}
-
-bool get_instance_from_arg(PyObject *args, PyObject *kwargs,
-			   struct tracefs_instance **instance)
-{
-	static char *kwlist[] = {"instance", NULL};
-	PyObject *py_inst = NULL;
-	*instance = NULL;
-
-	if (!PyArg_ParseTupleAndKeywords(args,
-					 kwargs,
-					 "|O",
-					 kwlist,
-					 &py_inst)) {
-		return false;
-	}
-
-	if (!get_optional_instance(py_inst, instance))
-		return NULL;
-
-	return true;
-}
-
 PyObject *PyFtrace_available_tracers(PyObject *self, PyObject *args,
 						     PyObject *kwargs)
 {
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index 07d2cac..d09c8bf 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -101,6 +101,24 @@ PyObject *PyTraceHist_sort_keys(PyTraceHist *self, PyObject *args,
 PyObject *PyTraceHist_sort_key_direction(PyTraceHist *self, PyObject *args,
 							    PyObject *kwargs);
 
+PyObject *PyTraceHist_start(PyTraceHist *self, PyObject *args,
+					       PyObject *kwargs);
+
+PyObject *PyTraceHist_stop(PyTraceHist *self, PyObject *args,
+					      PyObject *kwargs);
+
+PyObject *PyTraceHist_resume(PyTraceHist *self, PyObject *args,
+						PyObject *kwargs);
+
+PyObject *PyTraceHist_clear(PyTraceHist *self, PyObject *args,
+					       PyObject *kwargs);
+
+PyObject *PyTraceHist_read(PyTraceHist *self, PyObject *args,
+					      PyObject *kwargs);
+
+PyObject *PyTraceHist_close(PyTraceHist *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 b91cda9..b270b71 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -184,6 +184,36 @@ static PyMethodDef PyTraceHist_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Set the direction of a sort key field."
 	},
+	{"start",
+	 (PyCFunction) PyTraceHist_start,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Start acquiring data."
+	},
+	{"stop",
+	 (PyCFunction) PyTraceHist_stop,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Pause acquiring data."
+	},
+	{"resume",
+	 (PyCFunction) PyTraceHist_resume,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Continue acquiring data."
+	},
+	{"clear",
+	 (PyCFunction) PyTraceHist_clear,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Reset the histogram."
+	},
+	{"read",
+	 (PyCFunction) PyTraceHist_read,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Read the content of the histogram."
+	},
+	{"close",
+	 (PyCFunction) PyTraceHist_close,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Destroy the histogram."
+	},
 	{NULL, NULL, 0, NULL}
 };
 
-- 
2.32.0


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

* [PATCH 5/5] trace-cruncher: Add kernel histogram example
  2021-12-07 14:28 [PATCH 0/5] trace-cruncher: Kernel histograms Yordan Karadzhov (VMware)
                   ` (3 preceding siblings ...)
  2021-12-07 14:28 ` [PATCH 4/5] trace-cruncher: Add APIs for histogram control Yordan Karadzhov (VMware)
@ 2021-12-07 14:28 ` Yordan Karadzhov (VMware)
  4 siblings, 0 replies; 6+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-12-07 14:28 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

This is a very basic possible example, demonstration the usage of
the new APIs for kernel histograms.

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

diff --git a/examples/hist.py b/examples/hist.py
new file mode 100755
index 0000000..d668039
--- /dev/null
+++ b/examples/hist.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+"""
+SPDX-License-Identifier: CC-BY-4.0
+
+Copyright 2021 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
+"""
+
+import sys
+import time
+
+import tracecruncher.ftracepy as ft
+
+inst_name = 'khist_example'
+
+cmds = ['start', 'stop', 'show', 'continue', 'clear', 'close']
+
+def get_hist():
+    hist = ft.hist(name='h1',
+                   system='kmem',
+                   event='kmalloc',
+                   axes={'call_site': 'sym',
+                         'bytes_req': 'n'})
+
+    hist.add_value(value='bytes_alloc')
+    hist.sort_keys(keys=['bytes_req', 'bytes_alloc'])
+    hist.sort_key_direction(sort_key='bytes_req', direction='desc')
+
+    return hist
+
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        sys.exit(1)
+
+    if not sys.argv[1].isdigit() and not sys.argv[1] in cmds:
+        sys.exit(1)
+
+    arg1 = sys.argv[1]
+    if  arg1.isdigit() or arg1 == 'start':
+        inst = ft.create_instance(name=inst_name)
+        hist = get_hist()
+        hist.start(inst)
+
+        if arg1.isdigit():
+            time.sleep(int(arg1))
+            hist.stop(inst)
+            print(hist.read(inst))
+            hist.close(inst)
+        else:
+            ft.detach(inst)
+    else:
+        inst = ft.find_instance(name=inst_name)
+        hist = get_hist()
+
+        if arg1 == 'stop':
+            hist.stop(inst)
+        elif arg1 == 'show':
+            print(hist.read(inst))
+        elif arg1 == 'continue':
+            hist.resume(inst)
+        elif arg1 == 'clear':
+            hist.clear(inst)
+
+        if arg1 == 'close':
+            ft.attach(inst)
+            hist.close(inst)
-- 
2.32.0


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

end of thread, other threads:[~2021-12-07 14:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-07 14:28 [PATCH 0/5] trace-cruncher: Kernel histograms Yordan Karadzhov (VMware)
2021-12-07 14:28 ` [PATCH 1/5] trace-cruncher: Define Python type for trace histograms Yordan Karadzhov (VMware)
2021-12-07 14:28 ` [PATCH 2/5] trace-cruncher: Define constructor " Yordan Karadzhov (VMware)
2021-12-07 14:28 ` [PATCH 3/5] trace-cruncher: Add APIs to setup a histogram Yordan Karadzhov (VMware)
2021-12-07 14:28 ` [PATCH 4/5] trace-cruncher: Add APIs for histogram control Yordan Karadzhov (VMware)
2021-12-07 14:28 ` [PATCH 5/5] trace-cruncher: Add kernel histogram example 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).