Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'perf-core-for-mingo-4.12-20170314' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

New features:

- Add PERF_RECORD_NAMESPACES so that the kernel can record information
required to associate samples to namespaces, helping in container
problem characterization.

Now the 'perf record has a --namespace' option to ask for such info,
and when present, it can be used, initially, via a new sort order,
'cgroup_id', allowing histogram entry bucketization by a (device, inode)
based cgroup identifier (Hari Bathini)

- Add --next option to 'perf sched timehist', showing what is the next
thread to run (Brendan Gregg)

Fixes:

- Fix segfault with basic block 'cycles' sort dimension (Changbin Du)

- Add c2c to command-list.txt, making it appear in the 'perf help'
output (Changbin Du)

- Fix zeroing of 'abs_path' variable in the perf hists browser switch
file code (Changbin Du)

- Hide tips messages when -q/--quiet is given to 'perf report' (Namhyung Kim)

Infrastructure changes:

- Use ref_reloc_sym + offset to setup kretprobes (Naveen Rao)

- Ignore generated files pmu-events/{jevents,pmu-events.c} for git (Changbin Du)

Documentation changes:

- Document +field style argument support for --field option (Changbin Du)

- Clarify 'perf c2c --stats' help message (Namhyung Kim)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

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