mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo 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.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									e422267322
								
							
						
					
					
						commit
						f3b3614a28
					
				
					 28 changed files with 296 additions and 4 deletions
				
			
		| 
						 | 
					@ -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 {
 | 
				
			||||||
	__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 {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	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
 | 
				
			||||||
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)
 | 
				
			||||||
			.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 = {
 | 
				
			||||||
	.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,
 | 
				
			||||||
	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)
 | 
				
			||||||
		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 = {
 | 
				
			||||||
	.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)
 | 
				
			||||||
	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,
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
			.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)
 | 
				
			||||||
	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 = {
 | 
				
			||||||
		.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[] = {
 | 
				
			||||||
			  "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)
 | 
				
			||||||
			.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)
 | 
				
			||||||
		.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)
 | 
				
			||||||
			.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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2417,6 +2417,7 @@ static int trace__replay(struct trace *trace)
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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
 | 
				
			||||||
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,
 | 
				
			||||||
			.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[] = {
 | 
				
			||||||
	[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[] = {
 | 
				
			||||||
	[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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	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,
 | 
				
			||||||
	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)
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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,
 | 
				
			||||||
			       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);
 | 
				
			||||||
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,
 | 
				
			||||||
	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 @@
 | 
				
			||||||
#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
 | 
				
			||||||
	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,
 | 
				
			||||||
		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,
 | 
				
			||||||
					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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										36
									
								
								tools/perf/util/namespaces.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								tools/perf/util/namespaces.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								tools/perf/util/namespaces.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tools/perf/util/namespaces.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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,
 | 
				
			||||||
		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)
 | 
				
			||||||
		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 @@
 | 
				
			||||||
#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)
 | 
				
			||||||
		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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
		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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
	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 {
 | 
				
			||||||
	event_op	mmap,
 | 
						event_op	mmap,
 | 
				
			||||||
			mmap2,
 | 
								mmap2,
 | 
				
			||||||
			comm,
 | 
								comm,
 | 
				
			||||||
 | 
								namespaces,
 | 
				
			||||||
			fork,
 | 
								fork,
 | 
				
			||||||
			exit,
 | 
								exit,
 | 
				
			||||||
			lost,
 | 
								lost,
 | 
				
			||||||
| 
						 | 
					@ -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 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue