perf inject fails to detect jitdump file produced by a process
running in a different PID namespace if this process has not exited
yet.
The PID namespace heuristic in jit_detect() compares two PIDs:
* pid: outermost NStgid of mmap(jitdump) caller from perf's PoV.
* nsinfo__nstgid(nsi): innermost NStgid of mmap(jitdump) caller from
perf's PoV.
The semantics of the in_pidns variable can be seen in, e.g.,
nsinfo__get_nspid(): it's true if and only if perf and the profiled
process are in different PID namespaces.
The current logic is clearly inverted: if pid and nsinfo__nstgid(nsi)
are different, then the profiled process must be in a different PID
namespace. This, of course, ignores that fact that they may end up
being equal by accident, but that's not the point here.
Fix by flipping the comparison.
Changing just that, however, breaks the case when the process has
exited. Add explicit support for that by adding "synthesized" field to
nsinfo, which tracks whether NStgid was obtained from a running
process (ignoring considerations of PID reuse or running inject on
a different machine). When the namespace information is synthesized,
assume the process ran in a different PID namespace.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
tools/perf/util/jitdump.c | 27 +++++++++++++++++++++------
tools/perf/util/namespaces.c | 9 +++++++++
tools/perf/util/namespaces.h | 2 ++
3 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index b062b1f234b62..19e4bc139935b 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -788,15 +788,30 @@ jit_detect(const char *mmap_name, pid_t pid, struct nsinfo *nsi, bool *in_pidns)
if (!end)
return -1;
- *in_pidns = pid == nsinfo__nstgid(nsi);
/*
- * pid does not match mmap pid
- * pid==0 in system-wide mode (synthesized)
+ * Determine whether the process ran inside a container, and whether it
+ * mapped jit.dump for profiling purposes or by accident. Record this
+ * for further use in jit_inject(). The kernel does not provide PID
+ * namespace information, so we have to resort to guesswork.
*
- * If the pid in the file name is equal to the nstgid, then
- * the agent ran inside a container and perf outside the
- * container, so record it for further use in jit_inject().
+ * If the process exited and perf had to synthesize the namespace
+ * information, then it's not possible to have any certainty; be
+ * aggressive and assume that the process ran inside a container. This
+ * allows the user to proceed with injection at the cost of a small
+ * probability of injecting irrelevant data.
+ *
+ * If the process' NStgid as observed by perf is different from its
+ * innermost NStgid, then it must have run inside a container. There is
+ * a very small probability that NStgids randomly happenned to be the
+ * same; ignore it.
+ *
+ * pid == 0 means system-wide mode, just proceed.
+ *
+ * Finally, the most straightforward case: if the PID in the file name
+ * is equal to the process' NStgid as observed by perf, then it must be
+ * a match.
*/
+ *in_pidns = nsinfo__synthesized(nsi) || pid != nsinfo__nstgid(nsi);
if (pid && !(pid2 == pid || *in_pidns))
return -1;
/*
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
index 01502570b32d0..7de5d62e271c4 100644
--- a/tools/perf/util/namespaces.c
+++ b/tools/perf/util/namespaces.c
@@ -132,6 +132,8 @@ int nsinfo__init(struct nsinfo *nsi)
rv = nsinfo__get_nspid(&RC_CHK_ACCESS(nsi)->tgid, &RC_CHK_ACCESS(nsi)->nstgid,
&RC_CHK_ACCESS(nsi)->in_pidns, spath);
+ if (rv == 0)
+ RC_CHK_ACCESS(nsi)->synthesized = false;
out:
free(newns);
@@ -166,6 +168,7 @@ struct nsinfo *nsinfo__new(pid_t pid)
RC_CHK_ACCESS(nsi)->nstgid = pid;
nsinfo__clear_need_setns(nsi);
RC_CHK_ACCESS(nsi)->in_pidns = false;
+ RC_CHK_ACCESS(nsi)->synthesized = true;
/* Init may fail if the process exits while we're trying to look at its
* proc information. In that case, save the pid but don't try to enter
* the namespace.
@@ -197,6 +200,7 @@ struct nsinfo *nsinfo__copy(const struct nsinfo *nsi)
RC_CHK_ACCESS(nnsi)->nstgid = nsinfo__nstgid(nsi);
RC_CHK_ACCESS(nnsi)->need_setns = nsinfo__need_setns(nsi);
RC_CHK_ACCESS(nnsi)->in_pidns = nsinfo__in_pidns(nsi);
+ RC_CHK_ACCESS(nnsi)->synthesized = nsinfo__synthesized(nsi);
if (nsinfo__mntns_path(nsi)) {
RC_CHK_ACCESS(nnsi)->mntns_path = strdup(nsinfo__mntns_path(nsi));
if (!RC_CHK_ACCESS(nnsi)->mntns_path) {
@@ -275,6 +279,11 @@ void nsinfo__set_in_pidns(struct nsinfo *nsi)
RC_CHK_ACCESS(nsi)->in_pidns = true;
}
+bool nsinfo__synthesized(const struct nsinfo *nsi)
+{
+ return RC_CHK_ACCESS(nsi)->synthesized;
+}
+
void nsinfo__mountns_enter(struct nsinfo *nsi,
struct nscookie *nc)
{
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
index e95c79b80e27c..41ba2ea8137e5 100644
--- a/tools/perf/util/namespaces.h
+++ b/tools/perf/util/namespaces.h
@@ -38,6 +38,7 @@ DECLARE_RC_STRUCT(nsinfo) {
bool in_pidns;
char *mntns_path;
refcount_t refcnt;
+ bool synthesized;
};
struct nscookie {
@@ -60,6 +61,7 @@ pid_t nsinfo__nstgid(const struct nsinfo *nsi);
pid_t nsinfo__pid(const struct nsinfo *nsi);
bool nsinfo__in_pidns(const struct nsinfo *nsi);
void nsinfo__set_in_pidns(struct nsinfo *nsi);
+bool nsinfo__synthesized(const struct nsinfo *nsi);
void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc);
void nsinfo__mountns_exit(struct nscookie *nc);
--
2.51.1
On Wed, Nov 05, 2025 at 08:10:24PM +0100, Ilya Leoshkevich wrote:
> perf inject fails to detect jitdump file produced by a process
> running in a different PID namespace if this process has not exited
> yet.
>
> The PID namespace heuristic in jit_detect() compares two PIDs:
>
> * pid: outermost NStgid of mmap(jitdump) caller from perf's PoV.
> * nsinfo__nstgid(nsi): innermost NStgid of mmap(jitdump) caller from
> perf's PoV.
>
> The semantics of the in_pidns variable can be seen in, e.g.,
> nsinfo__get_nspid(): it's true if and only if perf and the profiled
> process are in different PID namespaces.
>
> The current logic is clearly inverted: if pid and nsinfo__nstgid(nsi)
> are different, then the profiled process must be in a different PID
> namespace. This, of course, ignores that fact that they may end up
> being equal by accident, but that's not the point here.
>
> Fix by flipping the comparison.
>
> Changing just that, however, breaks the case when the process has
> exited. Add explicit support for that by adding "synthesized" field to
> nsinfo, which tracks whether NStgid was obtained from a running
> process (ignoring considerations of PID reuse or running inject on
> a different machine). When the namespace information is synthesized,
> assume the process ran in a different PID namespace.
I'm not sure I'm following. It'd be great if anyone understand the
topic well could review.
>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> tools/perf/util/jitdump.c | 27 +++++++++++++++++++++------
> tools/perf/util/namespaces.c | 9 +++++++++
> tools/perf/util/namespaces.h | 2 ++
> 3 files changed, 32 insertions(+), 6 deletions(-)
>
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index b062b1f234b62..19e4bc139935b 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -788,15 +788,30 @@ jit_detect(const char *mmap_name, pid_t pid, struct nsinfo *nsi, bool *in_pidns)
> if (!end)
> return -1;
>
> - *in_pidns = pid == nsinfo__nstgid(nsi);
> /*
> - * pid does not match mmap pid
> - * pid==0 in system-wide mode (synthesized)
> + * Determine whether the process ran inside a container, and whether it
> + * mapped jit.dump for profiling purposes or by accident. Record this
> + * for further use in jit_inject(). The kernel does not provide PID
> + * namespace information, so we have to resort to guesswork.
> *
> - * If the pid in the file name is equal to the nstgid, then
> - * the agent ran inside a container and perf outside the
> - * container, so record it for further use in jit_inject().
> + * If the process exited and perf had to synthesize the namespace
> + * information, then it's not possible to have any certainty; be
> + * aggressive and assume that the process ran inside a container. This
> + * allows the user to proceed with injection at the cost of a small
> + * probability of injecting irrelevant data.
> + *
> + * If the process' NStgid as observed by perf is different from its
> + * innermost NStgid, then it must have run inside a container. There is
> + * a very small probability that NStgids randomly happenned to be the
> + * same; ignore it.
> + *
> + * pid == 0 means system-wide mode, just proceed.
> + *
> + * Finally, the most straightforward case: if the PID in the file name
> + * is equal to the process' NStgid as observed by perf, then it must be
> + * a match.
> */
> + *in_pidns = nsinfo__synthesized(nsi) || pid != nsinfo__nstgid(nsi);
> if (pid && !(pid2 == pid || *in_pidns))
> return -1;
> /*
> diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
> index 01502570b32d0..7de5d62e271c4 100644
> --- a/tools/perf/util/namespaces.c
> +++ b/tools/perf/util/namespaces.c
> @@ -132,6 +132,8 @@ int nsinfo__init(struct nsinfo *nsi)
>
> rv = nsinfo__get_nspid(&RC_CHK_ACCESS(nsi)->tgid, &RC_CHK_ACCESS(nsi)->nstgid,
> &RC_CHK_ACCESS(nsi)->in_pidns, spath);
> + if (rv == 0)
> + RC_CHK_ACCESS(nsi)->synthesized = false;
>
> out:
> free(newns);
> @@ -166,6 +168,7 @@ struct nsinfo *nsinfo__new(pid_t pid)
> RC_CHK_ACCESS(nsi)->nstgid = pid;
> nsinfo__clear_need_setns(nsi);
> RC_CHK_ACCESS(nsi)->in_pidns = false;
> + RC_CHK_ACCESS(nsi)->synthesized = true;
> /* Init may fail if the process exits while we're trying to look at its
> * proc information. In that case, save the pid but don't try to enter
> * the namespace.
> @@ -197,6 +200,7 @@ struct nsinfo *nsinfo__copy(const struct nsinfo *nsi)
> RC_CHK_ACCESS(nnsi)->nstgid = nsinfo__nstgid(nsi);
> RC_CHK_ACCESS(nnsi)->need_setns = nsinfo__need_setns(nsi);
> RC_CHK_ACCESS(nnsi)->in_pidns = nsinfo__in_pidns(nsi);
> + RC_CHK_ACCESS(nnsi)->synthesized = nsinfo__synthesized(nsi);
> if (nsinfo__mntns_path(nsi)) {
> RC_CHK_ACCESS(nnsi)->mntns_path = strdup(nsinfo__mntns_path(nsi));
> if (!RC_CHK_ACCESS(nnsi)->mntns_path) {
> @@ -275,6 +279,11 @@ void nsinfo__set_in_pidns(struct nsinfo *nsi)
> RC_CHK_ACCESS(nsi)->in_pidns = true;
> }
>
> +bool nsinfo__synthesized(const struct nsinfo *nsi)
> +{
> + return RC_CHK_ACCESS(nsi)->synthesized;
> +}
> +
> void nsinfo__mountns_enter(struct nsinfo *nsi,
> struct nscookie *nc)
> {
> diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
> index e95c79b80e27c..41ba2ea8137e5 100644
> --- a/tools/perf/util/namespaces.h
> +++ b/tools/perf/util/namespaces.h
> @@ -38,6 +38,7 @@ DECLARE_RC_STRUCT(nsinfo) {
> bool in_pidns;
> char *mntns_path;
> refcount_t refcnt;
> + bool synthesized;
It'd be nice if you can put this along with other bool fields.
Thanks,
Namhyung
> };
>
> struct nscookie {
> @@ -60,6 +61,7 @@ pid_t nsinfo__nstgid(const struct nsinfo *nsi);
> pid_t nsinfo__pid(const struct nsinfo *nsi);
> bool nsinfo__in_pidns(const struct nsinfo *nsi);
> void nsinfo__set_in_pidns(struct nsinfo *nsi);
> +bool nsinfo__synthesized(const struct nsinfo *nsi);
>
> void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc);
> void nsinfo__mountns_exit(struct nscookie *nc);
> --
> 2.51.1
>
On Thu, 2025-11-06 at 18:16 -0800, Namhyung Kim wrote:
> On Wed, Nov 05, 2025 at 08:10:24PM +0100, Ilya Leoshkevich wrote:
> > perf inject fails to detect jitdump file produced by a process
> > running in a different PID namespace if this process has not exited
> > yet.
> >
> > The PID namespace heuristic in jit_detect() compares two PIDs:
> >
> > * pid: outermost NStgid of mmap(jitdump) caller from perf's PoV.
> > * nsinfo__nstgid(nsi): innermost NStgid of mmap(jitdump) caller
> > from
> > perf's PoV.
> >
> > The semantics of the in_pidns variable can be seen in, e.g.,
> > nsinfo__get_nspid(): it's true if and only if perf and the profiled
> > process are in different PID namespaces.
> >
> > The current logic is clearly inverted: if pid and
> > nsinfo__nstgid(nsi)
> > are different, then the profiled process must be in a different PID
> > namespace. This, of course, ignores that fact that they may end up
> > being equal by accident, but that's not the point here.
> >
> > Fix by flipping the comparison.
> >
> > Changing just that, however, breaks the case when the process has
> > exited. Add explicit support for that by adding "synthesized" field
> > to
> > nsinfo, which tracks whether NStgid was obtained from a running
> > process (ignoring considerations of PID reuse or running inject on
> > a different machine). When the namespace information is
> > synthesized,
> > assume the process ran in a different PID namespace.
>
> I'm not sure I'm following. It'd be great if anyone understand the
> topic well could review.
Perhaps some data from the testcase from [5/5] can make it more clear.
Here are the PIDs that exist in reality:
unshare[a] perf-record unshare[b] jshell
Host PIDNS: 1000 1001 1002 1003
PIDNS[a]: - 1 2 3
PIDNS[b]: - - - 1
In jit_detect() we deal with 2 of them.
- pid is jshell@PIDNS[a].
It is taken from the MMAP2 event, this is how perf sees jshell.
- pid2 is jshell@PIDNS[b].
It is taken from "jit-1.dump", this is how jshell sees itself.
- nsinfo__nstgid(nsi) ideally should be jshell@PIDNS[b].
This is jshell's innermost NStgid.
But perf can see it differently. This is the core of the problem this
series deals with.
Why does nsinfo__nstgid(nsi) vary? Because the kernel does not record
it, and perf has to guess it. I have a WIP patch to fix that [1], but
it needs a lot more work at this point.
How does perf guess it? It looks into /proc/$PID/status. This is quite
unreliable, but this is the best perf can do under circumstances. As a
result we have 3 possibilities:
- The original process is still around. This is the buggy case. In this
case nsinfo__nstgid(nsi) == jshell@PIDNS[b]. IMHO this is a very
clear indication of namespacing, and that's why the condition should
be flipped.
- The original process has exited and PID was not reused. I believe
this is the use case the current code has been extensively tested
with. In this case perf assumes there was no namespacing and
nsinfo__nstgid(nsi) == pid. That's why I need the "synthesized"
field: to indicate that NStgid is just an assumption and didn't come
from any real data source.
- The original process has exited ans PID was reused. I am not trying
to deal with this here, because this is rare and absolutely anything
is possible. The only concern is running perf inject on a different
machine, but I'm also not sure whether we should care about this.
[1]
https://github.com/iii-i/linux/commit/4b519b774eed850abe0757df39be13a704d2748e
[...]
> > diff --git a/tools/perf/util/namespaces.h
> > b/tools/perf/util/namespaces.h
> > index e95c79b80e27c..41ba2ea8137e5 100644
> > --- a/tools/perf/util/namespaces.h
> > +++ b/tools/perf/util/namespaces.h
> > @@ -38,6 +38,7 @@ DECLARE_RC_STRUCT(nsinfo) {
> > bool in_pidns;
> > char *mntns_path;
> > refcount_t refcnt;
> > + bool synthesized;
>
> It'd be nice if you can put this along with other bool fields.
Sure, will do.
[...]
>
Hello,
Sorry for the delay.
On Fri, Nov 07, 2025 at 09:19:47AM +0100, Ilya Leoshkevich wrote:
> On Thu, 2025-11-06 at 18:16 -0800, Namhyung Kim wrote:
> > On Wed, Nov 05, 2025 at 08:10:24PM +0100, Ilya Leoshkevich wrote:
> > > perf inject fails to detect jitdump file produced by a process
> > > running in a different PID namespace if this process has not exited
> > > yet.
> > >
> > > The PID namespace heuristic in jit_detect() compares two PIDs:
> > >
> > > * pid: outermost NStgid of mmap(jitdump) caller from perf's PoV.
> > > * nsinfo__nstgid(nsi): innermost NStgid of mmap(jitdump) caller
> > > from
> > > perf's PoV.
> > >
> > > The semantics of the in_pidns variable can be seen in, e.g.,
> > > nsinfo__get_nspid(): it's true if and only if perf and the profiled
> > > process are in different PID namespaces.
> > >
> > > The current logic is clearly inverted: if pid and
> > > nsinfo__nstgid(nsi)
> > > are different, then the profiled process must be in a different PID
> > > namespace. This, of course, ignores that fact that they may end up
> > > being equal by accident, but that's not the point here.
> > >
> > > Fix by flipping the comparison.
> > >
> > > Changing just that, however, breaks the case when the process has
> > > exited. Add explicit support for that by adding "synthesized" field
> > > to
> > > nsinfo, which tracks whether NStgid was obtained from a running
> > > process (ignoring considerations of PID reuse or running inject on
> > > a different machine). When the namespace information is
> > > synthesized,
> > > assume the process ran in a different PID namespace.
> >
> > I'm not sure I'm following. It'd be great if anyone understand the
> > topic well could review.
>
> Perhaps some data from the testcase from [5/5] can make it more clear.
> Here are the PIDs that exist in reality:
>
> unshare[a] perf-record unshare[b] jshell
> Host PIDNS: 1000 1001 1002 1003
> PIDNS[a]: - 1 2 3
> PIDNS[b]: - - - 1
>
> In jit_detect() we deal with 2 of them.
>
> - pid is jshell@PIDNS[a].
> It is taken from the MMAP2 event, this is how perf sees jshell.
>
> - pid2 is jshell@PIDNS[b].
> It is taken from "jit-1.dump", this is how jshell sees itself.
>
> - nsinfo__nstgid(nsi) ideally should be jshell@PIDNS[b].
> This is jshell's innermost NStgid.
> But perf can see it differently. This is the core of the problem this
> series deals with.
Thanks a lot for the example and explanation! I'm trying to understand.
:)
>
> Why does nsinfo__nstgid(nsi) vary? Because the kernel does not record
> it, and perf has to guess it. I have a WIP patch to fix that [1], but
> it needs a lot more work at this point.
>
> How does perf guess it? It looks into /proc/$PID/status. This is quite
> unreliable, but this is the best perf can do under circumstances. As a
> result we have 3 possibilities:
>
> - The original process is still around. This is the buggy case. In this
> case nsinfo__nstgid(nsi) == jshell@PIDNS[b]. IMHO this is a very
> clear indication of namespacing, and that's why the condition should
> be flipped.
So perf would look at /proc/3/status and the file would have the below
NStgid: 1003 3 1
and *in_pidns should be true, right?
>
> - The original process has exited and PID was not reused. I believe
> this is the use case the current code has been extensively tested
> with. In this case perf assumes there was no namespacing and
> nsinfo__nstgid(nsi) == pid. That's why I need the "synthesized"
> field: to indicate that NStgid is just an assumption and didn't come
> from any real data source.
Ok, can you please put short comments on each boolean field so that we
can see the meaning of them clearly?
>
> - The original process has exited ans PID was reused. I am not trying
> to deal with this here, because this is rare and absolutely anything
> is possible. The only concern is running perf inject on a different
> machine, but I'm also not sure whether we should care about this.
Fair enough.
Thanks,
Namhyung
>
> [1]
> https://github.com/iii-i/linux/commit/4b519b774eed850abe0757df39be13a704d2748e
>
> [...]
>
> > > diff --git a/tools/perf/util/namespaces.h
> > > b/tools/perf/util/namespaces.h
> > > index e95c79b80e27c..41ba2ea8137e5 100644
> > > --- a/tools/perf/util/namespaces.h
> > > +++ b/tools/perf/util/namespaces.h
> > > @@ -38,6 +38,7 @@ DECLARE_RC_STRUCT(nsinfo) {
> > > bool in_pidns;
> > > char *mntns_path;
> > > refcount_t refcnt;
> > > + bool synthesized;
> >
> > It'd be nice if you can put this along with other bool fields.
>
> Sure, will do.
>
> [...]
> >
On Fri, 2025-11-14 at 00:07 -0800, Namhyung Kim wrote:
> Hello,
>
> Sorry for the delay.
>
> On Fri, Nov 07, 2025 at 09:19:47AM +0100, Ilya Leoshkevich wrote:
> > On Thu, 2025-11-06 at 18:16 -0800, Namhyung Kim wrote:
> > > On Wed, Nov 05, 2025 at 08:10:24PM +0100, Ilya Leoshkevich wrote:
> > > > perf inject fails to detect jitdump file produced by a process
> > > > running in a different PID namespace if this process has not
> > > > exited
> > > > yet.
> > > >
> > > > The PID namespace heuristic in jit_detect() compares two PIDs:
> > > >
> > > > * pid: outermost NStgid of mmap(jitdump) caller from perf's
> > > > PoV.
> > > > * nsinfo__nstgid(nsi): innermost NStgid of mmap(jitdump) caller
> > > > from
> > > > perf's PoV.
> > > >
> > > > The semantics of the in_pidns variable can be seen in, e.g.,
> > > > nsinfo__get_nspid(): it's true if and only if perf and the
> > > > profiled
> > > > process are in different PID namespaces.
> > > >
> > > > The current logic is clearly inverted: if pid and
> > > > nsinfo__nstgid(nsi)
> > > > are different, then the profiled process must be in a different
> > > > PID
> > > > namespace. This, of course, ignores that fact that they may end
> > > > up
> > > > being equal by accident, but that's not the point here.
> > > >
> > > > Fix by flipping the comparison.
> > > >
> > > > Changing just that, however, breaks the case when the process
> > > > has
> > > > exited. Add explicit support for that by adding "synthesized"
> > > > field
> > > > to
> > > > nsinfo, which tracks whether NStgid was obtained from a running
> > > > process (ignoring considerations of PID reuse or running inject
> > > > on
> > > > a different machine). When the namespace information is
> > > > synthesized,
> > > > assume the process ran in a different PID namespace.
> > >
> > > I'm not sure I'm following. It'd be great if anyone understand
> > > the
> > > topic well could review.
> >
> > Perhaps some data from the testcase from [5/5] can make it more
> > clear.
> > Here are the PIDs that exist in reality:
> >
> > unshare[a] perf-record unshare[b] jshell
> > Host PIDNS: 1000 1001 1002 1003
> > PIDNS[a]: - 1 2 3
> > PIDNS[b]: - - - 1
> >
> > In jit_detect() we deal with 2 of them.
> >
> > - pid is jshell@PIDNS[a].
> > It is taken from the MMAP2 event, this is how perf sees jshell.
> >
> > - pid2 is jshell@PIDNS[b].
> > It is taken from "jit-1.dump", this is how jshell sees itself.
> >
> > - nsinfo__nstgid(nsi) ideally should be jshell@PIDNS[b].
> > This is jshell's innermost NStgid.
> > But perf can see it differently. This is the core of the problem
> > this
> > series deals with.
>
> Thanks a lot for the example and explanation! I'm trying to
> understand.
> :)
Thank you for the patience!
> > Why does nsinfo__nstgid(nsi) vary? Because the kernel does not
> > record
> > it, and perf has to guess it. I have a WIP patch to fix that [1],
> > but
> > it needs a lot more work at this point.
> >
> > How does perf guess it? It looks into /proc/$PID/status. This is
> > quite
> > unreliable, but this is the best perf can do under circumstances.
> > As a
> > result we have 3 possibilities:
> >
> > - The original process is still around. This is the buggy case. In
> > this
> > case nsinfo__nstgid(nsi) == jshell@PIDNS[b]. IMHO this is a very
> > clear indication of namespacing, and that's why the condition
> > should
> > be flipped.
>
> So perf would look at /proc/3/status and the file would have the
> below
>
> NStgid: 1003 3 1
>
> and *in_pidns should be true, right?
It should be
NStgid: 3 1
because perf itself is namespaced too - in this testcase nobody sees
the root PID namespace. I wrote it this way to make sure there are
no accidental leaks from the root PID namespace, but it's not very
important and perhaps obscures things somewhat unnecessarily.
But regardless, I believe that in this case setting *in_pidns to true
is the right thing.
> > - The original process has exited and PID was not reused. I believe
> > this is the use case the current code has been extensively tested
> > with. In this case perf assumes there was no namespacing and
> > nsinfo__nstgid(nsi) == pid. That's why I need the "synthesized"
> > field: to indicate that NStgid is just an assumption and didn't
> > come
> > from any real data source.
>
> Ok, can you please put short comments on each boolean field so that
> we
> can see the meaning of them clearly?
Sure, I can add this in v2.
[...]
On Fri, Nov 14, 2025 at 01:44:30PM +0100, Ilya Leoshkevich wrote: > On Fri, 2025-11-14 at 00:07 -0800, Namhyung Kim wrote: > > Hello, > > > > Sorry for the delay. > > > > On Fri, Nov 07, 2025 at 09:19:47AM +0100, Ilya Leoshkevich wrote: > > > On Thu, 2025-11-06 at 18:16 -0800, Namhyung Kim wrote: > > > > On Wed, Nov 05, 2025 at 08:10:24PM +0100, Ilya Leoshkevich wrote: > > > > > perf inject fails to detect jitdump file produced by a process > > > > > running in a different PID namespace if this process has not > > > > > exited > > > > > yet. > > > > > > > > > > The PID namespace heuristic in jit_detect() compares two PIDs: > > > > > > > > > > * pid: outermost NStgid of mmap(jitdump) caller from perf's > > > > > PoV. > > > > > * nsinfo__nstgid(nsi): innermost NStgid of mmap(jitdump) caller > > > > > from > > > > > perf's PoV. > > > > > > > > > > The semantics of the in_pidns variable can be seen in, e.g., > > > > > nsinfo__get_nspid(): it's true if and only if perf and the > > > > > profiled > > > > > process are in different PID namespaces. > > > > > > > > > > The current logic is clearly inverted: if pid and > > > > > nsinfo__nstgid(nsi) > > > > > are different, then the profiled process must be in a different > > > > > PID > > > > > namespace. This, of course, ignores that fact that they may end > > > > > up > > > > > being equal by accident, but that's not the point here. > > > > > > > > > > Fix by flipping the comparison. > > > > > > > > > > Changing just that, however, breaks the case when the process > > > > > has > > > > > exited. Add explicit support for that by adding "synthesized" > > > > > field > > > > > to > > > > > nsinfo, which tracks whether NStgid was obtained from a running > > > > > process (ignoring considerations of PID reuse or running inject > > > > > on > > > > > a different machine). When the namespace information is > > > > > synthesized, > > > > > assume the process ran in a different PID namespace. > > > > > > > > I'm not sure I'm following. It'd be great if anyone understand > > > > the > > > > topic well could review. > > > > > > Perhaps some data from the testcase from [5/5] can make it more > > > clear. > > > Here are the PIDs that exist in reality: > > > > > > unshare[a] perf-record unshare[b] jshell > > > Host PIDNS: 1000 1001 1002 1003 > > > PIDNS[a]: - 1 2 3 > > > PIDNS[b]: - - - 1 > > > > > > In jit_detect() we deal with 2 of them. > > > > > > - pid is jshell@PIDNS[a]. > > > It is taken from the MMAP2 event, this is how perf sees jshell. > > > > > > - pid2 is jshell@PIDNS[b]. > > > It is taken from "jit-1.dump", this is how jshell sees itself. > > > > > > - nsinfo__nstgid(nsi) ideally should be jshell@PIDNS[b]. > > > This is jshell's innermost NStgid. > > > But perf can see it differently. This is the core of the problem > > > this > > > series deals with. > > > > Thanks a lot for the example and explanation! I'm trying to > > understand. > > :) > > Thank you for the patience! > > > > Why does nsinfo__nstgid(nsi) vary? Because the kernel does not > > > record > > > it, and perf has to guess it. I have a WIP patch to fix that [1], > > > but > > > it needs a lot more work at this point. > > > > > > How does perf guess it? It looks into /proc/$PID/status. This is > > > quite > > > unreliable, but this is the best perf can do under circumstances. > > > As a > > > result we have 3 possibilities: > > > > > > - The original process is still around. This is the buggy case. In > > > this > > > case nsinfo__nstgid(nsi) == jshell@PIDNS[b]. IMHO this is a very > > > clear indication of namespacing, and that's why the condition > > > should > > > be flipped. > > > > So perf would look at /proc/3/status and the file would have the > > below > > > > NStgid: 1003 3 1 > > > > and *in_pidns should be true, right? > > It should be > > NStgid: 3 1 > > because perf itself is namespaced too - in this testcase nobody sees > the root PID namespace. I wrote it this way to make sure there are > no accidental leaks from the root PID namespace, but it's not very > important and perhaps obscures things somewhat unnecessarily. Ah, ok. Thanks for the correction. > > But regardless, I believe that in this case setting *in_pidns to true > is the right thing. Yep, I agree. > > > > - The original process has exited and PID was not reused. I believe > > > this is the use case the current code has been extensively tested > > > with. In this case perf assumes there was no namespacing and > > > nsinfo__nstgid(nsi) == pid. That's why I need the "synthesized" > > > field: to indicate that NStgid is just an assumption and didn't > > > come > > > from any real data source. > > > > Ok, can you please put short comments on each boolean field so that > > we > > can see the meaning of them clearly? > > Sure, I can add this in v2. Perhaps it's better to split the part adding "synthesize" field to nsinfo in a separate commit and this one focuses on setting in_pidns. Thanks, Namhyung
© 2016 - 2025 Red Hat, Inc.