Skip to content

Commit

Permalink
perf inject jit: Add namespaces support
Browse files Browse the repository at this point in the history
This patch fixes "perf inject --jit" to properly operate on
namespaced/containerized processes:

* jitdump files are generated by the process, thus they should be
  looked up in its mount NS.

* DSOs of injected MMAP events will later be looked up in the process
  mount NS, so write them into its NS.

* PIDs & TIDs from jitdump events need to be translated to the PID as
  seen by "perf record" before written into MMAP events.

For a process in a different PID NS, the TID & PID given in the jitdump
event are actually ignored; I use the TID & PID of the thread which
mmap()ed the jitdump file. This is simplified and won't do for forks of
the initial process, if they continue using the same jitdump file.
Future patches might improve it.

This was tested by recording a NodeJS process running with
"--perf-prof", inside a Docker container, and by recording another
NodeJS process running in the same namespaces as perf itself, to make
sure it's not broken for non-containerized processes.

Signed-off-by: Yonatan Goldschmidt <yonatan.goldschmidt@granulate.io>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20201105015604.1726943-1-yonatan.goldschmidt@granulate.io
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Yonatan Goldschmidt authored and Arnaldo Carvalho de Melo committed Feb 3, 2021
1 parent 2b51c71 commit 67dec92
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 22 deletions.
4 changes: 2 additions & 2 deletions tools/perf/builtin-inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,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, event->mmap.pid, &n);
event->mmap.filename, event->mmap.pid, event->mmap.tid, &n);
if (ret < 0)
return ret;
if (ret) {
Expand Down Expand Up @@ -413,7 +413,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, event->mmap2.pid, &n);
event->mmap2.filename, event->mmap2.pid, event->mmap2.tid, &n);
if (ret < 0)
return ret;
if (ret) {
Expand Down
2 changes: 1 addition & 1 deletion tools/perf/util/jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <data.h>

int jit_process(struct perf_session *session, struct perf_data *output,
struct machine *machine, char *filename, pid_t pid, u64 *nbytes);
struct machine *machine, char *filename, pid_t pid, pid_t tid, u64 *nbytes);

int jit_inject_record(const char *filename);

Expand Down
84 changes: 65 additions & 19 deletions tools/perf/util/jitdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "event.h"
#include "debug.h"
#include "evlist.h"
#include "namespaces.h"
#include "symbol.h"
#include <elf.h>

Expand All @@ -35,6 +36,7 @@ struct jit_buf_desc {
struct perf_data *output;
struct perf_session *session;
struct machine *machine;
struct nsinfo *nsi;
union jr_entry *entry;
void *buf;
uint64_t sample_type;
Expand Down Expand Up @@ -72,7 +74,8 @@ struct jit_tool {
#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))

static int
jit_emit_elf(char *filename,
jit_emit_elf(struct jit_buf_desc *jd,
char *filename,
const char *sym,
uint64_t code_addr,
const void *code,
Expand All @@ -83,14 +86,18 @@ jit_emit_elf(char *filename,
uint32_t unwinding_header_size,
uint32_t unwinding_size)
{
int ret, fd;
int ret, fd, saved_errno;
struct nscookie nsc;

if (verbose > 0)
fprintf(stderr, "write ELF image %s\n", filename);

nsinfo__mountns_enter(jd->nsi, &nsc);
fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
saved_errno = errno;
nsinfo__mountns_exit(&nsc);
if (fd == -1) {
pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(saved_errno));
return -1;
}

Expand All @@ -99,8 +106,11 @@ jit_emit_elf(char *filename,

close(fd);

if (ret)
unlink(filename);
if (ret) {
nsinfo__mountns_enter(jd->nsi, &nsc);
unlink(filename);
nsinfo__mountns_exit(&nsc);
}

return ret;
}
Expand Down Expand Up @@ -134,12 +144,15 @@ static int
jit_open(struct jit_buf_desc *jd, const char *name)
{
struct jitheader header;
struct nscookie nsc;
struct jr_prefix *prefix;
ssize_t bs, bsz = 0;
void *n, *buf = NULL;
int ret, retval = -1;

nsinfo__mountns_enter(jd->nsi, &nsc);
jd->in = fopen(name, "r");
nsinfo__mountns_exit(&nsc);
if (!jd->in)
return -1;

Expand Down Expand Up @@ -367,6 +380,20 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
return 0;
}

static pid_t jr_entry_pid(struct jit_buf_desc *jd, union jr_entry *jr)
{
if (jd->nsi && jd->nsi->in_pidns)
return jd->nsi->tgid;
return jr->load.pid;
}

static pid_t jr_entry_tid(struct jit_buf_desc *jd, union jr_entry *jr)
{
if (jd->nsi && jd->nsi->in_pidns)
return jd->nsi->pid;
return jr->load.tid;
}

static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
{
struct perf_tsc_conversion tc;
Expand Down Expand Up @@ -402,14 +429,15 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
const char *sym;
uint64_t count;
int ret, csize, usize;
pid_t pid, tid;
pid_t nspid, pid, tid;
struct {
u32 pid, tid;
u64 time;
} *id;

pid = jr->load.pid;
tid = jr->load.tid;
nspid = jr->load.pid;
pid = jr_entry_pid(jd, jr);
tid = jr_entry_tid(jd, jr);
csize = jr->load.code_size;
usize = jd->unwinding_mapped_size;
addr = jr->load.code_addr;
Expand All @@ -425,14 +453,14 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
filename = event->mmap2.filename;
size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so",
jd->dir,
pid,
nspid,
count);

size++; /* for \0 */

size = PERF_ALIGN(size, sizeof(u64));
uaddr = (uintptr_t)code;
ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries,
ret = jit_emit_elf(jd, filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries,
jd->unwinding_data, jd->eh_frame_hdr_size, jd->unwinding_size);

if (jd->debug_data && jd->nr_debug_entries) {
Expand All @@ -451,7 +479,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
free(event);
return -1;
}
if (stat(filename, &st))
if (nsinfo__stat(filename, &st, jd->nsi))
memset(&st, 0, sizeof(st));

event->mmap2.header.type = PERF_RECORD_MMAP2;
Expand Down Expand Up @@ -515,14 +543,15 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
int usize;
u16 idr_size;
int ret;
pid_t pid, tid;
pid_t nspid, pid, tid;
struct {
u32 pid, tid;
u64 time;
} *id;

pid = jr->move.pid;
tid = jr->move.tid;
nspid = jr->load.pid;
pid = jr_entry_pid(jd, jr);
tid = jr_entry_tid(jd, jr);
usize = jd->unwinding_mapped_size;
idr_size = jd->machine->id_hdr_size;

Expand All @@ -536,12 +565,12 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
filename = event->mmap2.filename;
size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so",
jd->dir,
pid,
nspid,
jr->move.code_index);

size++; /* for \0 */

if (stat(filename, &st))
if (nsinfo__stat(filename, &st, jd->nsi))
memset(&st, 0, sizeof(st));

size = PERF_ALIGN(size, sizeof(u64));
Expand Down Expand Up @@ -700,7 +729,7 @@ jit_inject(struct jit_buf_desc *jd, char *path)
* as captured in the RECORD_MMAP record
*/
static int
jit_detect(char *mmap_name, pid_t pid)
jit_detect(char *mmap_name, pid_t pid, struct nsinfo *nsi)
{
char *p;
char *end = NULL;
Expand Down Expand Up @@ -740,7 +769,7 @@ jit_detect(char *mmap_name, pid_t pid)
* pid does not match mmap pid
* pid==0 in system-wide mode (synthesized)
*/
if (pid && pid2 != pid)
if (pid && pid2 != nsi->nstgid)
return -1;
/*
* validate suffix
Expand Down Expand Up @@ -782,16 +811,30 @@ jit_process(struct perf_session *session,
struct machine *machine,
char *filename,
pid_t pid,
pid_t tid,
u64 *nbytes)
{
struct thread *thread;
struct nsinfo *nsi;
struct evsel *first;
struct jit_buf_desc jd;
int ret;

thread = machine__findnew_thread(machine, pid, tid);
if (thread == NULL) {
pr_err("problem processing JIT mmap event, skipping it.\n");
return 0;
}

nsi = nsinfo__get(thread->nsinfo);
thread__put(thread);

/*
* first, detect marker mmap (i.e., the jitdump mmap)
*/
if (jit_detect(filename, pid)) {
if (jit_detect(filename, pid, nsi)) {
nsinfo__put(nsi);

// Strip //anon* mmaps if we processed a jitdump for this pid
if (jit_has_pid(machine, pid) && (strncmp(filename, "//anon", 6) == 0))
return 1;
Expand All @@ -804,6 +847,7 @@ jit_process(struct perf_session *session,
jd.session = session;
jd.output = output;
jd.machine = machine;
jd.nsi = nsi;

/*
* track sample_type to compute id_all layout
Expand All @@ -821,5 +865,7 @@ jit_process(struct perf_session *session,
ret = 1;
}

nsinfo__put(jd.nsi);

return ret;
}
12 changes: 12 additions & 0 deletions tools/perf/util/namespaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,15 @@ char *nsinfo__realpath(const char *path, struct nsinfo *nsi)

return rpath;
}

int nsinfo__stat(const char *filename, struct stat *st, struct nsinfo *nsi)
{
int ret;
struct nscookie nsc;

nsinfo__mountns_enter(nsi, &nsc);
ret = stat(filename, st);
nsinfo__mountns_exit(&nsc);

return ret;
}
2 changes: 2 additions & 0 deletions tools/perf/util/namespaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define __PERF_NAMESPACES_H

#include <sys/types.h>
#include <sys/stat.h>
#include <linux/stddef.h>
#include <linux/perf_event.h>
#include <linux/refcount.h>
Expand Down Expand Up @@ -56,6 +57,7 @@ void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc);
void nsinfo__mountns_exit(struct nscookie *nc);

char *nsinfo__realpath(const char *path, struct nsinfo *nsi);
int nsinfo__stat(const char *filename, struct stat *st, struct nsinfo *nsi);

static inline void __nsinfo__zput(struct nsinfo **nsip)
{
Expand Down

0 comments on commit 67dec92

Please sign in to comment.