Skip to contentSkip to conversation

perf python: Add support to access tracepoint fields

PATCH Superseded Jiri Olsa 6 participants 16 messages Jul 15, 2016 – Jul 16, 2016 perf events

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Jiri Olsa

author reviewer
#0 lore raw

v2 cover perf python: Add support to access tracepoint fields

hi,
adding support to access tracepoint fields in python scripts.

v2 changes:
- most of the patches is already pulled in,
this is just leftover
- fixed is_printable_array [Steven]
- making is_printable_array global
- attached unrelated fix 3/3

With this patchset it's possible to access tracepoint fields in event python object like:

print "time %u prev_comm=%s prev_pid=%d prev_prio=%d prev_state=0x%x ==> next_comm=%s next_pid=%d next_prio=%d" % (
event.sample_time,
event.prev_comm,
event.prev_pid,
event.prev_prio,
event.prev_state,
event.next_comm,
event.next_pid,
event.next_prio)

Also available in:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/fixes

thanks,
jirka

Cc Steven Rostedt (Red Hat) <[email protected]>
Cc Jiri Pirko <[email protected]>
Cc Songshan Gong <[email protected]>

---
Jiri Olsa (3):
perf script python: Fix string vs byte array resolving perf tools: Make is_printable_array global tools lib api fs: Use base 0 in filename__read_ull

 tools/lib/api/fs/fs.c                                  |  7 ++++++-
 tools/perf/util/python.c                               | 12 ------------
 tools/perf/util/scripting-engines/trace-event-python.c | 25 ++++++++++++++++++-------
 tools/perf/util/util.c                                 | 14 ++++++++++++++
 tools/perf/util/util.h                                 |  1 +
 5 files changed, 39 insertions(+), 20 deletions(-)
author reviewer
#1 lore raw

PATCH v2 1/3 perf script python: Fix string vs byte array resolving

Jirka reported that python code returns all arrays as strings. This makes impossible to get all items for byte array tracepoint field containing 0x00 value item.

Fixing this by scanning full length of the array and returning it as PyByteArray object in case non printable byte is found.

---
 .../util/scripting-engines/trace-event-python.c    | 37 ++++++++++++++++++----
 1 file changed, 31 insertions(+), 6 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +31 -6
index 6ac6b7a33f42..1bc995de5a6d 100644
@@ -386,6 +386,19 @@ exit:
 	return pylist;
 }
 
+static int is_printable_array(char *p, unsigned int len)
+{
+	unsigned int i;
+
+	if (p[len - 1] == 0)
+		len--;
+
+	for (i = 0; i < len - 1; i++)
+		if (!isprint(p[i]) && !isspace(p[i]))
+			return 0;
+
+	return 1;
+}
 
 static void python_process_tracepoint(struct perf_sample *sample,
 				      struct perf_evsel *evsel,
@@ -457,14 +470,26 @@ static void python_process_tracepoint(struct perf_sample *sample,
 		pydict_set_item_string_decref(dict, "common_callchain", callchain);
 	}
 	for (field = event->format.fields; field; field = field->next) {
-		if (field->flags & FIELD_IS_STRING) {
-			int offset;
+		unsigned int offset, len;
+		unsigned long long val;
+
+		if (field->flags & FIELD_IS_ARRAY) {
+			offset = field->offset;
+			len    = field->size;
 			if (field->flags & FIELD_IS_DYNAMIC) {
-				offset = *(int *)(data + field->offset);
+				val     = pevent_read_number(scripting_context->pevent,
+							     data + offset, len);
+				offset  = val;
+				len     = offset >> 16;
 				offset &= 0xffff;
-			} else
-				offset = field->offset;
-			obj = PyString_FromString((char *)data + offset);
+			}
+			if (field->flags & FIELD_IS_STRING &&
+			    is_printable_array(data + offset, len)) {
+				obj = PyString_FromString((char *) data + offset);
+			} else {
+				obj = PyByteArray_FromStringAndSize((const char *) data + offset, len);
+				field->flags &= ~FIELD_IS_STRING;
+			}
 		} else { /* FIELD_IS_NUMERIC */
 			obj = get_field_numeric_entry(event, field, data);
 		}
Signature · 1 line
2.4.11
#2 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

Quoted 9 lines · Jiri Olsa

Jirka reported that python code returns all arrays as strings. This makes impossible to get all items for byte array tracepoint field containing 0x00 value item.

Fixing this by scanning full length of the array and returning it as PyByteArray object in case non printable byte is found.

Cc Steven Rostedt (Red Hat) <[email protected]>
Cc Jiri Pirko <[email protected]>

forgot:

Jirka,
could I please also have your tested-by on this version?

thanks,
jirka

Acked-by on v2 1/3
#3 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

In reply to Jiri Olsa
Quoted 4 lines · On Fri, 15 Jul 2016 09:29:55 +0200 Jiri Olsa <[email protected]> wrote:

Jirka reported that python code returns all arrays as strings. This makes impossible to get all items for byte array tracepoint field containing 0x00 value item.

Quoted 8 lines

Fixing this by scanning full length of the array and returning it as PyByteArray object in case non printable byte is found.

---

-- Steve

#4 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

In reply to Jiri Olsa
Quoted 23 lines · Fri, Jul 15, 2016 at 09:29:55AM CEST, [email protected] wrote:

Jirka reported that python code returns all arrays as strings. This makes impossible to get all items for byte array tracepoint field containing 0x00 value item.

Fixing this by scanning full length of the array and returning it as PyByteArray object in case non printable byte is found.

---
.../util/scripting-engines/trace-event-python.c | 37 ++++++++++++++++++----

1 file changed, 31 insertions(+), 6 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +0 -0
index 6ac6b7a33f42..1bc995de5a6d 100644
@@ -386,6 +386,19 @@ exit:
 	return pylist;
 }
 

tools/perf/util/scripting-engines/trace-event-python.c exit: · line 398

Quoted 10 lines
tools/perf/util/scripting-engines/trace-event-python.c +10 -0
+static int is_printable_array(char *p, unsigned int len)
+{
+	unsigned int i;
+
+	if (p[len - 1] == 0)
+		len--;
+
+	for (i = 0; i < len - 1; i++)
+		if (!isprint(p[i]) && !isspace(p[i]))
+			return 0;

for "AA\1\0" this returns "1" although that should return "0".

orig len 4
decremented len 3
for:
0 1

index 2 would not be inspected. Or am I missing something?

I think that the for check should be "i < len"

Thanks.

Quoted 42 lines
tools/perf/util/scripting-engines/trace-event-python.c +21 -6
+
+	return 1;
+}
 
 static void python_process_tracepoint(struct perf_sample *sample,
 				      struct perf_evsel *evsel,
@@ -457,14 +470,26 @@ static void python_process_tracepoint(struct perf_sample *sample,
 		pydict_set_item_string_decref(dict, "common_callchain", callchain);
 	}
 	for (field = event->format.fields; field; field = field->next) {
-		if (field->flags & FIELD_IS_STRING) {
-			int offset;
+		unsigned int offset, len;
+		unsigned long long val;
+
+		if (field->flags & FIELD_IS_ARRAY) {
+			offset = field->offset;
+			len    = field->size;
 			if (field->flags & FIELD_IS_DYNAMIC) {
-				offset = *(int *)(data + field->offset);
+				val     = pevent_read_number(scripting_context->pevent,
+							     data + offset, len);
+				offset  = val;
+				len     = offset >> 16;
 				offset &= 0xffff;
-			} else
-				offset = field->offset;
-			obj = PyString_FromString((char *)data + offset);
+			}
+			if (field->flags & FIELD_IS_STRING &&
+			    is_printable_array(data + offset, len)) {
+				obj = PyString_FromString((char *) data + offset);
+			} else {
+				obj = PyByteArray_FromStringAndSize((const char *) data + offset, len);
+				field->flags &= ~FIELD_IS_STRING;
+			}
 		} else { /* FIELD_IS_NUMERIC */
 			obj = get_field_numeric_entry(event, field, data);
 		}
Signature · 1 line
2.4.11
#5 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

Quoted 38 lines · On Fri, 15 Jul 2016 17:51:10 +0200 Jiri Pirko <[email protected]> wrote:
Quoted 23 lines · Fri, Jul 15, 2016 at 09:29:55AM CEST, [email protected] wrote:

Jirka reported that python code returns all arrays as strings. This makes impossible to get all items for byte array tracepoint field containing 0x00 value item.

Fixing this by scanning full length of the array and returning it as PyByteArray object in case non printable byte is found.

---
.../util/scripting-engines/trace-event-python.c | 37 ++++++++++++++++++----

1 file changed, 31 insertions(+), 6 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +0 -0
index 6ac6b7a33f42..1bc995de5a6d 100644
@@ -386,6 +386,19 @@ exit:
 	return pylist;
 }
 

tools/perf/util/scripting-engines/trace-event-python.c exit: · line 398

Quoted 10 lines
tools/perf/util/scripting-engines/trace-event-python.c +10 -0
+static int is_printable_array(char *p, unsigned int len)
+{
+	unsigned int i;
+
+	if (p[len - 1] == 0)
+		len--;
+
+	for (i = 0; i < len - 1; i++)
+		if (!isprint(p[i]) && !isspace(p[i]))
+			return 0;  

for "AA\1\0" this returns "1" although that should return "0".

Quoted 8 lines

orig len 4
decremented len 3
for:
0 1

index 2 would not be inspected. Or am I missing something?

I think that the for check should be "i < len"

Yes it should be. I think we got the two solutions mixed up.

With the above len--, it should be i < len, but when we did the check for zero at the end, we needed the i < len - 1

-- Steve

#6 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

On Fri, Jul 15, 2016 at 12:02:31PM -0400, Steven Rostedt wrote:

SNIP

Quoted 7 lines
Quoted 7 lines

for "AA\1\0" this returns "1" although that should return "0".

orig len 4
decremented len 3
for:
0 1

Quoted 8 lines
Quoted 3 lines

index 2 would not be inspected. Or am I missing something?

I think that the for check should be "i < len"

Yes it should be. I think we got the two solutions mixed up.

With the above len--, it should be i < len, but when we did the check for zero at the end, we needed the i < len - 1

ugh right.. should be 'i < len' check in the for loop,

there's also the patch 2/3 that needs to be changed

Arnaldo,
please let me know if you need me to resend this.

thanks,
jirka

#7 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

Em Fri, Jul 15, 2016 at 06:13:10PM +0200, Jiri Olsa escreveu:

Quoted 20 lines · Steven Rostedt

SNIP

Quoted 7 lines
Quoted 7 lines

for "AA\1\0" this returns "1" although that should return "0".

orig len 4
decremented len 3
for:
0 1

Quoted 8 lines
Quoted 3 lines

index 2 would not be inspected. Or am I missing something?

I think that the for check should be "i < len"

Yes it should be. I think we got the two solutions mixed up.

With the above len--, it should be i < len, but when we did the check for zero at the end, we needed the i < len - 1

Quoted 6 lines

ugh right.. should be 'i < len' check in the for loop,

there's also the patch 2/3 that needs to be changed

Arnaldo,
please let me know if you need me to resend this.

So I need to drop those, even with Rostedt's acked-by? Ok, please resend, hopefully this time with a Tested-by from the reporter?

- Arnaldo

#8 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

Em Fri, Jul 15, 2016 at 01:37:31PM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 23 lines

Em Fri, Jul 15, 2016 at 06:13:10PM +0200, Jiri Olsa escreveu:

Quoted 22 lines · Steven Rostedt

SNIP

Quoted 7 lines
Quoted 7 lines

for "AA\1\0" this returns "1" although that should return "0".

orig len 4
decremented len 3
for:
0 1

Quoted 8 lines
Quoted 3 lines

index 2 would not be inspected. Or am I missing something?

I think that the for check should be "i < len"

Yes it should be. I think we got the two solutions mixed up.

With the above len--, it should be i < len, but when we did the check for zero at the end, we needed the i < len - 1

ugh right.. should be 'i < len' check in the for loop,

Quoted 7 lines
Quoted 4 lines

there's also the patch 2/3 that needs to be changed

Arnaldo,
please let me know if you need me to resend this.

So I need to drop those, even with Rostedt's acked-by? Ok, please resend, hopefully this time with a Tested-by from the reporter?

I removed the first two, as the second needs context from the first, kept the third one, so please resend just the first two.

- Arnaldo

#9 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

In reply to Jiri Olsa
Quoted 15 lines · On Fri, 15 Jul 2016 18:13:10 +0200 Jiri Olsa <[email protected]> wrote:

On Fri, Jul 15, 2016 at 12:02:31PM -0400, Steven Rostedt wrote:

SNIP

Quoted 11 lines
Quoted 10 lines

for "AA\1\0" this returns "1" although that should return "0".

orig len 4
decremented len 3
for:
0 1

index 2 would not be inspected. Or am I missing something?

I think that the for check should be "i < len"

Quoted 9 lines
Quoted 4 lines

Yes it should be. I think we got the two solutions mixed up.

With the above len--, it should be i < len, but when we did the check for zero at the end, we needed the i < len - 1

ugh right.. should be 'i < len' check in the for loop,

there's also the patch 2/3 that needs to be changed

I'm wondering if we should also add at the beginning:

	if (!len)
		return 0;

Otherwise we will be accessing out of bounds with the len-1.

-- Steve

#10 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

In reply to Jiri Olsa

tools/perf/util/scripting-engines/trace-event-python.c static void python_process_tracepoint(struct perf_sample *sample, · line 488

Quoted 3 lines · On Fri, 15 Jul 2016 09:29:55 +0200 Jiri Olsa <[email protected]> wrote:
tools/perf/util/scripting-engines/trace-event-python.c +3 -0
+			if (field->flags & FIELD_IS_STRING &&
+			    is_printable_array(data + offset, len)) {
+				obj = PyString_FromString((char *) data + offset);

Hmm. As I stated, It is possible that strings can be non nul terminated. But I'm looking here and thinking we need to make sure that it is nul terminated.

Can PyString_FromString() handle a non nul terminated string?

-- Steve

Quoted 7 lines
tools/perf/util/scripting-engines/trace-event-python.c +4 -0
+			} else {
+				obj = PyByteArray_FromStringAndSize((const char *) data + offset, len);
+				field->flags &= ~FIELD_IS_STRING;
+			}
 		} else { /* FIELD_IS_NUMERIC */
 			obj = get_field_numeric_entry(event, field, data);
 		}
#11 lore raw

Re: [PATCH 1/3] perf script python: Fix string vs byte array resolving

Quoted 11 lines · Steven Rostedt

tools/perf/util/scripting-engines/trace-event-python.c static void python_process_tracepoint(struct perf_sample *sample, · line 488

Quoted 3 lines · On Fri, 15 Jul 2016 09:29:55 +0200 Jiri Olsa <[email protected]> wrote:
tools/perf/util/scripting-engines/trace-event-python.c +3 -0
+			if (field->flags & FIELD_IS_STRING &&
+			    is_printable_array(data + offset, len)) {
+				obj = PyString_FromString((char *) data + offset);

Hmm. As I stated, It is possible that strings can be non nul terminated. But I'm looking here and thinking we need to make sure that it is nul terminated.

Quoted 1 line

Can PyString_FromString() handle a non nul terminated string?

couldn't find in the doc.. but I think it's necessary, there's no other way it could tell the end ;-)

I'll make the is_printable_array in case the final 0 is missing

thanks,
jirka

author reviewer
#12 lore raw

PATCH v2 2/3 perf tools: Make is_printable_array global

In reply to Jiri Olsa

It's used from 2 objects in perf, so it's better
to keep just one copy.

---
 tools/perf/util/python.c                               | 12 ------------
 tools/perf/util/scripting-engines/trace-event-python.c | 14 --------------
 tools/perf/util/util.c                                 | 14 ++++++++++++++
 tools/perf/util/util.h                                 |  1 +
 4 files changed, 15 insertions(+), 26 deletions(-)
tools/perf/util/python.c +0 -12
index d32f97033718..a5fbc012e3df 100644
@@ -295,18 +295,6 @@ static bool is_tracepoint(struct pyrf_event *pevent)
 	return pevent->evsel->attr.type == PERF_TYPE_TRACEPOINT;
 }
 
-static int is_printable_array(char *p, unsigned int len)
-{
-	unsigned int i;
-
-	for (i = 0; i < len; i++) {
-		if (!isprint(p[i]) && !isspace(p[i]))
-			return 0;
-	}
-
-	return 1;
-}
-
 static PyObject*
 tracepoint_field(struct pyrf_event *pe, struct format_field *field)
 {
tools/perf/util/scripting-engines/trace-event-python.c +0 -14
index 1bc995de5a6d..e0203b979474 100644
@@ -386,20 +386,6 @@ exit:
 	return pylist;
 }
 
-static int is_printable_array(char *p, unsigned int len)
-{
-	unsigned int i;
-
-	if (p[len - 1] == 0)
-		len--;
-
-	for (i = 0; i < len - 1; i++)
-		if (!isprint(p[i]) && !isspace(p[i]))
-			return 0;
-
-	return 1;
-}
-
 static void python_process_tracepoint(struct perf_sample *sample,
 				      struct perf_evsel *evsel,
 				      struct addr_location *al)
tools/perf/util/util.c +14 -0
index 5f44a21955cd..7ca4719787d0 100644
@@ -746,3 +746,17 @@ void print_binary(unsigned char *data, size_t len,
 	}
 	printer(BINARY_PRINT_DATA_END, -1, extra);
 }
+
+int is_printable_array(char *p, unsigned int len)
+{
+	unsigned int i;
+
+	if (p[len - 1] == 0)
+		len--;
+
+	for (i = 0; i < len - 1; i++)
+		if (!isprint(p[i]) && !isspace(p[i]))
+			return 0;
+
+	return 1;
+}
tools/perf/util/util.h +1 -0
index 6178cab82374..66d24bdbac33 100644
@@ -364,4 +364,5 @@ void print_binary(unsigned char *data, size_t len,
 extern int sched_getcpu(void);
 #endif
 
+int is_printable_array(char *p, unsigned int len);
 #endif /* GIT_COMPAT_UTIL_H */
Signature · 1 line
2.4.11
author reviewer
#14 lore raw

PATCH v2 3/3 tools lib api fs: Use base 0 in filename__read_ull

In reply to Jiri Olsa

By using 0 for base, the strtoull detects the base automatically (see man strtoull).

ATM we have just one user of this function, the cpu__get_max_freq function reading cpuinfo_max_freq sysfs. It should not get affected by this change.

---
 tools/lib/api/fs/fs.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
tools/lib/api/fs/fs.c +6 -1
index 08556cf2c70d..ba7094b945ff 100644
@@ -283,6 +283,11 @@ int filename__read_int(const char *filename, int *value)
 	return err;
 }
 
+/*
+ * Parses @value out of @filename with strtoull.
+ * By using 0 for base, the strtoull detects the
+ * base automatically (see man strtoull).
+ */
 int filename__read_ull(const char *filename, unsigned long long *value)
 {
 	char line[64];
@@ -292,7 +297,7 @@ int filename__read_ull(const char *filename, unsigned long long *value)
 		return -1;
 
 	if (read(fd, line, sizeof(line)) > 0) {
-		*value = strtoull(line, NULL, 10);
+		*value = strtoull(line, NULL, 0);
 		if (*value != ULLONG_MAX)
 			err = 0;
 	}
Signature · 1 line
2.4.11
#15 lore raw

[tip:perf/core] tools lib api fs: Use base 0 in filename__read_ull

tools lib api fs: Use base 0 in filename__read_ull
Commit-ID:  db49120a32b347fb93aea3319305932657dd118c
Gitweb:     http://git.kernel.org/tip/db49120a32b347fb93aea3319305932657dd118c
Author:     Jiri Olsa <[email protected]>
AuthorDate: Fri, 15 Jul 2016 09:29:57 +0200
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 15 Jul 2016 13:38:05 -0300

tools lib api fs: Use base 0 in filename__read_ull

By using 0 for base, the strtoull() detects the base automatically (see 'man strtoull').

ATM we have just one user of this function, the cpu__get_max_freq function reading the "cpuinfo_max_freq" sysfs file. It should not get affected by this change.

Committer note:

This change seems motivated by this discussion:

"[PATCH] [RFC V1]s390/perf: fix 'start' address of module's map"
http://lkml.kernel.org/r/20160711120155.GA29929@krava

I.e. this patches paves the way for filename__read_ull() to be used in a S/390 related fix.

---
 tools/lib/api/fs/fs.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
tools/lib/api/fs/fs.c +6 -1
index 08556cf..ba7094b 100644
@@ -283,6 +283,11 @@ int filename__read_int(const char *filename, int *value)
 	return err;
 }
 
+/*
+ * Parses @value out of @filename with strtoull.
+ * By using 0 for base, the strtoull detects the
+ * base automatically (see man strtoull).
+ */
 int filename__read_ull(const char *filename, unsigned long long *value)
 {
 	char line[64];
@@ -292,7 +297,7 @@ int filename__read_ull(const char *filename, unsigned long long *value)
 		return -1;
 
 	if (read(fd, line, sizeof(line)) > 0) {
-		*value = strtoull(line, NULL, 10);
+		*value = strtoull(line, NULL, 0);
 		if (*value != ULLONG_MAX)
 			err = 0;
 	}