2019-09-30 21:03:50

by Steve MacLean

[permalink] [raw]
Subject: [PATCH 3/4 RESEND] perf inject --jit: Remove //anon mmap events

While a JIT is jitting code it will eventually need to commit more pages and
change these pages to executable permissions.

Typically the JIT will want these collocated to minimize branch displacements.

The kernel will coalesce these anonymous mapping with identical permissions
before sending an mmap event for the new pages. This means the mmap event for
the new pages will include the older pages.

These anonymous mmap events will obscure the jitdump injected pseudo events.
This means that the jitdump generated symbols, machine code, debugging info,
and unwind info will no longer be used.

Observations:

When a process emits a jit dump marker and a jitdump file, the perf-xxx.map
file represents inferior information which has been superseded by the
jitdump jit-xxx.dump file.

Further the '//anon*' mmap events are only required for the legacy
perf-xxx.map mapping.

Summary:

Add rbtree to track which pids have successfully injected a jitdump file.

During "perf inject --jit", discard "//anon*" mmap events for any pid which
has successfully processed a jitdump file.

Committer testing:

// jitdump case
perf record <app with jitdump>
perf inject --jit --input perf.data --output perfjit.data

// verify mmap "//anon" events present initially
perf script --input perf.data --show-mmap-events | grep '//anon'
// verify mmap "//anon" events removed
perf script --input perfjit.data --show-mmap-events | grep '//anon'

// no jitdump case
perf record <app without jitdump>
perf inject --jit --input perf.data --output perfjit.data

// verify mmap "//anon" events present initially
perf script --input perf.data --show-mmap-events | grep '//anon'
// verify mmap "//anon" events not removed
perf script --input perfjit.data --show-mmap-events | grep '//anon'

Repro:

This issue was discovered while testing the initial CoreCLR jitdump
implementation. https://github.com/dotnet/coreclr/pull/26897.

Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: [email protected]
Signed-off-by: Steve MacLean <[email protected]>
---
tools/perf/builtin-inject.c | 4 +--
tools/perf/util/jitdump.c | 63 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index c14f40b8..4c921e0 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -261,7 +261,7 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
* if jit marker, then inject jit mmaps and generate ELF images
*/
ret = jit_process(inject->session, &inject->output, machine,
- event->mmap.filename, sample->pid, &n);
+ event->mmap.filename, event->mmap.pid, &n);
if (ret < 0)
return ret;
if (ret) {
@@ -299,7 +299,7 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
* if jit marker, then inject jit mmaps and generate ELF images
*/
ret = jit_process(inject->session, &inject->output, machine,
- event->mmap2.filename, sample->pid, &n);
+ event->mmap2.filename, event->mmap2.pid, &n);
if (ret < 0)
return ret;
if (ret) {
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 22d09c4..6a1563f 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -751,6 +751,59 @@ jit_detect(char *mmap_name, pid_t pid)
return 0;
}

+struct pid_rbtree
+{
+ struct rb_node node;
+ pid_t pid;
+};
+
+static void jit_add_pid(struct rb_root *root, pid_t pid)
+{
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
+ struct pid_rbtree* data = NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ struct pid_rbtree *this = container_of(*new, struct pid_rbtree, node);
+ pid_t nodePid = this->pid;
+
+ parent = *new;
+ if (pid < nodePid)
+ new = &((*new)->rb_left);
+ else if (pid > nodePid)
+ new = &((*new)->rb_right);
+ else
+ return;
+ }
+
+ data = malloc(sizeof(struct pid_rbtree));
+ data->pid = pid;
+
+ /* Add new node and rebalance tree. */
+ rb_link_node(&data->node, parent, new);
+ rb_insert_color(&data->node, root);
+
+ return;
+}
+
+static bool jit_has_pid(struct rb_root *root, pid_t pid)
+{
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct pid_rbtree *this = container_of(node, struct pid_rbtree, node);
+ pid_t nodePid = this->pid;
+
+ if (pid < nodePid)
+ node = node->rb_left;
+ else if (pid > nodePid)
+ node = node->rb_right;
+ else
+ return 1;
+ }
+ return 0;
+}
+
int
jit_process(struct perf_session *session,
struct perf_data *output,
@@ -762,12 +815,21 @@ jit_process(struct perf_session *session,
struct evsel *first;
struct jit_buf_desc jd;
int ret;
+ static struct rb_root jitdump_pids = RB_ROOT;

/*
* first, detect marker mmap (i.e., the jitdump mmap)
*/
if (jit_detect(filename, pid))
+ {
+ /*
+ * Strip //anon* mmaps if we processed a jitdump for this pid
+ */
+ if (jit_has_pid(&jitdump_pids, pid) && (strncmp(filename, "//anon", 6) == 0))
+ return 1;
+
return 0;
+ }

memset(&jd, 0, sizeof(jd));

@@ -786,6 +848,7 @@ jit_process(struct perf_session *session,

ret = jit_inject(&jd, filename);
if (!ret) {
+ jit_add_pid(&jitdump_pids, pid);
*nbytes = jd.bytes_written;
ret = 1;
}
--
2.7.4


2019-10-01 08:58:18

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 3/4 RESEND] perf inject --jit: Remove //anon mmap events

On Mon, Sep 30, 2019 at 09:00:01PM +0000, Steve MacLean wrote:
> While a JIT is jitting code it will eventually need to commit more pages and
> change these pages to executable permissions.
>
> Typically the JIT will want these collocated to minimize branch displacements.
>
> The kernel will coalesce these anonymous mapping with identical permissions
> before sending an mmap event for the new pages. This means the mmap event for
> the new pages will include the older pages.
>
> These anonymous mmap events will obscure the jitdump injected pseudo events.
> This means that the jitdump generated symbols, machine code, debugging info,
> and unwind info will no longer be used.
>
> Observations:
>
> When a process emits a jit dump marker and a jitdump file, the perf-xxx.map
> file represents inferior information which has been superseded by the
> jitdump jit-xxx.dump file.
>
> Further the '//anon*' mmap events are only required for the legacy
> perf-xxx.map mapping.
>
> Summary:
>
> Add rbtree to track which pids have successfully injected a jitdump file.
>
> During "perf inject --jit", discard "//anon*" mmap events for any pid which
> has successfully processed a jitdump file.
>
> Committer testing:
>
> // jitdump case
> perf record <app with jitdump>
> perf inject --jit --input perf.data --output perfjit.data
>
> // verify mmap "//anon" events present initially
> perf script --input perf.data --show-mmap-events | grep '//anon'
> // verify mmap "//anon" events removed
> perf script --input perfjit.data --show-mmap-events | grep '//anon'
>
> // no jitdump case
> perf record <app without jitdump>
> perf inject --jit --input perf.data --output perfjit.data
>
> // verify mmap "//anon" events present initially
> perf script --input perf.data --show-mmap-events | grep '//anon'
> // verify mmap "//anon" events not removed
> perf script --input perfjit.data --show-mmap-events | grep '//anon'
>
> Repro:
>
> This issue was discovered while testing the initial CoreCLR jitdump
> implementation. https://github.com/dotnet/coreclr/pull/26897.
>
> Cc: Peter Zijlstra <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: Alexander Shishkin <[email protected]>
> Cc: Jiri Olsa <[email protected]>
> Cc: Namhyung Kim <[email protected]>
> Cc: Stephane Eranian <[email protected]>
> Cc: [email protected]
> Signed-off-by: Steve MacLean <[email protected]>
> ---
> tools/perf/builtin-inject.c | 4 +--
> tools/perf/util/jitdump.c | 63 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 65 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index c14f40b8..4c921e0 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -261,7 +261,7 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
> * if jit marker, then inject jit mmaps and generate ELF images
> */
> ret = jit_process(inject->session, &inject->output, machine,
> - event->mmap.filename, sample->pid, &n);
> + event->mmap.filename, event->mmap.pid, &n);
> if (ret < 0)
> return ret;
> if (ret) {
> @@ -299,7 +299,7 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
> * if jit marker, then inject jit mmaps and generate ELF images
> */
> ret = jit_process(inject->session, &inject->output, machine,
> - event->mmap2.filename, sample->pid, &n);
> + event->mmap2.filename, event->mmap2.pid, &n);
> if (ret < 0)
> return ret;
> if (ret) {
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 22d09c4..6a1563f 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -751,6 +751,59 @@ jit_detect(char *mmap_name, pid_t pid)
> return 0;
> }
>
> +struct pid_rbtree
> +{
> + struct rb_node node;
> + pid_t pid;
> +};
> +
> +static void jit_add_pid(struct rb_root *root, pid_t pid)
> +{
> + struct rb_node **new = &(root->rb_node), *parent = NULL;
> + struct pid_rbtree* data = NULL;
> +
> + /* Figure out where to put new node */
> + while (*new) {
> + struct pid_rbtree *this = container_of(*new, struct pid_rbtree, node);
> + pid_t nodePid = this->pid;

looks like Andi is right, I'm still getting malformed patch error

the patch has extra characters '=20' and broken lines, like:


--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -751,6 +751,59 @@ jit_detect(char *mmap_name, pid_t pid)
return 0;
}
=20
+struct pid_rbtree
+{
+ struct rb_node node;
+ pid_t pid;
+};
+
+static void jit_add_pid(struct rb_root *root, pid_t pid)
+{
+ struct rb_node **new =3D &(root->rb_node), *parent =3D NULL;
+ struct pid_rbtree* data =3D NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ struct pid_rbtree *this =3D container_of(*new, struct pid_r=
btree, node);
+ pid_t nodePid =3D this->pid;


jirka

2019-10-02 21:54:40

by Steve MacLean

[permalink] [raw]
Subject: RE: [PATCH 3/4 RESEND] perf inject --jit: Remove //anon mmap events

> looks like Andi is right, I'm still getting malformed patch error

> the patch has extra characters '=20' and broken lines, like:

My apologies, I was trying to get by with an inappropriate mailer.

I have an sendmail account now, and will resend.