All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/3] perf: add support for analyzing events for containers
@ 2017-02-08  8:31 Hari Bathini
  2017-02-08  8:31 ` [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info Hari Bathini
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-08  8:31 UTC (permalink / raw)
  To: ast, peterz, lkml, acme, alexander.shishkin, mingo
  Cc: daniel, rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg, jolsa

Currently, there is no trivial mechanism to analyze events based on
containers. perf -G can be used, but it will not filter events for the
containers created after perf is invoked, making it difficult to assess/
analyze performance issues of multiple containers at once.

This patch-set is aimed at addressing this limitation by introducing a
new PERF_RECORD_NAMESPACES event that records namespaces related info.
As containers are created with namespaces, the new data can be used to
in assessment/analysis of multiple containers.

The first patch introduces PERF_RECORD_NAMESPACES in kernel while the
second patch makes the corresponding changes in perf tool to read this
PERF_RECORD_NAMESPACES events. The third patch demonstrates analysis
of containers with this data by adding a cgroup identifier column in
perf report, which contains the cgroup namespace's device and inode
numbers. This is based on the assumption that each container is created
with it's own cgroup namespace. The third patch has scope for improvement
based on the conventions a container is attributed with, going forward.

Changes from v5:
* Updated changelogs of patches 1 & 3
* Rebased the patches on perf/core in tip

---

Hari Bathini (3):
      perf: add PERF_RECORD_NAMESPACES to include namespaces related info
      perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
      perf tool: add cgroup identifier entry in perf report


 include/linux/perf_event.h            |    2 
 include/uapi/linux/perf_event.h       |   38 +++++++++
 kernel/events/core.c                  |  142 +++++++++++++++++++++++++++++++++
 kernel/fork.c                         |    3 +
 kernel/nsproxy.c                      |    5 +
 tools/include/uapi/linux/perf_event.h |   38 +++++++++
 tools/perf/builtin-annotate.c         |    1 
 tools/perf/builtin-diff.c             |    1 
 tools/perf/builtin-inject.c           |   14 +++
 tools/perf/builtin-kmem.c             |    1 
 tools/perf/builtin-kvm.c              |    2 
 tools/perf/builtin-lock.c             |    1 
 tools/perf/builtin-mem.c              |    1 
 tools/perf/builtin-record.c           |   33 +++++++-
 tools/perf/builtin-report.c           |    1 
 tools/perf/builtin-sched.c            |    1 
 tools/perf/builtin-script.c           |   41 +++++++++
 tools/perf/builtin-trace.c            |    3 -
 tools/perf/perf.h                     |    1 
 tools/perf/util/Build                 |    1 
 tools/perf/util/data-convert-bt.c     |    2 
 tools/perf/util/event.c               |  143 ++++++++++++++++++++++++++++++++-
 tools/perf/util/event.h               |   19 ++++
 tools/perf/util/evsel.c               |    3 +
 tools/perf/util/hist.c                |    7 ++
 tools/perf/util/hist.h                |    1 
 tools/perf/util/machine.c             |   34 ++++++++
 tools/perf/util/machine.h             |    3 +
 tools/perf/util/namespaces.c          |   35 ++++++++
 tools/perf/util/namespaces.h          |   26 ++++++
 tools/perf/util/session.c             |    7 ++
 tools/perf/util/sort.c                |   41 +++++++++
 tools/perf/util/sort.h                |    7 ++
 tools/perf/util/thread.c              |   44 ++++++++++
 tools/perf/util/thread.h              |    6 +
 tools/perf/util/tool.h                |    2 
 36 files changed, 695 insertions(+), 15 deletions(-)
 create mode 100644 tools/perf/util/namespaces.c
 create mode 100644 tools/perf/util/namespaces.h

--
Signature

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 [PATCH v6 0/3] perf: add support for analyzing events for containers Hari Bathini
@ 2017-02-08  8:31 ` Hari Bathini
  2017-02-16 10:28   ` Peter Zijlstra
  2017-02-16 11:25   ` Eric W. Biederman
  2017-02-08  8:31 ` [PATCH v6 2/3] perf tool: " Hari Bathini
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-08  8:31 UTC (permalink / raw)
  To: ast, peterz, lkml, acme, alexander.shishkin, mingo
  Cc: daniel, rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg, jolsa

With the advert of container technologies like docker, that depend
on namespaces for isolation, there is a need for tracing support for
namespaces. This patch introduces new PERF_RECORD_NAMESPACES event
for tracing based on namespaces related info. This event records
the device and inode numbers for every namespace of all processes.

While device number is same for all namespaces currently, that may
change in future, to avoid the need for a namespace of namespaces.
Recording device number along with inode number will take care of such
scenario. Also, recording device and inode numbers for every namespace
lets the userspace take a call on the definition of a container and
update perf tool accordingly.

Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
---
 include/linux/perf_event.h      |    2 +
 include/uapi/linux/perf_event.h |   38 ++++++++++
 kernel/events/core.c            |  142 +++++++++++++++++++++++++++++++++++++++
 kernel/fork.c                   |    3 +
 kernel/nsproxy.c                |    5 +
 5 files changed, 189 insertions(+), 1 deletion(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5c58e93..4547fb6 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1110,6 +1110,7 @@ extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks
 
 extern void perf_event_exec(void);
 extern void perf_event_comm(struct task_struct *tsk, bool exec);
+extern void perf_event_namespaces(struct task_struct *tsk);
 extern void perf_event_fork(struct task_struct *tsk);
 
 /* Callchains */
@@ -1313,6 +1314,7 @@ static inline int perf_unregister_guest_info_callbacks
 static inline void perf_event_mmap(struct vm_area_struct *vma)		{ }
 static inline void perf_event_exec(void)				{ }
 static inline void perf_event_comm(struct task_struct *tsk, bool exec)	{ }
+static inline void perf_event_namespaces(struct task_struct *tsk)	{ }
 static inline void perf_event_fork(struct task_struct *tsk)		{ }
 static inline void perf_event_init(void)				{ }
 static inline int  perf_swevent_get_recursion_context(void)		{ return -1; }
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index c66a485..ee60f54 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -344,7 +344,8 @@ struct perf_event_attr {
 				use_clockid    :  1, /* use @clockid for time fields */
 				context_switch :  1, /* context switch data */
 				write_backward :  1, /* Write ring buffer from end to beginning */
-				__reserved_1   : 36;
+				namespaces     :  1, /* include namespaces data */
+				__reserved_1   : 35;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
@@ -610,6 +611,29 @@ struct perf_event_header {
 	__u16	size;
 };
 
+/*
+ * The maximum size of the name of each namespace
+ */
+#define NS_NAME_SIZE				8
+
+struct perf_ns_link_info {
+	char	name[NS_NAME_SIZE];
+	__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,
+
+	NAMESPACES_MAX,		/* maximum available namespaces */
+};
+
 enum perf_event_type {
 
 	/*
@@ -862,6 +886,18 @@ enum perf_event_type {
 	 */
 	PERF_RECORD_SWITCH_CPU_WIDE		= 15,
 
+	/*
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *	u32				pid;
+	 *	u32				tid;
+	 *	u32				nr_namespaces;
+	 *	struct namespace_link_info	link_info[NAMESPACES_MAX];
+	 *	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_NAMESPACES			= 16,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 88676ff..4427102 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -46,6 +46,8 @@
 #include <linux/filter.h>
 #include <linux/namei.h>
 #include <linux/parser.h>
+#include <linux/proc_ns.h>
+#include <linux/mount.h>
 
 #include "internal.h"
 
@@ -377,6 +379,7 @@ static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
 
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
+static atomic_t nr_namespaces_events __read_mostly;
 static atomic_t nr_task_events __read_mostly;
 static atomic_t nr_freq_events __read_mostly;
 static atomic_t nr_switch_events __read_mostly;
@@ -3982,6 +3985,8 @@ static void unaccount_event(struct perf_event *event)
 		atomic_dec(&nr_mmap_events);
 	if (event->attr.comm)
 		atomic_dec(&nr_comm_events);
+	if (event->attr.namespaces)
+		atomic_dec(&nr_namespaces_events);
 	if (event->attr.task)
 		atomic_dec(&nr_task_events);
 	if (event->attr.freq)
@@ -6482,6 +6487,7 @@ static void perf_event_task(struct task_struct *task,
 void perf_event_fork(struct task_struct *task)
 {
 	perf_event_task(task, NULL, 1);
+	perf_event_namespaces(task);
 }
 
 /*
@@ -6584,6 +6590,135 @@ void perf_event_comm(struct task_struct *task, bool exec)
 }
 
 /*
+ * namespaces tracking
+ */
+
+struct namespaces_event_id {
+	struct perf_event_header	header;
+
+	u32				pid;
+	u32				tid;
+	u32				nr_namespaces;
+	struct perf_ns_link_info	link_info[NAMESPACES_MAX];
+};
+
+struct perf_namespaces_event {
+	struct task_struct		*task;
+
+	struct namespaces_event_id	event_id;
+};
+
+static int perf_event_namespaces_match(struct perf_event *event)
+{
+	return event->attr.namespaces;
+}
+
+static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
+				   struct task_struct *task,
+				   const struct proc_ns_operations *ns_ops)
+{
+	struct path ns_path;
+	struct inode *ns_inode;
+	void *error;
+
+	error = ns_get_path(&ns_path, task, ns_ops);
+	if (!error) {
+		snprintf(ns_link_info->name, NS_NAME_SIZE,
+			 "%s", ns_path.dentry->d_iname);
+
+		ns_inode = ns_path.dentry->d_inode;
+		ns_link_info->dev = new_encode_dev(ns_inode->i_sb->s_dev);
+		ns_link_info->ino = ns_inode->i_ino;
+	}
+}
+
+static void perf_event_namespaces_output(struct perf_event *event,
+					 void *data)
+{
+	struct perf_namespaces_event *namespaces_event = data;
+	struct perf_output_handle handle;
+	struct perf_sample_data sample;
+	struct namespaces_event_id *ei;
+	struct task_struct *task = namespaces_event->task;
+	int ret;
+
+	if (!perf_event_namespaces_match(event))
+		return;
+
+	ei = &namespaces_event->event_id;
+	perf_event_header__init_id(&ei->header, &sample, event);
+	ret = perf_output_begin(&handle, event,	ei->header.size);
+	if (ret)
+		return;
+
+	ei->pid = perf_event_pid(event, task);
+	ei->tid = perf_event_tid(event, task);
+
+	ei->nr_namespaces = NAMESPACES_MAX;
+
+	perf_fill_ns_link_info(&ei->link_info[MNT_NS_INDEX],
+			       task, &mntns_operations);
+
+#ifdef CONFIG_USER_NS
+	perf_fill_ns_link_info(&ei->link_info[USER_NS_INDEX],
+			       task, &userns_operations);
+#endif
+#ifdef CONFIG_NET_NS
+	perf_fill_ns_link_info(&ei->link_info[NET_NS_INDEX],
+			       task, &netns_operations);
+#endif
+#ifdef CONFIG_UTS_NS
+	perf_fill_ns_link_info(&ei->link_info[UTS_NS_INDEX],
+			       task, &utsns_operations);
+#endif
+#ifdef CONFIG_IPC_NS
+	perf_fill_ns_link_info(&ei->link_info[IPC_NS_INDEX],
+			       task, &ipcns_operations);
+#endif
+#ifdef CONFIG_PID_NS
+	perf_fill_ns_link_info(&ei->link_info[PID_NS_INDEX],
+			       task, &pidns_operations);
+#endif
+#ifdef CONFIG_CGROUPS
+	perf_fill_ns_link_info(&ei->link_info[CGROUP_NS_INDEX],
+			       task, &cgroupns_operations);
+#endif
+
+	perf_output_put(&handle, namespaces_event->event_id);
+
+	perf_event__output_id_sample(event, &handle, &sample);
+
+	perf_output_end(&handle);
+}
+
+void perf_event_namespaces(struct task_struct *task)
+{
+	struct perf_namespaces_event namespaces_event;
+
+	if (!atomic_read(&nr_namespaces_events))
+		return;
+
+	namespaces_event = (struct perf_namespaces_event){
+		.task	= task,
+		.event_id  = {
+			.header = {
+				.type = PERF_RECORD_NAMESPACES,
+				.misc = 0,
+				.size = sizeof(namespaces_event.event_id),
+			},
+			/* .pid */
+			/* .tid */
+			/* .nr_namespaces */
+			/* .link_info[NAMESPACES_MAX] */
+		},
+	};
+
+	perf_iterate_sb(perf_event_namespaces_output,
+			&namespaces_event,
+			NULL);
+}
+
+/*
  * mmap tracking
  */
 
@@ -9122,6 +9257,8 @@ static void account_event(struct perf_event *event)
 		atomic_inc(&nr_mmap_events);
 	if (event->attr.comm)
 		atomic_inc(&nr_comm_events);
+	if (event->attr.namespaces)
+		atomic_inc(&nr_namespaces_events);
 	if (event->attr.task)
 		atomic_inc(&nr_task_events);
 	if (event->attr.freq)
@@ -9667,6 +9804,11 @@ SYSCALL_DEFINE5(perf_event_open,
 			return -EACCES;
 	}
 
+	if (attr.namespaces) {
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+	}
+
 	if (attr.freq) {
 		if (attr.sample_freq > sysctl_perf_event_sample_rate)
 			return -EINVAL;
diff --git a/kernel/fork.c b/kernel/fork.c
index 11c5c8a..fd77e67 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2289,6 +2289,9 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
 		free_fs_struct(new_fs);
 
 bad_unshare_out:
+	if (!err)
+		perf_event_namespaces(current);
+
 	return err;
 }
 
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 782102e..4c25e6e 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -26,6 +26,7 @@
 #include <linux/file.h>
 #include <linux/syscalls.h>
 #include <linux/cgroup.h>
+#include <linux/perf_event.h>
 
 static struct kmem_cache *nsproxy_cachep;
 
@@ -264,6 +265,10 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
 	switch_task_namespaces(tsk, new_nsproxy);
 out:
 	fput(file);
+
+	if (!err)
+		perf_event_namespaces(tsk);
+
 	return err;
 }
 

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v6 2/3] perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 [PATCH v6 0/3] perf: add support for analyzing events for containers Hari Bathini
  2017-02-08  8:31 ` [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info Hari Bathini
@ 2017-02-08  8:31 ` Hari Bathini
  2017-02-08 12:57   ` Jiri Olsa
                     ` (2 more replies)
  2017-02-08  8:32 ` [PATCH v6 3/3] perf tool: add cgroup identifier entry in perf report Hari Bathini
  2017-02-16  6:20 ` [PATCH v6 0/3] perf: add support for analyzing events for containers Eric W. Biederman
  3 siblings, 3 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-08  8:31 UTC (permalink / raw)
  To: ast, peterz, lkml, acme, alexander.shishkin, mingo
  Cc: daniel, rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg, jolsa

This patch updates perf tool to examine PERF_RECORD_NAMESPACES events
emitted by the kernel when fork, clone, setns or unshare are invoked.
Also, it synthesizes PERF_RECORD_NAMESPACES events for processes that
were running prior to invocation of perf record, the data for which
is taken from /proc/$PID/ns. These changes make way for analyzing
events with regard to namespaces.

Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
---
 tools/include/uapi/linux/perf_event.h |   38 +++++++++
 tools/perf/builtin-annotate.c         |    1 
 tools/perf/builtin-diff.c             |    1 
 tools/perf/builtin-inject.c           |   14 +++
 tools/perf/builtin-kmem.c             |    1 
 tools/perf/builtin-kvm.c              |    2 
 tools/perf/builtin-lock.c             |    1 
 tools/perf/builtin-mem.c              |    1 
 tools/perf/builtin-record.c           |   33 +++++++-
 tools/perf/builtin-report.c           |    1 
 tools/perf/builtin-sched.c            |    1 
 tools/perf/builtin-script.c           |   41 +++++++++
 tools/perf/builtin-trace.c            |    3 -
 tools/perf/perf.h                     |    1 
 tools/perf/util/Build                 |    1 
 tools/perf/util/data-convert-bt.c     |    2 
 tools/perf/util/event.c               |  143 ++++++++++++++++++++++++++++++++-
 tools/perf/util/event.h               |   19 ++++
 tools/perf/util/evsel.c               |    3 +
 tools/perf/util/machine.c             |   34 ++++++++
 tools/perf/util/machine.h             |    3 +
 tools/perf/util/namespaces.c          |   35 ++++++++
 tools/perf/util/namespaces.h          |   26 ++++++
 tools/perf/util/session.c             |    7 ++
 tools/perf/util/thread.c              |   44 ++++++++++
 tools/perf/util/thread.h              |    6 +
 tools/perf/util/tool.h                |    2 
 27 files changed, 450 insertions(+), 14 deletions(-)
 create mode 100644 tools/perf/util/namespaces.c
 create mode 100644 tools/perf/util/namespaces.h

diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index c66a485..ee60f54 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -344,7 +344,8 @@ struct perf_event_attr {
 				use_clockid    :  1, /* use @clockid for time fields */
 				context_switch :  1, /* context switch data */
 				write_backward :  1, /* Write ring buffer from end to beginning */
-				__reserved_1   : 36;
+				namespaces     :  1, /* include namespaces data */
+				__reserved_1   : 35;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
@@ -610,6 +611,29 @@ struct perf_event_header {
 	__u16	size;
 };
 
+/*
+ * The maximum size of the name of each namespace
+ */
+#define NS_NAME_SIZE				8
+
+struct perf_ns_link_info {
+	char	name[NS_NAME_SIZE];
+	__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,
+
+	NAMESPACES_MAX,		/* maximum available namespaces */
+};
+
 enum perf_event_type {
 
 	/*
@@ -862,6 +886,18 @@ enum perf_event_type {
 	 */
 	PERF_RECORD_SWITCH_CPU_WIDE		= 15,
 
+	/*
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *	u32				pid;
+	 *	u32				tid;
+	 *	u32				nr_namespaces;
+	 *	struct namespace_link_info	link_info[NAMESPACES_MAX];
+	 *	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_NAMESPACES			= 16,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index ebb6283..1b63dc4 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -393,6 +393,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 			.comm	= perf_event__process_comm,
 			.exit	= perf_event__process_exit,
 			.fork	= perf_event__process_fork,
+			.namespaces = perf_event__process_namespaces,
 			.ordered_events = true,
 			.ordering_requires_timestamps = true,
 		},
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 933aeec..37cfbaa 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -354,6 +354,7 @@ static struct perf_tool tool = {
 	.exit	= perf_event__process_exit,
 	.fork	= perf_event__process_fork,
 	.lost	= perf_event__process_lost,
+	.namespaces = perf_event__process_namespaces,
 	.ordered_events = true,
 	.ordering_requires_timestamps = true,
 };
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index b9bc7e3..c5ddc73 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -333,6 +333,19 @@ static int perf_event__repipe_comm(struct perf_tool *tool,
 	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;
+
+	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,
 				   union perf_event *event,
 				   struct perf_sample *sample,
@@ -660,6 +673,7 @@ static int __cmd_inject(struct perf_inject *inject)
 		session->itrace_synth_opts = &inject->itrace_synth_opts;
 		inject->itrace_synth_opts.inject = true;
 		inject->tool.comm	    = perf_event__repipe_comm;
+		inject->tool.namespaces	    = perf_event__repipe_namespaces;
 		inject->tool.exit	    = perf_event__repipe_exit;
 		inject->tool.id_index	    = perf_event__repipe_id_index;
 		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 29f4751..1b53852 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -964,6 +964,7 @@ static struct perf_tool perf_kmem = {
 	.comm		 = perf_event__process_comm,
 	.mmap		 = perf_event__process_mmap,
 	.mmap2		 = perf_event__process_mmap2,
+	.namespaces	 = perf_event__process_namespaces,
 	.ordered_events	 = true,
 };
 
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 08fa88f..18e6c38 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1044,6 +1044,7 @@ static int read_events(struct perf_kvm_stat *kvm)
 	struct perf_tool eops = {
 		.sample			= process_sample_event,
 		.comm			= perf_event__process_comm,
+		.namespaces		= perf_event__process_namespaces,
 		.ordered_events		= true,
 	};
 	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.fork   = perf_event__process_fork;
 	kvm->tool.lost   = process_lost_event;
+	kvm->tool.namespaces  = perf_event__process_namespaces;
 	kvm->tool.ordered_events = true;
 	perf_tool__fill_defaults(&kvm->tool);
 
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index ce3bfb4..d750cca 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -858,6 +858,7 @@ static int __cmd_report(bool display_info)
 	struct perf_tool eops = {
 		.sample		 = process_sample_event,
 		.comm		 = perf_event__process_comm,
+		.namespaces	 = perf_event__process_namespaces,
 		.ordered_events	 = true,
 	};
 	struct perf_data_file file = {
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index cd7bc4d..430656c 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -342,6 +342,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
 			.lost		= perf_event__process_lost,
 			.fork		= perf_event__process_fork,
 			.build_id	= perf_event__process_build_id,
+			.namespaces	= perf_event__process_namespaces,
 			.ordered_events	= true,
 		},
 		.input_name		 = "perf.data",
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ffac8ca..1946a17 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -875,6 +875,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	signal(SIGTERM, sig_handler);
 	signal(SIGSEGV, sigsegv_handler);
 
+	if (rec->opts.record_namespaces)
+		tool->namespace_events = true;
+
 	if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) {
 		signal(SIGUSR2, snapshot_sig_handler);
 		if (rec->opts.auxtrace_snapshot_mode)
@@ -982,6 +985,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	 */
 	if (forks) {
 		union perf_event *event;
+		pid_t tgid;
 
 		event = malloc(sizeof(event->comm) + machine->id_hdr_size);
 		if (event == NULL) {
@@ -995,10 +999,28 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		 * cannot see a correct process name for those events.
 		 * Synthesize COMM event to prevent it.
 		 */
-		perf_event__synthesize_comm(tool, event,
-					    rec->evlist->workload.pid,
-					    process_synthesized_event,
-					    machine);
+		tgid = perf_event__synthesize_comm(tool, event,
+						   rec->evlist->workload.pid,
+						   process_synthesized_event,
+						   machine);
+		free(event);
+
+		if (tgid == -1)
+			goto out_child;
+
+		event = malloc(sizeof(event->namespaces) + machine->id_hdr_size);
+		if (event == NULL) {
+			err = -ENOMEM;
+			goto out_child;
+		}
+
+		/*
+		 * Synthesize NAMESPACES event for the command specified.
+		 */
+		perf_event__synthesize_namespaces(tool, event,
+						  rec->evlist->workload.pid,
+						  tgid, process_synthesized_event,
+						  machine);
 		free(event);
 
 		perf_evlist__start_workload(rec->evlist);
@@ -1496,6 +1518,7 @@ static struct record record = {
 		.fork		= perf_event__process_fork,
 		.exit		= perf_event__process_exit,
 		.comm		= perf_event__process_comm,
+		.namespaces	= perf_event__process_namespaces,
 		.mmap		= perf_event__process_mmap,
 		.mmap2		= perf_event__process_mmap2,
 		.ordered_events	= true,
@@ -1610,6 +1633,8 @@ static struct option __record_options[] = {
 			  "opts", "AUX area tracing Snapshot Mode", ""),
 	OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
 			"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,
 		    "Record context switch events"),
 	OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index dbd7fa0..5c92c75 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -694,6 +694,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 			.mmap		 = perf_event__process_mmap,
 			.mmap2		 = perf_event__process_mmap2,
 			.comm		 = perf_event__process_comm,
+			.namespaces	 = perf_event__process_namespaces,
 			.exit		 = perf_event__process_exit,
 			.fork		 = perf_event__process_fork,
 			.lost		 = perf_event__process_lost,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index daceb32..109baf6 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -3272,6 +3272,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
 		.tool = {
 			.sample		 = perf_sched__process_tracepoint_sample,
 			.comm		 = perf_event__process_comm,
+			.namespaces	 = perf_event__process_namespaces,
 			.lost		 = perf_event__process_lost,
 			.fork		 = perf_sched__process_fork_event,
 			.ordered_events = true,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c0783b4..b0672cc 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -830,6 +830,7 @@ struct perf_script {
 	bool			show_task_events;
 	bool			show_mmap_events;
 	bool			show_switch_events;
+	bool			show_namespaces_events;
 	bool			allocated;
 	struct cpu_map		*cpus;
 	struct thread_map	*threads;
@@ -1118,6 +1119,41 @@ static int process_comm_event(struct perf_tool *tool,
 	return ret;
 }
 
+static int process_namespaces_event(struct perf_tool *tool,
+				    union perf_event *event,
+				    struct perf_sample *sample,
+				    struct machine *machine)
+{
+	struct thread *thread;
+	struct perf_script *script = container_of(tool, struct perf_script, tool);
+	struct perf_session *session = script->session;
+	struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
+	int ret = -1;
+
+	thread = machine__findnew_thread(machine, event->namespaces.pid,
+					 event->namespaces.tid);
+	if (thread == NULL) {
+		pr_debug("problem processing NAMESPACES event, skipping it.\n");
+		return -1;
+	}
+
+	if (perf_event__process_namespaces(tool, event, sample, machine) < 0)
+		goto out;
+
+	if (!evsel->attr.sample_id_all) {
+		sample->cpu = 0;
+		sample->time = 0;
+		sample->tid = event->namespaces.tid;
+		sample->pid = event->namespaces.pid;
+	}
+	print_sample_start(sample, thread, evsel);
+	perf_event__fprintf(event, stdout);
+	ret = 0;
+out:
+	thread__put(thread);
+	return ret;
+}
+
 static int process_fork_event(struct perf_tool *tool,
 			      union perf_event *event,
 			      struct perf_sample *sample,
@@ -1293,6 +1329,8 @@ static int __cmd_script(struct perf_script *script)
 	}
 	if (script->show_switch_events)
 		script->tool.context_switch = process_switch_event;
+	if (script->show_namespaces_events)
+		script->tool.namespaces = process_namespaces_event;
 
 	ret = perf_session__process_events(script->session);
 
@@ -2097,6 +2135,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 			.mmap		 = perf_event__process_mmap,
 			.mmap2		 = perf_event__process_mmap2,
 			.comm		 = perf_event__process_comm,
+			.namespaces	 = perf_event__process_namespaces,
 			.exit		 = perf_event__process_exit,
 			.fork		 = perf_event__process_fork,
 			.attr		 = process_attr,
@@ -2180,6 +2219,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 		    "Show the mmap events"),
 	OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events,
 		    "Show context switch events (if recorded)"),
+	OPT_BOOLEAN('\0', "show-namespaces-events", &script.show_namespaces_events,
+		    "Show namespaces events (if recorded)"),
 	OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
 	OPT_BOOLEAN(0, "ns", &nanosecs,
 		    "Use 9 decimal places when displaying time"),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 40ef9b2..0bcd32f 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace)
 	trace->tool.exit	  = perf_event__process_exit;
 	trace->tool.fork	  = perf_event__process_fork;
 	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.namespaces	  = perf_event__process_namespaces;
 
 	trace->tool.ordered_events = true;
 	trace->tool.ordering_requires_timestamps = true;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 1c27d94..806c216 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -50,6 +50,7 @@ struct record_opts {
 	bool	     running_time;
 	bool	     full_auxtrace;
 	bool	     auxtrace_snapshot_mode;
+	bool	     record_namespaces;
 	bool	     record_switch_events;
 	bool	     all_kernel;
 	bool	     all_user;
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5da376b..2ea5ee1 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -42,6 +42,7 @@ libperf-y += pstack.o
 libperf-y += session.o
 libperf-$(CONFIG_AUDIT) += syscalltbl.o
 libperf-y += ordered-events.o
+libperf-y += namespaces.o
 libperf-y += comm.o
 libperf-y += thread.o
 libperf-y += thread_map.o
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 4e6cbc9..3b408f7 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1468,6 +1468,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
 			.lost            = perf_event__process_lost,
 			.tracing_data    = perf_event__process_tracing_data,
 			.build_id        = perf_event__process_build_id,
+			.namespaces      = perf_event__process_namespaces,
 			.ordered_events  = true,
 			.ordering_requires_timestamps = true,
 		},
@@ -1479,6 +1480,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
 		c.tool.comm = process_comm_event;
 		c.tool.exit = process_exit_event;
 		c.tool.fork = process_fork_event;
+		c.tool.namespaces = process_namespaces_event;
 	}
 
 	err = perf_config(convert__config, &c);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8ab0d7d..0ac1a8d 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -31,6 +31,7 @@ static const char *perf_event__names[] = {
 	[PERF_RECORD_LOST_SAMPLES]		= "LOST_SAMPLES",
 	[PERF_RECORD_SWITCH]			= "SWITCH",
 	[PERF_RECORD_SWITCH_CPU_WIDE]		= "SWITCH_CPU_WIDE",
+	[PERF_RECORD_NAMESPACES]		= "NAMESPACES",
 	[PERF_RECORD_HEADER_ATTR]		= "ATTR",
 	[PERF_RECORD_HEADER_EVENT_TYPE]		= "EVENT_TYPE",
 	[PERF_RECORD_HEADER_TRACING_DATA]	= "TRACING_DATA",
@@ -203,6 +204,74 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
 	return tgid;
 }
 
+static void perf_event__get_ns_link_info(pid_t pid, const char *ns,
+					 struct perf_ns_link_info *ns_link_info)
+{
+	struct stat64 st;
+	char proc_ns[128];
+
+	snprintf(ns_link_info->name, NS_NAME_SIZE, "%s", ns);
+
+	sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
+	if (stat64(proc_ns, &st) == 0) {
+		ns_link_info->dev = st.st_dev;
+		ns_link_info->ino = st.st_ino;
+	}
+}
+
+int perf_event__synthesize_namespaces(struct perf_tool *tool,
+				      union perf_event *event,
+				      pid_t pid, pid_t tgid,
+				      perf_event__handler_t process,
+				      struct machine *machine)
+{
+	struct perf_ns_link_info *ns_link_info;
+
+	if (!tool->namespace_events)
+		return 0;
+
+	memset(&event->namespaces, 0,
+	       sizeof(event->namespaces) + machine->id_hdr_size);
+
+	event->namespaces.pid = tgid;
+	event->namespaces.tid = pid;
+
+	event->namespaces.nr_namespaces = NAMESPACES_MAX;
+
+	ns_link_info = event->namespaces.link_info;
+
+	perf_event__get_ns_link_info(pid, "mnt",
+				     &ns_link_info[MNT_NS_INDEX]);
+
+	perf_event__get_ns_link_info(pid, "net",
+				     &ns_link_info[NET_NS_INDEX]);
+
+	perf_event__get_ns_link_info(pid, "uts",
+				     &ns_link_info[UTS_NS_INDEX]);
+
+	perf_event__get_ns_link_info(pid, "ipc",
+				     &ns_link_info[IPC_NS_INDEX]);
+
+	perf_event__get_ns_link_info(pid, "pid",
+				     &ns_link_info[PID_NS_INDEX]);
+
+	perf_event__get_ns_link_info(pid, "user",
+				     &ns_link_info[USER_NS_INDEX]);
+
+	perf_event__get_ns_link_info(pid, "cgroup",
+				     &ns_link_info[CGROUP_NS_INDEX]);
+
+	event->namespaces.header.type = PERF_RECORD_NAMESPACES;
+
+	event->namespaces.header.size = (sizeof(event->namespaces) +
+					 machine->id_hdr_size);
+
+	if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
+		return -1;
+
+	return 0;
+}
+
 static int perf_event__synthesize_fork(struct perf_tool *tool,
 				       union perf_event *event,
 				       pid_t pid, pid_t tgid, pid_t ppid,
@@ -434,8 +503,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
 static int __event__synthesize_thread(union perf_event *comm_event,
 				      union perf_event *mmap_event,
 				      union perf_event *fork_event,
+				      union perf_event *namespaces_event,
 				      pid_t pid, int full,
-					  perf_event__handler_t process,
+				      perf_event__handler_t process,
 				      struct perf_tool *tool,
 				      struct machine *machine,
 				      bool mmap_data,
@@ -455,6 +525,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
 		if (tgid == -1)
 			return -1;
 
+		if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,
+						      tgid, process, machine) < 0)
+			return -1;
+
+
 		return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
 							  process, machine, mmap_data,
 							  proc_map_timeout);
@@ -488,6 +563,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
 		if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
 						ppid, process, machine) < 0)
 			break;
+
+		if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
+						      tgid, process, machine) < 0)
+			break;
+
 		/*
 		 * Send the prepared comm event
 		 */
@@ -516,6 +596,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
 				      unsigned int proc_map_timeout)
 {
 	union perf_event *comm_event, *mmap_event, *fork_event;
+	union perf_event *namespaces_event;
 	int err = -1, thread, j;
 
 	comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -530,10 +611,15 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
 	if (fork_event == NULL)
 		goto out_free_mmap;
 
+	namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
+				  machine->id_hdr_size);
+	if (namespaces_event == NULL)
+		goto out_free_fork;
+
 	err = 0;
 	for (thread = 0; thread < threads->nr; ++thread) {
 		if (__event__synthesize_thread(comm_event, mmap_event,
-					       fork_event,
+					       fork_event, namespaces_event,
 					       thread_map__pid(threads, thread), 0,
 					       process, tool, machine,
 					       mmap_data, proc_map_timeout)) {
@@ -559,7 +645,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
 			/* if not, generate events for it */
 			if (need_leader &&
 			    __event__synthesize_thread(comm_event, mmap_event,
-						       fork_event,
+						       fork_event, namespaces_event,
 						       comm_event->comm.pid, 0,
 						       process, tool, machine,
 						       mmap_data, proc_map_timeout)) {
@@ -568,6 +654,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
 			}
 		}
 	}
+	free(namespaces_event);
+out_free_fork:
 	free(fork_event);
 out_free_mmap:
 	free(mmap_event);
@@ -587,6 +675,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
 	char proc_path[PATH_MAX];
 	struct dirent *dirent;
 	union perf_event *comm_event, *mmap_event, *fork_event;
+	union perf_event *namespaces_event;
 	int err = -1;
 
 	if (machine__is_default_guest(machine))
@@ -604,11 +693,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
 	if (fork_event == NULL)
 		goto out_free_mmap;
 
+	namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
+				  machine->id_hdr_size);
+	if (namespaces_event == NULL)
+		goto out_free_fork;
+
 	snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
 	proc = opendir(proc_path);
 
 	if (proc == NULL)
-		goto out_free_fork;
+		goto out_free_namespaces;
 
 	while ((dirent = readdir(proc)) != NULL) {
 		char *end;
@@ -620,13 +714,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
  		 * We may race with exiting thread, so don't stop just because
  		 * one thread couldn't be synthesized.
  		 */
-		__event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
-					   1, process, tool, machine, mmap_data,
+		__event__synthesize_thread(comm_event, mmap_event, fork_event,
+					   namespaces_event, pid, 1, process,
+					   tool, machine, mmap_data,
 					   proc_map_timeout);
 	}
 
 	err = 0;
 	closedir(proc);
+out_free_namespaces:
+	free(namespaces_event);
 out_free_fork:
 	free(fork_event);
 out_free_mmap:
@@ -1008,6 +1105,29 @@ 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);
 }
 
+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 [",
+		       event->namespaces.pid,
+		       event->namespaces.tid,
+		       nr_namespaces);
+
+	for (idx = 0; idx < nr_namespaces; idx++)
+		ret  += fprintf(fp, "%s: %lu/0x%lx%s", ns_link_info[idx].name,
+				(u64)ns_link_info[idx].dev,
+				(u64)ns_link_info[idx].ino,
+				((idx + 1) != nr_namespaces) ? ", " : "]\n\n");
+
+	return ret;
+}
+
 int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
 			     union perf_event *event,
 			     struct perf_sample *sample,
@@ -1016,6 +1136,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
 	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,
 			     union perf_event *event,
 			     struct perf_sample *sample,
@@ -1196,6 +1324,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
 	case PERF_RECORD_MMAP:
 		ret += perf_event__fprintf_mmap(event, fp);
 		break;
+	case PERF_RECORD_NAMESPACES:
+		ret += perf_event__fprintf_namespaces(event, fp);
+		break;
 	case PERF_RECORD_MMAP2:
 		ret += perf_event__fprintf_mmap2(event, fp);
 		break;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c735c53..09fde83 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -39,6 +39,13 @@ struct comm_event {
 	char comm[16];
 };
 
+struct namespaces_event {
+	struct perf_event_header header;
+	u32 pid, tid;
+	u32 nr_namespaces;
+	struct perf_ns_link_info link_info[NAMESPACES_MAX];
+};
+
 struct fork_event {
 	struct perf_event_header header;
 	u32 pid, ppid;
@@ -485,6 +492,7 @@ union perf_event {
 	struct mmap_event		mmap;
 	struct mmap2_event		mmap2;
 	struct comm_event		comm;
+	struct namespaces_event		namespaces;
 	struct fork_event		fork;
 	struct lost_event		lost;
 	struct lost_samples_event	lost_samples;
@@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool,
 			       union perf_event *event,
 			       struct perf_sample *sample,
 			       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,
 			     union perf_event *event,
 			     struct perf_sample *sample,
@@ -636,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
 				  perf_event__handler_t process,
 				  struct machine *machine);
 
+int perf_event__synthesize_namespaces(struct perf_tool *tool,
+				      union perf_event *event,
+				      pid_t pid, pid_t tgid,
+				      perf_event__handler_t process,
+				      struct machine *machine);
+
 int perf_event__synthesize_mmap_events(struct perf_tool *tool,
 				       union perf_event *event,
 				       pid_t pid, pid_t tgid,
@@ -653,6 +671,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_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_namespaces(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,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 04e536a..e94f807 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -932,6 +932,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
 	attr->mmap2 = track && !perf_missing_features.mmap2;
 	attr->comm  = track;
 
+	if (opts->record_namespaces)
+		attr->namespaces  = track;
+
 	if (opts->record_switch_events)
 		attr->context_switch = track;
 
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 747a034..ecdf1f0 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -13,6 +13,7 @@
 #include <symbol/kallsyms.h>
 #include "unwind.h"
 #include "linux/hash.h"
+#include "asm/bug.h"
 
 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;
 }
 
+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 > NAMESPACES_MAX,
+		  "\nWARNING: kernel seems to support more namespaces than perf"
+		  " tool.\nTry updating the perf tool..\n\n");
+
+	WARN_ONCE(event->namespaces.nr_namespaces < NAMESPACES_MAX,
+		  "\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,
 				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;
 	case PERF_RECORD_MMAP:
 		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:
 		ret = machine__process_mmap2_event(machine, event, sample); break;
 	case PERF_RECORD_FORK:
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index a283050..3cdb134 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine,
 					union perf_event *event);
 int machine__process_switch_event(struct machine *machine,
 				  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,
 				struct perf_sample *sample);
 int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
new file mode 100644
index 0000000..3134c00
--- /dev/null
+++ b/tools/perf/util/namespaces.c
@@ -0,0 +1,35 @@
+/*
+ * 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 = zalloc(sizeof(*namespaces));
+
+	if (!namespaces)
+		return NULL;
+
+	namespaces->end_time = -1;
+
+	if (event) {
+		memcpy(namespaces->link_info, event->link_info,
+		       sizeof(namespaces->link_info));
+	}
+
+	return namespaces;
+}
+
+void namespaces__free(struct namespaces *namespaces)
+{
+	free(namespaces);
+}
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
new file mode 100644
index 0000000..e42487e
--- /dev/null
+++ b/tools/perf/util/namespaces.h
@@ -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[NAMESPACES_MAX];
+};
+
+struct namespaces *namespaces__new(struct namespaces_event *event);
+void namespaces__free(struct namespaces *namespaces);
+
+#endif  /* __PERF_NAMESPACES_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 349c681..d868661 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1239,6 +1239,8 @@ static int machines__deliver_event(struct machines *machines,
 		return tool->mmap2(tool, event, sample, machine);
 	case PERF_RECORD_COMM:
 		return tool->comm(tool, event, sample, machine);
+	case PERF_RECORD_NAMESPACES:
+		return tool->namespaces(tool, event, sample, machine);
 	case PERF_RECORD_FORK:
 		return tool->fork(tool, event, sample, machine);
 	case PERF_RECORD_EXIT:
@@ -1494,6 +1496,11 @@ int perf_session__register_idle_thread(struct perf_session *session)
 		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 */
 	thread__put(thread);
 	return err;
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index f5af87f..b9fe432 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,6 +7,7 @@
 #include "thread-stack.h"
 #include "util.h"
 #include "debug.h"
+#include "namespaces.h"
 #include "comm.h"
 #include "unwind.h"
 
@@ -40,6 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		thread->tid = tid;
 		thread->ppid = -1;
 		thread->cpu = -1;
+		INIT_LIST_HEAD(&thread->namespaces_list);
 		INIT_LIST_HEAD(&thread->comm_list);
 
 		comm_str = malloc(32);
@@ -66,7 +68,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 
 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));
 
@@ -76,7 +79,12 @@ void thread__delete(struct thread *thread)
 		map_groups__put(thread->mg);
 		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);
 		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)
 {
 	if (list_empty(&thread->comm_list))
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 99263cb..b18b5a2 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -28,6 +28,7 @@ struct thread {
 	bool			comm_set;
 	int			comm_len;
 	bool			dead; /* if set thread has exited */
+	struct list_head	namespaces_list;
 	struct list_head	comm_list;
 	u64			db_id;
 
@@ -40,6 +41,7 @@ struct thread {
 };
 
 struct machine;
+struct namespaces;
 struct comm;
 
 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;
 }
 
+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,
 		       bool exec);
 static inline int thread__set_comm(struct thread *thread, const char *comm,
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index ac2590a..829471a 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -40,6 +40,7 @@ struct perf_tool {
 	event_op	mmap,
 			mmap2,
 			comm,
+			namespaces,
 			fork,
 			exit,
 			lost,
@@ -66,6 +67,7 @@ struct perf_tool {
 	event_op3	auxtrace;
 	bool		ordered_events;
 	bool		ordering_requires_timestamps;
+	bool		namespace_events;
 };
 
 #endif /* __PERF_TOOL_H */

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v6 3/3] perf tool: add cgroup identifier entry in perf report
  2017-02-08  8:31 [PATCH v6 0/3] perf: add support for analyzing events for containers Hari Bathini
  2017-02-08  8:31 ` [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info Hari Bathini
  2017-02-08  8:31 ` [PATCH v6 2/3] perf tool: " Hari Bathini
@ 2017-02-08  8:32 ` Hari Bathini
  2017-02-16  6:20 ` [PATCH v6 0/3] perf: add support for analyzing events for containers Eric W. Biederman
  3 siblings, 0 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-08  8:32 UTC (permalink / raw)
  To: ast, peterz, lkml, acme, alexander.shishkin, mingo
  Cc: daniel, rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg, jolsa

This patch introduces a cgroup identifier entry field in perf report to
identify or distinguish data of different cgroups. It uses the device
number and inode number of cgroup namespace, included in perf data with
the new PERF_RECORD_NAMESPACES event, as cgroup identifier. With the
assumption that each container is created with it's own cgroup namespace,
this allows assessment/analysis of multiple containers at once.

Shown below is the output of perf report, sorted based on cgroup id, on
a system that was running three containers at the time of perf record
and clearly showing one of the containers' considerable use of kernel
memory in comparison with others:


	$ perf report -s cgroup_id,sample --stdio
	#
	# Total Lost Samples: 0
	#
	# Samples: 16K of event 'kmem:kmalloc'
	# Event count (approx.): 16043
	#
	# Overhead  cgroup id (dev/inode)       Samples
	# ........  .....................  ............
	#
	    96.33%  3/0xf00000d0                  15454
	     3.02%  3/0xeffffffb                    485
	     0.31%  3/0xf00000ce                     49
	     0.29%  3/0xf00000cf                     47
	     0.05%  0/0x0                             8

While this is a start, there is further scope of improving this. For
example, instead of cgroup namespace's device and inode numbers, dev
and inode numbers of some or all namespaces may be used to distinguish
which processes are running in a given container context. Also, scripts
to map device and inode info to containers sounds plausible for better
tracing of containers.

Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
---
 tools/perf/util/hist.c |    7 +++++++
 tools/perf/util/hist.h |    1 +
 tools/perf/util/sort.c |   41 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/sort.h |    7 +++++++
 4 files changed, 56 insertions(+)

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 32c6a93..559ea27 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -3,6 +3,7 @@
 #include "hist.h"
 #include "map.h"
 #include "session.h"
+#include "namespaces.h"
 #include "sort.h"
 #include "evlist.h"
 #include "evsel.h"
@@ -169,6 +170,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 		hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
 	}
 
+	hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
 	hists__new_col_len(hists, HISTC_CPU, 3);
 	hists__new_col_len(hists, HISTC_SOCKET, 6);
 	hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
@@ -574,9 +576,14 @@ __hists__add_entry(struct hists *hists,
 		   bool sample_self,
 		   struct hist_entry_ops *ops)
 {
+	struct namespaces *ns = thread__namespaces(al->thread);
 	struct hist_entry entry = {
 		.thread	= al->thread,
 		.comm = thread__comm(al->thread),
+		.cgroup_id = {
+			.dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
+			.ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
+		},
 		.ms = {
 			.map	= al->map,
 			.sym	= al->sym,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 28c216e..4c1da48 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -30,6 +30,7 @@ enum hist_column {
 	HISTC_DSO,
 	HISTC_THREAD,
 	HISTC_COMM,
+	HISTC_CGROUP_ID,
 	HISTC_PARENT,
 	HISTC_CPU,
 	HISTC_SOCKET,
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index df622f4..9f5f404 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -536,6 +536,46 @@ struct sort_entry sort_cpu = {
 	.se_width_idx	= HISTC_CPU,
 };
 
+/* --sort cgroup_id */
+
+static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev)
+{
+	return (int64_t)(right_dev - left_dev);
+}
+
+static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino)
+{
+	return (int64_t)(right_ino - left_ino);
+}
+
+static int64_t
+sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+	int64_t ret;
+
+	ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev);
+	if (ret != 0)
+		return ret;
+
+	return _sort__cgroup_inode_cmp(right->cgroup_id.ino,
+				       left->cgroup_id.ino);
+}
+
+static int hist_entry__cgroup_id_snprintf(struct hist_entry *he,
+					  char *bf, size_t size,
+					  unsigned int width __maybe_unused)
+{
+	return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev,
+			       he->cgroup_id.ino);
+}
+
+struct sort_entry sort_cgroup_id = {
+	.se_header      = "cgroup id (dev/inode)",
+	.se_cmp	        = sort__cgroup_id_cmp,
+	.se_snprintf    = hist_entry__cgroup_id_snprintf,
+	.se_width_idx	= HISTC_CGROUP_ID,
+};
+
 /* --sort socket */
 
 static int64_t
@@ -1418,6 +1458,7 @@ static struct sort_dimension common_sort_dimensions[] = {
 	DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
 	DIM(SORT_TRANSACTION, "transaction", sort_transaction),
 	DIM(SORT_TRACE, "trace", sort_trace),
+	DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
 };
 
 #undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 7aff317..68a5abb 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -54,6 +54,11 @@ struct he_stat {
 	u32			nr_events;
 };
 
+struct namespace_id {
+	u64			dev;
+	u64			ino;
+};
+
 struct hist_entry_diff {
 	bool	computed;
 	union {
@@ -91,6 +96,7 @@ struct hist_entry {
 	struct map_symbol	ms;
 	struct thread		*thread;
 	struct comm		*comm;
+	struct namespace_id	cgroup_id;
 	u64			ip;
 	u64			transaction;
 	s32			socket;
@@ -211,6 +217,7 @@ enum sort_type {
 	SORT_GLOBAL_WEIGHT,
 	SORT_TRANSACTION,
 	SORT_TRACE,
+	SORT_CGROUP_ID,
 
 	/* branch stack specific sort keys */
 	__SORT_BRANCH_STACK,

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 2/3] perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 ` [PATCH v6 2/3] perf tool: " Hari Bathini
@ 2017-02-08 12:57   ` Jiri Olsa
  2017-02-08 12:57   ` Jiri Olsa
  2017-02-08 12:57   ` Jiri Olsa
  2 siblings, 0 replies; 15+ messages in thread
From: Jiri Olsa @ 2017-02-08 12:57 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg

On Wed, Feb 08, 2017 at 02:01:49PM +0530, Hari Bathini wrote:

SNIP

> +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 [",
> +		       event->namespaces.pid,
> +		       event->namespaces.tid,
> +		       nr_namespaces);
> +
> +	for (idx = 0; idx < nr_namespaces; idx++)
> +		ret  += fprintf(fp, "%s: %lu/0x%lx%s", ns_link_info[idx].name,
> +				(u64)ns_link_info[idx].dev,
> +				(u64)ns_link_info[idx].ino,
> +				((idx + 1) != nr_namespaces) ? ", " : "]\n\n");

could you please shape the output the same way we do
for other events, currently you display namespaces like:

  0 0x1848 [0xd0]: PERF_RECORD_NAMESPACES 3006/3006 - nr_namespaces: 7 [net: 3/0xf0000081, uts: 3/0xeffffffe, ipc: 3/0xefffffff, pid: 3/0xeffffffc, user: 3/0xeffffffd, mnt: 3/0xf0000000, cgroup: 3/0xeffffffb]

it also screws the less output of perf report -D for me..

usually we do multiple lines output, like:

1941502405539 0x1f48 [0x28]: PERF_RECORD_SAMPLE(IP, 0x2): 3006/3006: 0x55d47fdf2436 period: 422589 addr: 0
 ... thread: ls:3006
 ...... dso: /usr/bin/ls


thanks,
jirka

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 2/3] perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 ` [PATCH v6 2/3] perf tool: " Hari Bathini
  2017-02-08 12:57   ` Jiri Olsa
@ 2017-02-08 12:57   ` Jiri Olsa
  2017-02-08 12:57   ` Jiri Olsa
  2 siblings, 0 replies; 15+ messages in thread
From: Jiri Olsa @ 2017-02-08 12:57 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg

On Wed, Feb 08, 2017 at 02:01:49PM +0530, Hari Bathini wrote:

SNIP

> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index ffac8ca..1946a17 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -875,6 +875,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
>  	signal(SIGTERM, sig_handler);
>  	signal(SIGSEGV, sigsegv_handler);
>  
> +	if (rec->opts.record_namespaces)
> +		tool->namespace_events = true;

should we do this by default? seems like low traffic event
with info that should be always present

also in case we keep the --namespace option, please add
it to the record's doc

jirka

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 2/3] perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 ` [PATCH v6 2/3] perf tool: " Hari Bathini
  2017-02-08 12:57   ` Jiri Olsa
  2017-02-08 12:57   ` Jiri Olsa
@ 2017-02-08 12:57   ` Jiri Olsa
  2017-02-21 14:03     ` Hari Bathini
  2 siblings, 1 reply; 15+ messages in thread
From: Jiri Olsa @ 2017-02-08 12:57 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg

On Wed, Feb 08, 2017 at 02:01:49PM +0530, Hari Bathini wrote:
> This patch updates perf tool to examine PERF_RECORD_NAMESPACES events
> emitted by the kernel when fork, clone, setns or unshare are invoked.
> Also, it synthesizes PERF_RECORD_NAMESPACES events for processes that
> were running prior to invocation of perf record, the data for which
> is taken from /proc/$PID/ns. These changes make way for analyzing
> events with regard to namespaces.
> 
> Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
> ---
>  tools/include/uapi/linux/perf_event.h |   38 +++++++++
>  tools/perf/builtin-annotate.c         |    1 
>  tools/perf/builtin-diff.c             |    1 
>  tools/perf/builtin-inject.c           |   14 +++
>  tools/perf/builtin-kmem.c             |    1 
>  tools/perf/builtin-kvm.c              |    2 
>  tools/perf/builtin-lock.c             |    1 
>  tools/perf/builtin-mem.c              |    1 
>  tools/perf/builtin-record.c           |   33 +++++++-
>  tools/perf/builtin-report.c           |    1 
>  tools/perf/builtin-sched.c            |    1 
>  tools/perf/builtin-script.c           |   41 +++++++++
>  tools/perf/builtin-trace.c            |    3 -
>  tools/perf/perf.h                     |    1 
>  tools/perf/util/Build                 |    1 
>  tools/perf/util/data-convert-bt.c     |    2 
>  tools/perf/util/event.c               |  143 ++++++++++++++++++++++++++++++++-
>  tools/perf/util/event.h               |   19 ++++
>  tools/perf/util/evsel.c               |    3 +
>  tools/perf/util/machine.c             |   34 ++++++++
>  tools/perf/util/machine.h             |    3 +
>  tools/perf/util/namespaces.c          |   35 ++++++++
>  tools/perf/util/namespaces.h          |   26 ++++++
>  tools/perf/util/session.c             |    7 ++
>  tools/perf/util/thread.c              |   44 ++++++++++
>  tools/perf/util/thread.h              |    6 +
>  tools/perf/util/tool.h                |    2 
>  27 files changed, 450 insertions(+), 14 deletions(-)
>  create mode 100644 tools/perf/util/namespaces.c
>  create mode 100644 tools/perf/util/namespaces.h

could you please split this patch into logically separated changes, like:
  - adding PERF_RECORD_NAMESPACES event with perf_event__process_namespaces
    machinery
  - synthesize support (perf_event__synthesize_namespaces) for record
  - script print support
  - perf_event__fprintf print support

or any other split that'd make sense, it's too many changes for one patch now

thanks,
jirka

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 0/3] perf: add support for analyzing events for containers
  2017-02-08  8:31 [PATCH v6 0/3] perf: add support for analyzing events for containers Hari Bathini
                   ` (2 preceding siblings ...)
  2017-02-08  8:32 ` [PATCH v6 3/3] perf tool: add cgroup identifier entry in perf report Hari Bathini
@ 2017-02-16  6:20 ` Eric W. Biederman
  3 siblings, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2017-02-16  6:20 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

Hari Bathini <hbathini@linux.vnet.ibm.com> writes:

> Currently, there is no trivial mechanism to analyze events based on
> containers. perf -G can be used, but it will not filter events for the
> containers created after perf is invoked, making it difficult to assess/
> analyze performance issues of multiple containers at once.
>
> This patch-set is aimed at addressing this limitation by introducing a
> new PERF_RECORD_NAMESPACES event that records namespaces related info.
> As containers are created with namespaces, the new data can be used to
> in assessment/analysis of multiple containers.
>
> The first patch introduces PERF_RECORD_NAMESPACES in kernel while the
> second patch makes the corresponding changes in perf tool to read this
> PERF_RECORD_NAMESPACES events. The third patch demonstrates analysis
> of containers with this data by adding a cgroup identifier column in
> perf report, which contains the cgroup namespace's device and inode
> numbers. This is based on the assumption that each container is created
> with it's own cgroup namespace. The third patch has scope for improvement
> based on the conventions a container is attributed with, going
> forward.

Ack for the namespace interface bits.
Everything I asked for is in there.

Eric


>
> Changes from v5:
> * Updated changelogs of patches 1 & 3
> * Rebased the patches on perf/core in tip
>
> ---
>
> Hari Bathini (3):
>       perf: add PERF_RECORD_NAMESPACES to include namespaces related info
>       perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
>       perf tool: add cgroup identifier entry in perf report
>
>
>  include/linux/perf_event.h            |    2 
>  include/uapi/linux/perf_event.h       |   38 +++++++++
>  kernel/events/core.c                  |  142 +++++++++++++++++++++++++++++++++
>  kernel/fork.c                         |    3 +
>  kernel/nsproxy.c                      |    5 +
>  tools/include/uapi/linux/perf_event.h |   38 +++++++++
>  tools/perf/builtin-annotate.c         |    1 
>  tools/perf/builtin-diff.c             |    1 
>  tools/perf/builtin-inject.c           |   14 +++
>  tools/perf/builtin-kmem.c             |    1 
>  tools/perf/builtin-kvm.c              |    2 
>  tools/perf/builtin-lock.c             |    1 
>  tools/perf/builtin-mem.c              |    1 
>  tools/perf/builtin-record.c           |   33 +++++++-
>  tools/perf/builtin-report.c           |    1 
>  tools/perf/builtin-sched.c            |    1 
>  tools/perf/builtin-script.c           |   41 +++++++++
>  tools/perf/builtin-trace.c            |    3 -
>  tools/perf/perf.h                     |    1 
>  tools/perf/util/Build                 |    1 
>  tools/perf/util/data-convert-bt.c     |    2 
>  tools/perf/util/event.c               |  143 ++++++++++++++++++++++++++++++++-
>  tools/perf/util/event.h               |   19 ++++
>  tools/perf/util/evsel.c               |    3 +
>  tools/perf/util/hist.c                |    7 ++
>  tools/perf/util/hist.h                |    1 
>  tools/perf/util/machine.c             |   34 ++++++++
>  tools/perf/util/machine.h             |    3 +
>  tools/perf/util/namespaces.c          |   35 ++++++++
>  tools/perf/util/namespaces.h          |   26 ++++++
>  tools/perf/util/session.c             |    7 ++
>  tools/perf/util/sort.c                |   41 +++++++++
>  tools/perf/util/sort.h                |    7 ++
>  tools/perf/util/thread.c              |   44 ++++++++++
>  tools/perf/util/thread.h              |    6 +
>  tools/perf/util/tool.h                |    2 
>  36 files changed, 695 insertions(+), 15 deletions(-)
>  create mode 100644 tools/perf/util/namespaces.c
>  create mode 100644 tools/perf/util/namespaces.h
>
> --

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 ` [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info Hari Bathini
@ 2017-02-16 10:28   ` Peter Zijlstra
  2017-02-16 10:36     ` Peter Zijlstra
  2017-02-20  4:11     ` Hari Bathini
  2017-02-16 11:25   ` Eric W. Biederman
  1 sibling, 2 replies; 15+ messages in thread
From: Peter Zijlstra @ 2017-02-16 10:28 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, lkml, acme, alexander.shishkin, mingo, daniel, rostedt,
	Ananth N Mavinakayanahalli, ebiederm, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

On Wed, Feb 08, 2017 at 02:01:24PM +0530, Hari Bathini wrote:
> With the advert of container technologies like docker, that depend
> on namespaces for isolation, there is a need for tracing support for
> namespaces. This patch introduces new PERF_RECORD_NAMESPACES event
> for tracing based on namespaces related info. This event records
> the device and inode numbers for every namespace of all processes.
> 
> While device number is same for all namespaces currently, that may

'While device numbers are the same ..." ?

> change in future, to avoid the need for a namespace of namespaces.

Unfinished sentence

> Recording device number along with inode number will take care of such
> scenario.

More words on why this is so? Because I've no clue.

> Also, recording device and inode numbers for every namespace
> lets the userspace take a call on the definition of a container and
> update perf tool accordingly.


> @@ -862,6 +886,18 @@ enum perf_event_type {
>  	 */
>  	PERF_RECORD_SWITCH_CPU_WIDE		= 15,
>  
> +	/*
> +	 * struct {
> +	 *	struct perf_event_header	header;
> +	 *	u32				pid;
> +	 *	u32				tid;
> +	 *	u32				nr_namespaces;
> +	 *	struct namespace_link_info	link_info[NAMESPACES_MAX];
> +	 *	struct sample_id		sample_id;
> +	 * };
> +	 */
> +	PERF_RECORD_NAMESPACES			= 16,

This thing works by accident, there's a u32 hole in that structure.
Also, the array isn't NAMESPACES_MAX long, its nr_namespaces, that's
what its there for. The entries should be internally consistent.


> @@ -6584,6 +6590,135 @@ void perf_event_comm(struct task_struct *task, bool exec)
>  }
>  
>  /*
> + * namespaces tracking
> + */
> +
> +struct namespaces_event_id {
> +	struct perf_event_header	header;
> +
> +	u32				pid;
> +	u32				tid;
> +	u32				nr_namespaces;
> +	struct perf_ns_link_info	link_info[NAMESPACES_MAX];
> +};

Contains the same hole and makes the record depend on architecture
alignment requirements.

> +static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
> +				   struct task_struct *task,
> +				   const struct proc_ns_operations *ns_ops)
> +{
> +	struct path ns_path;
> +	struct inode *ns_inode;
> +	void *error;
> +
> +	error = ns_get_path(&ns_path, task, ns_ops);
> +	if (!error) {
> +		snprintf(ns_link_info->name, NS_NAME_SIZE,
> +			 "%s", ns_path.dentry->d_iname);
> +
> +		ns_inode = ns_path.dentry->d_inode;
> +		ns_link_info->dev = new_encode_dev(ns_inode->i_sb->s_dev);
> +		ns_link_info->ino = ns_inode->i_ino;
> +	}
> +}
> +
> +static void perf_event_namespaces_output(struct perf_event *event,
> +					 void *data)
> +{
> +	struct perf_namespaces_event *namespaces_event = data;
> +	struct perf_output_handle handle;
> +	struct perf_sample_data sample;
> +	struct namespaces_event_id *ei;
> +	struct task_struct *task = namespaces_event->task;
> +	int ret;
> +
> +	if (!perf_event_namespaces_match(event))
> +		return;
> +
> +	ei = &namespaces_event->event_id;
> +	perf_event_header__init_id(&ei->header, &sample, event);
> +	ret = perf_output_begin(&handle, event,	ei->header.size);
> +	if (ret)
> +		return;
> +
> +	ei->pid = perf_event_pid(event, task);
> +	ei->tid = perf_event_tid(event, task);
> +
> +	ei->nr_namespaces = NAMESPACES_MAX;
> +
> +	perf_fill_ns_link_info(&ei->link_info[MNT_NS_INDEX],
> +			       task, &mntns_operations);
> +
> +#ifdef CONFIG_USER_NS
> +	perf_fill_ns_link_info(&ei->link_info[USER_NS_INDEX],
> +			       task, &userns_operations);
> +#endif
> +#ifdef CONFIG_NET_NS
> +	perf_fill_ns_link_info(&ei->link_info[NET_NS_INDEX],
> +			       task, &netns_operations);
> +#endif
> +#ifdef CONFIG_UTS_NS
> +	perf_fill_ns_link_info(&ei->link_info[UTS_NS_INDEX],
> +			       task, &utsns_operations);
> +#endif
> +#ifdef CONFIG_IPC_NS
> +	perf_fill_ns_link_info(&ei->link_info[IPC_NS_INDEX],
> +			       task, &ipcns_operations);
> +#endif
> +#ifdef CONFIG_PID_NS
> +	perf_fill_ns_link_info(&ei->link_info[PID_NS_INDEX],
> +			       task, &pidns_operations);
> +#endif
> +#ifdef CONFIG_CGROUPS
> +	perf_fill_ns_link_info(&ei->link_info[CGROUP_NS_INDEX],
> +			       task, &cgroupns_operations);
> +#endif

Two points here, since you've given these thingies a string identifier,
do you still need to rely on their positional index? If not, you could
generate smaller events if we lack some of these CONFIG knobs.

Secondly, does anything in here depend on @event? Afaict you're
generating the exact same information for each event.

The reason we set {pid,tid} for each event is because of PID_NS, we
report the pid number as per the namespace associated with the event.

But from what I can tell, there is no such namespace of namespaces
dependency here and this should live in the function below.

> +	perf_output_put(&handle, namespaces_event->event_id);

And if you do smaller events, this needs changing..

> +	perf_event__output_id_sample(event, &handle, &sample);
> +
> +	perf_output_end(&handle);
> +}
> +
> +void perf_event_namespaces(struct task_struct *task)
> +{
> +	struct perf_namespaces_event namespaces_event;
> +
> +	if (!atomic_read(&nr_namespaces_events))
> +		return;
> +
> +	namespaces_event = (struct perf_namespaces_event){
> +		.task	= task,
> +		.event_id  = {
> +			.header = {
> +				.type = PERF_RECORD_NAMESPACES,
> +				.misc = 0,
> +				.size = sizeof(namespaces_event.event_id),
> +			},
> +			/* .pid */
> +			/* .tid */
> +			/* .nr_namespaces */
> +			/* .link_info[NAMESPACES_MAX] */
> +		},
> +	};

So this would be the right place to generate the NS information, since
it doesn't appear to depend on the namespace of the event.

> +	perf_iterate_sb(perf_event_namespaces_output,
> +			&namespaces_event,
> +			NULL);
> +}



> @@ -9667,6 +9804,11 @@ SYSCALL_DEFINE5(perf_event_open,
>  			return -EACCES;
>  	}
>  
> +	if (attr.namespaces) {
> +		if (!capable(CAP_SYS_ADMIN))
> +			return -EACCES;
> +	}

Many times we allow users access to such information; should this be
qualified with something like perf_paranoid_kernel() or somesuch?

> +
>  	if (attr.freq) {
>  		if (attr.sample_freq > sysctl_perf_event_sample_rate)
>  			return -EINVAL;
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 11c5c8a..fd77e67 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -2289,6 +2289,9 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
>  		free_fs_struct(new_fs);
>  
>  bad_unshare_out:
> +	if (!err)
> +		perf_event_namespaces(current);
> +
>  	return err;
>  }

That seems like a very odd place, why not put it right before the
bad_unshare_cleanup_cred: label?


> @@ -264,6 +265,10 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
>  	switch_task_namespaces(tsk, new_nsproxy);
>  out:
>  	fput(file);
> +
> +	if (!err)
> +		perf_event_namespaces(tsk);
> +
>  	return err;
>  }

Same again..

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-16 10:28   ` Peter Zijlstra
@ 2017-02-16 10:36     ` Peter Zijlstra
  2017-02-20  4:11     ` Hari Bathini
  1 sibling, 0 replies; 15+ messages in thread
From: Peter Zijlstra @ 2017-02-16 10:36 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, lkml, acme, alexander.shishkin, mingo, daniel, rostedt,
	Ananth N Mavinakayanahalli, ebiederm, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

On Thu, Feb 16, 2017 at 11:28:24AM +0100, Peter Zijlstra wrote:
> On Wed, Feb 08, 2017 at 02:01:24PM +0530, Hari Bathini wrote:
> > @@ -862,6 +886,18 @@ enum perf_event_type {
> >  	 */
> >  	PERF_RECORD_SWITCH_CPU_WIDE		= 15,
> >  
> > +	/*
> > +	 * struct {
> > +	 *	struct perf_event_header	header;
> > +	 *	u32				pid;
> > +	 *	u32				tid;
> > +	 *	u32				nr_namespaces;
> > +	 *	struct namespace_link_info	link_info[NAMESPACES_MAX];
> > +	 *	struct sample_id		sample_id;
> > +	 * };
> > +	 */
> > +	PERF_RECORD_NAMESPACES			= 16,
> 
> This thing works by accident, there's a u32 hole in that structure.
> Also, the array isn't NAMESPACES_MAX long, its nr_namespaces, that's
> what its there for. The entries should be internally consistent.

Also, namespace_link_info isn't specified.

Easies would be to write something like:

	{ char name[8];
	  u64  inode;
	  u64  dev;    }[nr_namespace];

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08  8:31 ` [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info Hari Bathini
  2017-02-16 10:28   ` Peter Zijlstra
@ 2017-02-16 11:25   ` Eric W. Biederman
  2017-02-16 11:47     ` Peter Zijlstra
  2017-02-20  4:16     ` Hari Bathini
  1 sibling, 2 replies; 15+ messages in thread
From: Eric W. Biederman @ 2017-02-16 11:25 UTC (permalink / raw)
  To: Hari Bathini
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

> +/*
> + * The maximum size of the name of each namespace
> + */
> +#define NS_NAME_SIZE				8
> +
> +struct perf_ns_link_info {
> +	char	name[NS_NAME_SIZE];
> +	__u64	dev;
> +	__u64	ino;
> +};

Ugh. I missed the name the first time around.

That really looks like useless clutter.  You already know the index so
the name doesn't add any information, so unless I am missing something
that name will just slow down the perf kernel implementation with
useless work.

The userspace reader can have the information just as reliably by
looking at the index and indexing into a table.

The set of namespaces changes slowly enough that this is not likely to
be a problem in practice.  Especially as perf is released with the
kernel.

Plus who knows how long the name of the next namespace is going to be.

Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-16 11:25   ` Eric W. Biederman
@ 2017-02-16 11:47     ` Peter Zijlstra
  2017-02-20  4:16     ` Hari Bathini
  1 sibling, 0 replies; 15+ messages in thread
From: Peter Zijlstra @ 2017-02-16 11:47 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Hari Bathini, ast, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

On Fri, Feb 17, 2017 at 12:25:27AM +1300, Eric W. Biederman wrote:
> > +/*
> > + * The maximum size of the name of each namespace
> > + */
> > +#define NS_NAME_SIZE				8
> > +
> > +struct perf_ns_link_info {
> > +	char	name[NS_NAME_SIZE];
> > +	__u64	dev;
> > +	__u64	ino;
> > +};
> 
> Ugh. I missed the name the first time around.
> 
> That really looks like useless clutter.  You already know the index so
> the name doesn't add any information, so unless I am missing something
> that name will just slow down the perf kernel implementation with
> useless work.
> 
> The userspace reader can have the information just as reliably by
> looking at the index and indexing into a table.
> 
> The set of namespaces changes slowly enough that this is not likely to
> be a problem in practice.  Especially as perf is released with the
> kernel.

Right; Hari, please ditch that name thing.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-16 10:28   ` Peter Zijlstra
  2017-02-16 10:36     ` Peter Zijlstra
@ 2017-02-20  4:11     ` Hari Bathini
  1 sibling, 0 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-20  4:11 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: ast, lkml, acme, alexander.shishkin, mingo, daniel, rostedt,
	Ananth N Mavinakayanahalli, ebiederm, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

Hi Peter,


On Thursday 16 February 2017 03:58 PM, Peter Zijlstra wrote:
> On Wed, Feb 08, 2017 at 02:01:24PM +0530, Hari Bathini wrote:
>> With the advert of container technologies like docker, that depend
>> on namespaces for isolation, there is a need for tracing support for
>> namespaces. This patch introduces new PERF_RECORD_NAMESPACES event
>> for tracing based on namespaces related info. This event records
>> the device and inode numbers for every namespace of all processes.
>>
>> While device number is same for all namespaces currently, that may
> 'While device numbers are the same ..." ?
>
>> change in future, to avoid the need for a namespace of namespaces.
> Unfinished sentence

Unnecessary comma spoiled the sentence, I guess.

>> Recording device number along with inode number will take care of such
>> scenario.
> More words on why this is so? Because I've no clue.

This should have read:

    "Each namespace has a combination of device and inode numbers. Though
     every namespace has the same device number currently, that may change
     in future to avoid the need for a namespace of namespaces. Considering
     such possibility, record both device and inode numbers separately for
     each namespace."

Will update changelog accordingly..

>> @@ -6584,6 +6590,135 @@ void perf_event_comm(struct task_struct *task, bool exec)
>>   }
>>   
>>   /*
>> + * namespaces tracking
>> + */
>> +
>> +struct namespaces_event_id {
>> +	struct perf_event_header	header;
>> +
>> +	u32				pid;
>> +	u32				tid;
>> +	u32				nr_namespaces;
>> +	struct perf_ns_link_info	link_info[NAMESPACES_MAX];
>> +};
> Contains the same hole and makes the record depend on architecture
> alignment requirements.

Ugh! Let me change nr_namespaces type to u64 and also drop name field
in perf_ns_link_info struct.

>> +static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
>> +				   struct task_struct *task,
>> +				   const struct proc_ns_operations *ns_ops)
>> +{
>> +	struct path ns_path;
>> +	struct inode *ns_inode;
>> +	void *error;
>> +
>> +	error = ns_get_path(&ns_path, task, ns_ops);
>> +	if (!error) {
>> +		snprintf(ns_link_info->name, NS_NAME_SIZE,
>> +			 "%s", ns_path.dentry->d_iname);
>> +
>> +		ns_inode = ns_path.dentry->d_inode;
>> +		ns_link_info->dev = new_encode_dev(ns_inode->i_sb->s_dev);
>> +		ns_link_info->ino = ns_inode->i_ino;
>> +	}
>> +}
>> +
>> +static void perf_event_namespaces_output(struct perf_event *event,
>> +					 void *data)
>> +{
>> +	struct perf_namespaces_event *namespaces_event = data;
>> +	struct perf_output_handle handle;
>> +	struct perf_sample_data sample;
>> +	struct namespaces_event_id *ei;
>> +	struct task_struct *task = namespaces_event->task;
>> +	int ret;
>> +
>> +	if (!perf_event_namespaces_match(event))
>> +		return;
>> +
>> +	ei = &namespaces_event->event_id;
>> +	perf_event_header__init_id(&ei->header, &sample, event);
>> +	ret = perf_output_begin(&handle, event,	ei->header.size);
>> +	if (ret)
>> +		return;
>> +
>> +	ei->pid = perf_event_pid(event, task);
>> +	ei->tid = perf_event_tid(event, task);
>> +
>> +	ei->nr_namespaces = NAMESPACES_MAX;
>> +
>> +	perf_fill_ns_link_info(&ei->link_info[MNT_NS_INDEX],
>> +			       task, &mntns_operations);
>> +
>> +#ifdef CONFIG_USER_NS
>> +	perf_fill_ns_link_info(&ei->link_info[USER_NS_INDEX],
>> +			       task, &userns_operations);
>> +#endif
>> +#ifdef CONFIG_NET_NS
>> +	perf_fill_ns_link_info(&ei->link_info[NET_NS_INDEX],
>> +			       task, &netns_operations);
>> +#endif
>> +#ifdef CONFIG_UTS_NS
>> +	perf_fill_ns_link_info(&ei->link_info[UTS_NS_INDEX],
>> +			       task, &utsns_operations);
>> +#endif
>> +#ifdef CONFIG_IPC_NS
>> +	perf_fill_ns_link_info(&ei->link_info[IPC_NS_INDEX],
>> +			       task, &ipcns_operations);
>> +#endif
>> +#ifdef CONFIG_PID_NS
>> +	perf_fill_ns_link_info(&ei->link_info[PID_NS_INDEX],
>> +			       task, &pidns_operations);
>> +#endif
>> +#ifdef CONFIG_CGROUPS
>> +	perf_fill_ns_link_info(&ei->link_info[CGROUP_NS_INDEX],
>> +			       task, &cgroupns_operations);
>> +#endif
> Two points here, since you've given these thingies a string identifier,
> do you still need to rely on their positional index? If not, you could
> generate smaller events if we lack some of these CONFIG knobs.

Dropping name field. So, I don't think this applies now..

> Secondly, does anything in here depend on @event? Afaict you're
> generating the exact same information for each event.
>
> The reason we set {pid,tid} for each event is because of PID_NS, we
> report the pid number as per the namespace associated with the event.
>
> But from what I can tell, there is no such namespace of namespaces
> dependency here and this should live in the function below.

Right. I will move it to perf_event_namespaces() function.

>> @@ -9667,6 +9804,11 @@ SYSCALL_DEFINE5(perf_event_open,
>>   			return -EACCES;
>>   	}
>>   
>> +	if (attr.namespaces) {
>> +		if (!capable(CAP_SYS_ADMIN))
>> +			return -EACCES;
>> +	}
> Many times we allow users access to such information; should this be
> qualified with something like perf_paranoid_kernel() or somesuch?

Hmmm.. Need access to namespace info of every process. Synthesized events
try and access /proc/1/ns/ and the like needing CAP_SYS_ADMIN. So, the
question is, should running perf tool be allowed with perf_paranoid_kernel()
check and complain later when access to /proc/1/ns and the like fails 
(on running
perf tool without CAP_SYS_ADMIN)?

>> +
>>   	if (attr.freq) {
>>   		if (attr.sample_freq > sysctl_perf_event_sample_rate)
>>   			return -EINVAL;
>> diff --git a/kernel/fork.c b/kernel/fork.c
>> index 11c5c8a..fd77e67 100644
>> --- a/kernel/fork.c
>> +++ b/kernel/fork.c
>> @@ -2289,6 +2289,9 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
>>   		free_fs_struct(new_fs);
>>   
>>   bad_unshare_out:
>> +	if (!err)
>> +		perf_event_namespaces(current);
>> +
>>   	return err;
>>   }
> That seems like a very odd place, why not put it right before the
> bad_unshare_cleanup_cred: label?
>

>> @@ -264,6 +265,10 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
>>   	switch_task_namespaces(tsk, new_nsproxy);
>>   out:
>>   	fput(file);
>> +
>> +	if (!err)
>> +		perf_event_namespaces(tsk);
>> +
>>   	return err;
>>   }
> Same again..

My bad! Will change that..

Thanks
Hari

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-16 11:25   ` Eric W. Biederman
  2017-02-16 11:47     ` Peter Zijlstra
@ 2017-02-20  4:16     ` Hari Bathini
  1 sibling, 0 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-20  4:16 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, sargun, Aravinda Prasad,
	brendan.d.gregg, jolsa

Hi Eric,


On Thursday 16 February 2017 04:55 PM, Eric W. Biederman wrote:
>> +/*
>> + * The maximum size of the name of each namespace
>> + */
>> +#define NS_NAME_SIZE				8
>> +
>> +struct perf_ns_link_info {
>> +	char	name[NS_NAME_SIZE];
>> +	__u64	dev;
>> +	__u64	ino;
>> +};
> Ugh. I missed the name the first time around.
>
> That really looks like useless clutter.  You already know the index so
> the name doesn't add any information, so unless I am missing something
> that name will just slow down the perf kernel implementation with
> useless work.
>
> The userspace reader can have the information just as reliably by
> looking at the index and indexing into a table.
>
> The set of namespaces changes slowly enough that this is not likely to
> be a problem in practice.  Especially as perf is released with the
> kernel.
>
> Plus who knows how long the name of the next namespace is going to be.
>

Agreed. Will drop name field from the structure and use an indexing
table to get names in userspace..

Thanks
Hari

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v6 2/3] perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
  2017-02-08 12:57   ` Jiri Olsa
@ 2017-02-21 14:03     ` Hari Bathini
  0 siblings, 0 replies; 15+ messages in thread
From: Hari Bathini @ 2017-02-21 14:03 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: ast, peterz, lkml, acme, alexander.shishkin, mingo, daniel,
	rostedt, Ananth N Mavinakayanahalli, ebiederm, sargun,
	Aravinda Prasad, brendan.d.gregg

Hi Jiri,


On Wednesday 08 February 2017 06:27 PM, Jiri Olsa wrote:
> On Wed, Feb 08, 2017 at 02:01:49PM +0530, Hari Bathini wrote:
>> This patch updates perf tool to examine PERF_RECORD_NAMESPACES events
>> emitted by the kernel when fork, clone, setns or unshare are invoked.
>> Also, it synthesizes PERF_RECORD_NAMESPACES events for processes that
>> were running prior to invocation of perf record, the data for which
>> is taken from /proc/$PID/ns. These changes make way for analyzing
>> events with regard to namespaces.
>>
>> Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
>> ---
>>   tools/include/uapi/linux/perf_event.h |   38 +++++++++
>>   tools/perf/builtin-annotate.c         |    1
>>   tools/perf/builtin-diff.c             |    1
>>   tools/perf/builtin-inject.c           |   14 +++
>>   tools/perf/builtin-kmem.c             |    1
>>   tools/perf/builtin-kvm.c              |    2
>>   tools/perf/builtin-lock.c             |    1
>>   tools/perf/builtin-mem.c              |    1
>>   tools/perf/builtin-record.c           |   33 +++++++-
>>   tools/perf/builtin-report.c           |    1
>>   tools/perf/builtin-sched.c            |    1
>>   tools/perf/builtin-script.c           |   41 +++++++++
>>   tools/perf/builtin-trace.c            |    3 -
>>   tools/perf/perf.h                     |    1
>>   tools/perf/util/Build                 |    1
>>   tools/perf/util/data-convert-bt.c     |    2
>>   tools/perf/util/event.c               |  143 ++++++++++++++++++++++++++++++++-
>>   tools/perf/util/event.h               |   19 ++++
>>   tools/perf/util/evsel.c               |    3 +
>>   tools/perf/util/machine.c             |   34 ++++++++
>>   tools/perf/util/machine.h             |    3 +
>>   tools/perf/util/namespaces.c          |   35 ++++++++
>>   tools/perf/util/namespaces.h          |   26 ++++++
>>   tools/perf/util/session.c             |    7 ++
>>   tools/perf/util/thread.c              |   44 ++++++++++
>>   tools/perf/util/thread.h              |    6 +
>>   tools/perf/util/tool.h                |    2
>>   27 files changed, 450 insertions(+), 14 deletions(-)
>>   create mode 100644 tools/perf/util/namespaces.c
>>   create mode 100644 tools/perf/util/namespaces.h
> could you please split this patch into logically separated changes, like:
>    - adding PERF_RECORD_NAMESPACES event with perf_event__process_namespaces
>      machinery
>    - synthesize support (perf_event__synthesize_namespaces) for record
>    - script print support
>    - perf_event__fprintf print support
>
> or any other split that'd make sense, it's too many changes for one patch now
>
>

Thanks for the review.
Posted v7 with the changes included..

- Hari

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-02-21 14:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-08  8:31 [PATCH v6 0/3] perf: add support for analyzing events for containers Hari Bathini
2017-02-08  8:31 ` [PATCH v6 1/3] perf: add PERF_RECORD_NAMESPACES to include namespaces related info Hari Bathini
2017-02-16 10:28   ` Peter Zijlstra
2017-02-16 10:36     ` Peter Zijlstra
2017-02-20  4:11     ` Hari Bathini
2017-02-16 11:25   ` Eric W. Biederman
2017-02-16 11:47     ` Peter Zijlstra
2017-02-20  4:16     ` Hari Bathini
2017-02-08  8:31 ` [PATCH v6 2/3] perf tool: " Hari Bathini
2017-02-08 12:57   ` Jiri Olsa
2017-02-08 12:57   ` Jiri Olsa
2017-02-08 12:57   ` Jiri Olsa
2017-02-21 14:03     ` Hari Bathini
2017-02-08  8:32 ` [PATCH v6 3/3] perf tool: add cgroup identifier entry in perf report Hari Bathini
2017-02-16  6:20 ` [PATCH v6 0/3] perf: add support for analyzing events for containers Eric W. Biederman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.