linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] trace-cruncher: Add generic methods for printing
@ 2021-07-29 13:22 Yordan Karadzhov (VMware)
  2021-07-29 13:22 ` [PATCH 2/2] trace-cruncher: Provide short info print Yordan Karadzhov (VMware)
  0 siblings, 1 reply; 3+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-07-29 13:22 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

The new methods makes it easy to print:
 - the name and PID of the process that generated the trace record,
 - the unique fields of the record (called also 'info') or
 - all information for the event all together.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 examples/kprobe_open.py |   8 +-
 src/ftracepy-utils.c    | 159 ++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h    |   9 +++
 src/ftracepy.c          |  15 ++++
 4 files changed, 186 insertions(+), 5 deletions(-)

diff --git a/examples/kprobe_open.py b/examples/kprobe_open.py
index f8d4d8b..5b217d3 100755
--- a/examples/kprobe_open.py
+++ b/examples/kprobe_open.py
@@ -26,12 +26,10 @@ open_probe.add_ptr_arg(name='mode',
 
 open_probe.register()
 
+tep = tc.local_tep()
+
 def callback(event, record):
-    if event.id() == open_probe.id():
-        file_name = event.parse_record_field(record=record, field='file')
-        flags = event.parse_record_field(record, 'flags')
-        mode = event.parse_record_field(record, 'mode')
-        print('file: {0}  (flags: {1}; mode: {2})'.format(file_name, hex(flags), hex(mode)))
+    print(tep.info(event, record))
 
 
 if __name__ == "__main__":
diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 6739db7..3c000a7 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -298,6 +298,162 @@ PyObject *PyTep_get_event(PyTep *self, PyObject *args,
 	return PyTepEvent_New(event);
 }
 
+static struct trace_seq seq;
+
+static bool init_print_seq(void)
+{
+	if (!seq.buffer)
+		trace_seq_init(&seq);
+
+	if (!seq.buffer) {
+		PyErr_SetString(TFS_ERROR, "Unable to initialize 'trace_seq'.");
+		return false;
+	}
+
+	trace_seq_reset(&seq);
+
+	return true;
+}
+
+static char *get_comm_from_pid(int pid)
+{
+	char *comm_file, *comm = NULL;
+	char buff[PATH_MAX];
+	int fd, r;
+
+	if (asprintf(&comm_file, "/proc/%i/comm", pid) <= 0) {
+		MEM_ERROR;
+		return NULL;
+	}
+
+	/*
+	 * This file is not guaranteed to exist. Return NULL if the process
+	 * is no longer active.
+	 */
+	fd = open(comm_file, O_RDONLY);
+	free(comm_file);
+	if (fd < 0)
+		return NULL;
+
+	r = read(fd, buff, PATH_MAX);
+	close(fd);
+	if (r <= 0)
+		return NULL;
+
+	comm = strdup(buff);
+	if (!comm)
+		MEM_ERROR;
+
+	return comm;
+}
+
+static void print_comm_pid(struct tep_handle *tep,
+			   struct trace_seq *seq,
+			   struct tep_record *record,
+			   struct tep_event *event)
+{
+	int pid = get_pid(event, record);
+	if (!tep_is_pid_registered(tep, pid)) {
+		char *comm = get_comm_from_pid(pid);
+		if (comm) {
+			tep_register_comm(tep, comm, pid);
+			free(comm);
+		}
+	}
+
+	tep_print_event(tep, seq, record, "%s-%i",
+			TEP_PRINT_COMM,
+			TEP_PRINT_PID);
+}
+
+static void print_name_info(struct tep_handle *tep,
+			    struct trace_seq *seq,
+			    struct tep_record *record,
+			    struct tep_event *event)
+{
+	trace_seq_printf(seq, " %s: ", event->name);
+	tep_print_event(tep, seq, record, "%s", TEP_PRINT_INFO);
+}
+
+static void print_event(struct tep_handle *tep,
+			struct trace_seq *seq,
+			struct tep_record *record,
+			struct tep_event *event)
+{
+	tep_print_event(tep, seq, record, "%6.1000d ", TEP_PRINT_TIME);
+	print_comm_pid(tep, seq, record, event);
+	tep_print_event(tep, seq, record, " cpu=%i ", TEP_PRINT_CPU);
+	print_name_info(tep, seq, record, event);
+}
+
+static bool print_init(PyObject *args, PyObject *kwargs,
+		       struct tep_event **event,
+		       struct tep_record **record)
+{
+	static char *kwlist[] = { "event", "record", NULL};
+	PyTepRecord *py_record;
+	PyTepEvent *py_event;
+
+	if (!init_print_seq())
+		return false;
+
+	if(!PyArg_ParseTupleAndKeywords(args,
+					kwargs,
+					"OO",
+					kwlist,
+					&py_event,
+					&py_record)) {
+		return false;
+	}
+
+	*event = py_event->ptrObj;
+	*record = py_record->ptrObj;
+
+	return true;
+}
+
+PyObject *PyTep_event_record(PyTep *self, PyObject *args,
+					  PyObject *kwargs)
+{
+	struct tep_record *record;
+	struct tep_event *event;
+
+	if (!print_init(args, kwargs, &event, &record))
+		return NULL;
+
+	print_event(self->ptrObj, &seq, record, event);
+
+	return PyUnicode_FromString(seq.buffer);
+}
+
+PyObject *PyTep_info(PyTep *self, PyObject *args,
+				  PyObject *kwargs)
+{
+	struct tep_record *record;
+	struct tep_event *event;
+
+	if (!print_init(args, kwargs, &event, &record))
+		return NULL;
+
+	print_name_info(self->ptrObj, &seq, record, event);
+
+	return PyUnicode_FromString(seq.buffer);
+}
+
+PyObject *PyTep_process(PyTep *self, PyObject *args,
+				     PyObject *kwargs)
+{
+	struct tep_record *record;
+	struct tep_event *event;
+
+	if (!print_init(args, kwargs, &event, &record))
+		return NULL;
+
+	print_comm_pid(self->ptrObj, &seq, record, event);
+
+	return PyUnicode_FromString(seq.buffer);
+}
+
 static bool check_file(struct tracefs_instance *instance, const char *file)
 {
 	if (!tracefs_file_exists(instance, file)) {
@@ -2222,4 +2378,7 @@ void PyFtrace_at_exit(void)
 {
 	destroy_all_kprobes();
 	destroy_all_instances();
+
+	if (seq.buffer)
+		trace_seq_destroy(&seq);
 }
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index 5d7c19c..aca1ccc 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -44,6 +44,15 @@ PyObject *PyTep_init_local(PyTep *self, PyObject *args,
 PyObject *PyTep_get_event(PyTep *self, PyObject *args,
 				       PyObject *kwargs);
 
+PyObject *PyTep_event_record(PyTep *self, PyObject *args,
+					  PyObject *kwargs);
+
+PyObject *PyTep_info(PyTep *self, PyObject *args,
+				  PyObject *kwargs);
+
+PyObject *PyTep_process(PyTep *self, PyObject *args,
+				     PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_create_instance(PyObject *self, PyObject *args,
diff --git a/src/ftracepy.c b/src/ftracepy.c
index e3fec7b..e948b15 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -68,6 +68,21 @@ static PyMethodDef PyTep_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Get a PyTepEvent object."
 	},
+	{"event_record",
+	 (PyCFunction) PyTep_event_record,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Generic print of a trace event."
+	},
+	{"process",
+	 (PyCFunction) PyTep_process,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Generic print of the process that generated the trace event."
+	},
+	{"info",
+	 (PyCFunction) PyTep_info,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Generic print of a trace event info."
+	},
 	{NULL}
 };
 
-- 
2.30.2


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

* [PATCH 2/2] trace-cruncher: Provide short info print
  2021-07-29 13:22 [PATCH 1/2] trace-cruncher: Add generic methods for printing Yordan Karadzhov (VMware)
@ 2021-07-29 13:22 ` Yordan Karadzhov (VMware)
  0 siblings, 0 replies; 3+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-07-29 13:22 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

The default event handler for parsing ("info print") includes
the address of the probe. This address can be valuable for kernel
developers, but is meaningless if you only care for userspace.
Here we add a method that allows the user to register an alternative
event handler that doesn't show the address.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 examples/kprobe_open.py   |  5 ++--
 src/ftracepy-utils.c      | 54 +++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h      |  3 +++
 src/ftracepy.c            |  5 ++++
 tracecruncher/ft_utils.py |  7 +++++
 5 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/examples/kprobe_open.py b/examples/kprobe_open.py
index 5b217d3..7242e5e 100755
--- a/examples/kprobe_open.py
+++ b/examples/kprobe_open.py
@@ -17,16 +17,17 @@ open_probe.add_string_arg(name='file', param_id=2)
 
 open_probe.add_ptr_arg(name='flags',
                        param_id=3,
-                       param_type='x64')
+                       param_type='u64')
 
 open_probe.add_ptr_arg(name='mode',
                        param_id=3,
-                       param_type='x64',
+                       param_type='u64',
                        offset=8)
 
 open_probe.register()
 
 tep = tc.local_tep()
+tc.register_event_prints(tep, [open_probe])
 
 def callback(event, record):
     print(tep.info(event, record))
diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index 3c000a7..0f0e907 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -454,6 +454,60 @@ PyObject *PyTep_process(PyTep *self, PyObject *args,
 	return PyUnicode_FromString(seq.buffer);
 }
 
+static int info_short(struct trace_seq *s,
+		      struct tep_record *record,
+		      struct tep_event *event,
+		      void *context)
+{
+	struct tep_format_field *field;
+
+	field = event->format.fields->next;
+	while (field) {
+		/*
+		 * For the moment all number fields are printed as hex.
+		 *
+		 * TODO: Find a way to specify if the field will have
+		 * the bit flag TEP_FIELD_IS_LONG set at the time the
+		 * kprobe is created. This way we will be able to specify
+		 * if a number field in the probe will be printed as hex
+		 * or as dec.
+		 */
+		if (is_number(field))
+			field->flags |= TEP_FIELD_IS_LONG;
+
+		trace_seq_printf(s, " %s=", field->name);
+		tep_print_field(s, record->data, field);
+		field = field->next;
+	}
+
+	return 0;
+}
+
+PyObject *PyFtrace_register_event_print(PyTep *self, PyObject *args,
+						     PyObject *kwargs)
+{
+	static char *kwlist[] = {"system", "event", "id", NULL};
+	const char *system, *event;
+	int ret, id = -1;
+
+	system = event = NO_ARG;
+
+	if(!PyArg_ParseTupleAndKeywords(args,
+					kwargs,
+					"ss|i",
+					kwlist,
+					&system,
+					&event,
+					&id)) {
+		return false;
+	}
+
+	ret = tep_register_event_handler(self->ptrObj, id, system, event,
+					 info_short, NULL);
+
+	return PyLong_FromLong(ret);
+}
+
 static bool check_file(struct tracefs_instance *instance, const char *file)
 {
 	if (!tracefs_file_exists(instance, file)) {
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index aca1ccc..37b785e 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -53,6 +53,9 @@ PyObject *PyTep_info(PyTep *self, PyObject *args,
 PyObject *PyTep_process(PyTep *self, PyObject *args,
 				     PyObject *kwargs);
 
+PyObject *PyFtrace_register_event_print(PyTep *self, PyObject *args,
+						     PyObject *kwargs);
+
 PyObject *PyFtrace_dir(PyObject *self);
 
 PyObject *PyFtrace_create_instance(PyObject *self, PyObject *args,
diff --git a/src/ftracepy.c b/src/ftracepy.c
index e948b15..b095f64 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -83,6 +83,11 @@ static PyMethodDef PyTep_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Generic print of a trace event info."
 	},
+	{"register_event_parser",
+	 (PyCFunction) PyFtrace_register_event_print,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Register default event print."
+	},
 	{NULL}
 };
 
diff --git a/tracecruncher/ft_utils.py b/tracecruncher/ft_utils.py
index 8c245b1..9c4d330 100644
--- a/tracecruncher/ft_utils.py
+++ b/tracecruncher/ft_utils.py
@@ -29,6 +29,13 @@ def find_event_id(system, event):
     return tep.get_event(system=system, name=event).id()
 
 
+def register_event_prints(tep, events):
+    """ Register default (short) print for these events.
+    """
+    for e in events:
+        tep.register_event_parser(id=e.evt_id, system=e.system, event=e.name)
+
+
 class event:
     def __init__(self, system, name, static=True):
         """ Constructor.
-- 
2.30.2


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

* [PATCH 1/2] trace-cruncher: Add generic methods for printing
@ 2021-09-13 13:56 Yordan Karadzhov (VMware)
  0 siblings, 0 replies; 3+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-09-13 13:56 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

The new methods makes it easy to print:
 - the name and PID of the process that generated the trace record,
 - the unique fields of the record (called also 'info') or
 - all information for the event all together.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 examples/kprobe_open.py |   8 +-
 src/ftracepy-utils.c    | 168 ++++++++++++++++++++++++++++++++++++++++
 src/ftracepy-utils.h    |   9 +++
 src/ftracepy.c          |  15 ++++
 4 files changed, 195 insertions(+), 5 deletions(-)

diff --git a/examples/kprobe_open.py b/examples/kprobe_open.py
index 43b4212..99f6c8c 100755
--- a/examples/kprobe_open.py
+++ b/examples/kprobe_open.py
@@ -26,12 +26,10 @@ open_probe.add_ptr_arg(name='mode',
 
 open_probe.register()
 
+tep = tc.local_tep()
+
 def callback(event, record):
-    if event.id() == open_probe.id():
-        file_name = event.parse_record_field(record=record, field='file')
-        flags = event.parse_record_field(record, 'flags')
-        mode = event.parse_record_field(record, 'mode')
-        print('file: {0}  (flags: {1}; mode: {2})'.format(file_name, hex(flags), hex(mode)))
+    print(tep.info(event, record))
 
 
 if __name__ == "__main__":
diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c
index d4fa59e..c076d3b 100644
--- a/src/ftracepy-utils.c
+++ b/src/ftracepy-utils.c
@@ -367,6 +367,172 @@ PyObject *PyTep_get_event(PyTep *self, PyObject *args,
 	return PyTepEvent_New(event);
 }
 
+static struct trace_seq seq;
+
+static bool init_print_seq(void)
+{
+	if (!seq.buffer)
+		trace_seq_init(&seq);
+
+	if (!seq.buffer) {
+		PyErr_SetString(TFS_ERROR, "Unable to initialize 'trace_seq'.");
+		return false;
+	}
+
+	trace_seq_reset(&seq);
+
+	return true;
+}
+
+static char *get_comm_from_pid(int pid)
+{
+	char *comm_file, *comm = NULL;
+	char buff[PATH_MAX];
+	int fd, r;
+
+	if (asprintf(&comm_file, "/proc/%i/comm", pid) <= 0) {
+		MEM_ERROR;
+		return NULL;
+	}
+
+	/*
+	 * This file is not guaranteed to exist. Return NULL if the process
+	 * is no longer active.
+	 */
+	fd = open(comm_file, O_RDONLY);
+	free(comm_file);
+	if (fd < 0)
+		return NULL;
+
+	r = read(fd, buff, PATH_MAX);
+	close(fd);
+	if (r <= 0)
+		return NULL;
+
+	comm = strdup(buff);
+	if (!comm)
+		MEM_ERROR;
+
+	return comm;
+}
+
+static void print_comm_pid(struct tep_handle *tep,
+			   struct trace_seq *seq,
+			   struct tep_record *record,
+			   struct tep_event *event)
+{
+	int pid = get_pid(event, record);
+	if (!tep_is_pid_registered(tep, pid)) {
+		char *comm = get_comm_from_pid(pid);
+		if (comm) {
+			tep_register_comm(tep, comm, pid);
+			free(comm);
+		}
+	}
+
+	tep_print_event(tep, seq, record, "%s-%i",
+			TEP_PRINT_COMM,
+			TEP_PRINT_PID);
+}
+
+static void print_name_info(struct tep_handle *tep,
+			    struct trace_seq *seq,
+			    struct tep_record *record,
+			    struct tep_event *event)
+{
+	trace_seq_printf(seq, " %s: ", event->name);
+	tep_print_event(tep, seq, record, "%s", TEP_PRINT_INFO);
+}
+
+static void print_event(struct tep_handle *tep,
+			struct trace_seq *seq,
+			struct tep_record *record,
+			struct tep_event *event)
+{
+	tep_print_event(tep, seq, record, "%6.1000d ", TEP_PRINT_TIME);
+	print_comm_pid(tep, seq, record, event);
+	tep_print_event(tep, seq, record, " cpu=%i ", TEP_PRINT_CPU);
+	print_name_info(tep, seq, record, event);
+}
+
+static bool print_init(PyObject *args, PyObject *kwargs,
+		       struct tep_event **event,
+		       struct tep_record **record)
+{
+	static char *kwlist[] = { "event", "record", NULL};
+	PyObject *obj_rec, *obj_evt;
+	PyTepRecord *py_record;
+	PyTepEvent *py_event;
+
+	if (!init_print_seq())
+		return false;
+
+	if(!PyArg_ParseTupleAndKeywords(args,
+					kwargs,
+					"OO",
+					kwlist,
+					&obj_evt,
+					&obj_rec)) {
+		return false;
+	}
+
+	if (PyTepEvent_Check(obj_evt) && PyTepRecord_Check(obj_rec)) {
+		py_event = (PyTepEvent *)obj_evt;
+		*event = py_event->ptrObj;
+		py_record = (PyTepRecord *)obj_rec;
+		*record = py_record->ptrObj;
+
+		return true;
+	}
+
+	PyErr_SetString(TRACECRUNCHER_ERROR,
+			"Inconsistent arguments.");
+
+	return false;
+}
+
+PyObject *PyTep_event_record(PyTep *self, PyObject *args,
+					  PyObject *kwargs)
+{
+	struct tep_record *record;
+	struct tep_event *event;
+
+	if (!print_init(args, kwargs, &event, &record))
+		return NULL;
+
+	print_event(self->ptrObj, &seq, record, event);
+
+	return PyUnicode_FromString(seq.buffer);
+}
+
+PyObject *PyTep_info(PyTep *self, PyObject *args,
+				  PyObject *kwargs)
+{
+	struct tep_record *record;
+	struct tep_event *event;
+
+	if (!print_init(args, kwargs, &event, &record))
+		return NULL;
+
+	print_name_info(self->ptrObj, &seq, record, event);
+
+	return PyUnicode_FromString(seq.buffer);
+}
+
+PyObject *PyTep_process(PyTep *self, PyObject *args,
+				     PyObject *kwargs)
+{
+	struct tep_record *record;
+	struct tep_event *event;
+
+	if (!print_init(args, kwargs, &event, &record))
+		return NULL;
+
+	print_comm_pid(self->ptrObj, &seq, record, event);
+
+	return PyUnicode_FromString(seq.buffer);
+}
+
 static bool check_file(struct tracefs_instance *instance, const char *file)
 {
 	if (!tracefs_file_exists(instance, file)) {
@@ -2221,4 +2387,6 @@ PyObject *PyFtrace_clear_error_log(PyObject *self, PyObject *args,
 
 void PyFtrace_at_exit(void)
 {
+	if (seq.buffer)
+		trace_seq_destroy(&seq);
 }
diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h
index be1b37c..6c4a109 100644
--- a/src/ftracepy-utils.h
+++ b/src/ftracepy-utils.h
@@ -54,6 +54,15 @@ PyObject *PyTep_init_local(PyTep *self, PyObject *args,
 PyObject *PyTep_get_event(PyTep *self, PyObject *args,
 				       PyObject *kwargs);
 
+PyObject *PyTep_event_record(PyTep *self, PyObject *args,
+					  PyObject *kwargs);
+
+PyObject *PyTep_info(PyTep *self, PyObject *args,
+				  PyObject *kwargs);
+
+PyObject *PyTep_process(PyTep *self, PyObject *args,
+				     PyObject *kwargs);
+
 PyObject *PyTfsInstance_dir(PyTfsInstance *self);
 
 PyObject *PyKprobe_event(PyKprobe *self);
diff --git a/src/ftracepy.c b/src/ftracepy.c
index 763a7d2..c4458f0 100644
--- a/src/ftracepy.c
+++ b/src/ftracepy.c
@@ -68,6 +68,21 @@ static PyMethodDef PyTep_methods[] = {
 	 METH_VARARGS | METH_KEYWORDS,
 	 "Get a PyTepEvent object."
 	},
+	{"event_record",
+	 (PyCFunction) PyTep_event_record,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Generic print of a trace event."
+	},
+	{"process",
+	 (PyCFunction) PyTep_process,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Generic print of the process that generated the trace event."
+	},
+	{"info",
+	 (PyCFunction) PyTep_info,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Generic print of a trace event info."
+	},
 	{NULL}
 };
 
-- 
2.30.2


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

end of thread, other threads:[~2021-09-13 15:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-29 13:22 [PATCH 1/2] trace-cruncher: Add generic methods for printing Yordan Karadzhov (VMware)
2021-07-29 13:22 ` [PATCH 2/2] trace-cruncher: Provide short info print Yordan Karadzhov (VMware)
2021-09-13 13:56 [PATCH 1/2] trace-cruncher: Add generic methods for printing 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).