]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'linus' into perf/core, to pick up fixes
authorIngo Molnar <mingo@kernel.org>
Thu, 16 Mar 2017 08:50:50 +0000 (09:50 +0100)
committerIngo Molnar <mingo@kernel.org>
Thu, 16 Mar 2017 08:50:50 +0000 (09:50 +0100)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
99 files changed:
Documentation/trace/kprobetrace.txt
include/linux/kprobes.h
include/linux/perf_event.h
include/uapi/linux/perf_event.h
kernel/events/core.c
kernel/fork.c
kernel/kprobes.c
kernel/nsproxy.c
kernel/trace/trace.c
kernel/trace/trace_kprobe.c
tools/arch/x86/include/asm/atomic.h
tools/arch/x86/include/asm/cmpxchg.h [new file with mode: 0644]
tools/build/Makefile.feature
tools/build/feature/Makefile
tools/build/feature/test-all.c
tools/build/feature/test-sched_getcpu.c [new file with mode: 0644]
tools/include/asm-generic/atomic-gcc.h
tools/include/linux/atomic.h
tools/include/linux/compiler-gcc.h
tools/include/linux/compiler.h
tools/include/linux/kernel.h
tools/include/linux/refcount.h [new file with mode: 0644]
tools/include/uapi/linux/perf_event.h
tools/perf/.gitignore
tools/perf/Documentation/perf-ftrace.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-sched.txt
tools/perf/Documentation/perf-script.txt
tools/perf/MANIFEST
tools/perf/Makefile.config
tools/perf/arch/powerpc/util/sym-handling.c
tools/perf/bench/futex-hash.c
tools/perf/bench/futex-lock-pi.c
tools/perf/bench/futex-requeue.c
tools/perf/bench/futex-wake-parallel.c
tools/perf/bench/futex-wake.c
tools/perf/bench/futex.h
tools/perf/bench/numa.c
tools/perf/builtin-annotate.c
tools/perf/builtin-c2c.c
tools/perf/builtin-diff.c
tools/perf/builtin-ftrace.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-lock.c
tools/perf/builtin-mem.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-trace.c
tools/perf/command-list.txt
tools/perf/perf.h
tools/perf/pmu-events/arch/x86/mapfile.csv
tools/perf/tests/cpumap.c
tools/perf/tests/thread-map.c
tools/perf/tests/thread-mg-share.c
tools/perf/ui/browsers/hists.c
tools/perf/util/Build
tools/perf/util/cgroup.c
tools/perf/util/cgroup.h
tools/perf/util/cloexec.h
tools/perf/util/comm.c
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/data-convert-bt.c
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/namespaces.c [new file with mode: 0644]
tools/perf/util/namespaces.h [new file with mode: 0644]
tools/perf/util/parse-events.c
tools/perf/util/probe-event.c
tools/perf/util/probe-file.c
tools/perf/util/probe-file.h
tools/perf/util/session.c
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/thread_map.c
tools/perf/util/thread_map.h
tools/perf/util/tool.h
tools/perf/util/util.h
tools/scripts/Makefile.include

index 41ef9d8efe9517f602e59b21bfe1448196cb3450..5ea85059db3b964f31be6129d8f9c714ca578fbf 100644 (file)
@@ -8,8 +8,9 @@ Overview
 --------
 These events are similar to tracepoint based events. Instead of Tracepoint,
 this is based on kprobes (kprobe and kretprobe). So it can probe wherever
-kprobes can probe (this means, all functions body except for __kprobes
-functions). Unlike the Tracepoint based event, this can be added and removed
+kprobes can probe (this means, all functions except those with
+__kprobes/nokprobe_inline annotation and those marked NOKPROBE_SYMBOL).
+Unlike the Tracepoint based event, this can be added and removed
 dynamically, on the fly.
 
 To enable this feature, build your kernel with CONFIG_KPROBE_EVENTS=y.
index c328e4f7dcadb4276bddcfbcc97caa323c48a0a3..177bdf6c6aeb082369280b61d4167c60ca33c9e4 100644 (file)
@@ -267,6 +267,7 @@ extern int arch_init_kprobes(void);
 extern void show_registers(struct pt_regs *regs);
 extern void kprobes_inc_nmissed_count(struct kprobe *p);
 extern bool arch_within_kprobe_blacklist(unsigned long addr);
+extern bool arch_function_offset_within_entry(unsigned long offset);
 
 extern bool within_kprobe_blacklist(unsigned long addr);
 
index 000fdb211c7d7e2c8fc7351a99dbf6b58fbcb135..f19a8236285188e8e845c7f0945d9240ae43d51a 100644 (file)
@@ -1112,6 +1112,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 */
@@ -1315,6 +1316,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; }
index c66a485a24ac81e324ea53ea17b405a3c73b520a..bec0aad0e15cd3798f6858038d661b1b1ce1b3bc 100644 (file)
@@ -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,23 @@ struct perf_event_header {
        __u16   size;
 };
 
+struct perf_ns_link_info {
+       __u64   dev;
+       __u64   ino;
+};
+
+enum {
+       NET_NS_INDEX            = 0,
+       UTS_NS_INDEX            = 1,
+       IPC_NS_INDEX            = 2,
+       PID_NS_INDEX            = 3,
+       USER_NS_INDEX           = 4,
+       MNT_NS_INDEX            = 5,
+       CGROUP_NS_INDEX         = 6,
+
+       NR_NAMESPACES,          /* number of available namespaces */
+};
+
 enum perf_event_type {
 
        /*
@@ -862,6 +880,18 @@ enum perf_event_type {
         */
        PERF_RECORD_SWITCH_CPU_WIDE             = 15,
 
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid;
+        *      u32                             tid;
+        *      u64                             nr_namespaces;
+        *      { u64                           dev, inode; } [nr_namespaces];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_NAMESPACES                  = 16,
+
        PERF_RECORD_MAX,                        /* non-ABI */
 };
 
index a17ed56c8ce1f918519cfbf96ee3c938734ecb08..2d7990d4e9884ce9cf0b2e51676c96b362097afc 100644 (file)
@@ -48,6 +48,8 @@
 #include <linux/parser.h>
 #include <linux/sched/clock.h>
 #include <linux/sched/mm.h>
+#include <linux/proc_ns.h>
+#include <linux/mount.h>
 
 #include "internal.h"
 
@@ -379,6 +381,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;
@@ -3991,6 +3994,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)
@@ -6491,6 +6496,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);
 }
 
 /*
@@ -6592,6 +6598,132 @@ void perf_event_comm(struct task_struct *task, bool exec)
        perf_event_comm_event(&comm_event);
 }
 
+/*
+ * namespaces tracking
+ */
+
+struct perf_namespaces_event {
+       struct task_struct              *task;
+
+       struct {
+               struct perf_event_header        header;
+
+               u32                             pid;
+               u32                             tid;
+               u64                             nr_namespaces;
+               struct perf_ns_link_info        link_info[NR_NAMESPACES];
+       } event_id;
+};
+
+static int perf_event_namespaces_match(struct perf_event *event)
+{
+       return event->attr.namespaces;
+}
+
+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;
+       int ret;
+
+       if (!perf_event_namespaces_match(event))
+               return;
+
+       perf_event_header__init_id(&namespaces_event->event_id.header,
+                                  &sample, event);
+       ret = perf_output_begin(&handle, event,
+                               namespaces_event->event_id.header.size);
+       if (ret)
+               return;
+
+       namespaces_event->event_id.pid = perf_event_pid(event,
+                                                       namespaces_event->task);
+       namespaces_event->event_id.tid = perf_event_tid(event,
+                                                       namespaces_event->task);
+
+       perf_output_put(&handle, namespaces_event->event_id);
+
+       perf_event__output_id_sample(event, &handle, &sample);
+
+       perf_output_end(&handle);
+}
+
+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) {
+               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;
+       }
+}
+
+void perf_event_namespaces(struct task_struct *task)
+{
+       struct perf_namespaces_event namespaces_event;
+       struct perf_ns_link_info *ns_link_info;
+
+       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 = NR_NAMESPACES,
+                       /* .link_info[NR_NAMESPACES] */
+               },
+       };
+
+       ns_link_info = namespaces_event.event_id.link_info;
+
+       perf_fill_ns_link_info(&ns_link_info[MNT_NS_INDEX],
+                              task, &mntns_operations);
+
+#ifdef CONFIG_USER_NS
+       perf_fill_ns_link_info(&ns_link_info[USER_NS_INDEX],
+                              task, &userns_operations);
+#endif
+#ifdef CONFIG_NET_NS
+       perf_fill_ns_link_info(&ns_link_info[NET_NS_INDEX],
+                              task, &netns_operations);
+#endif
+#ifdef CONFIG_UTS_NS
+       perf_fill_ns_link_info(&ns_link_info[UTS_NS_INDEX],
+                              task, &utsns_operations);
+#endif
+#ifdef CONFIG_IPC_NS
+       perf_fill_ns_link_info(&ns_link_info[IPC_NS_INDEX],
+                              task, &ipcns_operations);
+#endif
+#ifdef CONFIG_PID_NS
+       perf_fill_ns_link_info(&ns_link_info[PID_NS_INDEX],
+                              task, &pidns_operations);
+#endif
+#ifdef CONFIG_CGROUPS
+       perf_fill_ns_link_info(&ns_link_info[CGROUP_NS_INDEX],
+                              task, &cgroupns_operations);
+#endif
+
+       perf_iterate_sb(perf_event_namespaces_output,
+                       &namespaces_event,
+                       NULL);
+}
+
 /*
  * mmap tracking
  */
@@ -9146,6 +9278,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)
@@ -9691,6 +9825,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;
index 6c463c80e93de8c3be3180f3cbd8694b955a1ac3..afa2947286cd84e3f311780cfd0116dcf7edc90e 100644 (file)
@@ -2352,6 +2352,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
                }
        }
 
+       perf_event_namespaces(current);
+
 bad_unshare_cleanup_cred:
        if (new_cred)
                put_cred(new_cred);
index 699c5bc51a9219d664578e4d7978dee94d291c82..4780ec23603539396e9e27ad3577a075bd995814 100644 (file)
@@ -1740,11 +1740,12 @@ void unregister_kprobes(struct kprobe **kps, int num)
 }
 EXPORT_SYMBOL_GPL(unregister_kprobes);
 
-int __weak __kprobes kprobe_exceptions_notify(struct notifier_block *self,
-                                             unsigned long val, void *data)
+int __weak kprobe_exceptions_notify(struct notifier_block *self,
+                                       unsigned long val, void *data)
 {
        return NOTIFY_DONE;
 }
+NOKPROBE_SYMBOL(kprobe_exceptions_notify);
 
 static struct notifier_block kprobe_exceptions_nb = {
        .notifier_call = kprobe_exceptions_notify,
@@ -1875,12 +1876,25 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(pre_handler_kretprobe);
 
+bool __weak arch_function_offset_within_entry(unsigned long offset)
+{
+       return !offset;
+}
+
 int register_kretprobe(struct kretprobe *rp)
 {
        int ret = 0;
        struct kretprobe_instance *inst;
        int i;
        void *addr;
+       unsigned long offset;
+
+       addr = kprobe_addr(&rp->kp);
+       if (!kallsyms_lookup_size_offset((unsigned long)addr, NULL, &offset))
+               return -EINVAL;
+
+       if (!arch_function_offset_within_entry(offset))
+               return -EINVAL;
 
        if (kretprobe_blacklist_size) {
                addr = kprobe_addr(&rp->kp);
index 782102e59eed5b4b5379126b865fb9c795892cdd..f6c5d330059ac7996a1aeb7a4c4fdfad128d847d 100644 (file)
@@ -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;
 
@@ -262,6 +263,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
                goto out;
        }
        switch_task_namespaces(tsk, new_nsproxy);
+
+       perf_event_namespaces(tsk);
 out:
        fput(file);
        return err;
index f35109514a015c38de8b2e1da99399fd5f399692..0ed834d6beb0feeb68a35a88f048931923970bfe 100644 (file)
@@ -4355,6 +4355,7 @@ static const char readme_msg[] =
        "\t           -:[<group>/]<event>\n"
 #ifdef CONFIG_KPROBE_EVENTS
        "\t    place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
+  "place (kretprobe): [<module>:]<symbol>[+<offset>]|<memaddr>\n"
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
        "\t    place: <path>:<offset>\n"
index 5f688cc724f00abcd9d09686adc75fb96e4b5b02..12fb540da0e5ec2367f6755b8a969cb1b3471b3e 100644 (file)
@@ -681,10 +681,6 @@ static int create_trace_kprobe(int argc, char **argv)
                return -EINVAL;
        }
        if (isdigit(argv[1][0])) {
-               if (is_return) {
-                       pr_info("Return probe point must be a symbol.\n");
-                       return -EINVAL;
-               }
                /* an address specified */
                ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr);
                if (ret) {
@@ -700,8 +696,9 @@ static int create_trace_kprobe(int argc, char **argv)
                        pr_info("Failed to parse symbol.\n");
                        return ret;
                }
-               if (offset && is_return) {
-                       pr_info("Return probe must be used without offset.\n");
+               if (offset && is_return &&
+                   !arch_function_offset_within_entry(offset)) {
+                       pr_info("Given offset is not valid for return probe.\n");
                        return -EINVAL;
                }
        }
index 059e33e94260ab5cab2dcf2b95a46704619a1756..328eeceec709803b91fa11ab14860341828f6639 100644 (file)
@@ -7,6 +7,8 @@
 
 #define LOCK_PREFIX "\n\tlock; "
 
+#include <asm/cmpxchg.h>
+
 /*
  * Atomic operations that C can't guarantee us.  Useful for
  * resource counting etc..
@@ -62,4 +64,9 @@ static inline int atomic_dec_and_test(atomic_t *v)
        GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e");
 }
 
+static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       return cmpxchg(&v->counter, old, new);
+}
+
 #endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */
diff --git a/tools/arch/x86/include/asm/cmpxchg.h b/tools/arch/x86/include/asm/cmpxchg.h
new file mode 100644 (file)
index 0000000..f525326
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef TOOLS_ASM_X86_CMPXCHG_H
+#define TOOLS_ASM_X86_CMPXCHG_H
+
+#include <linux/compiler.h>
+
+/*
+ * Non-existant functions to indicate usage errors at link time
+ * (or compile-time if the compiler implements __compiletime_error().
+ */
+extern void __cmpxchg_wrong_size(void)
+       __compiletime_error("Bad argument size for cmpxchg");
+
+/*
+ * Constants for operation sizes. On 32-bit, the 64-bit size it set to
+ * -1 because sizeof will never return -1, thereby making those switch
+ * case statements guaranteeed dead code which the compiler will
+ * eliminate, and allowing the "missing symbol in the default case" to
+ * indicate a usage error.
+ */
+#define __X86_CASE_B   1
+#define __X86_CASE_W   2
+#define __X86_CASE_L   4
+#ifdef __x86_64__
+#define __X86_CASE_Q   8
+#else
+#define        __X86_CASE_Q    -1              /* sizeof will never return -1 */
+#endif
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+#define __raw_cmpxchg(ptr, old, new, size, lock)                       \
+({                                                                     \
+       __typeof__(*(ptr)) __ret;                                       \
+       __typeof__(*(ptr)) __old = (old);                               \
+       __typeof__(*(ptr)) __new = (new);                               \
+       switch (size) {                                                 \
+       case __X86_CASE_B:                                              \
+       {                                                               \
+               volatile u8 *__ptr = (volatile u8 *)(ptr);              \
+               asm volatile(lock "cmpxchgb %2,%1"                      \
+                            : "=a" (__ret), "+m" (*__ptr)              \
+                            : "q" (__new), "0" (__old)                 \
+                            : "memory");                               \
+               break;                                                  \
+       }                                                               \
+       case __X86_CASE_W:                                              \
+       {                                                               \
+               volatile u16 *__ptr = (volatile u16 *)(ptr);            \
+               asm volatile(lock "cmpxchgw %2,%1"                      \
+                            : "=a" (__ret), "+m" (*__ptr)              \
+                            : "r" (__new), "0" (__old)                 \
+                            : "memory");                               \
+               break;                                                  \
+       }                                                               \
+       case __X86_CASE_L:                                              \
+       {                                                               \
+               volatile u32 *__ptr = (volatile u32 *)(ptr);            \
+               asm volatile(lock "cmpxchgl %2,%1"                      \
+                            : "=a" (__ret), "+m" (*__ptr)              \
+                            : "r" (__new), "0" (__old)                 \
+                            : "memory");                               \
+               break;                                                  \
+       }                                                               \
+       case __X86_CASE_Q:                                              \
+       {                                                               \
+               volatile u64 *__ptr = (volatile u64 *)(ptr);            \
+               asm volatile(lock "cmpxchgq %2,%1"                      \
+                            : "=a" (__ret), "+m" (*__ptr)              \
+                            : "r" (__new), "0" (__old)                 \
+                            : "memory");                               \
+               break;                                                  \
+       }                                                               \
+       default:                                                        \
+               __cmpxchg_wrong_size();                                 \
+       }                                                               \
+       __ret;                                                          \
+})
+
+#define __cmpxchg(ptr, old, new, size)                                 \
+       __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
+
+#define cmpxchg(ptr, old, new)                                         \
+       __cmpxchg(ptr, old, new, sizeof(*(ptr)))
+
+
+#endif /* TOOLS_ASM_X86_CMPXCHG_H */
index e3fb5ecbdcb65cee24172baecbe7f87da959b640..523911f316ce5e65511962f0c13fe0032a06427a 100644 (file)
@@ -63,6 +63,7 @@ FEATURE_TESTS_BASIC :=                  \
         lzma                            \
         get_cpuid                       \
         bpf                             \
+        sched_getcpu                   \
         sdt
 
 # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
index b564a2eea03904636f41101dd485e441d2d4fe00..09c9626ea666c9e974cbc8b6643bcce179ef1993 100644 (file)
@@ -48,12 +48,13 @@ FILES=                                          \
          test-get_cpuid.bin                     \
          test-sdt.bin                           \
          test-cxx.bin                           \
-         test-jvmti.bin
+         test-jvmti.bin                                \
+         test-sched_getcpu.bin
 
 FILES := $(addprefix $(OUTPUT),$(FILES))
 
-CC := $(CROSS_COMPILE)gcc -MD
-CXX := $(CROSS_COMPILE)g++ -MD
+CC ?= $(CROSS_COMPILE)gcc -MD
+CXX ?= $(CROSS_COMPILE)g++ -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
 LLVM_CONFIG ?= llvm-config
 
@@ -91,6 +92,9 @@ $(OUTPUT)test-libelf.bin:
 $(OUTPUT)test-glibc.bin:
        $(BUILD)
 
+$(OUTPUT)test-sched_getcpu.bin:
+       $(BUILD)
+
 DWARFLIBS := -ldw
 ifeq ($(findstring -static,${LDFLAGS}),-static)
 DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
index 699e43627397b5c3008cd74008016f4812550c77..cc6c7c01f4cadd5f8fe28ced947b9c80a2a0515d 100644 (file)
 # include "test-pthread-attr-setaffinity-np.c"
 #undef main
 
+#define main main_test_sched_getcpu
+# include "test-sched_getcpu.c"
+#undef main
+
 # if 0
 /*
  * Disable libbabeltrace check for test-all, because the requested
@@ -182,6 +186,7 @@ int main(int argc, char *argv[])
        main_test_get_cpuid();
        main_test_bpf();
        main_test_libcrypto();
+       main_test_sched_getcpu();
        main_test_sdt();
 
        return 0;
diff --git a/tools/build/feature/test-sched_getcpu.c b/tools/build/feature/test-sched_getcpu.c
new file mode 100644 (file)
index 0000000..c4a148d
--- /dev/null
@@ -0,0 +1,7 @@
+#define _GNU_SOURCE
+#include <sched.h>
+
+int main(void)
+{
+       return sched_getcpu();
+}
index 2ba78c9f570108ac8284fa96c209ea07498adf09..5e9738f97bf38f471067c7e4e205ed1d6bb5bd78 100644 (file)
@@ -60,4 +60,12 @@ static inline int atomic_dec_and_test(atomic_t *v)
        return __sync_sub_and_fetch(&v->counter, 1) == 0;
 }
 
+#define cmpxchg(ptr, oldval, newval) \
+       __sync_val_compare_and_swap(ptr, oldval, newval)
+
+static inline int atomic_cmpxchg(atomic_t *v, int oldval, int newval)
+{
+       return cmpxchg(&(v)->counter, oldval, newval);
+}
+
 #endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */
index 4e3d3d18ebab6271dec637a017620fe80666fd11..9f21fc2b092b834f3badabe0233ed4e8b509444b 100644 (file)
@@ -3,4 +3,10 @@
 
 #include <asm/atomic.h>
 
+/* atomic_cmpxchg_relaxed */
+#ifndef atomic_cmpxchg_relaxed
+#define  atomic_cmpxchg_relaxed                atomic_cmpxchg
+#define  atomic_cmpxchg_release         atomic_cmpxchg
+#endif /* atomic_cmpxchg_relaxed */
+
 #endif /* __TOOLS_LINUX_ATOMIC_H */
index 48af2f10a42d00942b5262391f3f576c9856c0e4..616935f1ff56473a3096e6f791963833f6021f43 100644 (file)
@@ -12,3 +12,7 @@
 #if GCC_VERSION >= 70000 && !defined(__CHECKER__)
 # define __fallthrough __attribute__ ((fallthrough))
 #endif
+
+#if GCC_VERSION >= 40300
+# define __compiletime_error(message) __attribute__((error(message)))
+#endif /* GCC_VERSION >= 40300 */
index 8de163b17c0d00011d33083d247936d8265465e7..c9e65e8faacdd0d02942b54fba9b262976d8b068 100644 (file)
@@ -5,6 +5,10 @@
 #include <linux/compiler-gcc.h>
 #endif
 
+#ifndef __compiletime_error
+# define __compiletime_error(message)
+#endif
+
 /* Optimization barrier */
 /* The "volatile" is due to gcc bugs */
 #define barrier() __asm__ __volatile__("": : :"memory")
index 28607db02bd3ed165cd535de415ffd3d4476753f..adb4d0147755ea57830bd689b2f74f69f62110c5 100644 (file)
@@ -5,6 +5,10 @@
 #include <stddef.h>
 #include <assert.h>
 
+#ifndef UINT_MAX
+#define UINT_MAX       (~0U)
+#endif
+
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 
 #define PERF_ALIGN(x, a)       __PERF_ALIGN_MASK(x, (typeof(x))(a)-1)
diff --git a/tools/include/linux/refcount.h b/tools/include/linux/refcount.h
new file mode 100644 (file)
index 0000000..a0177c1
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef _TOOLS_LINUX_REFCOUNT_H
+#define _TOOLS_LINUX_REFCOUNT_H
+
+/*
+ * Variant of atomic_t specialized for reference counts.
+ *
+ * The interface matches the atomic_t interface (to aid in porting) but only
+ * provides the few functions one should use for reference counting.
+ *
+ * It differs in that the counter saturates at UINT_MAX and will not move once
+ * there. This avoids wrapping the counter and causing 'spurious'
+ * use-after-free issues.
+ *
+ * Memory ordering rules are slightly relaxed wrt regular atomic_t functions
+ * and provide only what is strictly required for refcounts.
+ *
+ * The increments are fully relaxed; these will not provide ordering. The
+ * rationale is that whatever is used to obtain the object we're increasing the
+ * reference count on will provide the ordering. For locked data structures,
+ * its the lock acquire, for RCU/lockless data structures its the dependent
+ * load.
+ *
+ * Do note that inc_not_zero() provides a control dependency which will order
+ * future stores against the inc, this ensures we'll never modify the object
+ * if we did not in fact acquire a reference.
+ *
+ * The decrements will provide release order, such that all the prior loads and
+ * stores will be issued before, it also provides a control dependency, which
+ * will order us against the subsequent free().
+ *
+ * The control dependency is against the load of the cmpxchg (ll/sc) that
+ * succeeded. This means the stores aren't fully ordered, but this is fine
+ * because the 1->0 transition indicates no concurrency.
+ *
+ * Note that the allocator is responsible for ordering things between free()
+ * and alloc().
+ *
+ */
+
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+
+#ifdef NDEBUG
+#define REFCOUNT_WARN(cond, str) (void)(cond)
+#define __refcount_check
+#else
+#define REFCOUNT_WARN(cond, str) BUG_ON(cond)
+#define __refcount_check       __must_check
+#endif
+
+typedef struct refcount_struct {
+       atomic_t refs;
+} refcount_t;
+
+#define REFCOUNT_INIT(n)       { .refs = ATOMIC_INIT(n), }
+
+static inline void refcount_set(refcount_t *r, unsigned int n)
+{
+       atomic_set(&r->refs, n);
+}
+
+static inline unsigned int refcount_read(const refcount_t *r)
+{
+       return atomic_read(&r->refs);
+}
+
+/*
+ * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ */
+static inline __refcount_check
+bool refcount_inc_not_zero(refcount_t *r)
+{
+       unsigned int old, new, val = atomic_read(&r->refs);
+
+       for (;;) {
+               new = val + 1;
+
+               if (!val)
+                       return false;
+
+               if (unlikely(!new))
+                       return true;
+
+               old = atomic_cmpxchg_relaxed(&r->refs, val, new);
+               if (old == val)
+                       break;
+
+               val = old;
+       }
+
+       REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n");
+
+       return true;
+}
+
+/*
+ * Similar to atomic_inc(), will saturate at UINT_MAX and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller already has a
+ * reference on the object, will WARN when this is not so.
+ */
+static inline void refcount_inc(refcount_t *r)
+{
+       REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n");
+}
+
+/*
+ * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
+ * decrement when saturated at UINT_MAX.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before, and provides a control dependency such that free() must come after.
+ * See the comment on top.
+ */
+static inline __refcount_check
+bool refcount_sub_and_test(unsigned int i, refcount_t *r)
+{
+       unsigned int old, new, val = atomic_read(&r->refs);
+
+       for (;;) {
+               if (unlikely(val == UINT_MAX))
+                       return false;
+
+               new = val - i;
+               if (new > val) {
+                       REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n");
+                       return false;
+               }
+
+               old = atomic_cmpxchg_release(&r->refs, val, new);
+               if (old == val)
+                       break;
+
+               val = old;
+       }
+
+       return !new;
+}
+
+static inline __refcount_check
+bool refcount_dec_and_test(refcount_t *r)
+{
+       return refcount_sub_and_test(1, r);
+}
+
+
+#endif /* _ATOMIC_LINUX_REFCOUNT_H */
index c66a485a24ac81e324ea53ea17b405a3c73b520a..bec0aad0e15cd3798f6858038d661b1b1ce1b3bc 100644 (file)
@@ -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,23 @@ struct perf_event_header {
        __u16   size;
 };
 
+struct perf_ns_link_info {
+       __u64   dev;
+       __u64   ino;
+};
+
+enum {
+       NET_NS_INDEX            = 0,
+       UTS_NS_INDEX            = 1,
+       IPC_NS_INDEX            = 2,
+       PID_NS_INDEX            = 3,
+       USER_NS_INDEX           = 4,
+       MNT_NS_INDEX            = 5,
+       CGROUP_NS_INDEX         = 6,
+
+       NR_NAMESPACES,          /* number of available namespaces */
+};
+
 enum perf_event_type {
 
        /*
@@ -862,6 +880,18 @@ enum perf_event_type {
         */
        PERF_RECORD_SWITCH_CPU_WIDE             = 15,
 
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid;
+        *      u32                             tid;
+        *      u64                             nr_namespaces;
+        *      { u64                           dev, inode; } [nr_namespaces];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_NAMESPACES                  = 16,
+
        PERF_RECORD_MAX,                        /* non-ABI */
 };
 
index 3db3db9278be6f52af6bb9935eb7698eb1fc2f79..643cc4ba6872511d7941fad057ac875f5382deb2 100644 (file)
@@ -31,3 +31,5 @@ config.mak.autogen
 .config-detected
 util/intel-pt-decoder/inat-tables.c
 arch/*/include/generated/
+pmu-events/pmu-events.c
+pmu-events/jevents
index 2d96de6132a941dcd50d9808aafead39bc7df6ea..6e6a8b22c8594f42e9727c81a8e4b4adc8301e43 100644 (file)
@@ -30,6 +30,24 @@ OPTIONS
 --verbose=::
         Verbosity level.
 
+-p::
+--pid=::
+       Trace on existing process id (comma separated list).
+
+-a::
+--all-cpus::
+       Force system-wide collection.  Scripts run without a <command>
+       normally use -a by default, while scripts run with a <command>
+       normally don't - this option allows the latter to be run in
+       system-wide mode.
+
+-C::
+--cpu=::
+       Only trace for the list of CPUs provided.  Multiple CPUs can
+       be provided as a comma separated list with no space like: 0,1.
+       Ranges of CPUs are specified with -: 0-2.
+       Default is to trace on all online CPUs.
+
 
 SEE ALSO
 --------
index b16003ec14a743bcdcc8473798388b0849aa3523..ea3789d05e5e69fa60f2d8daf230f62aaae073c8 100644 (file)
@@ -347,6 +347,9 @@ Enable weightened sampling. An additional weight is recorded per sample and can
 displayed with the weight and local_weight sort keys.  This currently works for TSX
 abort events and some memory events in precise mode on modern Intel CPUs.
 
+--namespaces::
+Record events of type PERF_RECORD_NAMESPACES.
+
 --transaction::
 Record transaction flags for transaction related events.
 
index c04cc0647c16e6d8bbb458d655ab8ddbec3262c9..e9a61f5485eb1edf7f47e98be1da7365142d6904 100644 (file)
@@ -72,7 +72,8 @@ OPTIONS
 --sort=::
        Sort histogram entries by given key(s) - multiple keys can be specified
        in CSV format.  Following sort keys are available:
-       pid, comm, dso, symbol, parent, cpu, socket, srcline, weight, local_weight.
+       pid, comm, dso, symbol, parent, cpu, socket, srcline, weight,
+       local_weight, cgroup_id.
 
        Each key has following meaning:
 
@@ -80,6 +81,7 @@ OPTIONS
        - pid: command and tid of the task
        - dso: name of library or module executed at the time of sample
        - symbol: name of function executed at the time of sample
+       - symbol_size: size of function executed at the time of sample
        - parent: name of function matched to the parent regex filter. Unmatched
        entries are displayed as "[other]".
        - cpu: cpu number the task ran at the time of sample
@@ -91,6 +93,7 @@ OPTIONS
        - weight: Event specific weight, e.g. memory latency or transaction
        abort cost. This is the global weight.
        - local_weight: Local weight version of the weight above.
+       - cgroup_id: ID derived from cgroup namespace device and inode numbers.
        - transaction: Transaction abort flags.
        - overhead: Overhead percentage of sample
        - overhead_sys: Overhead percentage of sample running in system mode
@@ -172,6 +175,9 @@ OPTIONS
        By default, every sort keys not specified in -F will be appended
        automatically.
 
+       If the keys starts with a prefix '+', then it will append the specified
+        field(s) to the default field order. For example: perf report -F +period,sample.
+
 -p::
 --parent=<regex>::
         A regex filter to identify parent. The parent is a caller of this
index d33deddb0146cc9500f29fe6f0b1e65d6f237b10..a092a2499e8f8f2003681369c140a19a84b9c401 100644 (file)
@@ -132,6 +132,10 @@ OPTIONS for 'perf sched timehist'
 --migrations::
        Show migration events.
 
+-n::
+--next::
+       Show next task.
+
 -I::
 --idle-hist::
        Show idle-related events only.
index 4ed5f239ba7dee9fe2fc44854e3b8daa42091a97..62c9b0c77a3a9abb01d571ffbbb4abab21164c37 100644 (file)
@@ -248,6 +248,9 @@ OPTIONS
 --show-mmap-events
        Display mmap related events (e.g. MMAP, MMAP2).
 
+--show-namespace-events
+       Display namespace events i.e. events of type PERF_RECORD_NAMESPACES.
+
 --show-switch-events
        Display context switch events i.e. events of type PERF_RECORD_SWITCH or
        PERF_RECORD_SWITCH_CPU_WIDE.
index 8672f835ae4eff2659ff314c40bf77d3730b7986..28648c09dcd683c11b381661f270fcc1ed36c0a9 100644 (file)
@@ -12,6 +12,7 @@ tools/arch/sparc/include/asm/barrier_32.h
 tools/arch/sparc/include/asm/barrier_64.h
 tools/arch/tile/include/asm/barrier.h
 tools/arch/x86/include/asm/barrier.h
+tools/arch/x86/include/asm/cmpxchg.h
 tools/arch/x86/include/asm/cpufeatures.h
 tools/arch/x86/include/asm/disabled-features.h
 tools/arch/x86/include/asm/required-features.h
@@ -78,6 +79,7 @@ tools/include/uapi/linux/perf_event.h
 tools/include/linux/poison.h
 tools/include/linux/rbtree.h
 tools/include/linux/rbtree_augmented.h
+tools/include/linux/refcount.h
 tools/include/linux/string.h
 tools/include/linux/stringify.h
 tools/include/linux/types.h
index 27c9fbca7bd9c79eb703ad2d37d4280f9d286cc4..2b656de99495378e12767af7305d0f583a450ddd 100644 (file)
@@ -317,6 +317,10 @@ ifdef NO_DWARF
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
+ifeq ($(feature-sched_getcpu), 1)
+  CFLAGS += -DHAVE_SCHED_GETCPU_SUPPORT
+endif
+
 ifndef NO_LIBELF
   CFLAGS += -DHAVE_LIBELF_SUPPORT
   EXTLIBS += -lelf
index 1030a6e504bb9fe2a8f7eca185a419332613d924..39dbe512b9fcf3c8caeda0cebc5dea32d9696bec 100644 (file)
@@ -10,6 +10,7 @@
 #include "symbol.h"
 #include "map.h"
 #include "probe-event.h"
+#include "probe-file.h"
 
 #ifdef HAVE_LIBELF_SUPPORT
 bool elf__needs_adjust_symbols(GElf_Ehdr ehdr)
@@ -79,13 +80,18 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
         * However, if the user specifies an offset, we fall back to using the
         * GEP since all userspace applications (objdump/readelf) show function
         * disassembly with offsets from the GEP.
-        *
-        * In addition, we shouldn't specify an offset for kretprobes.
         */
-       if (pev->point.offset || (!pev->uprobes && pev->point.retprobe) ||
-           !map || !sym)
+       if (pev->point.offset || !map || !sym)
                return;
 
+       /* For kretprobes, add an offset only if the kernel supports it */
+       if (!pev->uprobes && pev->point.retprobe) {
+#ifdef HAVE_LIBELF_SUPPORT
+               if (!kretprobe_offset_is_supported())
+#endif
+                       return;
+       }
+
        lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
 
        if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS)
index da04b8c5568a39cf509b9aa5df844641866bcfd1..2499e1b0c6fb3ed9c86a12fd4af905dfdb3f146b 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /* For the CLR_() macros */
+#include <string.h>
 #include <pthread.h>
 
 #include <errno.h>
index 91877777ec6e3a4052e49eca9cba4793fa551f73..a20814d94af112337f6abf7e7ccf07447f0c38db 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 /* For the CLR_() macros */
+#include <string.h>
 #include <pthread.h>
 
 #include <signal.h>
index 2b9705a8734cd6005fd3149943e2ff20eecf4bbe..9fad1e4fcd3e9a718d300157c11fb8eda04f2f76 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /* For the CLR_() macros */
+#include <string.h>
 #include <pthread.h>
 
 #include <signal.h>
index 2c8fa67ad53767e43c7e91dc84279528268fcb3a..40f5fcf1d1206d4f45a272411f8cbfb92317cc2a 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 /* For the CLR_() macros */
+#include <string.h>
 #include <pthread.h>
 
 #include <signal.h>
index e246b1b8388a3fd3bfc7c9c398a90efc26d86c79..789490281ae3dfce3c6326c7033cea1e289c60e5 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /* For the CLR_() macros */
+#include <string.h>
 #include <pthread.h>
 
 #include <signal.h>
index b2e06d1190d0766694c97f7f0b808717442af604..e44fd32395305cc5e58042ec7a85fee2e9ef1748 100644 (file)
@@ -88,13 +88,11 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak
 
 #ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP
 #include <pthread.h>
-static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr,
-                                             size_t cpusetsize,
-                                             cpu_set_t *cpuset)
+#include <linux/compiler.h>
+static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr __maybe_unused,
+                                             size_t cpusetsize __maybe_unused,
+                                             cpu_set_t *cpuset __maybe_unused)
 {
-       attr = attr;
-       cpusetsize = cpusetsize;
-       cpuset = cpuset;
        return 0;
 }
 #endif
index 3083fc36282b564d3fc5da05864907c3ac222cf4..6bd0581de2985b9feff5746154f69097db16bc30 100644 (file)
@@ -187,7 +187,8 @@ static const struct option options[] = {
        OPT_INCR   ('d', "show_details" , &p0.show_details,     "Show details"),
        OPT_INCR   ('a', "all"          , &p0.run_all,          "Run all tests in the suite"),
        OPT_INTEGER('H', "thp"          , &p0.thp,              "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
-       OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
+       OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details, "
+                   "convergence is reached when each process (all its threads) is running on a single NUMA node."),
        OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
        OPT_BOOLEAN('q', "quiet"        , &p0.show_quiet,       "quiet mode"),
        OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
index 4f52d85f5ebc574daa91f29b1a3d24758c3d276d..e54b1f9fe1ee73da50c78eaa285d69c3bab54313 100644 (file)
@@ -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,
                },
index e2b21723bbf8acddac596ebf519ba5b7f82c84b3..5cd6d7a047b9d04a06cfa7cf0c5c0fdad19f81a6 100644 (file)
@@ -2334,7 +2334,7 @@ out:
 
 static void perf_c2c_display(struct perf_session *session)
 {
-       if (c2c.use_stdio)
+       if (use_browser == 0)
                perf_c2c__hists_fprintf(stdout, session);
        else
                perf_c2c__hists_browse(&c2c.hists.hists);
@@ -2536,7 +2536,7 @@ static int perf_c2c__report(int argc, const char **argv)
        OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
 #endif
        OPT_BOOLEAN(0, "stats", &c2c.stats_only,
-                   "Use the stdio interface"),
+                   "Display only statistic tables (implies --stdio)"),
        OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
                    "Display full length of symbols"),
        OPT_BOOLEAN(0, "no-source", &no_source,
index 1b96a3122228f913af671d315ad0a71cedb6c11d..5e48031586723fb6383fec91259b66bb8d6a793b 100644 (file)
@@ -364,6 +364,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,
 };
index c3e643666c722cf743252a7f89b0b2b50d46d604..6087295f8827fb4e1c4b6b1aba6309a6edaca15d 100644 (file)
 
 #include <unistd.h>
 #include <signal.h>
+#include <fcntl.h>
 
 #include "debug.h"
 #include <subcmd/parse-options.h>
 #include "evlist.h"
 #include "target.h"
+#include "cpumap.h"
 #include "thread_map.h"
 #include "util/config.h"
 
@@ -50,11 +52,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
        done = true;
 }
 
-static int write_tracing_file(const char *name, const char *val)
+static int __write_tracing_file(const char *name, const char *val, bool append)
 {
        char *file;
        int fd, ret = -1;
        ssize_t size = strlen(val);
+       int flags = O_WRONLY;
 
        file = get_tracing_file(name);
        if (!file) {
@@ -62,7 +65,12 @@ static int write_tracing_file(const char *name, const char *val)
                return -1;
        }
 
-       fd = open(file, O_WRONLY);
+       if (append)
+               flags |= O_APPEND;
+       else
+               flags |= O_TRUNC;
+
+       fd = open(file, flags);
        if (fd < 0) {
                pr_debug("cannot open tracing file: %s\n", name);
                goto out;
@@ -79,6 +87,18 @@ out:
        return ret;
 }
 
+static int write_tracing_file(const char *name, const char *val)
+{
+       return __write_tracing_file(name, val, false);
+}
+
+static int append_tracing_file(const char *name, const char *val)
+{
+       return __write_tracing_file(name, val, true);
+}
+
+static int reset_tracing_cpu(void);
+
 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 {
        if (write_tracing_file("tracing_on", "0") < 0)
@@ -90,14 +110,78 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
        if (write_tracing_file("set_ftrace_pid", " ") < 0)
                return -1;
 
+       if (reset_tracing_cpu() < 0)
+               return -1;
+
+       return 0;
+}
+
+static int set_tracing_pid(struct perf_ftrace *ftrace)
+{
+       int i;
+       char buf[16];
+
+       if (target__has_cpu(&ftrace->target))
+               return 0;
+
+       for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) {
+               scnprintf(buf, sizeof(buf), "%d",
+                         ftrace->evlist->threads->map[i]);
+               if (append_tracing_file("set_ftrace_pid", buf) < 0)
+                       return -1;
+       }
        return 0;
 }
 
+static int set_tracing_cpumask(struct cpu_map *cpumap)
+{
+       char *cpumask;
+       size_t mask_size;
+       int ret;
+       int last_cpu;
+
+       last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1);
+       mask_size = (last_cpu + 3) / 4 + 1;
+       mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */
+
+       cpumask = malloc(mask_size);
+       if (cpumask == NULL) {
+               pr_debug("failed to allocate cpu mask\n");
+               return -1;
+       }
+
+       cpu_map__snprint_mask(cpumap, cpumask, mask_size);
+
+       ret = write_tracing_file("tracing_cpumask", cpumask);
+
+       free(cpumask);
+       return ret;
+}
+
+static int set_tracing_cpu(struct perf_ftrace *ftrace)
+{
+       struct cpu_map *cpumap = ftrace->evlist->cpus;
+
+       if (!target__has_cpu(&ftrace->target))
+               return 0;
+
+       return set_tracing_cpumask(cpumap);
+}
+
+static int reset_tracing_cpu(void)
+{
+       struct cpu_map *cpumap = cpu_map__new(NULL);
+       int ret;
+
+       ret = set_tracing_cpumask(cpumap);
+       cpu_map__put(cpumap);
+       return ret;
+}
+
 static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 {
        char *trace_file;
        int trace_fd;
-       char *trace_pid;
        char buf[4096];
        struct pollfd pollfd = {
                .events = POLLIN,
@@ -108,42 +192,43 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
                return -1;
        }
 
-       if (argc < 1)
-               return -1;
-
        signal(SIGINT, sig_handler);
        signal(SIGUSR1, sig_handler);
        signal(SIGCHLD, sig_handler);
+       signal(SIGPIPE, sig_handler);
 
-       reset_tracing_files(ftrace);
+       if (reset_tracing_files(ftrace) < 0)
+               goto out;
 
        /* reset ftrace buffer */
        if (write_tracing_file("trace", "0") < 0)
                goto out;
 
-       if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target,
-                                         argv, false, ftrace__workload_exec_failed_signal) < 0)
+       if (argc && perf_evlist__prepare_workload(ftrace->evlist,
+                               &ftrace->target, argv, false,
+                               ftrace__workload_exec_failed_signal) < 0) {
                goto out;
+       }
 
-       if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
-               pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
-               goto out;
+       if (set_tracing_pid(ftrace) < 0) {
+               pr_err("failed to set ftrace pid\n");
+               goto out_reset;
        }
 
-       if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) {
-               pr_err("failed to allocate pid string\n");
-               goto out;
+       if (set_tracing_cpu(ftrace) < 0) {
+               pr_err("failed to set tracing cpumask\n");
+               goto out_reset;
        }
 
-       if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) {
-               pr_err("failed to set pid: %s\n", trace_pid);
-               goto out_free_pid;
+       if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
+               pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
+               goto out_reset;
        }
 
        trace_file = get_tracing_file("trace_pipe");
        if (!trace_file) {
                pr_err("failed to open trace_pipe\n");
-               goto out_free_pid;
+               goto out_reset;
        }
 
        trace_fd = open(trace_file, O_RDONLY);
@@ -152,7 +237,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 
        if (trace_fd < 0) {
                pr_err("failed to open trace_pipe\n");
-               goto out_free_pid;
+               goto out_reset;
        }
 
        fcntl(trace_fd, F_SETFL, O_NONBLOCK);
@@ -163,6 +248,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
                goto out_close_fd;
        }
 
+       setup_pager();
+
        perf_evlist__start_workload(ftrace->evlist);
 
        while (!done) {
@@ -191,11 +278,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
 
 out_close_fd:
        close(trace_fd);
-out_free_pid:
-       free(trace_pid);
-out:
+out_reset:
        reset_tracing_files(ftrace);
-
+out:
        return done ? 0 : -1;
 }
 
@@ -227,15 +312,21 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
                .target = { .uid = UINT_MAX, },
        };
        const char * const ftrace_usage[] = {
-               "perf ftrace [<options>] <command>",
+               "perf ftrace [<options>] [<command>]",
                "perf ftrace [<options>] -- <command> [<options>]",
                NULL
        };
        const struct option ftrace_options[] = {
        OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
                   "tracer to use: function_graph(default) or function"),
+       OPT_STRING('p', "pid", &ftrace.target.pid, "pid",
+                  "trace on existing process id"),
        OPT_INCR('v', "verbose", &verbose,
                 "be more verbose"),
+       OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
+                   "system-wide collection from all CPUs"),
+       OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
+                   "list of cpus to monitor"),
        OPT_END()
        };
 
@@ -245,9 +336,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
 
        argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
-       if (!argc)
+       if (!argc && target__none(&ftrace.target))
                usage_with_options(ftrace_usage, ftrace_options);
 
+       ret = target__validate(&ftrace.target);
+       if (ret) {
+               char errbuf[512];
+
+               target__strerror(&ftrace.target, ret, errbuf, 512);
+               pr_err("%s\n", errbuf);
+               return -EINVAL;
+       }
+
        ftrace.evlist = perf_evlist__new();
        if (ftrace.evlist == NULL)
                return -ENOMEM;
index b9bc7e39833a47055608feffa1f5917aada33174..8d1d13b9bab683b3bc068bc892ae8977e1010693 100644 (file)
@@ -333,6 +333,18 @@ 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 = 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 +672,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;
index 6da8d083e4e596d821673ed7408c814723029aca..d509e74bc6e8c22386ca8a513a07f41e40337033 100644 (file)
@@ -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,
 };
 
index 08fa88f62a246f4f309410da45379aa21949f14e..18e6c38864bc325b0b9699a0e01b9aed6e5c88d6 100644 (file)
@@ -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);
 
index ce3bfb48b26f0f309b5c90cf49bb4870fbd76a4b..d750ccaa978fbbb3680d8524afe996fc96cd88da 100644 (file)
@@ -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 = {
index 6114e07ca6131ca94ed1a6107fb69ae3ccbab145..030a6cfdda5986f48ceda0f7c4a292e78af1a4fc 100644 (file)
@@ -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",
index bc84a375295d7cb4920df6a4be1f91403bcdc04b..04faef79a54877c06552d535c829554dd86bb4b4 100644 (file)
@@ -876,6 +876,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)
@@ -983,6 +986,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) {
@@ -996,10 +1000,30 @@ 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) +
+                              (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+                              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);
@@ -1497,6 +1521,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,
@@ -1611,6 +1636,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,
index 0a88670e56f35f6d8c5397e80264001acaf35e94..5ab8117c3bfd4df89bb0b207cda735a02d0e3d98 100644 (file)
@@ -394,8 +394,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
                fprintf(stdout, "\n\n");
        }
 
-       if (sort_order == NULL &&
-           parent_pattern == default_parent_pattern)
+       if (!quiet)
                fprintf(stdout, "#\n# (%s)\n#\n", help);
 
        if (rep->show_threads) {
@@ -701,6 +700,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,
index b94cf0de715ab9a2d6205c12053916c31d276a13..b92c4d97192c256edc0d0dfe9e84ba96188a1c40 100644 (file)
@@ -221,6 +221,7 @@ struct perf_sched {
        unsigned int    max_stack;
        bool            show_cpu_visual;
        bool            show_wakeups;
+       bool            show_next;
        bool            show_migrations;
        bool            show_state;
        u64             skipped_samples;
@@ -1897,14 +1898,18 @@ static char task_state_char(struct thread *thread, int state)
 }
 
 static void timehist_print_sample(struct perf_sched *sched,
+                                 struct perf_evsel *evsel,
                                  struct perf_sample *sample,
                                  struct addr_location *al,
                                  struct thread *thread,
                                  u64 t, int state)
 {
        struct thread_runtime *tr = thread__priv(thread);
+       const char *next_comm = perf_evsel__strval(evsel, sample, "next_comm");
+       const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
        u32 max_cpus = sched->max_cpu + 1;
        char tstr[64];
+       char nstr[30];
        u64 wait_time;
 
        timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
@@ -1937,7 +1942,12 @@ static void timehist_print_sample(struct perf_sched *sched,
        if (sched->show_state)
                printf(" %5c ", task_state_char(thread, state));
 
-       if (sched->show_wakeups)
+       if (sched->show_next) {
+               snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid);
+               printf(" %-*s", comm_width, nstr);
+       }
+
+       if (sched->show_wakeups && !sched->show_next)
                printf("  %-*s", comm_width, "");
 
        if (thread->tid == 0)
@@ -2531,7 +2541,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
        }
 
        if (!sched->summary_only)
-               timehist_print_sample(sched, sample, &al, thread, t, state);
+               timehist_print_sample(sched, evsel, sample, &al, thread, t, state);
 
 out:
        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)
                .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,
@@ -3340,6 +3351,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN('S', "with-summary", &sched.summary,
                    "Show all syscalls and summary with statistics"),
        OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
+       OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"),
        OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
        OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
        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)
                        if (argc)
                                usage_with_options(timehist_usage, timehist_options);
                }
-               if (sched.show_wakeups && sched.summary_only) {
-                       pr_err(" Error: -s and -w are mutually exclusive.\n");
+               if ((sched.show_wakeups || sched.show_next) &&
+                   sched.summary_only) {
+                       pr_err(" Error: -s and -[n|w] are mutually exclusive.\n");
                        parse_options_usage(timehist_usage, timehist_options, "s", true);
-                       parse_options_usage(NULL, timehist_options, "w", true);
+                       if (sched.show_wakeups)
+                               parse_options_usage(NULL, timehist_options, "w", true);
+                       if (sched.show_next)
+                               parse_options_usage(NULL, timehist_options, "n", true);
                        return -EINVAL;
                }
 
index c0783b4f7b6c650e2c35ffebfe1e2d7bb3e51e61..66d62c98dff9d69f0dd7c2d64b159a3a8ac4fb85 100644 (file)
@@ -830,6 +830,7 @@ struct perf_script {
        bool                    show_task_events;
        bool                    show_mmap_events;
        bool                    show_switch_events;
+       bool                    show_namespace_events;
        bool                    allocated;
        struct cpu_map          *cpus;
        struct thread_map       *threads;
@@ -1118,6 +1119,41 @@ out:
        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_namespace_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-namespace-events", &script.show_namespace_events,
+                   "Show namespace 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"),
index 13b54999ad79ecd4f765d557bf57764486f1fac8..f53f449d864dab865fb3f8cfe4ce35add09ede33 100644 (file)
@@ -146,6 +146,7 @@ static aggr_get_id_t                aggr_get_id;
 static bool                    append_file;
 static const char              *output_name;
 static int                     output_fd;
+static int                     print_free_counters_hint;
 
 struct perf_stat {
        bool                     record;
@@ -1109,6 +1110,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
                        counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
                        csv_sep);
 
+               if (counter->supported)
+                       print_free_counters_hint = 1;
+
                fprintf(stat_config.output, "%-*s%s",
                        csv_output ? 0 : unit_width,
                        counter->unit, csv_sep);
@@ -1477,6 +1481,13 @@ static void print_footer(void)
                                avg_stats(&walltime_nsecs_stats));
        }
        fprintf(output, "\n\n");
+
+       if (print_free_counters_hint)
+               fprintf(output,
+"Some events weren't counted. Try disabling the NMI watchdog:\n"
+"      echo 0 > /proc/sys/kernel/nmi_watchdog\n"
+"      perf stat ...\n"
+"      echo 1 > /proc/sys/kernel/nmi_watchdog\n");
 }
 
 static void print_counters(struct timespec *ts, int argc, const char **argv)
@@ -2339,6 +2350,35 @@ static int __cmd_report(int argc, const char **argv)
        return 0;
 }
 
+static void setup_system_wide(int forks)
+{
+       /*
+        * Make system wide (-a) the default target if
+        * no target was specified and one of following
+        * conditions is met:
+        *
+        *   - there's no workload specified
+        *   - there is workload specified but all requested
+        *     events are system wide events
+        */
+       if (!target__none(&target))
+               return;
+
+       if (!forks)
+               target.system_wide = true;
+       else {
+               struct perf_evsel *counter;
+
+               evlist__for_each_entry(evsel_list, counter) {
+                       if (!counter->system_wide)
+                               return;
+               }
+
+               if (evsel_list->nr_entries)
+                       target.system_wide = true;
+       }
+}
+
 int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        const char * const stat_usage[] = {
@@ -2445,9 +2485,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
        } else if (big_num_opt == 0) /* User passed --no-big-num */
                big_num = false;
 
-       /* Make system wide (-a) the default target. */
-       if (!argc && target__none(&target))
-               target.system_wide = true;
+       setup_system_wide(argc);
 
        if (run_count < 0) {
                pr_err("Run count must be a positive number\n");
index 256f1fac6f7e0069ebb047cf080fa55999dd0ae1..912fedc5b42d0eb7cff554fa6d80e16c704894f2 100644 (file)
@@ -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;
index ac3efd396a727298802b49e6a24e530f696fcdf7..2d0caf20ff3a49dc11f8406959f46fd6d687c06b 100644 (file)
@@ -9,6 +9,7 @@ perf-buildid-cache              mainporcelain common
 perf-buildid-list              mainporcelain common
 perf-data                      mainporcelain common
 perf-diff                      mainporcelain common
+perf-c2c                       mainporcelain common
 perf-config                    mainporcelain common
 perf-evlist                    mainporcelain common
 perf-ftrace                    mainporcelain common
index 1c27d947c2fe55c9f0d0390695e6b586d839ec0b..806c216a1078210a028167c26eb442cec8e219b9 100644 (file)
@@ -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;
index 12181bb1da2a8a294da7487b00287413fb3d8c54..d1a12e584c1b8e1223dd66266dac6745247e0aff 100644 (file)
@@ -17,6 +17,7 @@ GenuineIntel-6-3A,v18,ivybridge,core
 GenuineIntel-6-3E,v19,ivytown,core
 GenuineIntel-6-2D,v20,jaketown,core
 GenuineIntel-6-57,v9,knightslanding,core
+GenuineIntel-6-85,v9,knightslanding,core
 GenuineIntel-6-1E,v2,nehalemep,core
 GenuineIntel-6-1F,v2,nehalemep,core
 GenuineIntel-6-1A,v2,nehalemep,core
index f168a85992d0ca3fec6c5abe4f2fd0efc3917224..4478773cdb9751b4f1f5a89f97c1808ad81d1bae 100644 (file)
@@ -66,7 +66,7 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
        TEST_ASSERT_VAL("wrong nr",  map->nr == 2);
        TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
        TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
-       TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1);
+       TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1);
        cpu_map__put(map);
        return 0;
 }
index f2d2e542d0ee77a8abf7bfc6074f0934da85b5c4..a63d6945807b3a0e7fe9247475068e258dbd9cdc 100644 (file)
@@ -29,7 +29,7 @@ int test__thread_map(int subtest __maybe_unused)
                        thread_map__comm(map, 0) &&
                        !strcmp(thread_map__comm(map, 0), NAME));
        TEST_ASSERT_VAL("wrong refcnt",
-                       atomic_read(&map->refcnt) == 1);
+                       refcount_read(&map->refcnt) == 1);
        thread_map__put(map);
 
        /* test dummy pid */
@@ -44,7 +44,7 @@ int test__thread_map(int subtest __maybe_unused)
                        thread_map__comm(map, 0) &&
                        !strcmp(thread_map__comm(map, 0), "dummy"));
        TEST_ASSERT_VAL("wrong refcnt",
-                       atomic_read(&map->refcnt) == 1);
+                       refcount_read(&map->refcnt) == 1);
        thread_map__put(map);
        return 0;
 }
@@ -71,7 +71,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
                        thread_map__comm(threads, 0) &&
                        !strcmp(thread_map__comm(threads, 0), NAME));
        TEST_ASSERT_VAL("wrong refcnt",
-                       atomic_read(&threads->refcnt) == 1);
+                       refcount_read(&threads->refcnt) == 1);
        thread_map__put(threads);
        return 0;
 }
index 188b63140fc841f8c3111d20439b78d7f73133db..76686dd6f5ecfd235705bca7b39d7abdc237a150 100644 (file)
@@ -43,7 +43,7 @@ int test__thread_mg_share(int subtest __maybe_unused)
                        leader && t1 && t2 && t3 && other);
 
        mg = leader->mg;
-       TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 4);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 4);
 
        /* test the map groups pointer is shared */
        TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
@@ -71,25 +71,25 @@ int test__thread_mg_share(int subtest __maybe_unused)
        machine__remove_thread(machine, other_leader);
 
        other_mg = other->mg;
-       TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&other_mg->refcnt), 2);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 2);
 
        TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
 
        /* release thread group */
        thread__put(leader);
-       TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 3);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 3);
 
        thread__put(t1);
-       TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 2);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 2);
 
        thread__put(t2);
-       TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 1);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 1);
 
        thread__put(t3);
 
        /* release other group  */
        thread__put(other_leader);
-       TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&other_mg->refcnt), 1);
+       TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 1);
 
        thread__put(other);
 
index fc4fb669ceee37404bdda0e2ba0652f4304c28f8..2dc82bec10c04461ec0df377eaa32ef9f7260dbf 100644 (file)
@@ -2308,7 +2308,7 @@ static int switch_data_file(void)
                return ret;
 
        memset(options, 0, sizeof(options));
-       memset(options, 0, sizeof(abs_path));
+       memset(abs_path, 0, sizeof(abs_path));
 
        while ((dent = readdir(pwd_dir))) {
                char path[PATH_MAX];
index 5da376bc1afca6733664f798e0e9d3050dab6e21..2ea5ee179a3b1a162d4cad72ef7557bddc3d32f7 100644 (file)
@@ -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
index eafbf11442b224f90ad9c5d704df75d86985f917..86399eda3684b2b1969a7d09cc3e5ebfa157cbca 100644 (file)
@@ -127,19 +127,19 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
                        goto found;
                n++;
        }
-       if (atomic_read(&cgrp->refcnt) == 0)
+       if (refcount_read(&cgrp->refcnt) == 0)
                free(cgrp);
 
        return -1;
 found:
-       atomic_inc(&cgrp->refcnt);
+       refcount_inc(&cgrp->refcnt);
        counter->cgrp = cgrp;
        return 0;
 }
 
 void close_cgroup(struct cgroup_sel *cgrp)
 {
-       if (cgrp && atomic_dec_and_test(&cgrp->refcnt)) {
+       if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
                close(cgrp->fd);
                zfree(&cgrp->name);
                free(cgrp);
index 31f8dcdbd7efefac48353b90715c027cf2c13386..d91966b97cbd7235f9fd756c50cd41ba7d7fadae 100644 (file)
@@ -1,14 +1,14 @@
 #ifndef __CGROUP_H__
 #define __CGROUP_H__
 
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 
 struct option;
 
 struct cgroup_sel {
        char *name;
        int fd;
-       atomic_t refcnt;
+       refcount_t refcnt;
 };
 
 
index d0d465953d36e16c07038ea69182e71c44db0558..94a5a7d829d5ba32efe646f9c04729ab363ac593 100644 (file)
@@ -3,10 +3,4 @@
 
 unsigned long perf_event_open_cloexec_flag(void);
 
-#ifdef __GLIBC_PREREQ
-#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
-int sched_getcpu(void) __THROW;
-#endif
-#endif
-
 #endif /* __PERF_CLOEXEC_H */
index 21b7ff382c3f0dfb2e0bff43074adae3c0b10973..32837b6f78794100df203b598d43fe573142d7e7 100644 (file)
@@ -2,12 +2,12 @@
 #include "util.h"
 #include <stdlib.h>
 #include <stdio.h>
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 
 struct comm_str {
        char *str;
        struct rb_node rb_node;
-       atomic_t refcnt;
+       refcount_t refcnt;
 };
 
 /* Should perhaps be moved to struct machine */
@@ -16,13 +16,13 @@ static struct rb_root comm_str_root;
 static struct comm_str *comm_str__get(struct comm_str *cs)
 {
        if (cs)
-               atomic_inc(&cs->refcnt);
+               refcount_inc(&cs->refcnt);
        return cs;
 }
 
 static void comm_str__put(struct comm_str *cs)
 {
-       if (cs && atomic_dec_and_test(&cs->refcnt)) {
+       if (cs && refcount_dec_and_test(&cs->refcnt)) {
                rb_erase(&cs->rb_node, &comm_str_root);
                zfree(&cs->str);
                free(cs);
@@ -43,7 +43,7 @@ static struct comm_str *comm_str__alloc(const char *str)
                return NULL;
        }
 
-       atomic_set(&cs->refcnt, 0);
+       refcount_set(&cs->refcnt, 1);
 
        return cs;
 }
@@ -61,7 +61,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
 
                cmp = strcmp(str, iter->str);
                if (!cmp)
-                       return iter;
+                       return comm_str__get(iter);
 
                if (cmp < 0)
                        p = &(*p)->rb_left;
@@ -95,8 +95,6 @@ struct comm *comm__new(const char *str, u64 timestamp, bool exec)
                return NULL;
        }
 
-       comm_str__get(comm->comm_str);
-
        return comm;
 }
 
@@ -108,7 +106,6 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
        if (!new)
                return -ENOMEM;
 
-       comm_str__get(new);
        comm_str__put(old);
        comm->comm_str = new;
        comm->start = timestamp;
index 8c750493911369976d0fa171e74f3b678f62c054..061018b4239341f7a74409fe64973c9a7f0bcd33 100644 (file)
@@ -29,7 +29,7 @@ static struct cpu_map *cpu_map__default_new(void)
                        cpus->map[i] = i;
 
                cpus->nr = nr_cpus;
-               atomic_set(&cpus->refcnt, 1);
+               refcount_set(&cpus->refcnt, 1);
        }
 
        return cpus;
@@ -43,7 +43,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
        if (cpus != NULL) {
                cpus->nr = nr_cpus;
                memcpy(cpus->map, tmp_cpus, payload_size);
-               atomic_set(&cpus->refcnt, 1);
+               refcount_set(&cpus->refcnt, 1);
        }
 
        return cpus;
@@ -252,7 +252,7 @@ struct cpu_map *cpu_map__dummy_new(void)
        if (cpus != NULL) {
                cpus->nr = 1;
                cpus->map[0] = -1;
-               atomic_set(&cpus->refcnt, 1);
+               refcount_set(&cpus->refcnt, 1);
        }
 
        return cpus;
@@ -269,7 +269,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
                for (i = 0; i < nr; i++)
                        cpus->map[i] = -1;
 
-               atomic_set(&cpus->refcnt, 1);
+               refcount_set(&cpus->refcnt, 1);
        }
 
        return cpus;
@@ -278,7 +278,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
 static void cpu_map__delete(struct cpu_map *map)
 {
        if (map) {
-               WARN_ONCE(atomic_read(&map->refcnt) != 0,
+               WARN_ONCE(refcount_read(&map->refcnt) != 0,
                          "cpu_map refcnt unbalanced\n");
                free(map);
        }
@@ -287,13 +287,13 @@ static void cpu_map__delete(struct cpu_map *map)
 struct cpu_map *cpu_map__get(struct cpu_map *map)
 {
        if (map)
-               atomic_inc(&map->refcnt);
+               refcount_inc(&map->refcnt);
        return map;
 }
 
 void cpu_map__put(struct cpu_map *map)
 {
-       if (map && atomic_dec_and_test(&map->refcnt))
+       if (map && refcount_dec_and_test(&map->refcnt))
                cpu_map__delete(map);
 }
 
@@ -357,7 +357,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
        /* ensure we process id in increasing order */
        qsort(c->map, c->nr, sizeof(int), cmp_ids);
 
-       atomic_set(&c->refcnt, 1);
+       refcount_set(&c->refcnt, 1);
        *res = c;
        return 0;
 }
@@ -673,3 +673,49 @@ size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size)
        pr_debug("cpumask list: %s\n", buf);
        return ret;
 }
+
+static char hex_char(unsigned char val)
+{
+       if (val < 10)
+               return val + '0';
+       if (val < 16)
+               return val - 10 + 'a';
+       return '?';
+}
+
+size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size)
+{
+       int i, cpu;
+       char *ptr = buf;
+       unsigned char *bitmap;
+       int last_cpu = cpu_map__cpu(map, map->nr - 1);
+
+       bitmap = zalloc((last_cpu + 7) / 8);
+       if (bitmap == NULL) {
+               buf[0] = '\0';
+               return 0;
+       }
+
+       for (i = 0; i < map->nr; i++) {
+               cpu = cpu_map__cpu(map, i);
+               bitmap[cpu / 8] |= 1 << (cpu % 8);
+       }
+
+       for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) {
+               unsigned char bits = bitmap[cpu / 8];
+
+               if (cpu % 8)
+                       bits >>= 4;
+               else
+                       bits &= 0xf;
+
+               *ptr++ = hex_char(bits);
+               if ((cpu % 32) == 0 && cpu > 0)
+                       *ptr++ = ',';
+       }
+       *ptr = '\0';
+       free(bitmap);
+
+       buf[size - 1] = '\0';
+       return ptr - buf;
+}
index 1a0549af8f5c944b4fc2b8b619164a107dcf613d..6b8bff87481d090a0e72f7391772bb307d0e1f7c 100644 (file)
@@ -3,13 +3,13 @@
 
 #include <stdio.h>
 #include <stdbool.h>
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 
 #include "perf.h"
 #include "util/debug.h"
 
 struct cpu_map {
-       atomic_t refcnt;
+       refcount_t refcnt;
        int nr;
        int map[];
 };
@@ -20,6 +20,7 @@ struct cpu_map *cpu_map__dummy_new(void);
 struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
 struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size);
+size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 int cpu_map__get_socket_id(int cpu);
 int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
index 4e6cbc99f08efc608c2d73ffb9054672d25fb7d9..89ece244571363e780cf37434c66c156de923952 100644 (file)
@@ -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,
                },
index d38b62a700ca126c293756baa83dbc27df61e53a..42db00d78573ebe80c11b0977698769388eebc63 100644 (file)
@@ -1109,7 +1109,7 @@ struct dso *dso__new(const char *name)
                INIT_LIST_HEAD(&dso->node);
                INIT_LIST_HEAD(&dso->data.open_entry);
                pthread_mutex_init(&dso->lock, NULL);
-               atomic_set(&dso->refcnt, 1);
+               refcount_set(&dso->refcnt, 1);
        }
 
        return dso;
@@ -1147,13 +1147,13 @@ void dso__delete(struct dso *dso)
 struct dso *dso__get(struct dso *dso)
 {
        if (dso)
-               atomic_inc(&dso->refcnt);
+               refcount_inc(&dso->refcnt);
        return dso;
 }
 
 void dso__put(struct dso *dso)
 {
-       if (dso && atomic_dec_and_test(&dso->refcnt))
+       if (dso && refcount_dec_and_test(&dso->refcnt))
                dso__delete(dso);
 }
 
index ecc4bbd3f82e3e172a89480d04466ba95eab7b09..12350b17172730adf0dffdf324cb9e0b4a4be2ba 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __PERF_DSO
 #define __PERF_DSO
 
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 #include <linux/types.h>
 #include <linux/rbtree.h>
 #include <sys/types.h>
@@ -187,7 +187,7 @@ struct dso {
                void     *priv;
                u64      db_id;
        };
-       atomic_t         refcnt;
+       refcount_t       refcnt;
        char             name[0];
 };
 
index 4ea7ce72ed9c8e3fb92ffca44b3f51fb09f6b01f..d082cb70445d29449c23ee38b8760e81e67748d4 100644 (file)
@@ -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",
@@ -49,6 +50,16 @@ static const char *perf_event__names[] = {
        [PERF_RECORD_TIME_CONV]                 = "TIME_CONV",
 };
 
+static const char *perf_ns__names[] = {
+       [NET_NS_INDEX]          = "net",
+       [UTS_NS_INDEX]          = "uts",
+       [IPC_NS_INDEX]          = "ipc",
+       [PID_NS_INDEX]          = "pid",
+       [USER_NS_INDEX]         = "user",
+       [MNT_NS_INDEX]          = "mnt",
+       [CGROUP_NS_INDEX]       = "cgroup",
+};
+
 const char *perf_event__name(unsigned int id)
 {
        if (id >= ARRAY_SIZE(perf_event__names))
@@ -58,6 +69,13 @@ const char *perf_event__name(unsigned int id)
        return perf_event__names[id];
 }
 
+static const char *perf_ns__name(unsigned int id)
+{
+       if (id >= ARRAY_SIZE(perf_ns__names))
+               return "UNKNOWN";
+       return perf_ns__names[id];
+}
+
 static int perf_tool__process_synth_event(struct perf_tool *tool,
                                          union perf_event *event,
                                          struct machine *machine,
@@ -203,6 +221,58 @@ 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];
+
+       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)
+{
+       u32 idx;
+       struct perf_ns_link_info *ns_link_info;
+
+       if (!tool || !tool->namespace_events)
+               return 0;
+
+       memset(&event->namespaces, 0, (sizeof(event->namespaces) +
+              (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+              machine->id_hdr_size));
+
+       event->namespaces.pid = tgid;
+       event->namespaces.tid = pid;
+
+       event->namespaces.nr_namespaces = NR_NAMESPACES;
+
+       ns_link_info = event->namespaces.link_info;
+
+       for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)
+               perf_event__get_ns_link_info(pid, perf_ns__name(idx),
+                                            &ns_link_info[idx]);
+
+       event->namespaces.header.type = PERF_RECORD_NAMESPACES;
+
+       event->namespaces.header.size = (sizeof(event->namespaces) +
+                       (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+                       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 +504,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 +526,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 +564,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 +597,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 +612,16 @@ 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) +
+                                 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+                                 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 +647,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 +656,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 +677,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 +695,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        if (fork_event == NULL)
                goto out_free_mmap;
 
+       namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
+                                 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+                                 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 +717,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 +1108,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
        return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
 }
 
+size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
+{
+       size_t ret = 0;
+       struct perf_ns_link_info *ns_link_info;
+       u32 nr_namespaces, idx;
+
+       ns_link_info = event->namespaces.link_info;
+       nr_namespaces = event->namespaces.nr_namespaces;
+
+       ret += fprintf(fp, " %d/%d - nr_namespaces: %u\n\t\t[",
+                      event->namespaces.pid,
+                      event->namespaces.tid,
+                      nr_namespaces);
+
+       for (idx = 0; idx < nr_namespaces; idx++) {
+               if (idx && (idx % 4 == 0))
+                       ret += fprintf(fp, "\n\t\t ");
+
+               ret  += fprintf(fp, "%u/%s: %" PRIu64 "/%#" PRIx64 "%s", idx,
+                               perf_ns__name(idx), (u64)ns_link_info[idx].dev,
+                               (u64)ns_link_info[idx].ino,
+                               ((idx + 1) != nr_namespaces) ? ", " : "]\n");
+       }
+
+       return ret;
+}
+
 int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
                             union perf_event *event,
                             struct perf_sample *sample,
@@ -1016,6 +1143,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 +1331,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;
index c735c53a26f8f6dcb37727299e0560d07a5f6ddb..e1d8166ebbd58f5184f40c64014c854b45514d0b 100644 (file)
@@ -39,6 +39,13 @@ struct comm_event {
        char comm[16];
 };
 
+struct namespaces_event {
+       struct perf_event_header header;
+       u32 pid, tid;
+       u64 nr_namespaces;
+       struct perf_ns_link_info link_info[];
+};
+
 struct fork_event {
        struct 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,
index b601f2814a30e9d7d2b6f689b5e495659c34e600..50420cd354467361615d8606d6dde73f5e588a45 100644 (file)
@@ -777,7 +777,7 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messu
        /*
         * Check if event was unmapped due to a POLLHUP/POLLERR.
         */
-       if (!atomic_read(&md->refcnt))
+       if (!refcount_read(&md->refcnt))
                return NULL;
 
        head = perf_mmap__read_head(md);
@@ -794,7 +794,7 @@ perf_mmap__read_backward(struct perf_mmap *md)
        /*
         * Check if event was unmapped due to a POLLHUP/POLLERR.
         */
-       if (!atomic_read(&md->refcnt))
+       if (!refcount_read(&md->refcnt))
                return NULL;
 
        head = perf_mmap__read_head(md);
@@ -856,7 +856,7 @@ void perf_mmap__read_catchup(struct perf_mmap *md)
 {
        u64 head;
 
-       if (!atomic_read(&md->refcnt))
+       if (!refcount_read(&md->refcnt))
                return;
 
        head = perf_mmap__read_head(md);
@@ -875,14 +875,14 @@ static bool perf_mmap__empty(struct perf_mmap *md)
 
 static void perf_mmap__get(struct perf_mmap *map)
 {
-       atomic_inc(&map->refcnt);
+       refcount_inc(&map->refcnt);
 }
 
 static void perf_mmap__put(struct perf_mmap *md)
 {
-       BUG_ON(md->base && atomic_read(&md->refcnt) == 0);
+       BUG_ON(md->base && refcount_read(&md->refcnt) == 0);
 
-       if (atomic_dec_and_test(&md->refcnt))
+       if (refcount_dec_and_test(&md->refcnt))
                perf_mmap__munmap(md);
 }
 
@@ -894,7 +894,7 @@ void perf_mmap__consume(struct perf_mmap *md, bool overwrite)
                perf_mmap__write_tail(md, old);
        }
 
-       if (atomic_read(&md->refcnt) == 1 && perf_mmap__empty(md))
+       if (refcount_read(&md->refcnt) == 1 && perf_mmap__empty(md))
                perf_mmap__put(md);
 }
 
@@ -937,7 +937,7 @@ static void perf_mmap__munmap(struct perf_mmap *map)
                munmap(map->base, perf_mmap__mmap_len(map));
                map->base = NULL;
                map->fd = -1;
-               atomic_set(&map->refcnt, 0);
+               refcount_set(&map->refcnt, 0);
        }
        auxtrace_mmap__munmap(&map->auxtrace_mmap);
 }
@@ -974,8 +974,19 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist)
        if (!map)
                return NULL;
 
-       for (i = 0; i < evlist->nr_mmaps; i++)
+       for (i = 0; i < evlist->nr_mmaps; i++) {
                map[i].fd = -1;
+               /*
+                * When the perf_mmap() call is made we grab one refcount, plus
+                * one extra to let perf_evlist__mmap_consume() get the last
+                * events after all real references (perf_mmap__get()) are
+                * dropped.
+                *
+                * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
+                * thus does perf_mmap__get() on it.
+                */
+               refcount_set(&map[i].refcnt, 0);
+       }
        return map;
 }
 
@@ -1001,7 +1012,7 @@ static int perf_mmap__mmap(struct perf_mmap *map,
         * evlist layer can't just drop it when filtering events in
         * perf_evlist__filter_pollfd().
         */
-       atomic_set(&map->refcnt, 2);
+       refcount_set(&map->refcnt, 2);
        map->prev = 0;
        map->mask = mp->mask;
        map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
index 389b9ccdf8c75db39d8e2163d6909a4db01e65a8..39942995f537cb0c118888897565536999b9a9d2 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __PERF_EVLIST_H
 #define __PERF_EVLIST_H 1
 
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 #include <linux/list.h>
 #include <api/fd/array.h>
 #include <stdio.h>
@@ -29,7 +29,7 @@ struct perf_mmap {
        void             *base;
        int              mask;
        int              fd;
-       atomic_t         refcnt;
+       refcount_t       refcnt;
        u64              prev;
        struct auxtrace_mmap auxtrace_mmap;
        char             event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
index ac59710b79e0b4cbee35cacc1e40a2102e091d8e..175dc2305aa8211aba29f728d4ef23b97c32539a 100644 (file)
@@ -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;
 
index eaf72a938fb423ed4ba46982c69324d2341839bc..e3b38f629504097a8d3d2aedcdbd5a815dba6eaa 100644 (file)
@@ -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,
index 28c216e3d5b72557825a8918ab2aa6d6369c40f8..ee3670a388df8f825fd6c79cb698e5fb6d7e5695 100644 (file)
@@ -30,6 +30,7 @@ enum hist_column {
        HISTC_DSO,
        HISTC_THREAD,
        HISTC_COMM,
+       HISTC_CGROUP_ID,
        HISTC_PARENT,
        HISTC_CPU,
        HISTC_SOCKET,
@@ -57,6 +58,7 @@ enum hist_column {
        HISTC_SRCLINE_FROM,
        HISTC_SRCLINE_TO,
        HISTC_TRACE,
+       HISTC_SYM_SIZE,
        HISTC_NR_COLS, /* Last entry */
 };
 
index 4f3c758d875d6ce6855db7fa0731436f9bb06671..459352a9978fb2970840751807295a8b3dfb523c 100644 (file)
@@ -39,6 +39,8 @@ static void intel_pt_insn_decoder(struct insn *insn,
        enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;
        int ext;
 
+       intel_pt_insn->rel = 0;
+
        if (insn_is_avx(insn)) {
                intel_pt_insn->op = INTEL_PT_OP_OTHER;
                intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
index 71c9720d49730066dc1100defee124a4d3c198b9..dfc600446586957f620fd22a53760f2982bff94f 100644 (file)
@@ -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 > NR_NAMESPACES,
+                 "\nWARNING: kernel seems to support more namespaces than perf"
+                 " tool.\nTry updating the perf tool..\n\n");
+
+       WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES,
+                 "\nWARNING: perf tool seems to support more namespaces than"
+                 " the kernel.\nTry updating the kernel..\n\n");
+
+       if (dump_trace)
+               perf_event__fprintf_namespaces(event, stdout);
+
+       if (thread == NULL ||
+           thread__set_namespaces(thread, sample->time, &event->namespaces)) {
+               dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
+               err = -1;
+       }
+
+       thread__put(thread);
+
+       return err;
+}
+
 int machine__process_lost_event(struct machine *machine __maybe_unused,
                                union perf_event *event, struct perf_sample *sample __maybe_unused)
 {
@@ -1439,7 +1471,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th,
        if (machine->last_match == th)
                machine->last_match = NULL;
 
-       BUG_ON(atomic_read(&th->refcnt) == 0);
+       BUG_ON(refcount_read(&th->refcnt) == 0);
        if (lock)
                pthread_rwlock_wrlock(&machine->threads_lock);
        rb_erase_init(&th->rb_node, &machine->threads);
@@ -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:
index a28305029711c08f56c89385c85fa49611e55aa3..3cdb1340f9170ad388e827b218fae3cd541502fc 100644 (file)
@@ -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,
index 0a943e7b1ea7fc745485f016875395e91feca8c8..1d9ebcf9e38e867d3626069865dfb61f2385f599 100644 (file)
@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,
        RB_CLEAR_NODE(&map->rb_node);
        map->groups   = NULL;
        map->erange_warned = false;
-       atomic_set(&map->refcnt, 1);
+       refcount_set(&map->refcnt, 1);
 }
 
 struct map *map__new(struct machine *machine, u64 start, u64 len,
@@ -255,7 +255,7 @@ void map__delete(struct map *map)
 
 void map__put(struct map *map)
 {
-       if (map && atomic_dec_and_test(&map->refcnt))
+       if (map && refcount_dec_and_test(&map->refcnt))
                map__delete(map);
 }
 
@@ -354,7 +354,7 @@ struct map *map__clone(struct map *from)
        struct map *map = memdup(from, sizeof(*map));
 
        if (map != NULL) {
-               atomic_set(&map->refcnt, 1);
+               refcount_set(&map->refcnt, 1);
                RB_CLEAR_NODE(&map->rb_node);
                dso__get(map->dso);
                map->groups = NULL;
@@ -485,7 +485,7 @@ void map_groups__init(struct map_groups *mg, struct machine *machine)
                maps__init(&mg->maps[i]);
        }
        mg->machine = machine;
-       atomic_set(&mg->refcnt, 1);
+       refcount_set(&mg->refcnt, 1);
 }
 
 static void __maps__purge(struct maps *maps)
@@ -547,7 +547,7 @@ void map_groups__delete(struct map_groups *mg)
 
 void map_groups__put(struct map_groups *mg)
 {
-       if (mg && atomic_dec_and_test(&mg->refcnt))
+       if (mg && refcount_dec_and_test(&mg->refcnt))
                map_groups__delete(mg);
 }
 
index abdacf800c98a78148565f23b7d9b4c916cbacaf..c8a5a644c0a9797f309fb58d9d2f69bd163cb598 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __PERF_MAP_H
 #define __PERF_MAP_H
 
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 #include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
@@ -51,7 +51,7 @@ struct map {
 
        struct dso              *dso;
        struct map_groups       *groups;
-       atomic_t                refcnt;
+       refcount_t              refcnt;
 };
 
 struct kmap {
@@ -67,7 +67,7 @@ struct maps {
 struct map_groups {
        struct maps      maps[MAP__NR_TYPES];
        struct machine   *machine;
-       atomic_t         refcnt;
+       refcount_t       refcnt;
 };
 
 struct map_groups *map_groups__new(struct machine *machine);
@@ -77,7 +77,7 @@ bool map_groups__empty(struct map_groups *mg);
 static inline struct map_groups *map_groups__get(struct map_groups *mg)
 {
        if (mg)
-               atomic_inc(&mg->refcnt);
+               refcount_inc(&mg->refcnt);
        return mg;
 }
 
@@ -150,7 +150,7 @@ struct map *map__clone(struct map *map);
 static inline struct map *map__get(struct map *map)
 {
        if (map)
-               atomic_inc(&map->refcnt);
+               refcount_inc(&map->refcnt);
        return map;
 }
 
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
new file mode 100644 (file)
index 0000000..2de8da6
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2017 Hari Bathini, IBM Corporation
+ */
+
+#include "namespaces.h"
+#include "util.h"
+#include "event.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+struct namespaces *namespaces__new(struct namespaces_event *event)
+{
+       struct namespaces *namespaces;
+       u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
+                             sizeof(struct perf_ns_link_info));
+
+       namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
+       if (!namespaces)
+               return NULL;
+
+       namespaces->end_time = -1;
+
+       if (event)
+               memcpy(namespaces->link_info, event->link_info, link_info_size);
+
+       return namespaces;
+}
+
+void namespaces__free(struct namespaces *namespaces)
+{
+       free(namespaces);
+}
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
new file mode 100644 (file)
index 0000000..468f1e9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2017 Hari Bathini, IBM Corporation
+ */
+
+#ifndef __PERF_NAMESPACES_H
+#define __PERF_NAMESPACES_H
+
+#include "../perf.h"
+#include <linux/list.h>
+
+struct namespaces_event;
+
+struct namespaces {
+       struct list_head list;
+       u64 end_time;
+       struct perf_ns_link_info link_info[];
+};
+
+struct namespaces *namespaces__new(struct namespaces_event *event);
+void namespaces__free(struct namespaces *namespaces);
+
+#endif  /* __PERF_NAMESPACES_H */
index 67a8aebc67ab492a9936ad56ae9655526f9d9781..54355d3caf09383a5b97424f0cea5ce06d249550 100644 (file)
@@ -316,8 +316,9 @@ __add_event(struct list_head *list, int *idx,
                return NULL;
 
        (*idx)++;
-       evsel->cpus     = cpu_map__get(cpus);
-       evsel->own_cpus = cpu_map__get(cpus);
+       evsel->cpus        = cpu_map__get(cpus);
+       evsel->own_cpus    = cpu_map__get(cpus);
+       evsel->system_wide = !!cpus;
 
        if (name)
                evsel->name = strdup(name);
index 28fb62c32678483cd6d54a9c88e620022e1f9d08..c9bdc9ded0c34cfff5419110c5a0ccce6154663d 100644 (file)
@@ -757,7 +757,9 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
        }
 
        for (i = 0; i < ntevs; i++) {
-               if (!tevs[i].point.address || tevs[i].point.retprobe)
+               if (!tevs[i].point.address)
+                       continue;
+               if (tevs[i].point.retprobe && !kretprobe_offset_is_supported())
                        continue;
                /* If we found a wrong one, mark it by NULL symbol */
                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)
                return -EINVAL;
        }
 
-       if (pp->retprobe && !pp->function) {
-               semantic_error("Return probe requires an entry function.\n");
-               return -EINVAL;
-       }
-
        if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
                semantic_error("Offset/Line/Lazy pattern can't be used with "
                               "return probe.\n");
@@ -2841,7 +2838,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
        }
 
        /* Note that the symbols in the kmodule are not relocated */
-       if (!pev->uprobes && !pp->retprobe && !pev->target) {
+       if (!pev->uprobes && !pev->target &&
+                       (!pp->retprobe || kretprobe_offset_is_supported())) {
                reloc_sym = kernel_get_ref_reloc_sym();
                if (!reloc_sym) {
                        pr_warning("Relocated base symbol is not found!\n");
index 436b64731f65112f3c624a70a077f7370532da5a..1542cd0d67991d1ffc204a63d82d9fbe0ac8e5e6 100644 (file)
@@ -70,7 +70,7 @@ static void print_both_open_warning(int kerr, int uerr)
        }
 }
 
-static int open_probe_events(const char *trace_file, bool readwrite)
+int open_trace_file(const char *trace_file, bool readwrite)
 {
        char buf[PATH_MAX];
        int ret;
@@ -92,12 +92,12 @@ static int open_probe_events(const char *trace_file, bool readwrite)
 
 static int open_kprobe_events(bool readwrite)
 {
-       return open_probe_events("kprobe_events", readwrite);
+       return open_trace_file("kprobe_events", readwrite);
 }
 
 static int open_uprobe_events(bool readwrite)
 {
-       return open_probe_events("uprobe_events", readwrite);
+       return open_trace_file("uprobe_events", readwrite);
 }
 
 int probe_file__open(int flag)
@@ -877,59 +877,72 @@ int probe_cache__show_all_caches(struct strfilter *filter)
        return 0;
 }
 
+enum ftrace_readme {
+       FTRACE_README_PROBE_TYPE_X = 0,
+       FTRACE_README_KRETPROBE_OFFSET,
+       FTRACE_README_END,
+};
+
 static struct {
        const char *pattern;
-       bool    avail;
-       bool    checked;
-} probe_type_table[] = {
-#define DEFINE_TYPE(idx, pat, def_avail)       \
-       [idx] = {.pattern = pat, .avail = (def_avail)}
-       DEFINE_TYPE(PROBE_TYPE_U, "* u8/16/32/64,*", true),
-       DEFINE_TYPE(PROBE_TYPE_S, "* s8/16/32/64,*", true),
-       DEFINE_TYPE(PROBE_TYPE_X, "* x8/16/32/64,*", false),
-       DEFINE_TYPE(PROBE_TYPE_STRING, "* string,*", true),
-       DEFINE_TYPE(PROBE_TYPE_BITFIELD,
-                   "* b<bit-width>@<bit-offset>/<container-size>", true),
+       bool avail;
+} ftrace_readme_table[] = {
+#define DEFINE_TYPE(idx, pat)                  \
+       [idx] = {.pattern = pat, .avail = false}
+       DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
+       DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
 };
 
-bool probe_type_is_available(enum probe_type type)
+static bool scan_ftrace_readme(enum ftrace_readme type)
 {
+       int fd;
        FILE *fp;
        char *buf = NULL;
        size_t len = 0;
-       bool target_line = false;
-       bool ret = probe_type_table[type].avail;
+       bool ret = false;
+       static bool scanned = false;
 
-       if (type >= PROBE_TYPE_END)
-               return false;
-       /* We don't have to check the type which supported by default */
-       if (ret || probe_type_table[type].checked)
-               return ret;
+       if (scanned)
+               goto result;
 
-       if (asprintf(&buf, "%s/README", tracing_path) < 0)
+       fd = open_trace_file("README", false);
+       if (fd < 0)
                return ret;
 
-       fp = fopen(buf, "r");
-       if (!fp)
-               goto end;
-
-       zfree(&buf);
-       while (getline(&buf, &len, fp) > 0 && !ret) {
-               if (!target_line) {
-                       target_line = !!strstr(buf, " type: ");
-                       if (!target_line)
-                               continue;
-               } else if (strstr(buf, "\t          ") != buf)
-                       break;
-               ret = strglobmatch(buf, probe_type_table[type].pattern);
+       fp = fdopen(fd, "r");
+       if (!fp) {
+               close(fd);
+               return ret;
        }
-       /* Cache the result */
-       probe_type_table[type].checked = true;
-       probe_type_table[type].avail = ret;
+
+       while (getline(&buf, &len, fp) > 0)
+               for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
+                       if (!ftrace_readme_table[i].avail)
+                               ftrace_readme_table[i].avail =
+                                       strglobmatch(buf, ftrace_readme_table[i].pattern);
+       scanned = true;
 
        fclose(fp);
-end:
        free(buf);
 
-       return ret;
+result:
+       if (type >= FTRACE_README_END)
+               return false;
+
+       return ftrace_readme_table[type].avail;
+}
+
+bool probe_type_is_available(enum probe_type type)
+{
+       if (type >= PROBE_TYPE_END)
+               return false;
+       else if (type == PROBE_TYPE_X)
+               return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
+
+       return true;
+}
+
+bool kretprobe_offset_is_supported(void)
+{
+       return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
 }
index eba44c3e9dca9ac670d06736237feb49fb21734b..dbf95a00864ae3d33ade24b68025c81c340ad23b 100644 (file)
@@ -35,6 +35,7 @@ enum probe_type {
 
 /* probe-file.c depends on libelf */
 #ifdef HAVE_LIBELF_SUPPORT
+int open_trace_file(const char *trace_file, bool readwrite);
 int probe_file__open(int flag);
 int probe_file__open_both(int *kfd, int *ufd, int flag);
 struct strlist *probe_file__get_namelist(int fd);
@@ -64,6 +65,7 @@ struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
                                        const char *group, const char *event);
 int probe_cache__show_all_caches(struct strfilter *filter);
 bool probe_type_is_available(enum probe_type type);
+bool kretprobe_offset_is_supported(void);
 #else  /* ! HAVE_LIBELF_SUPPORT */
 static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused)
 {
index 1dd617d116b5d844f23c88592f9dac9f061a7ff6..ae42e742d46181963cbeaebbb90b72928929b5a3 100644 (file)
@@ -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;
index 0ff622288d243c4edad03a904b6da3a52cf4da50..8b0d4e39f6402fa6f836821d43ee9a52115aea36 100644 (file)
@@ -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
@@ -846,6 +886,9 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
 static int64_t
 sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
 {
+       if (!left->branch_info || !right->branch_info)
+               return cmp_null(left->branch_info, right->branch_info);
+
        return left->branch_info->flags.cycles -
                right->branch_info->flags.cycles;
 }
@@ -853,6 +896,8 @@ sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
                                    size_t size, unsigned int width)
 {
+       if (!he->branch_info)
+               return scnprintf(bf, size, "%-.*s", width, "N/A");
        if (he->branch_info->flags.cycles == 0)
                return repsep_snprintf(bf, size, "%-*s", width, "-");
        return repsep_snprintf(bf, size, "%-*hd", width,
@@ -1396,6 +1441,46 @@ struct sort_entry sort_transaction = {
        .se_width_idx   = HISTC_TRANSACTION,
 };
 
+/* --sort symbol_size */
+
+static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r)
+{
+       int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0;
+       int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0;
+
+       return size_l < size_r ? -1 :
+               size_l == size_r ? 0 : 1;
+}
+
+static int64_t
+sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return _sort__sym_size_cmp(right->ms.sym, left->ms.sym);
+}
+
+static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf,
+                                         size_t bf_size, unsigned int width)
+{
+       if (sym)
+               return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym));
+
+       return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
+}
+
+static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf,
+                                        size_t size, unsigned int width)
+{
+       return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width);
+}
+
+struct sort_entry sort_sym_size = {
+       .se_header      = "Symbol size",
+       .se_cmp         = sort__sym_size_cmp,
+       .se_snprintf    = hist_entry__sym_size_snprintf,
+       .se_width_idx   = HISTC_SYM_SIZE,
+};
+
+
 struct sort_dimension {
        const char              *name;
        struct sort_entry       *entry;
@@ -1418,6 +1503,8 @@ 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_SYM_SIZE, "symbol_size", sort_sym_size),
+       DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
 };
 
 #undef DIM
index 796c847e2f000d6722ed2cb35321e7f3b8b0489e..baf20a399f34a3f76920eede2b973864a5103a1d 100644 (file)
@@ -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,8 @@ enum sort_type {
        SORT_GLOBAL_WEIGHT,
        SORT_TRANSACTION,
        SORT_TRACE,
+       SORT_SYM_SIZE,
+       SORT_CGROUP_ID,
 
        /* branch stack specific sort keys */
        __SORT_BRANCH_STACK,
index f5af87f6666303df886d4c70fd2d565c1d0436e9..dcdb87a5d0a13a4698518e8a47b67bb4f76bfede 100644 (file)
@@ -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);
@@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                        goto err_thread;
 
                list_add(&comm->list, &thread->comm_list);
-               atomic_set(&thread->refcnt, 1);
+               refcount_set(&thread->refcnt, 1);
                RB_CLEAR_NODE(&thread->rb_node);
        }
 
@@ -66,7 +68,8 @@ err_thread:
 
 void thread__delete(struct thread *thread)
 {
-       struct comm *comm, *tmp;
+       struct namespaces *namespaces, *tmp_namespaces;
+       struct comm *comm, *tmp_comm;
 
        BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
 
@@ -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);
        }
@@ -88,13 +96,13 @@ void thread__delete(struct thread *thread)
 struct thread *thread__get(struct thread *thread)
 {
        if (thread)
-               atomic_inc(&thread->refcnt);
+               refcount_inc(&thread->refcnt);
        return thread;
 }
 
 void thread__put(struct thread *thread)
 {
-       if (thread && atomic_dec_and_test(&thread->refcnt)) {
+       if (thread && refcount_dec_and_test(&thread->refcnt)) {
                /*
                 * Remove it from the dead_threads list, as last reference
                 * is gone.
@@ -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))
index 99263cb6e6b646bd987fc3ff410c2efa495f3944..4eb849e9098f5ca0115cb90527dd9f564476e4ea 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __PERF_THREAD_H
 #define __PERF_THREAD_H
 
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 #include <linux/rbtree.h>
 #include <linux/list.h>
 #include <unistd.h>
@@ -23,11 +23,12 @@ struct thread {
        pid_t                   tid;
        pid_t                   ppid;
        int                     cpu;
-       atomic_t                refcnt;
+       refcount_t              refcnt;
        char                    shortname[3];
        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,
index 7c3fcc538a705f9df580c33b6444512547b3f453..9026408ea55bda68f477092d4ed36ebf56f1c14c 100644 (file)
@@ -66,7 +66,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
                for (i = 0; i < items; i++)
                        thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
                threads->nr = items;
-               atomic_set(&threads->refcnt, 1);
+               refcount_set(&threads->refcnt, 1);
        }
 
        for (i=0; i<items; i++)
@@ -83,7 +83,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
        if (threads != NULL) {
                thread_map__set_pid(threads, 0, tid);
                threads->nr = 1;
-               atomic_set(&threads->refcnt, 1);
+               refcount_set(&threads->refcnt, 1);
        }
 
        return threads;
@@ -105,7 +105,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
                goto out_free_threads;
 
        threads->nr = 0;
-       atomic_set(&threads->refcnt, 1);
+       refcount_set(&threads->refcnt, 1);
 
        while ((dirent = readdir(proc)) != NULL) {
                char *end;
@@ -235,7 +235,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
 out:
        strlist__delete(slist);
        if (threads)
-               atomic_set(&threads->refcnt, 1);
+               refcount_set(&threads->refcnt, 1);
        return threads;
 
 out_free_namelist:
@@ -255,7 +255,7 @@ struct thread_map *thread_map__new_dummy(void)
        if (threads != NULL) {
                thread_map__set_pid(threads, 0, -1);
                threads->nr = 1;
-               atomic_set(&threads->refcnt, 1);
+               refcount_set(&threads->refcnt, 1);
        }
        return threads;
 }
@@ -300,7 +300,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
        }
 out:
        if (threads)
-               atomic_set(&threads->refcnt, 1);
+               refcount_set(&threads->refcnt, 1);
        return threads;
 
 out_free_threads:
@@ -326,7 +326,7 @@ static void thread_map__delete(struct thread_map *threads)
        if (threads) {
                int i;
 
-               WARN_ONCE(atomic_read(&threads->refcnt) != 0,
+               WARN_ONCE(refcount_read(&threads->refcnt) != 0,
                          "thread map refcnt unbalanced\n");
                for (i = 0; i < threads->nr; i++)
                        free(thread_map__comm(threads, i));
@@ -337,13 +337,13 @@ static void thread_map__delete(struct thread_map *threads)
 struct thread_map *thread_map__get(struct thread_map *map)
 {
        if (map)
-               atomic_inc(&map->refcnt);
+               refcount_inc(&map->refcnt);
        return map;
 }
 
 void thread_map__put(struct thread_map *map)
 {
-       if (map && atomic_dec_and_test(&map->refcnt))
+       if (map && refcount_dec_and_test(&map->refcnt))
                thread_map__delete(map);
 }
 
@@ -423,7 +423,7 @@ static void thread_map__copy_event(struct thread_map *threads,
                threads->map[i].comm = strndup(event->entries[i].comm, 16);
        }
 
-       atomic_set(&threads->refcnt, 1);
+       refcount_set(&threads->refcnt, 1);
 }
 
 struct thread_map *thread_map__new_event(struct thread_map_event *event)
index ea0ef08c6303413b6ececf2b93ec905914e558aa..bd34d7a0b9fa9fbcd92224e3f83208f7479cac09 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <sys/types.h>
 #include <stdio.h>
-#include <linux/atomic.h>
+#include <linux/refcount.h>
 
 struct thread_map_data {
        pid_t    pid;
@@ -11,7 +11,7 @@ struct thread_map_data {
 };
 
 struct thread_map {
-       atomic_t refcnt;
+       refcount_t refcnt;
        int nr;
        struct thread_map_data map[];
 };
index ac2590a3de2d1586fa60a1893d9ec4233967b5e0..829471a1c6d76bc637c5fcefbeaec89b8d61d39a 100644 (file)
@@ -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 */
index c74708da857129356e2a308cd987dec34f371104..b2cfa47990dcc7bc3a95a8c7f3a7bae1d565a700 100644 (file)
@@ -355,8 +355,8 @@ void print_binary(unsigned char *data, size_t len,
                  size_t bytes_per_line, print_binary_t printer,
                  void *extra);
 
-#if !defined(__GLIBC__) && !defined(__ANDROID__)
-extern int sched_getcpu(void);
+#ifndef HAVE_SCHED_GETCPU_SUPPORT
+int sched_getcpu(void);
 #endif
 
 int is_printable_array(char *p, unsigned int len);
index 621578aa12d6fe456134369b97968126c3a1981e..fc74db62fef4d11851422586a87eb5dee6b17176 100644 (file)
@@ -43,6 +43,15 @@ ifneq ($(CC), clang)
 EXTRA_WARNINGS += -Wstrict-aliasing=3
 endif
 
+# Hack to avoid type-punned warnings on old systems such as RHEL5:
+# We should be changing CFLAGS and checking gcc version, but this
+# will do for now and keep the above -Wstrict-aliasing=3 in place
+# in newer systems.
+# Needed for the __raw_cmpxchg in tools/arch/x86/include/asm/cmpxchg.h
+ifneq ($(filter 3.%,$(MAKE_VERSION)),)  # make-3
+EXTRA_WARNINGS += -fno-strict-aliasing
+endif
+
 ifneq ($(findstring $(MAKEFLAGS), w),w)
 PRINT_DIR = --no-print-directory
 else