aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/trace/kprobetrace.txt5
-rw-r--r--include/linux/perf_event.h2
-rw-r--r--include/uapi/linux/perf_event.h32
-rw-r--r--kernel/events/core.c139
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/kprobes.c5
-rw-r--r--kernel/nsproxy.c3
-rw-r--r--tools/include/uapi/linux/perf_event.h32
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt7
-rw-r--r--tools/perf/Documentation/perf-sched.txt4
-rw-r--r--tools/perf/Documentation/perf-script.txt3
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c14
-rw-r--r--tools/perf/builtin-annotate.c1
-rw-r--r--tools/perf/builtin-c2c.c4
-rw-r--r--tools/perf/builtin-diff.c1
-rw-r--r--tools/perf/builtin-inject.c13
-rw-r--r--tools/perf/builtin-kmem.c1
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-lock.c1
-rw-r--r--tools/perf/builtin-mem.c1
-rw-r--r--tools/perf/builtin-record.c35
-rw-r--r--tools/perf/builtin-report.c4
-rw-r--r--tools/perf/builtin-sched.c26
-rw-r--r--tools/perf/builtin-script.c41
-rw-r--r--tools/perf/builtin-trace.c3
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/ui/browsers/hists.c2
-rw-r--r--tools/perf/util/Build1
-rw-r--r--tools/perf/util/data-convert-bt.c1
-rw-r--r--tools/perf/util/event.c150
-rw-r--r--tools/perf/util/event.h19
-rw-r--r--tools/perf/util/evsel.c3
-rw-r--r--tools/perf/util/hist.c7
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/machine.c34
-rw-r--r--tools/perf/util/machine.h3
-rw-r--r--tools/perf/util/namespaces.c36
-rw-r--r--tools/perf/util/namespaces.h26
-rw-r--r--tools/perf/util/probe-event.c12
-rw-r--r--tools/perf/util/probe-file.c77
-rw-r--r--tools/perf/util/probe-file.h1
-rw-r--r--tools/perf/util/session.c7
-rw-r--r--tools/perf/util/sort.c46
-rw-r--r--tools/perf/util/sort.h7
-rw-r--r--tools/perf/util/thread.c44
-rw-r--r--tools/perf/util/thread.h6
-rw-r--r--tools/perf/util/tool.h2
50 files changed, 799 insertions, 74 deletions
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt
index 41ef9d8efe95..5ea85059db3b 100644
--- a/Documentation/trace/kprobetrace.txt
+++ b/Documentation/trace/kprobetrace.txt
@@ -8,8 +8,9 @@ Overview
8-------- 8--------
9These events are similar to tracepoint based events. Instead of Tracepoint, 9These events are similar to tracepoint based events. Instead of Tracepoint,
10this is based on kprobes (kprobe and kretprobe). So it can probe wherever 10this is based on kprobes (kprobe and kretprobe). So it can probe wherever
11kprobes can probe (this means, all functions body except for __kprobes 11kprobes can probe (this means, all functions except those with
12functions). Unlike the Tracepoint based event, this can be added and removed 12__kprobes/nokprobe_inline annotation and those marked NOKPROBE_SYMBOL).
13Unlike the Tracepoint based event, this can be added and removed
13dynamically, on the fly. 14dynamically, on the fly.
14 15
15To enable this feature, build your kernel with CONFIG_KPROBE_EVENTS=y. 16To enable this feature, build your kernel with CONFIG_KPROBE_EVENTS=y.
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 000fdb211c7d..f19a82362851 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1112,6 +1112,7 @@ extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks
1112 1112
1113extern void perf_event_exec(void); 1113extern void perf_event_exec(void);
1114extern void perf_event_comm(struct task_struct *tsk, bool exec); 1114extern void perf_event_comm(struct task_struct *tsk, bool exec);
1115extern void perf_event_namespaces(struct task_struct *tsk);
1115extern void perf_event_fork(struct task_struct *tsk); 1116extern void perf_event_fork(struct task_struct *tsk);
1116 1117
1117/* Callchains */ 1118/* Callchains */
@@ -1315,6 +1316,7 @@ static inline int perf_unregister_guest_info_callbacks
1315static inline void perf_event_mmap(struct vm_area_struct *vma) { } 1316static inline void perf_event_mmap(struct vm_area_struct *vma) { }
1316static inline void perf_event_exec(void) { } 1317static inline void perf_event_exec(void) { }
1317static inline void perf_event_comm(struct task_struct *tsk, bool exec) { } 1318static inline void perf_event_comm(struct task_struct *tsk, bool exec) { }
1319static inline void perf_event_namespaces(struct task_struct *tsk) { }
1318static inline void perf_event_fork(struct task_struct *tsk) { } 1320static inline void perf_event_fork(struct task_struct *tsk) { }
1319static inline void perf_event_init(void) { } 1321static inline void perf_event_init(void) { }
1320static inline int perf_swevent_get_recursion_context(void) { return -1; } 1322static 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 c66a485a24ac..bec0aad0e15c 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -344,7 +344,8 @@ struct perf_event_attr {
344 use_clockid : 1, /* use @clockid for time fields */ 344 use_clockid : 1, /* use @clockid for time fields */
345 context_switch : 1, /* context switch data */ 345 context_switch : 1, /* context switch data */
346 write_backward : 1, /* Write ring buffer from end to beginning */ 346 write_backward : 1, /* Write ring buffer from end to beginning */
347 __reserved_1 : 36; 347 namespaces : 1, /* include namespaces data */
348 __reserved_1 : 35;
348 349
349 union { 350 union {
350 __u32 wakeup_events; /* wakeup every n events */ 351 __u32 wakeup_events; /* wakeup every n events */
@@ -610,6 +611,23 @@ struct perf_event_header {
610 __u16 size; 611 __u16 size;
611}; 612};
612 613
614struct perf_ns_link_info {
615 __u64 dev;
616 __u64 ino;
617};
618
619enum {
620 NET_NS_INDEX = 0,
621 UTS_NS_INDEX = 1,
622 IPC_NS_INDEX = 2,
623 PID_NS_INDEX = 3,
624 USER_NS_INDEX = 4,
625 MNT_NS_INDEX = 5,
626 CGROUP_NS_INDEX = 6,
627
628 NR_NAMESPACES, /* number of available namespaces */
629};
630
613enum perf_event_type { 631enum perf_event_type {
614 632
615 /* 633 /*
@@ -862,6 +880,18 @@ enum perf_event_type {
862 */ 880 */
863 PERF_RECORD_SWITCH_CPU_WIDE = 15, 881 PERF_RECORD_SWITCH_CPU_WIDE = 15,
864 882
883 /*
884 * struct {
885 * struct perf_event_header header;
886 * u32 pid;
887 * u32 tid;
888 * u64 nr_namespaces;
889 * { u64 dev, inode; } [nr_namespaces];
890 * struct sample_id sample_id;
891 * };
892 */
893 PERF_RECORD_NAMESPACES = 16,
894
865 PERF_RECORD_MAX, /* non-ABI */ 895 PERF_RECORD_MAX, /* non-ABI */
866}; 896};
867 897
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 6f41548f2e32..16c877a121c8 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -48,6 +48,8 @@
48#include <linux/parser.h> 48#include <linux/parser.h>
49#include <linux/sched/clock.h> 49#include <linux/sched/clock.h>
50#include <linux/sched/mm.h> 50#include <linux/sched/mm.h>
51#include <linux/proc_ns.h>
52#include <linux/mount.h>
51 53
52#include "internal.h" 54#include "internal.h"
53 55
@@ -379,6 +381,7 @@ static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
379 381
380static atomic_t nr_mmap_events __read_mostly; 382static atomic_t nr_mmap_events __read_mostly;
381static atomic_t nr_comm_events __read_mostly; 383static atomic_t nr_comm_events __read_mostly;
384static atomic_t nr_namespaces_events __read_mostly;
382static atomic_t nr_task_events __read_mostly; 385static atomic_t nr_task_events __read_mostly;
383static atomic_t nr_freq_events __read_mostly; 386static atomic_t nr_freq_events __read_mostly;
384static atomic_t nr_switch_events __read_mostly; 387static atomic_t nr_switch_events __read_mostly;
@@ -3991,6 +3994,8 @@ static void unaccount_event(struct perf_event *event)
3991 atomic_dec(&nr_mmap_events); 3994 atomic_dec(&nr_mmap_events);
3992 if (event->attr.comm) 3995 if (event->attr.comm)
3993 atomic_dec(&nr_comm_events); 3996 atomic_dec(&nr_comm_events);
3997 if (event->attr.namespaces)
3998 atomic_dec(&nr_namespaces_events);
3994 if (event->attr.task) 3999 if (event->attr.task)
3995 atomic_dec(&nr_task_events); 4000 atomic_dec(&nr_task_events);
3996 if (event->attr.freq) 4001 if (event->attr.freq)
@@ -6491,6 +6496,7 @@ static void perf_event_task(struct task_struct *task,
6491void perf_event_fork(struct task_struct *task) 6496void perf_event_fork(struct task_struct *task)
6492{ 6497{
6493 perf_event_task(task, NULL, 1); 6498 perf_event_task(task, NULL, 1);
6499 perf_event_namespaces(task);
6494} 6500}
6495 6501
6496/* 6502/*
@@ -6593,6 +6599,132 @@ void perf_event_comm(struct task_struct *task, bool exec)
6593} 6599}
6594 6600
6595/* 6601/*
6602 * namespaces tracking
6603 */
6604
6605struct perf_namespaces_event {
6606 struct task_struct *task;
6607
6608 struct {
6609 struct perf_event_header header;
6610
6611 u32 pid;
6612 u32 tid;
6613 u64 nr_namespaces;
6614 struct perf_ns_link_info link_info[NR_NAMESPACES];
6615 } event_id;
6616};
6617
6618static int perf_event_namespaces_match(struct perf_event *event)
6619{
6620 return event->attr.namespaces;
6621}
6622
6623static void perf_event_namespaces_output(struct perf_event *event,
6624 void *data)
6625{
6626 struct perf_namespaces_event *namespaces_event = data;
6627 struct perf_output_handle handle;
6628 struct perf_sample_data sample;
6629 int ret;
6630
6631 if (!perf_event_namespaces_match(event))
6632 return;
6633
6634 perf_event_header__init_id(&namespaces_event->event_id.header,
6635 &sample, event);
6636 ret = perf_output_begin(&handle, event,
6637 namespaces_event->event_id.header.size);
6638 if (ret)
6639 return;
6640
6641 namespaces_event->event_id.pid = perf_event_pid(event,
6642 namespaces_event->task);
6643 namespaces_event->event_id.tid = perf_event_tid(event,
6644 namespaces_event->task);
6645
6646 perf_output_put(&handle, namespaces_event->event_id);
6647
6648 perf_event__output_id_sample(event, &handle, &sample);
6649
6650 perf_output_end(&handle);
6651}
6652
6653static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
6654 struct task_struct *task,
6655 const struct proc_ns_operations *ns_ops)
6656{
6657 struct path ns_path;
6658 struct inode *ns_inode;
6659 void *error;
6660
6661 error = ns_get_path(&ns_path, task, ns_ops);
6662 if (!error) {
6663 ns_inode = ns_path.dentry->d_inode;
6664 ns_link_info->dev = new_encode_dev(ns_inode->i_sb->s_dev);
6665 ns_link_info->ino = ns_inode->i_ino;
6666 }
6667}
6668
6669void perf_event_namespaces(struct task_struct *task)
6670{
6671 struct perf_namespaces_event namespaces_event;
6672 struct perf_ns_link_info *ns_link_info;
6673
6674 if (!atomic_read(&nr_namespaces_events))
6675 return;
6676
6677 namespaces_event = (struct perf_namespaces_event){
6678 .task = task,
6679 .event_id = {
6680 .header = {
6681 .type = PERF_RECORD_NAMESPACES,
6682 .misc = 0,
6683 .size = sizeof(namespaces_event.event_id),
6684 },
6685 /* .pid */
6686 /* .tid */
6687 .nr_namespaces = NR_NAMESPACES,
6688 /* .link_info[NR_NAMESPACES] */
6689 },
6690 };
6691
6692 ns_link_info = namespaces_event.event_id.link_info;
6693
6694 perf_fill_ns_link_info(&ns_link_info[MNT_NS_INDEX],
6695 task, &mntns_operations);
6696
6697#ifdef CONFIG_USER_NS
6698 perf_fill_ns_link_info(&ns_link_info[USER_NS_INDEX],
6699 task, &userns_operations);
6700#endif
6701#ifdef CONFIG_NET_NS
6702 perf_fill_ns_link_info(&ns_link_info[NET_NS_INDEX],
6703 task, &netns_operations);
6704#endif
6705#ifdef CONFIG_UTS_NS
6706 perf_fill_ns_link_info(&ns_link_info[UTS_NS_INDEX],
6707 task, &utsns_operations);
6708#endif
6709#ifdef CONFIG_IPC_NS
6710 perf_fill_ns_link_info(&ns_link_info[IPC_NS_INDEX],
6711 task, &ipcns_operations);
6712#endif
6713#ifdef CONFIG_PID_NS
6714 perf_fill_ns_link_info(&ns_link_info[PID_NS_INDEX],
6715 task, &pidns_operations);
6716#endif
6717#ifdef CONFIG_CGROUPS
6718 perf_fill_ns_link_info(&ns_link_info[CGROUP_NS_INDEX],
6719 task, &cgroupns_operations);
6720#endif
6721
6722 perf_iterate_sb(perf_event_namespaces_output,
6723 &namespaces_event,
6724 NULL);
6725}
6726
6727/*
6596 * mmap tracking 6728 * mmap tracking
6597 */ 6729 */
6598 6730
@@ -9146,6 +9278,8 @@ static void account_event(struct perf_event *event)
9146 atomic_inc(&nr_mmap_events); 9278 atomic_inc(&nr_mmap_events);
9147 if (event->attr.comm) 9279 if (event->attr.comm)
9148 atomic_inc(&nr_comm_events); 9280 atomic_inc(&nr_comm_events);
9281 if (event->attr.namespaces)
9282 atomic_inc(&nr_namespaces_events);
9149 if (event->attr.task) 9283 if (event->attr.task)
9150 atomic_inc(&nr_task_events); 9284 atomic_inc(&nr_task_events);
9151 if (event->attr.freq) 9285 if (event->attr.freq)
@@ -9691,6 +9825,11 @@ SYSCALL_DEFINE5(perf_event_open,
9691 return -EACCES; 9825 return -EACCES;
9692 } 9826 }
9693 9827
9828 if (attr.namespaces) {
9829 if (!capable(CAP_SYS_ADMIN))
9830 return -EACCES;
9831 }
9832
9694 if (attr.freq) { 9833 if (attr.freq) {
9695 if (attr.sample_freq > sysctl_perf_event_sample_rate) 9834 if (attr.sample_freq > sysctl_perf_event_sample_rate)
9696 return -EINVAL; 9835 return -EINVAL;
diff --git a/kernel/fork.c b/kernel/fork.c
index 6c463c80e93d..afa2947286cd 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2352,6 +2352,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
2352 } 2352 }
2353 } 2353 }
2354 2354
2355 perf_event_namespaces(current);
2356
2355bad_unshare_cleanup_cred: 2357bad_unshare_cleanup_cred:
2356 if (new_cred) 2358 if (new_cred)
2357 put_cred(new_cred); 2359 put_cred(new_cred);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 448759d4a263..4780ec236035 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1740,11 +1740,12 @@ void unregister_kprobes(struct kprobe **kps, int num)
1740} 1740}
1741EXPORT_SYMBOL_GPL(unregister_kprobes); 1741EXPORT_SYMBOL_GPL(unregister_kprobes);
1742 1742
1743int __weak __kprobes kprobe_exceptions_notify(struct notifier_block *self, 1743int __weak kprobe_exceptions_notify(struct notifier_block *self,
1744 unsigned long val, void *data) 1744 unsigned long val, void *data)
1745{ 1745{
1746 return NOTIFY_DONE; 1746 return NOTIFY_DONE;
1747} 1747}
1748NOKPROBE_SYMBOL(kprobe_exceptions_notify);
1748 1749
1749static struct notifier_block kprobe_exceptions_nb = { 1750static struct notifier_block kprobe_exceptions_nb = {
1750 .notifier_call = kprobe_exceptions_notify, 1751 .notifier_call = kprobe_exceptions_notify,
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 782102e59eed..f6c5d330059a 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -26,6 +26,7 @@
26#include <linux/file.h> 26#include <linux/file.h>
27#include <linux/syscalls.h> 27#include <linux/syscalls.h>
28#include <linux/cgroup.h> 28#include <linux/cgroup.h>
29#include <linux/perf_event.h>
29 30
30static struct kmem_cache *nsproxy_cachep; 31static struct kmem_cache *nsproxy_cachep;
31 32
@@ -262,6 +263,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
262 goto out; 263 goto out;
263 } 264 }
264 switch_task_namespaces(tsk, new_nsproxy); 265 switch_task_namespaces(tsk, new_nsproxy);
266
267 perf_event_namespaces(tsk);
265out: 268out:
266 fput(file); 269 fput(file);
267 return err; 270 return err;
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index c66a485a24ac..bec0aad0e15c 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 {
344 use_clockid : 1, /* use @clockid for time fields */ 344 use_clockid : 1, /* use @clockid for time fields */
345 context_switch : 1, /* context switch data */ 345 context_switch : 1, /* context switch data */
346 write_backward : 1, /* Write ring buffer from end to beginning */ 346 write_backward : 1, /* Write ring buffer from end to beginning */
347 __reserved_1 : 36; 347 namespaces : 1, /* include namespaces data */
348 __reserved_1 : 35;
348 349
349 union { 350 union {
350 __u32 wakeup_events; /* wakeup every n events */ 351 __u32 wakeup_events; /* wakeup every n events */
@@ -610,6 +611,23 @@ struct perf_event_header {
610 __u16 size; 611 __u16 size;
611}; 612};
612 613
614struct perf_ns_link_info {
615 __u64 dev;
616 __u64 ino;
617};
618
619enum {
620 NET_NS_INDEX = 0,
621 UTS_NS_INDEX = 1,
622 IPC_NS_INDEX = 2,
623 PID_NS_INDEX = 3,
624 USER_NS_INDEX = 4,
625 MNT_NS_INDEX = 5,
626 CGROUP_NS_INDEX = 6,
627
628 NR_NAMESPACES, /* number of available namespaces */
629};
630
613enum perf_event_type { 631enum perf_event_type {
614 632
615 /* 633 /*
@@ -862,6 +880,18 @@ enum perf_event_type {
862 */ 880 */
863 PERF_RECORD_SWITCH_CPU_WIDE = 15, 881 PERF_RECORD_SWITCH_CPU_WIDE = 15,
864 882
883 /*
884 * struct {
885 * struct perf_event_header header;
886 * u32 pid;
887 * u32 tid;
888 * u64 nr_namespaces;
889 * { u64 dev, inode; } [nr_namespaces];
890 * struct sample_id sample_id;
891 * };
892 */
893 PERF_RECORD_NAMESPACES = 16,
894
865 PERF_RECORD_MAX, /* non-ABI */ 895 PERF_RECORD_MAX, /* non-ABI */
866}; 896};
867 897
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 3db3db9278be..643cc4ba6872 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -31,3 +31,5 @@ config.mak.autogen
31.config-detected 31.config-detected
32util/intel-pt-decoder/inat-tables.c 32util/intel-pt-decoder/inat-tables.c
33arch/*/include/generated/ 33arch/*/include/generated/
34pmu-events/pmu-events.c
35pmu-events/jevents
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index b16003ec14a7..ea3789d05e5e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -347,6 +347,9 @@ Enable weightened sampling. An additional weight is recorded per sample and can
347displayed with the weight and local_weight sort keys. This currently works for TSX 347displayed with the weight and local_weight sort keys. This currently works for TSX
348abort events and some memory events in precise mode on modern Intel CPUs. 348abort events and some memory events in precise mode on modern Intel CPUs.
349 349
350--namespaces::
351Record events of type PERF_RECORD_NAMESPACES.
352
350--transaction:: 353--transaction::
351Record transaction flags for transaction related events. 354Record transaction flags for transaction related events.
352 355
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 33f91906f5dc..e9a61f5485eb 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -72,7 +72,8 @@ OPTIONS
72--sort=:: 72--sort=::
73 Sort histogram entries by given key(s) - multiple keys can be specified 73 Sort histogram entries by given key(s) - multiple keys can be specified
74 in CSV format. Following sort keys are available: 74 in CSV format. Following sort keys are available:
75 pid, comm, dso, symbol, parent, cpu, socket, srcline, weight, local_weight. 75 pid, comm, dso, symbol, parent, cpu, socket, srcline, weight,
76 local_weight, cgroup_id.
76 77
77 Each key has following meaning: 78 Each key has following meaning:
78 79
@@ -92,6 +93,7 @@ OPTIONS
92 - weight: Event specific weight, e.g. memory latency or transaction 93 - weight: Event specific weight, e.g. memory latency or transaction
93 abort cost. This is the global weight. 94 abort cost. This is the global weight.
94 - local_weight: Local weight version of the weight above. 95 - local_weight: Local weight version of the weight above.
96 - cgroup_id: ID derived from cgroup namespace device and inode numbers.
95 - transaction: Transaction abort flags. 97 - transaction: Transaction abort flags.
96 - overhead: Overhead percentage of sample 98 - overhead: Overhead percentage of sample
97 - overhead_sys: Overhead percentage of sample running in system mode 99 - overhead_sys: Overhead percentage of sample running in system mode
@@ -173,6 +175,9 @@ OPTIONS
173 By default, every sort keys not specified in -F will be appended 175 By default, every sort keys not specified in -F will be appended
174 automatically. 176 automatically.
175 177
178 If the keys starts with a prefix '+', then it will append the specified
179 field(s) to the default field order. For example: perf report -F +period,sample.
180
176-p:: 181-p::
177--parent=<regex>:: 182--parent=<regex>::
178 A regex filter to identify parent. The parent is a caller of this 183 A regex filter to identify parent. The parent is a caller of this
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index d33deddb0146..a092a2499e8f 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -132,6 +132,10 @@ OPTIONS for 'perf sched timehist'
132--migrations:: 132--migrations::
133 Show migration events. 133 Show migration events.
134 134
135-n::
136--next::
137 Show next task.
138
135-I:: 139-I::
136--idle-hist:: 140--idle-hist::
137 Show idle-related events only. 141 Show idle-related events only.
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 4ed5f239ba7d..62c9b0c77a3a 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -248,6 +248,9 @@ OPTIONS
248--show-mmap-events 248--show-mmap-events
249 Display mmap related events (e.g. MMAP, MMAP2). 249 Display mmap related events (e.g. MMAP, MMAP2).
250 250
251--show-namespace-events
252 Display namespace events i.e. events of type PERF_RECORD_NAMESPACES.
253
251--show-switch-events 254--show-switch-events
252 Display context switch events i.e. events of type PERF_RECORD_SWITCH or 255 Display context switch events i.e. events of type PERF_RECORD_SWITCH or
253 PERF_RECORD_SWITCH_CPU_WIDE. 256 PERF_RECORD_SWITCH_CPU_WIDE.
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index 1030a6e504bb..39dbe512b9fc 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -10,6 +10,7 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "map.h" 11#include "map.h"
12#include "probe-event.h" 12#include "probe-event.h"
13#include "probe-file.h"
13 14
14#ifdef HAVE_LIBELF_SUPPORT 15#ifdef HAVE_LIBELF_SUPPORT
15bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) 16bool elf__needs_adjust_symbols(GElf_Ehdr ehdr)
@@ -79,13 +80,18 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
79 * However, if the user specifies an offset, we fall back to using the 80 * However, if the user specifies an offset, we fall back to using the
80 * GEP since all userspace applications (objdump/readelf) show function 81 * GEP since all userspace applications (objdump/readelf) show function
81 * disassembly with offsets from the GEP. 82 * disassembly with offsets from the GEP.
82 *
83 * In addition, we shouldn't specify an offset for kretprobes.
84 */ 83 */
85 if (pev->point.offset || (!pev->uprobes && pev->point.retprobe) || 84 if (pev->point.offset || !map || !sym)
86 !map || !sym)
87 return; 85 return;
88 86
87 /* For kretprobes, add an offset only if the kernel supports it */
88 if (!pev->uprobes && pev->point.retprobe) {
89#ifdef HAVE_LIBELF_SUPPORT
90 if (!kretprobe_offset_is_supported())
91#endif
92 return;
93 }
94
89 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 95 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
90 96
91 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) 97 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4f52d85f5ebc..e54b1f9fe1ee 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)
393 .comm = perf_event__process_comm, 393 .comm = perf_event__process_comm,
394 .exit = perf_event__process_exit, 394 .exit = perf_event__process_exit,
395 .fork = perf_event__process_fork, 395 .fork = perf_event__process_fork,
396 .namespaces = perf_event__process_namespaces,
396 .ordered_events = true, 397 .ordered_events = true,
397 .ordering_requires_timestamps = true, 398 .ordering_requires_timestamps = true,
398 }, 399 },
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index e2b21723bbf8..5cd6d7a047b9 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -2334,7 +2334,7 @@ out:
2334 2334
2335static void perf_c2c_display(struct perf_session *session) 2335static void perf_c2c_display(struct perf_session *session)
2336{ 2336{
2337 if (c2c.use_stdio) 2337 if (use_browser == 0)
2338 perf_c2c__hists_fprintf(stdout, session); 2338 perf_c2c__hists_fprintf(stdout, session);
2339 else 2339 else
2340 perf_c2c__hists_browse(&c2c.hists.hists); 2340 perf_c2c__hists_browse(&c2c.hists.hists);
@@ -2536,7 +2536,7 @@ static int perf_c2c__report(int argc, const char **argv)
2536 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"), 2536 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2537#endif 2537#endif
2538 OPT_BOOLEAN(0, "stats", &c2c.stats_only, 2538 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
2539 "Use the stdio interface"), 2539 "Display only statistic tables (implies --stdio)"),
2540 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full, 2540 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
2541 "Display full length of symbols"), 2541 "Display full length of symbols"),
2542 OPT_BOOLEAN(0, "no-source", &no_source, 2542 OPT_BOOLEAN(0, "no-source", &no_source,
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 1b96a3122228..5e4803158672 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -364,6 +364,7 @@ static struct perf_tool tool = {
364 .exit = perf_event__process_exit, 364 .exit = perf_event__process_exit,
365 .fork = perf_event__process_fork, 365 .fork = perf_event__process_fork,
366 .lost = perf_event__process_lost, 366 .lost = perf_event__process_lost,
367 .namespaces = perf_event__process_namespaces,
367 .ordered_events = true, 368 .ordered_events = true,
368 .ordering_requires_timestamps = true, 369 .ordering_requires_timestamps = true,
369}; 370};
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index b9bc7e39833a..8d1d13b9bab6 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -333,6 +333,18 @@ static int perf_event__repipe_comm(struct perf_tool *tool,
333 return err; 333 return err;
334} 334}
335 335
336static int perf_event__repipe_namespaces(struct perf_tool *tool,
337 union perf_event *event,
338 struct perf_sample *sample,
339 struct machine *machine)
340{
341 int err = perf_event__process_namespaces(tool, event, sample, machine);
342
343 perf_event__repipe(tool, event, sample, machine);
344
345 return err;
346}
347
336static int perf_event__repipe_exit(struct perf_tool *tool, 348static int perf_event__repipe_exit(struct perf_tool *tool,
337 union perf_event *event, 349 union perf_event *event,
338 struct perf_sample *sample, 350 struct perf_sample *sample,
@@ -660,6 +672,7 @@ static int __cmd_inject(struct perf_inject *inject)
660 session->itrace_synth_opts = &inject->itrace_synth_opts; 672 session->itrace_synth_opts = &inject->itrace_synth_opts;
661 inject->itrace_synth_opts.inject = true; 673 inject->itrace_synth_opts.inject = true;
662 inject->tool.comm = perf_event__repipe_comm; 674 inject->tool.comm = perf_event__repipe_comm;
675 inject->tool.namespaces = perf_event__repipe_namespaces;
663 inject->tool.exit = perf_event__repipe_exit; 676 inject->tool.exit = perf_event__repipe_exit;
664 inject->tool.id_index = perf_event__repipe_id_index; 677 inject->tool.id_index = perf_event__repipe_id_index;
665 inject->tool.auxtrace_info = perf_event__process_auxtrace_info; 678 inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 6da8d083e4e5..d509e74bc6e8 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -964,6 +964,7 @@ static struct perf_tool perf_kmem = {
964 .comm = perf_event__process_comm, 964 .comm = perf_event__process_comm,
965 .mmap = perf_event__process_mmap, 965 .mmap = perf_event__process_mmap,
966 .mmap2 = perf_event__process_mmap2, 966 .mmap2 = perf_event__process_mmap2,
967 .namespaces = perf_event__process_namespaces,
967 .ordered_events = true, 968 .ordered_events = true,
968}; 969};
969 970
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 08fa88f62a24..18e6c38864bc 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)
1044 struct perf_tool eops = { 1044 struct perf_tool eops = {
1045 .sample = process_sample_event, 1045 .sample = process_sample_event,
1046 .comm = perf_event__process_comm, 1046 .comm = perf_event__process_comm,
1047 .namespaces = perf_event__process_namespaces,
1047 .ordered_events = true, 1048 .ordered_events = true,
1048 }; 1049 };
1049 struct perf_data_file file = { 1050 struct perf_data_file file = {
@@ -1348,6 +1349,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1348 kvm->tool.exit = perf_event__process_exit; 1349 kvm->tool.exit = perf_event__process_exit;
1349 kvm->tool.fork = perf_event__process_fork; 1350 kvm->tool.fork = perf_event__process_fork;
1350 kvm->tool.lost = process_lost_event; 1351 kvm->tool.lost = process_lost_event;
1352 kvm->tool.namespaces = perf_event__process_namespaces;
1351 kvm->tool.ordered_events = true; 1353 kvm->tool.ordered_events = true;
1352 perf_tool__fill_defaults(&kvm->tool); 1354 perf_tool__fill_defaults(&kvm->tool);
1353 1355
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index ce3bfb48b26f..d750ccaa978f 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -858,6 +858,7 @@ static int __cmd_report(bool display_info)
858 struct perf_tool eops = { 858 struct perf_tool eops = {
859 .sample = process_sample_event, 859 .sample = process_sample_event,
860 .comm = perf_event__process_comm, 860 .comm = perf_event__process_comm,
861 .namespaces = perf_event__process_namespaces,
861 .ordered_events = true, 862 .ordered_events = true,
862 }; 863 };
863 struct perf_data_file file = { 864 struct perf_data_file file = {
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 6114e07ca613..030a6cfdda59 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)
342 .lost = perf_event__process_lost, 342 .lost = perf_event__process_lost,
343 .fork = perf_event__process_fork, 343 .fork = perf_event__process_fork,
344 .build_id = perf_event__process_build_id, 344 .build_id = perf_event__process_build_id,
345 .namespaces = perf_event__process_namespaces,
345 .ordered_events = true, 346 .ordered_events = true,
346 }, 347 },
347 .input_name = "perf.data", 348 .input_name = "perf.data",
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index bc84a375295d..04faef79a548 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -876,6 +876,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
876 signal(SIGTERM, sig_handler); 876 signal(SIGTERM, sig_handler);
877 signal(SIGSEGV, sigsegv_handler); 877 signal(SIGSEGV, sigsegv_handler);
878 878
879 if (rec->opts.record_namespaces)
880 tool->namespace_events = true;
881
879 if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) { 882 if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) {
880 signal(SIGUSR2, snapshot_sig_handler); 883 signal(SIGUSR2, snapshot_sig_handler);
881 if (rec->opts.auxtrace_snapshot_mode) 884 if (rec->opts.auxtrace_snapshot_mode)
@@ -983,6 +986,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
983 */ 986 */
984 if (forks) { 987 if (forks) {
985 union perf_event *event; 988 union perf_event *event;
989 pid_t tgid;
986 990
987 event = malloc(sizeof(event->comm) + machine->id_hdr_size); 991 event = malloc(sizeof(event->comm) + machine->id_hdr_size);
988 if (event == NULL) { 992 if (event == NULL) {
@@ -996,10 +1000,30 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
996 * cannot see a correct process name for those events. 1000 * cannot see a correct process name for those events.
997 * Synthesize COMM event to prevent it. 1001 * Synthesize COMM event to prevent it.
998 */ 1002 */
999 perf_event__synthesize_comm(tool, event, 1003 tgid = perf_event__synthesize_comm(tool, event,
1000 rec->evlist->workload.pid, 1004 rec->evlist->workload.pid,
1001 process_synthesized_event, 1005 process_synthesized_event,
1002 machine); 1006 machine);
1007 free(event);
1008
1009 if (tgid == -1)
1010 goto out_child;
1011
1012 event = malloc(sizeof(event->namespaces) +
1013 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
1014 machine->id_hdr_size);
1015 if (event == NULL) {
1016 err = -ENOMEM;
1017 goto out_child;
1018 }
1019
1020 /*
1021 * Synthesize NAMESPACES event for the command specified.
1022 */
1023 perf_event__synthesize_namespaces(tool, event,
1024 rec->evlist->workload.pid,
1025 tgid, process_synthesized_event,
1026 machine);
1003 free(event); 1027 free(event);
1004 1028
1005 perf_evlist__start_workload(rec->evlist); 1029 perf_evlist__start_workload(rec->evlist);
@@ -1497,6 +1521,7 @@ static struct record record = {
1497 .fork = perf_event__process_fork, 1521 .fork = perf_event__process_fork,
1498 .exit = perf_event__process_exit, 1522 .exit = perf_event__process_exit,
1499 .comm = perf_event__process_comm, 1523 .comm = perf_event__process_comm,
1524 .namespaces = perf_event__process_namespaces,
1500 .mmap = perf_event__process_mmap, 1525 .mmap = perf_event__process_mmap,
1501 .mmap2 = perf_event__process_mmap2, 1526 .mmap2 = perf_event__process_mmap2,
1502 .ordered_events = true, 1527 .ordered_events = true,
@@ -1611,6 +1636,8 @@ static struct option __record_options[] = {
1611 "opts", "AUX area tracing Snapshot Mode", ""), 1636 "opts", "AUX area tracing Snapshot Mode", ""),
1612 OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout, 1637 OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
1613 "per thread proc mmap processing timeout in ms"), 1638 "per thread proc mmap processing timeout in ms"),
1639 OPT_BOOLEAN(0, "namespaces", &record.opts.record_namespaces,
1640 "Record namespaces events"),
1614 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1641 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1615 "Record context switch events"), 1642 "Record context switch events"),
1616 OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel, 1643 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 0a88670e56f3..5ab8117c3bfd 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -394,8 +394,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
394 fprintf(stdout, "\n\n"); 394 fprintf(stdout, "\n\n");
395 } 395 }
396 396
397 if (sort_order == NULL && 397 if (!quiet)
398 parent_pattern == default_parent_pattern)
399 fprintf(stdout, "#\n# (%s)\n#\n", help); 398 fprintf(stdout, "#\n# (%s)\n#\n", help);
400 399
401 if (rep->show_threads) { 400 if (rep->show_threads) {
@@ -701,6 +700,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
701 .mmap = perf_event__process_mmap, 700 .mmap = perf_event__process_mmap,
702 .mmap2 = perf_event__process_mmap2, 701 .mmap2 = perf_event__process_mmap2,
703 .comm = perf_event__process_comm, 702 .comm = perf_event__process_comm,
703 .namespaces = perf_event__process_namespaces,
704 .exit = perf_event__process_exit, 704 .exit = perf_event__process_exit,
705 .fork = perf_event__process_fork, 705 .fork = perf_event__process_fork,
706 .lost = perf_event__process_lost, 706 .lost = perf_event__process_lost,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b94cf0de715a..b92c4d97192c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -221,6 +221,7 @@ struct perf_sched {
221 unsigned int max_stack; 221 unsigned int max_stack;
222 bool show_cpu_visual; 222 bool show_cpu_visual;
223 bool show_wakeups; 223 bool show_wakeups;
224 bool show_next;
224 bool show_migrations; 225 bool show_migrations;
225 bool show_state; 226 bool show_state;
226 u64 skipped_samples; 227 u64 skipped_samples;
@@ -1897,14 +1898,18 @@ static char task_state_char(struct thread *thread, int state)
1897} 1898}
1898 1899
1899static void timehist_print_sample(struct perf_sched *sched, 1900static void timehist_print_sample(struct perf_sched *sched,
1901 struct perf_evsel *evsel,
1900 struct perf_sample *sample, 1902 struct perf_sample *sample,
1901 struct addr_location *al, 1903 struct addr_location *al,
1902 struct thread *thread, 1904 struct thread *thread,
1903 u64 t, int state) 1905 u64 t, int state)
1904{ 1906{
1905 struct thread_runtime *tr = thread__priv(thread); 1907 struct thread_runtime *tr = thread__priv(thread);
1908 const char *next_comm = perf_evsel__strval(evsel, sample, "next_comm");
1909 const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1906 u32 max_cpus = sched->max_cpu + 1; 1910 u32 max_cpus = sched->max_cpu + 1;
1907 char tstr[64]; 1911 char tstr[64];
1912 char nstr[30];
1908 u64 wait_time; 1913 u64 wait_time;
1909 1914
1910 timestamp__scnprintf_usec(t, tstr, sizeof(tstr)); 1915 timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
@@ -1937,7 +1942,12 @@ static void timehist_print_sample(struct perf_sched *sched,
1937 if (sched->show_state) 1942 if (sched->show_state)
1938 printf(" %5c ", task_state_char(thread, state)); 1943 printf(" %5c ", task_state_char(thread, state));
1939 1944
1940 if (sched->show_wakeups) 1945 if (sched->show_next) {
1946 snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid);
1947 printf(" %-*s", comm_width, nstr);
1948 }
1949
1950 if (sched->show_wakeups && !sched->show_next)
1941 printf(" %-*s", comm_width, ""); 1951 printf(" %-*s", comm_width, "");
1942 1952
1943 if (thread->tid == 0) 1953 if (thread->tid == 0)
@@ -2531,7 +2541,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2531 } 2541 }
2532 2542
2533 if (!sched->summary_only) 2543 if (!sched->summary_only)
2534 timehist_print_sample(sched, sample, &al, thread, t, state); 2544 timehist_print_sample(sched, evsel, sample, &al, thread, t, state);
2535 2545
2536out: 2546out:
2537 if (sched->hist_time.start == 0 && t >= ptime->start) 2547 if (sched->hist_time.start == 0 && t >= ptime->start)
@@ -3272,6 +3282,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3272 .tool = { 3282 .tool = {
3273 .sample = perf_sched__process_tracepoint_sample, 3283 .sample = perf_sched__process_tracepoint_sample,
3274 .comm = perf_event__process_comm, 3284 .comm = perf_event__process_comm,
3285 .namespaces = perf_event__process_namespaces,
3275 .lost = perf_event__process_lost, 3286 .lost = perf_event__process_lost,
3276 .fork = perf_sched__process_fork_event, 3287 .fork = perf_sched__process_fork_event,
3277 .ordered_events = true, 3288 .ordered_events = true,
@@ -3340,6 +3351,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3340 OPT_BOOLEAN('S', "with-summary", &sched.summary, 3351 OPT_BOOLEAN('S', "with-summary", &sched.summary,
3341 "Show all syscalls and summary with statistics"), 3352 "Show all syscalls and summary with statistics"),
3342 OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), 3353 OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
3354 OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"),
3343 OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), 3355 OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
3344 OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), 3356 OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
3345 OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"), 3357 OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
@@ -3437,10 +3449,14 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3437 if (argc) 3449 if (argc)
3438 usage_with_options(timehist_usage, timehist_options); 3450 usage_with_options(timehist_usage, timehist_options);
3439 } 3451 }
3440 if (sched.show_wakeups && sched.summary_only) { 3452 if ((sched.show_wakeups || sched.show_next) &&
3441 pr_err(" Error: -s and -w are mutually exclusive.\n"); 3453 sched.summary_only) {
3454 pr_err(" Error: -s and -[n|w] are mutually exclusive.\n");
3442 parse_options_usage(timehist_usage, timehist_options, "s", true); 3455 parse_options_usage(timehist_usage, timehist_options, "s", true);
3443 parse_options_usage(NULL, timehist_options, "w", true); 3456 if (sched.show_wakeups)
3457 parse_options_usage(NULL, timehist_options, "w", true);
3458 if (sched.show_next)
3459 parse_options_usage(NULL, timehist_options, "n", true);
3444 return -EINVAL; 3460 return -EINVAL;
3445 } 3461 }
3446 3462
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c0783b4f7b6c..66d62c98dff9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -830,6 +830,7 @@ struct perf_script {
830 bool show_task_events; 830 bool show_task_events;
831 bool show_mmap_events; 831 bool show_mmap_events;
832 bool show_switch_events; 832 bool show_switch_events;
833 bool show_namespace_events;
833 bool allocated; 834 bool allocated;
834 struct cpu_map *cpus; 835 struct cpu_map *cpus;
835 struct thread_map *threads; 836 struct thread_map *threads;
@@ -1118,6 +1119,41 @@ out:
1118 return ret; 1119 return ret;
1119} 1120}
1120 1121
1122static int process_namespaces_event(struct perf_tool *tool,
1123 union perf_event *event,
1124 struct perf_sample *sample,
1125 struct machine *machine)
1126{
1127 struct thread *thread;
1128 struct perf_script *script = container_of(tool, struct perf_script, tool);
1129 struct perf_session *session = script->session;
1130 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
1131 int ret = -1;
1132
1133 thread = machine__findnew_thread(machine, event->namespaces.pid,
1134 event->namespaces.tid);
1135 if (thread == NULL) {
1136 pr_debug("problem processing NAMESPACES event, skipping it.\n");
1137 return -1;
1138 }
1139
1140 if (perf_event__process_namespaces(tool, event, sample, machine) < 0)
1141 goto out;
1142
1143 if (!evsel->attr.sample_id_all) {
1144 sample->cpu = 0;
1145 sample->time = 0;
1146 sample->tid = event->namespaces.tid;
1147 sample->pid = event->namespaces.pid;
1148 }
1149 print_sample_start(sample, thread, evsel);
1150 perf_event__fprintf(event, stdout);
1151 ret = 0;
1152out:
1153 thread__put(thread);
1154 return ret;
1155}
1156
1121static int process_fork_event(struct perf_tool *tool, 1157static int process_fork_event(struct perf_tool *tool,
1122 union perf_event *event, 1158 union perf_event *event,
1123 struct perf_sample *sample, 1159 struct perf_sample *sample,
@@ -1293,6 +1329,8 @@ static int __cmd_script(struct perf_script *script)
1293 } 1329 }
1294 if (script->show_switch_events) 1330 if (script->show_switch_events)
1295 script->tool.context_switch = process_switch_event; 1331 script->tool.context_switch = process_switch_event;
1332 if (script->show_namespace_events)
1333 script->tool.namespaces = process_namespaces_event;
1296 1334
1297 ret = perf_session__process_events(script->session); 1335 ret = perf_session__process_events(script->session);
1298 1336
@@ -2097,6 +2135,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2097 .mmap = perf_event__process_mmap, 2135 .mmap = perf_event__process_mmap,
2098 .mmap2 = perf_event__process_mmap2, 2136 .mmap2 = perf_event__process_mmap2,
2099 .comm = perf_event__process_comm, 2137 .comm = perf_event__process_comm,
2138 .namespaces = perf_event__process_namespaces,
2100 .exit = perf_event__process_exit, 2139 .exit = perf_event__process_exit,
2101 .fork = perf_event__process_fork, 2140 .fork = perf_event__process_fork,
2102 .attr = process_attr, 2141 .attr = process_attr,
@@ -2180,6 +2219,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2180 "Show the mmap events"), 2219 "Show the mmap events"),
2181 OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, 2220 OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events,
2182 "Show context switch events (if recorded)"), 2221 "Show context switch events (if recorded)"),
2222 OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events,
2223 "Show namespace events (if recorded)"),
2183 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), 2224 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
2184 OPT_BOOLEAN(0, "ns", &nanosecs, 2225 OPT_BOOLEAN(0, "ns", &nanosecs,
2185 "Use 9 decimal places when displaying time"), 2226 "Use 9 decimal places when displaying time"),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 256f1fac6f7e..912fedc5b42d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace)
2415 trace->tool.exit = perf_event__process_exit; 2415 trace->tool.exit = perf_event__process_exit;
2416 trace->tool.fork = perf_event__process_fork; 2416 trace->tool.fork = perf_event__process_fork;
2417 trace->tool.attr = perf_event__process_attr; 2417 trace->tool.attr = perf_event__process_attr;
2418 trace->tool.tracing_data = perf_event__process_tracing_data; 2418 trace->tool.tracing_data = perf_event__process_tracing_data;
2419 trace->tool.build_id = perf_event__process_build_id; 2419 trace->tool.build_id = perf_event__process_build_id;
2420 trace->tool.namespaces = perf_event__process_namespaces;
2420 2421
2421 trace->tool.ordered_events = true; 2422 trace->tool.ordered_events = true;
2422 trace->tool.ordering_requires_timestamps = true; 2423 trace->tool.ordering_requires_timestamps = true;
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index ac3efd396a72..2d0caf20ff3a 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-data mainporcelain common 10perf-data mainporcelain common
11perf-diff mainporcelain common 11perf-diff mainporcelain common
12perf-c2c mainporcelain common
12perf-config mainporcelain common 13perf-config mainporcelain common
13perf-evlist mainporcelain common 14perf-evlist mainporcelain common
14perf-ftrace mainporcelain common 15perf-ftrace mainporcelain common
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 1c27d947c2fe..806c216a1078 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -50,6 +50,7 @@ struct record_opts {
50 bool running_time; 50 bool running_time;
51 bool full_auxtrace; 51 bool full_auxtrace;
52 bool auxtrace_snapshot_mode; 52 bool auxtrace_snapshot_mode;
53 bool record_namespaces;
53 bool record_switch_events; 54 bool record_switch_events;
54 bool all_kernel; 55 bool all_kernel;
55 bool all_user; 56 bool all_user;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index fc4fb669ceee..2dc82bec10c0 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2308,7 +2308,7 @@ static int switch_data_file(void)
2308 return ret; 2308 return ret;
2309 2309
2310 memset(options, 0, sizeof(options)); 2310 memset(options, 0, sizeof(options));
2311 memset(options, 0, sizeof(abs_path)); 2311 memset(abs_path, 0, sizeof(abs_path));
2312 2312
2313 while ((dent = readdir(pwd_dir))) { 2313 while ((dent = readdir(pwd_dir))) {
2314 char path[PATH_MAX]; 2314 char path[PATH_MAX];
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5da376bc1afc..2ea5ee179a3b 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -42,6 +42,7 @@ libperf-y += pstack.o
42libperf-y += session.o 42libperf-y += session.o
43libperf-$(CONFIG_AUDIT) += syscalltbl.o 43libperf-$(CONFIG_AUDIT) += syscalltbl.o
44libperf-y += ordered-events.o 44libperf-y += ordered-events.o
45libperf-y += namespaces.o
45libperf-y += comm.o 46libperf-y += comm.o
46libperf-y += thread.o 47libperf-y += thread.o
47libperf-y += thread_map.o 48libperf-y += thread_map.o
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 4e6cbc99f08e..89ece2445713 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,
1468 .lost = perf_event__process_lost, 1468 .lost = perf_event__process_lost,
1469 .tracing_data = perf_event__process_tracing_data, 1469 .tracing_data = perf_event__process_tracing_data,
1470 .build_id = perf_event__process_build_id, 1470 .build_id = perf_event__process_build_id,
1471 .namespaces = perf_event__process_namespaces,
1471 .ordered_events = true, 1472 .ordered_events = true,
1472 .ordering_requires_timestamps = true, 1473 .ordering_requires_timestamps = true,
1473 }, 1474 },
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 4ea7ce72ed9c..d082cb70445d 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -31,6 +31,7 @@ static const char *perf_event__names[] = {
31 [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES", 31 [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES",
32 [PERF_RECORD_SWITCH] = "SWITCH", 32 [PERF_RECORD_SWITCH] = "SWITCH",
33 [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE", 33 [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE",
34 [PERF_RECORD_NAMESPACES] = "NAMESPACES",
34 [PERF_RECORD_HEADER_ATTR] = "ATTR", 35 [PERF_RECORD_HEADER_ATTR] = "ATTR",
35 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 36 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
36 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 37 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
@@ -49,6 +50,16 @@ static const char *perf_event__names[] = {
49 [PERF_RECORD_TIME_CONV] = "TIME_CONV", 50 [PERF_RECORD_TIME_CONV] = "TIME_CONV",
50}; 51};
51 52
53static const char *perf_ns__names[] = {
54 [NET_NS_INDEX] = "net",
55 [UTS_NS_INDEX] = "uts",
56 [IPC_NS_INDEX] = "ipc",
57 [PID_NS_INDEX] = "pid",
58 [USER_NS_INDEX] = "user",
59 [MNT_NS_INDEX] = "mnt",
60 [CGROUP_NS_INDEX] = "cgroup",
61};
62
52const char *perf_event__name(unsigned int id) 63const char *perf_event__name(unsigned int id)
53{ 64{
54 if (id >= ARRAY_SIZE(perf_event__names)) 65 if (id >= ARRAY_SIZE(perf_event__names))
@@ -58,6 +69,13 @@ const char *perf_event__name(unsigned int id)
58 return perf_event__names[id]; 69 return perf_event__names[id];
59} 70}
60 71
72static const char *perf_ns__name(unsigned int id)
73{
74 if (id >= ARRAY_SIZE(perf_ns__names))
75 return "UNKNOWN";
76 return perf_ns__names[id];
77}
78
61static int perf_tool__process_synth_event(struct perf_tool *tool, 79static int perf_tool__process_synth_event(struct perf_tool *tool,
62 union perf_event *event, 80 union perf_event *event,
63 struct machine *machine, 81 struct machine *machine,
@@ -203,6 +221,58 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
203 return tgid; 221 return tgid;
204} 222}
205 223
224static void perf_event__get_ns_link_info(pid_t pid, const char *ns,
225 struct perf_ns_link_info *ns_link_info)
226{
227 struct stat64 st;
228 char proc_ns[128];
229
230 sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
231 if (stat64(proc_ns, &st) == 0) {
232 ns_link_info->dev = st.st_dev;
233 ns_link_info->ino = st.st_ino;
234 }
235}
236
237int perf_event__synthesize_namespaces(struct perf_tool *tool,
238 union perf_event *event,
239 pid_t pid, pid_t tgid,
240 perf_event__handler_t process,
241 struct machine *machine)
242{
243 u32 idx;
244 struct perf_ns_link_info *ns_link_info;
245
246 if (!tool || !tool->namespace_events)
247 return 0;
248
249 memset(&event->namespaces, 0, (sizeof(event->namespaces) +
250 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
251 machine->id_hdr_size));
252
253 event->namespaces.pid = tgid;
254 event->namespaces.tid = pid;
255
256 event->namespaces.nr_namespaces = NR_NAMESPACES;
257
258 ns_link_info = event->namespaces.link_info;
259
260 for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)
261 perf_event__get_ns_link_info(pid, perf_ns__name(idx),
262 &ns_link_info[idx]);
263
264 event->namespaces.header.type = PERF_RECORD_NAMESPACES;
265
266 event->namespaces.header.size = (sizeof(event->namespaces) +
267 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
268 machine->id_hdr_size);
269
270 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
271 return -1;
272
273 return 0;
274}
275
206static int perf_event__synthesize_fork(struct perf_tool *tool, 276static int perf_event__synthesize_fork(struct perf_tool *tool,
207 union perf_event *event, 277 union perf_event *event,
208 pid_t pid, pid_t tgid, pid_t ppid, 278 pid_t pid, pid_t tgid, pid_t ppid,
@@ -434,8 +504,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
434static int __event__synthesize_thread(union perf_event *comm_event, 504static int __event__synthesize_thread(union perf_event *comm_event,
435 union perf_event *mmap_event, 505 union perf_event *mmap_event,
436 union perf_event *fork_event, 506 union perf_event *fork_event,
507 union perf_event *namespaces_event,
437 pid_t pid, int full, 508 pid_t pid, int full,
438 perf_event__handler_t process, 509 perf_event__handler_t process,
439 struct perf_tool *tool, 510 struct perf_tool *tool,
440 struct machine *machine, 511 struct machine *machine,
441 bool mmap_data, 512 bool mmap_data,
@@ -455,6 +526,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
455 if (tgid == -1) 526 if (tgid == -1)
456 return -1; 527 return -1;
457 528
529 if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,
530 tgid, process, machine) < 0)
531 return -1;
532
533
458 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 534 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
459 process, machine, mmap_data, 535 process, machine, mmap_data,
460 proc_map_timeout); 536 proc_map_timeout);
@@ -488,6 +564,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
488 if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 564 if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
489 ppid, process, machine) < 0) 565 ppid, process, machine) < 0)
490 break; 566 break;
567
568 if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
569 tgid, process, machine) < 0)
570 break;
571
491 /* 572 /*
492 * Send the prepared comm event 573 * Send the prepared comm event
493 */ 574 */
@@ -516,6 +597,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
516 unsigned int proc_map_timeout) 597 unsigned int proc_map_timeout)
517{ 598{
518 union perf_event *comm_event, *mmap_event, *fork_event; 599 union perf_event *comm_event, *mmap_event, *fork_event;
600 union perf_event *namespaces_event;
519 int err = -1, thread, j; 601 int err = -1, thread, j;
520 602
521 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 603 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -530,10 +612,16 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
530 if (fork_event == NULL) 612 if (fork_event == NULL)
531 goto out_free_mmap; 613 goto out_free_mmap;
532 614
615 namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
616 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
617 machine->id_hdr_size);
618 if (namespaces_event == NULL)
619 goto out_free_fork;
620
533 err = 0; 621 err = 0;
534 for (thread = 0; thread < threads->nr; ++thread) { 622 for (thread = 0; thread < threads->nr; ++thread) {
535 if (__event__synthesize_thread(comm_event, mmap_event, 623 if (__event__synthesize_thread(comm_event, mmap_event,
536 fork_event, 624 fork_event, namespaces_event,
537 thread_map__pid(threads, thread), 0, 625 thread_map__pid(threads, thread), 0,
538 process, tool, machine, 626 process, tool, machine,
539 mmap_data, proc_map_timeout)) { 627 mmap_data, proc_map_timeout)) {
@@ -559,7 +647,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
559 /* if not, generate events for it */ 647 /* if not, generate events for it */
560 if (need_leader && 648 if (need_leader &&
561 __event__synthesize_thread(comm_event, mmap_event, 649 __event__synthesize_thread(comm_event, mmap_event,
562 fork_event, 650 fork_event, namespaces_event,
563 comm_event->comm.pid, 0, 651 comm_event->comm.pid, 0,
564 process, tool, machine, 652 process, tool, machine,
565 mmap_data, proc_map_timeout)) { 653 mmap_data, proc_map_timeout)) {
@@ -568,6 +656,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
568 } 656 }
569 } 657 }
570 } 658 }
659 free(namespaces_event);
660out_free_fork:
571 free(fork_event); 661 free(fork_event);
572out_free_mmap: 662out_free_mmap:
573 free(mmap_event); 663 free(mmap_event);
@@ -587,6 +677,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
587 char proc_path[PATH_MAX]; 677 char proc_path[PATH_MAX];
588 struct dirent *dirent; 678 struct dirent *dirent;
589 union perf_event *comm_event, *mmap_event, *fork_event; 679 union perf_event *comm_event, *mmap_event, *fork_event;
680 union perf_event *namespaces_event;
590 int err = -1; 681 int err = -1;
591 682
592 if (machine__is_default_guest(machine)) 683 if (machine__is_default_guest(machine))
@@ -604,11 +695,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
604 if (fork_event == NULL) 695 if (fork_event == NULL)
605 goto out_free_mmap; 696 goto out_free_mmap;
606 697
698 namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
699 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
700 machine->id_hdr_size);
701 if (namespaces_event == NULL)
702 goto out_free_fork;
703
607 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 704 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
608 proc = opendir(proc_path); 705 proc = opendir(proc_path);
609 706
610 if (proc == NULL) 707 if (proc == NULL)
611 goto out_free_fork; 708 goto out_free_namespaces;
612 709
613 while ((dirent = readdir(proc)) != NULL) { 710 while ((dirent = readdir(proc)) != NULL) {
614 char *end; 711 char *end;
@@ -620,13 +717,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
620 * We may race with exiting thread, so don't stop just because 717 * We may race with exiting thread, so don't stop just because
621 * one thread couldn't be synthesized. 718 * one thread couldn't be synthesized.
622 */ 719 */
623 __event__synthesize_thread(comm_event, mmap_event, fork_event, pid, 720 __event__synthesize_thread(comm_event, mmap_event, fork_event,
624 1, process, tool, machine, mmap_data, 721 namespaces_event, pid, 1, process,
722 tool, machine, mmap_data,
625 proc_map_timeout); 723 proc_map_timeout);
626 } 724 }
627 725
628 err = 0; 726 err = 0;
629 closedir(proc); 727 closedir(proc);
728out_free_namespaces:
729 free(namespaces_event);
630out_free_fork: 730out_free_fork:
631 free(fork_event); 731 free(fork_event);
632out_free_mmap: 732out_free_mmap:
@@ -1008,6 +1108,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
1008 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); 1108 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
1009} 1109}
1010 1110
1111size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
1112{
1113 size_t ret = 0;
1114 struct perf_ns_link_info *ns_link_info;
1115 u32 nr_namespaces, idx;
1116
1117 ns_link_info = event->namespaces.link_info;
1118 nr_namespaces = event->namespaces.nr_namespaces;
1119
1120 ret += fprintf(fp, " %d/%d - nr_namespaces: %u\n\t\t[",
1121 event->namespaces.pid,
1122 event->namespaces.tid,
1123 nr_namespaces);
1124
1125 for (idx = 0; idx < nr_namespaces; idx++) {
1126 if (idx && (idx % 4 == 0))
1127 ret += fprintf(fp, "\n\t\t ");
1128
1129 ret += fprintf(fp, "%u/%s: %" PRIu64 "/%#" PRIx64 "%s", idx,
1130 perf_ns__name(idx), (u64)ns_link_info[idx].dev,
1131 (u64)ns_link_info[idx].ino,
1132 ((idx + 1) != nr_namespaces) ? ", " : "]\n");
1133 }
1134
1135 return ret;
1136}
1137
1011int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 1138int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
1012 union perf_event *event, 1139 union perf_event *event,
1013 struct perf_sample *sample, 1140 struct perf_sample *sample,
@@ -1016,6 +1143,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
1016 return machine__process_comm_event(machine, event, sample); 1143 return machine__process_comm_event(machine, event, sample);
1017} 1144}
1018 1145
1146int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused,
1147 union perf_event *event,
1148 struct perf_sample *sample,
1149 struct machine *machine)
1150{
1151 return machine__process_namespaces_event(machine, event, sample);
1152}
1153
1019int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 1154int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
1020 union perf_event *event, 1155 union perf_event *event,
1021 struct perf_sample *sample, 1156 struct perf_sample *sample,
@@ -1196,6 +1331,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
1196 case PERF_RECORD_MMAP: 1331 case PERF_RECORD_MMAP:
1197 ret += perf_event__fprintf_mmap(event, fp); 1332 ret += perf_event__fprintf_mmap(event, fp);
1198 break; 1333 break;
1334 case PERF_RECORD_NAMESPACES:
1335 ret += perf_event__fprintf_namespaces(event, fp);
1336 break;
1199 case PERF_RECORD_MMAP2: 1337 case PERF_RECORD_MMAP2:
1200 ret += perf_event__fprintf_mmap2(event, fp); 1338 ret += perf_event__fprintf_mmap2(event, fp);
1201 break; 1339 break;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c735c53a26f8..e1d8166ebbd5 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -39,6 +39,13 @@ struct comm_event {
39 char comm[16]; 39 char comm[16];
40}; 40};
41 41
42struct namespaces_event {
43 struct perf_event_header header;
44 u32 pid, tid;
45 u64 nr_namespaces;
46 struct perf_ns_link_info link_info[];
47};
48
42struct fork_event { 49struct fork_event {
43 struct perf_event_header header; 50 struct perf_event_header header;
44 u32 pid, ppid; 51 u32 pid, ppid;
@@ -485,6 +492,7 @@ union perf_event {
485 struct mmap_event mmap; 492 struct mmap_event mmap;
486 struct mmap2_event mmap2; 493 struct mmap2_event mmap2;
487 struct comm_event comm; 494 struct comm_event comm;
495 struct namespaces_event namespaces;
488 struct fork_event fork; 496 struct fork_event fork;
489 struct lost_event lost; 497 struct lost_event lost;
490 struct lost_samples_event lost_samples; 498 struct lost_samples_event lost_samples;
@@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool,
587 union perf_event *event, 595 union perf_event *event,
588 struct perf_sample *sample, 596 struct perf_sample *sample,
589 struct machine *machine); 597 struct machine *machine);
598int perf_event__process_namespaces(struct perf_tool *tool,
599 union perf_event *event,
600 struct perf_sample *sample,
601 struct machine *machine);
590int perf_event__process_mmap(struct perf_tool *tool, 602int perf_event__process_mmap(struct perf_tool *tool,
591 union perf_event *event, 603 union perf_event *event,
592 struct perf_sample *sample, 604 struct perf_sample *sample,
@@ -636,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
636 perf_event__handler_t process, 648 perf_event__handler_t process,
637 struct machine *machine); 649 struct machine *machine);
638 650
651int perf_event__synthesize_namespaces(struct perf_tool *tool,
652 union perf_event *event,
653 pid_t pid, pid_t tgid,
654 perf_event__handler_t process,
655 struct machine *machine);
656
639int perf_event__synthesize_mmap_events(struct perf_tool *tool, 657int perf_event__synthesize_mmap_events(struct perf_tool *tool,
640 union perf_event *event, 658 union perf_event *event,
641 pid_t pid, pid_t tgid, 659 pid_t pid, pid_t tgid,
@@ -653,6 +671,7 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
653size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); 671size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
654size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); 672size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
655size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); 673size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
674size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
656size_t perf_event__fprintf(union perf_event *event, FILE *fp); 675size_t perf_event__fprintf(union perf_event *event, FILE *fp);
657 676
658u64 kallsyms__get_function_start(const char *kallsyms_filename, 677u64 kallsyms__get_function_start(const char *kallsyms_filename,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ac59710b79e0..175dc2305aa8 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,
932 attr->mmap2 = track && !perf_missing_features.mmap2; 932 attr->mmap2 = track && !perf_missing_features.mmap2;
933 attr->comm = track; 933 attr->comm = track;
934 934
935 if (opts->record_namespaces)
936 attr->namespaces = track;
937
935 if (opts->record_switch_events) 938 if (opts->record_switch_events)
936 attr->context_switch = track; 939 attr->context_switch = track;
937 940
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index eaf72a938fb4..e3b38f629504 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -3,6 +3,7 @@
3#include "hist.h" 3#include "hist.h"
4#include "map.h" 4#include "map.h"
5#include "session.h" 5#include "session.h"
6#include "namespaces.h"
6#include "sort.h" 7#include "sort.h"
7#include "evlist.h" 8#include "evlist.h"
8#include "evsel.h" 9#include "evsel.h"
@@ -169,6 +170,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
169 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); 170 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
170 } 171 }
171 172
173 hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
172 hists__new_col_len(hists, HISTC_CPU, 3); 174 hists__new_col_len(hists, HISTC_CPU, 3);
173 hists__new_col_len(hists, HISTC_SOCKET, 6); 175 hists__new_col_len(hists, HISTC_SOCKET, 6);
174 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); 176 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
@@ -574,9 +576,14 @@ __hists__add_entry(struct hists *hists,
574 bool sample_self, 576 bool sample_self,
575 struct hist_entry_ops *ops) 577 struct hist_entry_ops *ops)
576{ 578{
579 struct namespaces *ns = thread__namespaces(al->thread);
577 struct hist_entry entry = { 580 struct hist_entry entry = {
578 .thread = al->thread, 581 .thread = al->thread,
579 .comm = thread__comm(al->thread), 582 .comm = thread__comm(al->thread),
583 .cgroup_id = {
584 .dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
585 .ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
586 },
580 .ms = { 587 .ms = {
581 .map = al->map, 588 .map = al->map,
582 .sym = al->sym, 589 .sym = al->sym,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2e839bf40bdd..ee3670a388df 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -30,6 +30,7 @@ enum hist_column {
30 HISTC_DSO, 30 HISTC_DSO,
31 HISTC_THREAD, 31 HISTC_THREAD,
32 HISTC_COMM, 32 HISTC_COMM,
33 HISTC_CGROUP_ID,
33 HISTC_PARENT, 34 HISTC_PARENT,
34 HISTC_CPU, 35 HISTC_CPU,
35 HISTC_SOCKET, 36 HISTC_SOCKET,
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index b9974fe41bc1..dfc600446586 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -13,6 +13,7 @@
13#include <symbol/kallsyms.h> 13#include <symbol/kallsyms.h>
14#include "unwind.h" 14#include "unwind.h"
15#include "linux/hash.h" 15#include "linux/hash.h"
16#include "asm/bug.h"
16 17
17static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); 18static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);
18 19
@@ -501,6 +502,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
501 return err; 502 return err;
502} 503}
503 504
505int machine__process_namespaces_event(struct machine *machine __maybe_unused,
506 union perf_event *event,
507 struct perf_sample *sample __maybe_unused)
508{
509 struct thread *thread = machine__findnew_thread(machine,
510 event->namespaces.pid,
511 event->namespaces.tid);
512 int err = 0;
513
514 WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES,
515 "\nWARNING: kernel seems to support more namespaces than perf"
516 " tool.\nTry updating the perf tool..\n\n");
517
518 WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES,
519 "\nWARNING: perf tool seems to support more namespaces than"
520 " the kernel.\nTry updating the kernel..\n\n");
521
522 if (dump_trace)
523 perf_event__fprintf_namespaces(event, stdout);
524
525 if (thread == NULL ||
526 thread__set_namespaces(thread, sample->time, &event->namespaces)) {
527 dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
528 err = -1;
529 }
530
531 thread__put(thread);
532
533 return err;
534}
535
504int machine__process_lost_event(struct machine *machine __maybe_unused, 536int machine__process_lost_event(struct machine *machine __maybe_unused,
505 union perf_event *event, struct perf_sample *sample __maybe_unused) 537 union perf_event *event, struct perf_sample *sample __maybe_unused)
506{ 538{
@@ -1538,6 +1570,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
1538 ret = machine__process_comm_event(machine, event, sample); break; 1570 ret = machine__process_comm_event(machine, event, sample); break;
1539 case PERF_RECORD_MMAP: 1571 case PERF_RECORD_MMAP:
1540 ret = machine__process_mmap_event(machine, event, sample); break; 1572 ret = machine__process_mmap_event(machine, event, sample); break;
1573 case PERF_RECORD_NAMESPACES:
1574 ret = machine__process_namespaces_event(machine, event, sample); break;
1541 case PERF_RECORD_MMAP2: 1575 case PERF_RECORD_MMAP2:
1542 ret = machine__process_mmap2_event(machine, event, sample); break; 1576 ret = machine__process_mmap2_event(machine, event, sample); break;
1543 case PERF_RECORD_FORK: 1577 case PERF_RECORD_FORK:
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index a28305029711..3cdb1340f917 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,
97 union perf_event *event); 97 union perf_event *event);
98int machine__process_switch_event(struct machine *machine, 98int machine__process_switch_event(struct machine *machine,
99 union perf_event *event); 99 union perf_event *event);
100int machine__process_namespaces_event(struct machine *machine,
101 union perf_event *event,
102 struct perf_sample *sample);
100int machine__process_mmap_event(struct machine *machine, union perf_event *event, 103int machine__process_mmap_event(struct machine *machine, union perf_event *event,
101 struct perf_sample *sample); 104 struct perf_sample *sample);
102int machine__process_mmap2_event(struct machine *machine, union perf_event *event, 105int 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 000000000000..2de8da64d90c
--- /dev/null
+++ b/tools/perf/util/namespaces.c
@@ -0,0 +1,36 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
7 */
8
9#include "namespaces.h"
10#include "util.h"
11#include "event.h"
12#include <stdlib.h>
13#include <stdio.h>
14
15struct namespaces *namespaces__new(struct namespaces_event *event)
16{
17 struct namespaces *namespaces;
18 u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
19 sizeof(struct perf_ns_link_info));
20
21 namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
22 if (!namespaces)
23 return NULL;
24
25 namespaces->end_time = -1;
26
27 if (event)
28 memcpy(namespaces->link_info, event->link_info, link_info_size);
29
30 return namespaces;
31}
32
33void namespaces__free(struct namespaces *namespaces)
34{
35 free(namespaces);
36}
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
new file mode 100644
index 000000000000..468f1e9a1484
--- /dev/null
+++ b/tools/perf/util/namespaces.h
@@ -0,0 +1,26 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
7 */
8
9#ifndef __PERF_NAMESPACES_H
10#define __PERF_NAMESPACES_H
11
12#include "../perf.h"
13#include <linux/list.h>
14
15struct namespaces_event;
16
17struct namespaces {
18 struct list_head list;
19 u64 end_time;
20 struct perf_ns_link_info link_info[];
21};
22
23struct namespaces *namespaces__new(struct namespaces_event *event);
24void namespaces__free(struct namespaces *namespaces);
25
26#endif /* __PERF_NAMESPACES_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 28fb62c32678..c9bdc9ded0c3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -757,7 +757,9 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
757 } 757 }
758 758
759 for (i = 0; i < ntevs; i++) { 759 for (i = 0; i < ntevs; i++) {
760 if (!tevs[i].point.address || tevs[i].point.retprobe) 760 if (!tevs[i].point.address)
761 continue;
762 if (tevs[i].point.retprobe && !kretprobe_offset_is_supported())
761 continue; 763 continue;
762 /* If we found a wrong one, mark it by NULL symbol */ 764 /* If we found a wrong one, mark it by NULL symbol */
763 if (kprobe_warn_out_range(tevs[i].point.symbol, 765 if (kprobe_warn_out_range(tevs[i].point.symbol,
@@ -1528,11 +1530,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
1528 return -EINVAL; 1530 return -EINVAL;
1529 } 1531 }
1530 1532
1531 if (pp->retprobe && !pp->function) {
1532 semantic_error("Return probe requires an entry function.\n");
1533 return -EINVAL;
1534 }
1535
1536 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 1533 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
1537 semantic_error("Offset/Line/Lazy pattern can't be used with " 1534 semantic_error("Offset/Line/Lazy pattern can't be used with "
1538 "return probe.\n"); 1535 "return probe.\n");
@@ -2841,7 +2838,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2841 } 2838 }
2842 2839
2843 /* Note that the symbols in the kmodule are not relocated */ 2840 /* Note that the symbols in the kmodule are not relocated */
2844 if (!pev->uprobes && !pp->retprobe && !pev->target) { 2841 if (!pev->uprobes && !pev->target &&
2842 (!pp->retprobe || kretprobe_offset_is_supported())) {
2845 reloc_sym = kernel_get_ref_reloc_sym(); 2843 reloc_sym = kernel_get_ref_reloc_sym();
2846 if (!reloc_sym) { 2844 if (!reloc_sym) {
2847 pr_warning("Relocated base symbol is not found!\n"); 2845 pr_warning("Relocated base symbol is not found!\n");
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 1a62daceb028..1542cd0d6799 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -877,35 +877,33 @@ int probe_cache__show_all_caches(struct strfilter *filter)
877 return 0; 877 return 0;
878} 878}
879 879
880enum ftrace_readme {
881 FTRACE_README_PROBE_TYPE_X = 0,
882 FTRACE_README_KRETPROBE_OFFSET,
883 FTRACE_README_END,
884};
885
880static struct { 886static struct {
881 const char *pattern; 887 const char *pattern;
882 bool avail; 888 bool avail;
883 bool checked; 889} ftrace_readme_table[] = {
884} probe_type_table[] = { 890#define DEFINE_TYPE(idx, pat) \
885#define DEFINE_TYPE(idx, pat, def_avail) \ 891 [idx] = {.pattern = pat, .avail = false}
886 [idx] = {.pattern = pat, .avail = (def_avail)} 892 DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
887 DEFINE_TYPE(PROBE_TYPE_U, "* u8/16/32/64,*", true), 893 DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
888 DEFINE_TYPE(PROBE_TYPE_S, "* s8/16/32/64,*", true),
889 DEFINE_TYPE(PROBE_TYPE_X, "* x8/16/32/64,*", false),
890 DEFINE_TYPE(PROBE_TYPE_STRING, "* string,*", true),
891 DEFINE_TYPE(PROBE_TYPE_BITFIELD,
892 "* b<bit-width>@<bit-offset>/<container-size>", true),
893}; 894};
894 895
895bool probe_type_is_available(enum probe_type type) 896static bool scan_ftrace_readme(enum ftrace_readme type)
896{ 897{
898 int fd;
897 FILE *fp; 899 FILE *fp;
898 char *buf = NULL; 900 char *buf = NULL;
899 size_t len = 0; 901 size_t len = 0;
900 bool target_line = false; 902 bool ret = false;
901 bool ret = probe_type_table[type].avail; 903 static bool scanned = false;
902 int fd;
903 904
904 if (type >= PROBE_TYPE_END) 905 if (scanned)
905 return false; 906 goto result;
906 /* We don't have to check the type which supported by default */
907 if (ret || probe_type_table[type].checked)
908 return ret;
909 907
910 fd = open_trace_file("README", false); 908 fd = open_trace_file("README", false);
911 if (fd < 0) 909 if (fd < 0)
@@ -917,21 +915,34 @@ bool probe_type_is_available(enum probe_type type)
917 return ret; 915 return ret;
918 } 916 }
919 917
920 while (getline(&buf, &len, fp) > 0 && !ret) { 918 while (getline(&buf, &len, fp) > 0)
921 if (!target_line) { 919 for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
922 target_line = !!strstr(buf, " type: "); 920 if (!ftrace_readme_table[i].avail)
923 if (!target_line) 921 ftrace_readme_table[i].avail =
924 continue; 922 strglobmatch(buf, ftrace_readme_table[i].pattern);
925 } else if (strstr(buf, "\t ") != buf) 923 scanned = true;
926 break;
927 ret = strglobmatch(buf, probe_type_table[type].pattern);
928 }
929 /* Cache the result */
930 probe_type_table[type].checked = true;
931 probe_type_table[type].avail = ret;
932 924
933 fclose(fp); 925 fclose(fp);
934 free(buf); 926 free(buf);
935 927
936 return ret; 928result:
929 if (type >= FTRACE_README_END)
930 return false;
931
932 return ftrace_readme_table[type].avail;
933}
934
935bool probe_type_is_available(enum probe_type type)
936{
937 if (type >= PROBE_TYPE_END)
938 return false;
939 else if (type == PROBE_TYPE_X)
940 return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
941
942 return true;
943}
944
945bool kretprobe_offset_is_supported(void)
946{
947 return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
937} 948}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index a17a82eff8a0..dbf95a00864a 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -65,6 +65,7 @@ struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
65 const char *group, const char *event); 65 const char *group, const char *event);
66int probe_cache__show_all_caches(struct strfilter *filter); 66int probe_cache__show_all_caches(struct strfilter *filter);
67bool probe_type_is_available(enum probe_type type); 67bool probe_type_is_available(enum probe_type type);
68bool kretprobe_offset_is_supported(void);
68#else /* ! HAVE_LIBELF_SUPPORT */ 69#else /* ! HAVE_LIBELF_SUPPORT */
69static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused) 70static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused)
70{ 71{
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1dd617d116b5..ae42e742d461 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,
1239 return tool->mmap2(tool, event, sample, machine); 1239 return tool->mmap2(tool, event, sample, machine);
1240 case PERF_RECORD_COMM: 1240 case PERF_RECORD_COMM:
1241 return tool->comm(tool, event, sample, machine); 1241 return tool->comm(tool, event, sample, machine);
1242 case PERF_RECORD_NAMESPACES:
1243 return tool->namespaces(tool, event, sample, machine);
1242 case PERF_RECORD_FORK: 1244 case PERF_RECORD_FORK:
1243 return tool->fork(tool, event, sample, machine); 1245 return tool->fork(tool, event, sample, machine);
1244 case PERF_RECORD_EXIT: 1246 case PERF_RECORD_EXIT:
@@ -1494,6 +1496,11 @@ int perf_session__register_idle_thread(struct perf_session *session)
1494 err = -1; 1496 err = -1;
1495 } 1497 }
1496 1498
1499 if (thread == NULL || thread__set_namespaces(thread, 0, NULL)) {
1500 pr_err("problem inserting idle task.\n");
1501 err = -1;
1502 }
1503
1497 /* machine__findnew_thread() got the thread, so put it */ 1504 /* machine__findnew_thread() got the thread, so put it */
1498 thread__put(thread); 1505 thread__put(thread);
1499 return err; 1506 return err;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index f8f16c0e20b6..8b0d4e39f640 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -536,6 +536,46 @@ struct sort_entry sort_cpu = {
536 .se_width_idx = HISTC_CPU, 536 .se_width_idx = HISTC_CPU,
537}; 537};
538 538
539/* --sort cgroup_id */
540
541static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev)
542{
543 return (int64_t)(right_dev - left_dev);
544}
545
546static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino)
547{
548 return (int64_t)(right_ino - left_ino);
549}
550
551static int64_t
552sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right)
553{
554 int64_t ret;
555
556 ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev);
557 if (ret != 0)
558 return ret;
559
560 return _sort__cgroup_inode_cmp(right->cgroup_id.ino,
561 left->cgroup_id.ino);
562}
563
564static int hist_entry__cgroup_id_snprintf(struct hist_entry *he,
565 char *bf, size_t size,
566 unsigned int width __maybe_unused)
567{
568 return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev,
569 he->cgroup_id.ino);
570}
571
572struct sort_entry sort_cgroup_id = {
573 .se_header = "cgroup id (dev/inode)",
574 .se_cmp = sort__cgroup_id_cmp,
575 .se_snprintf = hist_entry__cgroup_id_snprintf,
576 .se_width_idx = HISTC_CGROUP_ID,
577};
578
539/* --sort socket */ 579/* --sort socket */
540 580
541static int64_t 581static int64_t
@@ -846,6 +886,9 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
846static int64_t 886static int64_t
847sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) 887sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
848{ 888{
889 if (!left->branch_info || !right->branch_info)
890 return cmp_null(left->branch_info, right->branch_info);
891
849 return left->branch_info->flags.cycles - 892 return left->branch_info->flags.cycles -
850 right->branch_info->flags.cycles; 893 right->branch_info->flags.cycles;
851} 894}
@@ -853,6 +896,8 @@ sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
853static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, 896static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
854 size_t size, unsigned int width) 897 size_t size, unsigned int width)
855{ 898{
899 if (!he->branch_info)
900 return scnprintf(bf, size, "%-.*s", width, "N/A");
856 if (he->branch_info->flags.cycles == 0) 901 if (he->branch_info->flags.cycles == 0)
857 return repsep_snprintf(bf, size, "%-*s", width, "-"); 902 return repsep_snprintf(bf, size, "%-*s", width, "-");
858 return repsep_snprintf(bf, size, "%-*hd", width, 903 return repsep_snprintf(bf, size, "%-*hd", width,
@@ -1459,6 +1504,7 @@ static struct sort_dimension common_sort_dimensions[] = {
1459 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1504 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1460 DIM(SORT_TRACE, "trace", sort_trace), 1505 DIM(SORT_TRACE, "trace", sort_trace),
1461 DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), 1506 DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
1507 DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
1462}; 1508};
1463 1509
1464#undef DIM 1510#undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index f583325a3743..baf20a399f34 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -54,6 +54,11 @@ struct he_stat {
54 u32 nr_events; 54 u32 nr_events;
55}; 55};
56 56
57struct namespace_id {
58 u64 dev;
59 u64 ino;
60};
61
57struct hist_entry_diff { 62struct hist_entry_diff {
58 bool computed; 63 bool computed;
59 union { 64 union {
@@ -91,6 +96,7 @@ struct hist_entry {
91 struct map_symbol ms; 96 struct map_symbol ms;
92 struct thread *thread; 97 struct thread *thread;
93 struct comm *comm; 98 struct comm *comm;
99 struct namespace_id cgroup_id;
94 u64 ip; 100 u64 ip;
95 u64 transaction; 101 u64 transaction;
96 s32 socket; 102 s32 socket;
@@ -212,6 +218,7 @@ enum sort_type {
212 SORT_TRANSACTION, 218 SORT_TRANSACTION,
213 SORT_TRACE, 219 SORT_TRACE,
214 SORT_SYM_SIZE, 220 SORT_SYM_SIZE,
221 SORT_CGROUP_ID,
215 222
216 /* branch stack specific sort keys */ 223 /* branch stack specific sort keys */
217 __SORT_BRANCH_STACK, 224 __SORT_BRANCH_STACK,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 74e79d26b421..dcdb87a5d0a1 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,6 +7,7 @@
7#include "thread-stack.h" 7#include "thread-stack.h"
8#include "util.h" 8#include "util.h"
9#include "debug.h" 9#include "debug.h"
10#include "namespaces.h"
10#include "comm.h" 11#include "comm.h"
11#include "unwind.h" 12#include "unwind.h"
12 13
@@ -40,6 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
40 thread->tid = tid; 41 thread->tid = tid;
41 thread->ppid = -1; 42 thread->ppid = -1;
42 thread->cpu = -1; 43 thread->cpu = -1;
44 INIT_LIST_HEAD(&thread->namespaces_list);
43 INIT_LIST_HEAD(&thread->comm_list); 45 INIT_LIST_HEAD(&thread->comm_list);
44 46
45 comm_str = malloc(32); 47 comm_str = malloc(32);
@@ -66,7 +68,8 @@ err_thread:
66 68
67void thread__delete(struct thread *thread) 69void thread__delete(struct thread *thread)
68{ 70{
69 struct comm *comm, *tmp; 71 struct namespaces *namespaces, *tmp_namespaces;
72 struct comm *comm, *tmp_comm;
70 73
71 BUG_ON(!RB_EMPTY_NODE(&thread->rb_node)); 74 BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
72 75
@@ -76,7 +79,12 @@ void thread__delete(struct thread *thread)
76 map_groups__put(thread->mg); 79 map_groups__put(thread->mg);
77 thread->mg = NULL; 80 thread->mg = NULL;
78 } 81 }
79 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 82 list_for_each_entry_safe(namespaces, tmp_namespaces,
83 &thread->namespaces_list, list) {
84 list_del(&namespaces->list);
85 namespaces__free(namespaces);
86 }
87 list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
80 list_del(&comm->list); 88 list_del(&comm->list);
81 comm__free(comm); 89 comm__free(comm);
82 } 90 }
@@ -104,6 +112,38 @@ void thread__put(struct thread *thread)
104 } 112 }
105} 113}
106 114
115struct namespaces *thread__namespaces(const struct thread *thread)
116{
117 if (list_empty(&thread->namespaces_list))
118 return NULL;
119
120 return list_first_entry(&thread->namespaces_list, struct namespaces, list);
121}
122
123int thread__set_namespaces(struct thread *thread, u64 timestamp,
124 struct namespaces_event *event)
125{
126 struct namespaces *new, *curr = thread__namespaces(thread);
127
128 new = namespaces__new(event);
129 if (!new)
130 return -ENOMEM;
131
132 list_add(&new->list, &thread->namespaces_list);
133
134 if (timestamp && curr) {
135 /*
136 * setns syscall must have changed few or all the namespaces
137 * of this thread. Update end time for the namespaces
138 * previously used.
139 */
140 curr = list_next_entry(new, list);
141 curr->end_time = timestamp;
142 }
143
144 return 0;
145}
146
107struct comm *thread__comm(const struct thread *thread) 147struct comm *thread__comm(const struct thread *thread)
108{ 148{
109 if (list_empty(&thread->comm_list)) 149 if (list_empty(&thread->comm_list))
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index e57188546465..4eb849e9098f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -28,6 +28,7 @@ struct thread {
28 bool comm_set; 28 bool comm_set;
29 int comm_len; 29 int comm_len;
30 bool dead; /* if set thread has exited */ 30 bool dead; /* if set thread has exited */
31 struct list_head namespaces_list;
31 struct list_head comm_list; 32 struct list_head comm_list;
32 u64 db_id; 33 u64 db_id;
33 34
@@ -40,6 +41,7 @@ struct thread {
40}; 41};
41 42
42struct machine; 43struct machine;
44struct namespaces;
43struct comm; 45struct comm;
44 46
45struct thread *thread__new(pid_t pid, pid_t tid); 47struct thread *thread__new(pid_t pid, pid_t tid);
@@ -62,6 +64,10 @@ static inline void thread__exited(struct thread *thread)
62 thread->dead = true; 64 thread->dead = true;
63} 65}
64 66
67struct namespaces *thread__namespaces(const struct thread *thread);
68int thread__set_namespaces(struct thread *thread, u64 timestamp,
69 struct namespaces_event *event);
70
65int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, 71int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
66 bool exec); 72 bool exec);
67static inline int thread__set_comm(struct thread *thread, const char *comm, 73static 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 ac2590a3de2d..829471a1c6d7 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -40,6 +40,7 @@ struct perf_tool {
40 event_op mmap, 40 event_op mmap,
41 mmap2, 41 mmap2,
42 comm, 42 comm,
43 namespaces,
43 fork, 44 fork,
44 exit, 45 exit,
45 lost, 46 lost,
@@ -66,6 +67,7 @@ struct perf_tool {
66 event_op3 auxtrace; 67 event_op3 auxtrace;
67 bool ordered_events; 68 bool ordered_events;
68 bool ordering_requires_timestamps; 69 bool ordering_requires_timestamps;
70 bool namespace_events;
69}; 71};
70 72
71#endif /* __PERF_TOOL_H */ 73#endif /* __PERF_TOOL_H */