Commit f3b3614a authored by Hari Bathini's avatar Hari Bathini Committed by Arnaldo Carvalho de Melo

perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info

Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.

Committer notes:

Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.

Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:

  util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
     ret  += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
                                         ^
Testing it:

  # perf record --namespaces -a
  ^C[ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
  #
  # perf report -D
  <SNIP>
  3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
                [0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
                 4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]

  0x1151e0 [0x30]: event: 9
  .
  . ... raw event: size 48 bytes
  .  0000:  09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00  ......0..q.h....
  .  0010:  a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00  .9...9...(.c....
  .  0020:  03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00  ................
  <SNIP>
        NAMESPACES events:          1
  <SNIP>
  #
Signed-off-by: default avatarHari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent e4222673
...@@ -344,7 +344,8 @@ struct perf_event_attr { ...@@ -344,7 +344,8 @@ struct perf_event_attr {
use_clockid : 1, /* use @clockid for time fields */ use_clockid : 1, /* use @clockid for time fields */
context_switch : 1, /* context switch data */ context_switch : 1, /* context switch data */
write_backward : 1, /* Write ring buffer from end to beginning */ write_backward : 1, /* Write ring buffer from end to beginning */
__reserved_1 : 36; namespaces : 1, /* include namespaces data */
__reserved_1 : 35;
union { union {
__u32 wakeup_events; /* wakeup every n events */ __u32 wakeup_events; /* wakeup every n events */
...@@ -610,6 +611,23 @@ struct perf_event_header { ...@@ -610,6 +611,23 @@ struct perf_event_header {
__u16 size; __u16 size;
}; };
struct perf_ns_link_info {
__u64 dev;
__u64 ino;
};
enum {
NET_NS_INDEX = 0,
UTS_NS_INDEX = 1,
IPC_NS_INDEX = 2,
PID_NS_INDEX = 3,
USER_NS_INDEX = 4,
MNT_NS_INDEX = 5,
CGROUP_NS_INDEX = 6,
NR_NAMESPACES, /* number of available namespaces */
};
enum perf_event_type { enum perf_event_type {
/* /*
...@@ -862,6 +880,18 @@ enum perf_event_type { ...@@ -862,6 +880,18 @@ enum perf_event_type {
*/ */
PERF_RECORD_SWITCH_CPU_WIDE = 15, PERF_RECORD_SWITCH_CPU_WIDE = 15,
/*
* struct {
* struct perf_event_header header;
* u32 pid;
* u32 tid;
* u64 nr_namespaces;
* { u64 dev, inode; } [nr_namespaces];
* struct sample_id sample_id;
* };
*/
PERF_RECORD_NAMESPACES = 16,
PERF_RECORD_MAX, /* non-ABI */ PERF_RECORD_MAX, /* non-ABI */
}; };
......
...@@ -347,6 +347,9 @@ Enable weightened sampling. An additional weight is recorded per sample and can ...@@ -347,6 +347,9 @@ Enable weightened sampling. An additional weight is recorded per sample and can
displayed with the weight and local_weight sort keys. This currently works for TSX displayed with the weight and local_weight sort keys. This currently works for TSX
abort events and some memory events in precise mode on modern Intel CPUs. abort events and some memory events in precise mode on modern Intel CPUs.
--namespaces::
Record events of type PERF_RECORD_NAMESPACES.
--transaction:: --transaction::
Record transaction flags for transaction related events. Record transaction flags for transaction related events.
......
...@@ -393,6 +393,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -393,6 +393,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}, },
......
...@@ -364,6 +364,7 @@ static struct perf_tool tool = { ...@@ -364,6 +364,7 @@ static struct perf_tool tool = {
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}; };
......
...@@ -333,6 +333,18 @@ static int perf_event__repipe_comm(struct perf_tool *tool, ...@@ -333,6 +333,18 @@ static int perf_event__repipe_comm(struct perf_tool *tool,
return err; return err;
} }
static int perf_event__repipe_namespaces(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
int err = perf_event__process_namespaces(tool, event, sample, machine);
perf_event__repipe(tool, event, sample, machine);
return err;
}
static int perf_event__repipe_exit(struct perf_tool *tool, static int perf_event__repipe_exit(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -660,6 +672,7 @@ static int __cmd_inject(struct perf_inject *inject) ...@@ -660,6 +672,7 @@ static int __cmd_inject(struct perf_inject *inject)
session->itrace_synth_opts = &inject->itrace_synth_opts; session->itrace_synth_opts = &inject->itrace_synth_opts;
inject->itrace_synth_opts.inject = true; inject->itrace_synth_opts.inject = true;
inject->tool.comm = perf_event__repipe_comm; inject->tool.comm = perf_event__repipe_comm;
inject->tool.namespaces = perf_event__repipe_namespaces;
inject->tool.exit = perf_event__repipe_exit; inject->tool.exit = perf_event__repipe_exit;
inject->tool.id_index = perf_event__repipe_id_index; inject->tool.id_index = perf_event__repipe_id_index;
inject->tool.auxtrace_info = perf_event__process_auxtrace_info; inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
......
...@@ -964,6 +964,7 @@ static struct perf_tool perf_kmem = { ...@@ -964,6 +964,7 @@ static struct perf_tool perf_kmem = {
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
}; };
......
...@@ -1044,6 +1044,7 @@ static int read_events(struct perf_kvm_stat *kvm) ...@@ -1044,6 +1044,7 @@ static int read_events(struct perf_kvm_stat *kvm)
struct perf_tool eops = { struct perf_tool eops = {
.sample = process_sample_event, .sample = process_sample_event,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
}; };
struct perf_data_file file = { struct perf_data_file file = {
...@@ -1348,6 +1349,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, ...@@ -1348,6 +1349,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
kvm->tool.exit = perf_event__process_exit; kvm->tool.exit = perf_event__process_exit;
kvm->tool.fork = perf_event__process_fork; kvm->tool.fork = perf_event__process_fork;
kvm->tool.lost = process_lost_event; kvm->tool.lost = process_lost_event;
kvm->tool.namespaces = perf_event__process_namespaces;
kvm->tool.ordered_events = true; kvm->tool.ordered_events = true;
perf_tool__fill_defaults(&kvm->tool); perf_tool__fill_defaults(&kvm->tool);
......
...@@ -858,6 +858,7 @@ static int __cmd_report(bool display_info) ...@@ -858,6 +858,7 @@ static int __cmd_report(bool display_info)
struct perf_tool eops = { struct perf_tool eops = {
.sample = process_sample_event, .sample = process_sample_event,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
}; };
struct perf_data_file file = { struct perf_data_file file = {
......
...@@ -342,6 +342,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -342,6 +342,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
}, },
.input_name = "perf.data", .input_name = "perf.data",
......
...@@ -876,6 +876,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -876,6 +876,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
signal(SIGSEGV, sigsegv_handler); signal(SIGSEGV, sigsegv_handler);
if (rec->opts.record_namespaces)
tool->namespace_events = true;
if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) { if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) {
signal(SIGUSR2, snapshot_sig_handler); signal(SIGUSR2, snapshot_sig_handler);
if (rec->opts.auxtrace_snapshot_mode) if (rec->opts.auxtrace_snapshot_mode)
...@@ -1497,6 +1500,7 @@ static struct record record = { ...@@ -1497,6 +1500,7 @@ static struct record record = {
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.ordered_events = true, .ordered_events = true,
...@@ -1611,6 +1615,8 @@ static struct option __record_options[] = { ...@@ -1611,6 +1615,8 @@ static struct option __record_options[] = {
"opts", "AUX area tracing Snapshot Mode", ""), "opts", "AUX area tracing Snapshot Mode", ""),
OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout, OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
"per thread proc mmap processing timeout in ms"), "per thread proc mmap processing timeout in ms"),
OPT_BOOLEAN(0, "namespaces", &record.opts.record_namespaces,
"Record namespaces events"),
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
"Record context switch events"), "Record context switch events"),
OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel, OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
......
...@@ -700,6 +700,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -700,6 +700,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
......
...@@ -3272,6 +3272,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3272,6 +3272,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
.tool = { .tool = {
.sample = perf_sched__process_tracepoint_sample, .sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.fork = perf_sched__process_fork_event, .fork = perf_sched__process_fork_event,
.ordered_events = true, .ordered_events = true,
......
...@@ -2097,6 +2097,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2097,6 +2097,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.attr = process_attr, .attr = process_attr,
......
...@@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace) ...@@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace)
trace->tool.exit = perf_event__process_exit; trace->tool.exit = perf_event__process_exit;
trace->tool.fork = perf_event__process_fork; trace->tool.fork = perf_event__process_fork;
trace->tool.attr = perf_event__process_attr; trace->tool.attr = perf_event__process_attr;
trace->tool.tracing_data = perf_event__process_tracing_data; trace->tool.tracing_data = perf_event__process_tracing_data;
trace->tool.build_id = perf_event__process_build_id; trace->tool.build_id = perf_event__process_build_id;
trace->tool.namespaces = perf_event__process_namespaces;
trace->tool.ordered_events = true; trace->tool.ordered_events = true;
trace->tool.ordering_requires_timestamps = true; trace->tool.ordering_requires_timestamps = true;
......
...@@ -50,6 +50,7 @@ struct record_opts { ...@@ -50,6 +50,7 @@ struct record_opts {
bool running_time; bool running_time;
bool full_auxtrace; bool full_auxtrace;
bool auxtrace_snapshot_mode; bool auxtrace_snapshot_mode;
bool record_namespaces;
bool record_switch_events; bool record_switch_events;
bool all_kernel; bool all_kernel;
bool all_user; bool all_user;
......
...@@ -42,6 +42,7 @@ libperf-y += pstack.o ...@@ -42,6 +42,7 @@ libperf-y += pstack.o
libperf-y += session.o libperf-y += session.o
libperf-$(CONFIG_AUDIT) += syscalltbl.o libperf-$(CONFIG_AUDIT) += syscalltbl.o
libperf-y += ordered-events.o libperf-y += ordered-events.o
libperf-y += namespaces.o
libperf-y += comm.o libperf-y += comm.o
libperf-y += thread.o libperf-y += thread.o
libperf-y += thread_map.o libperf-y += thread_map.o
......
...@@ -1468,6 +1468,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, ...@@ -1468,6 +1468,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.tracing_data = perf_event__process_tracing_data, .tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}, },
......
...@@ -31,6 +31,7 @@ static const char *perf_event__names[] = { ...@@ -31,6 +31,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES", [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES",
[PERF_RECORD_SWITCH] = "SWITCH", [PERF_RECORD_SWITCH] = "SWITCH",
[PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE", [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE",
[PERF_RECORD_NAMESPACES] = "NAMESPACES",
[PERF_RECORD_HEADER_ATTR] = "ATTR", [PERF_RECORD_HEADER_ATTR] = "ATTR",
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
[PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
...@@ -49,6 +50,16 @@ static const char *perf_event__names[] = { ...@@ -49,6 +50,16 @@ static const char *perf_event__names[] = {
[PERF_RECORD_TIME_CONV] = "TIME_CONV", [PERF_RECORD_TIME_CONV] = "TIME_CONV",
}; };
static const char *perf_ns__names[] = {
[NET_NS_INDEX] = "net",
[UTS_NS_INDEX] = "uts",
[IPC_NS_INDEX] = "ipc",
[PID_NS_INDEX] = "pid",
[USER_NS_INDEX] = "user",
[MNT_NS_INDEX] = "mnt",
[CGROUP_NS_INDEX] = "cgroup",
};
const char *perf_event__name(unsigned int id) const char *perf_event__name(unsigned int id)
{ {
if (id >= ARRAY_SIZE(perf_event__names)) if (id >= ARRAY_SIZE(perf_event__names))
...@@ -58,6 +69,13 @@ const char *perf_event__name(unsigned int id) ...@@ -58,6 +69,13 @@ const char *perf_event__name(unsigned int id)
return perf_event__names[id]; return perf_event__names[id];
} }
static const char *perf_ns__name(unsigned int id)
{
if (id >= ARRAY_SIZE(perf_ns__names))
return "UNKNOWN";
return perf_ns__names[id];
}
static int perf_tool__process_synth_event(struct perf_tool *tool, static int perf_tool__process_synth_event(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct machine *machine, struct machine *machine,
...@@ -1008,6 +1026,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) ...@@ -1008,6 +1026,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
} }
size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
{
size_t ret = 0;
struct perf_ns_link_info *ns_link_info;
u32 nr_namespaces, idx;
ns_link_info = event->namespaces.link_info;
nr_namespaces = event->namespaces.nr_namespaces;
ret += fprintf(fp, " %d/%d - nr_namespaces: %u\n\t\t[",
event->namespaces.pid,
event->namespaces.tid,
nr_namespaces);
for (idx = 0; idx < nr_namespaces; idx++) {
if (idx && (idx % 4 == 0))
ret += fprintf(fp, "\n\t\t ");
ret += fprintf(fp, "%u/%s: %" PRIu64 "/%#" PRIx64 "%s", idx,
perf_ns__name(idx), (u64)ns_link_info[idx].dev,
(u64)ns_link_info[idx].ino,
((idx + 1) != nr_namespaces) ? ", " : "]\n");
}
return ret;
}
int perf_event__process_comm(struct perf_tool *tool __maybe_unused, int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -1016,6 +1061,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused, ...@@ -1016,6 +1061,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
return machine__process_comm_event(machine, event, sample); return machine__process_comm_event(machine, event, sample);
} }
int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
return machine__process_namespaces_event(machine, event, sample);
}
int perf_event__process_lost(struct perf_tool *tool __maybe_unused, int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -1196,6 +1249,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) ...@@ -1196,6 +1249,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
ret += perf_event__fprintf_mmap(event, fp); ret += perf_event__fprintf_mmap(event, fp);
break; break;
case PERF_RECORD_NAMESPACES:
ret += perf_event__fprintf_namespaces(event, fp);
break;
case PERF_RECORD_MMAP2: case PERF_RECORD_MMAP2:
ret += perf_event__fprintf_mmap2(event, fp); ret += perf_event__fprintf_mmap2(event, fp);
break; break;
......
...@@ -39,6 +39,13 @@ struct comm_event { ...@@ -39,6 +39,13 @@ struct comm_event {
char comm[16]; char comm[16];
}; };
struct namespaces_event {
struct perf_event_header header;
u32 pid, tid;
u64 nr_namespaces;
struct perf_ns_link_info link_info[];
};
struct fork_event { struct fork_event {
struct perf_event_header header; struct perf_event_header header;
u32 pid, ppid; u32 pid, ppid;
...@@ -485,6 +492,7 @@ union perf_event { ...@@ -485,6 +492,7 @@ union perf_event {
struct mmap_event mmap; struct mmap_event mmap;
struct mmap2_event mmap2; struct mmap2_event mmap2;
struct comm_event comm; struct comm_event comm;
struct namespaces_event namespaces;
struct fork_event fork; struct fork_event fork;
struct lost_event lost; struct lost_event lost;
struct lost_samples_event lost_samples; struct lost_samples_event lost_samples;
...@@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool, ...@@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct machine *machine); struct machine *machine);
int perf_event__process_namespaces(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
int perf_event__process_mmap(struct perf_tool *tool, int perf_event__process_mmap(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -653,6 +665,7 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); ...@@ -653,6 +665,7 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp);
u64 kallsyms__get_function_start(const char *kallsyms_filename, u64 kallsyms__get_function_start(const char *kallsyms_filename,
......
...@@ -932,6 +932,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, ...@@ -932,6 +932,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
attr->mmap2 = track && !perf_missing_features.mmap2; attr->mmap2 = track && !perf_missing_features.mmap2;
attr->comm = track; attr->comm = track;
if (opts->record_namespaces)
attr->namespaces = track;
if (opts->record_switch_events) if (opts->record_switch_events)
attr->context_switch = track; attr->context_switch = track;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <symbol/kallsyms.h> #include <symbol/kallsyms.h>
#include "unwind.h" #include "unwind.h"
#include "linux/hash.h" #include "linux/hash.h"
#include "asm/bug.h"
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);
...@@ -501,6 +502,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event ...@@ -501,6 +502,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
return err; return err;
} }
int machine__process_namespaces_event(struct machine *machine __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused)
{
struct thread *thread = machine__findnew_thread(machine,
event->namespaces.pid,
event->namespaces.tid);
int err = 0;
WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES,
"\nWARNING: kernel seems to support more namespaces than perf"
" tool.\nTry updating the perf tool..\n\n");
WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES,
"\nWARNING: perf tool seems to support more namespaces than"
" the kernel.\nTry updating the kernel..\n\n");
if (dump_trace)
perf_event__fprintf_namespaces(event, stdout);
if (thread == NULL ||
thread__set_namespaces(thread, sample->time, &event->namespaces)) {
dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
err = -1;
}
thread__put(thread);
return err;
}
int machine__process_lost_event(struct machine *machine __maybe_unused, int machine__process_lost_event(struct machine *machine __maybe_unused,
union perf_event *event, struct perf_sample *sample __maybe_unused) union perf_event *event, struct perf_sample *sample __maybe_unused)
{ {
...@@ -1538,6 +1570,8 @@ int machine__process_event(struct machine *machine, union perf_event *event, ...@@ -1538,6 +1570,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
ret = machine__process_comm_event(machine, event, sample); break; ret = machine__process_comm_event(machine, event, sample); break;
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
ret = machine__process_mmap_event(machine, event, sample); break; ret = machine__process_mmap_event(machine, event, sample); break;
case PERF_RECORD_NAMESPACES:
ret = machine__process_namespaces_event(machine, event, sample); break;
case PERF_RECORD_MMAP2: case PERF_RECORD_MMAP2:
ret = machine__process_mmap2_event(machine, event, sample); break; ret = machine__process_mmap2_event(machine, event, sample); break;
case PERF_RECORD_FORK: case PERF_RECORD_FORK:
......
...@@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine, ...@@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine,
union perf_event *event); union perf_event *event);
int machine__process_switch_event(struct machine *machine, int machine__process_switch_event(struct machine *machine,
union perf_event *event); union perf_event *event);
int machine__process_namespaces_event(struct machine *machine,
union perf_event *event,
struct perf_sample *sample);
int machine__process_mmap_event(struct machine *machine, union perf_event *event, int machine__process_mmap_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample); struct perf_sample *sample);
int machine__process_mmap2_event(struct machine *machine, union perf_event *event, int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
......
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* Copyright (C) 2017 Hari Bathini, IBM Corporation
*/
#include "namespaces.h"
#include "util.h"
#include "event.h"
#include <stdlib.h>
#include <stdio.h>
struct namespaces *namespaces__new(struct namespaces_event *event)
{
struct namespaces *namespaces;
u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
sizeof(struct perf_ns_link_info));
namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
if (!namespaces)
return NULL;
namespaces->end_time = -1;
if (event)
memcpy(namespaces->link_info, event->link_info, link_info_size);
return namespaces;
}
void namespaces__free(struct namespaces *namespaces)
{
free(namespaces);
}
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* Copyright (C) 2017 Hari Bathini, IBM Corporation
*/
#ifndef __PERF_NAMESPACES_H
#define __PERF_NAMESPACES_H
#include "../perf.h"
#include <linux/list.h>
struct namespaces_event;
struct namespaces {
struct list_head list;
u64 end_time;
struct perf_ns_link_info link_info[];
};
struct namespaces *namespaces__new(struct namespaces_event *event);
void namespaces__free(struct namespaces *namespaces);
#endif /* __PERF_NAMESPACES_H */
...@@ -1239,6 +1239,8 @@ static int machines__deliver_event(struct machines *machines, ...@@ -1239,6 +1239,8 @@ static int machines__deliver_event(struct machines *machines,
return tool->mmap2(tool, event, sample, machine); return tool->mmap2(tool, event, sample, machine);
case PERF_RECORD_COMM: case PERF_RECORD_COMM:
return tool->comm(tool, event, sample, machine); return tool->comm(tool, event, sample, machine);
case PERF_RECORD_NAMESPACES:
return tool->namespaces(tool, event, sample, machine);
case PERF_RECORD_FORK: case PERF_RECORD_FORK:
return tool->fork(tool, event, sample, machine); return tool->fork(tool, event, sample, machine);
case PERF_RECORD_EXIT: case PERF_RECORD_EXIT:
...@@ -1494,6 +1496,11 @@ int perf_session__register_idle_thread(struct perf_session *session) ...@@ -1494,6 +1496,11 @@ int perf_session__register_idle_thread(struct perf_session *session)
err = -1; err = -1;
} }
if (thread == NULL || thread__set_namespaces(thread, 0, NULL)) {
pr_err("problem inserting idle task.\n");
err = -1;
}
/* machine__findnew_thread() got the thread, so put it */ /* machine__findnew_thread() got the thread, so put it */
thread__put(thread); thread__put(thread);
return err; return err;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "thread-stack.h" #include "thread-stack.h"
#include "util.h" #include "util.h"
#include "debug.h" #include "debug.h"
#include "namespaces.h"
#include "comm.h" #include "comm.h"
#include "unwind.h" #include "unwind.h"
...@@ -40,6 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) ...@@ -40,6 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
thread->tid = tid; thread->tid = tid;
thread->ppid = -1; thread->ppid = -1;
thread->cpu = -1; thread->cpu = -1;
INIT_LIST_HEAD(&thread->namespaces_list);
INIT_LIST_HEAD(&thread->comm_list); INIT_LIST_HEAD(&thread->comm_list);
comm_str = malloc(32); comm_str = malloc(32);
...@@ -66,7 +68,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) ...@@ -66,7 +68,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
void thread__delete(struct thread *thread) void thread__delete(struct thread *thread)
{ {
struct comm *comm, *tmp; struct namespaces *namespaces, *tmp_namespaces;
struct comm *comm, *tmp_comm;
BUG_ON(!RB_EMPTY_NODE(&thread->rb_node)); BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
...@@ -76,7 +79,12 @@ void thread__delete(struct thread *thread) ...@@ -76,7 +79,12 @@ void thread__delete(struct thread *thread)
map_groups__put(thread->mg); map_groups__put(thread->mg);
thread->mg = NULL; thread->mg = NULL;
} }
list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { list_for_each_entry_safe(namespaces, tmp_namespaces,
&thread->namespaces_list, list) {
list_del(&namespaces->list);
namespaces__free(namespaces);
}
list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
list_del(&comm->list); list_del(&comm->list);
comm__free(comm); comm__free(comm);
} }
...@@ -104,6 +112,38 @@ void thread__put(struct thread *thread) ...@@ -104,6 +112,38 @@ void thread__put(struct thread *thread)
} }
} }
struct namespaces *thread__namespaces(const struct thread *thread)
{
if (list_empty(&thread->namespaces_list))
return NULL;
return list_first_entry(&thread->namespaces_list, struct namespaces, list);
}
int thread__set_namespaces(struct thread *thread, u64 timestamp,
struct namespaces_event *event)
{
struct namespaces *new, *curr = thread__namespaces(thread);
new = namespaces__new(event);
if (!new)
return -ENOMEM;
list_add(&new->list, &thread->namespaces_list);
if (timestamp && curr) {
/*
* setns syscall must have changed few or all the namespaces
* of this thread. Update end time for the namespaces
* previously used.
*/
curr = list_next_entry(new, list);
curr->end_time = timestamp;
}
return 0;
}
struct comm *thread__comm(const struct thread *thread) struct comm *thread__comm(const struct thread *thread)
{ {
if (list_empty(&thread->comm_list)) if (list_empty(&thread->comm_list))
......
...@@ -28,6 +28,7 @@ struct thread { ...@@ -28,6 +28,7 @@ struct thread {
bool comm_set; bool comm_set;
int comm_len; int comm_len;
bool dead; /* if set thread has exited */ bool dead; /* if set thread has exited */
struct list_head namespaces_list;
struct list_head comm_list; struct list_head comm_list;
u64 db_id; u64 db_id;
...@@ -40,6 +41,7 @@ struct thread { ...@@ -40,6 +41,7 @@ struct thread {
}; };
struct machine; struct machine;
struct namespaces;
struct comm; struct comm;
struct thread *thread__new(pid_t pid, pid_t tid); struct thread *thread__new(pid_t pid, pid_t tid);
...@@ -62,6 +64,10 @@ static inline void thread__exited(struct thread *thread) ...@@ -62,6 +64,10 @@ static inline void thread__exited(struct thread *thread)
thread->dead = true; thread->dead = true;
} }
struct namespaces *thread__namespaces(const struct thread *thread);
int thread__set_namespaces(struct thread *thread, u64 timestamp,
struct namespaces_event *event);
int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
bool exec); bool exec);
static inline int thread__set_comm(struct thread *thread, const char *comm, static inline int thread__set_comm(struct thread *thread, const char *comm,
......
...@@ -40,6 +40,7 @@ struct perf_tool { ...@@ -40,6 +40,7 @@ struct perf_tool {
event_op mmap, event_op mmap,
mmap2, mmap2,
comm, comm,
namespaces,
fork, fork,
exit, exit,
lost, lost,
...@@ -66,6 +67,7 @@ struct perf_tool { ...@@ -66,6 +67,7 @@ struct perf_tool {
event_op3 auxtrace; event_op3 auxtrace;
bool ordered_events; bool ordered_events;
bool ordering_requires_timestamps; bool ordering_requires_timestamps;
bool namespace_events;
}; };
#endif /* __PERF_TOOL_H */ #endif /* __PERF_TOOL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment