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

perf tools: Add PERF_RECORD_NAMESPACES to include namespaces related info

Introduce a new option to record PERF_RECORD_NAMESPACES events emitted
by the kernel when fork, clone, setns or unshare are invoked. And update
perf-record documentation with the new option to record namespace
events.

Committer notes:

Combined it with a later patch to allow printing it via 'perf report -D'
and be able to test the feature introduced in this patch. Had to move
here also perf_ns__name(), that was introduced in another later patch.

Also used PRIu64 and PRIx64 to fix the build in some enfironments wrt:

util/event.c:1129:39: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'long long unsigned int' [-Werror=format=]
ret += fprintf(fp, "%u/%s: %lu/0x%lx%s", idx
^
Testing it:

# perf record --namespaces -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.083 MB perf.data (423 samples) ]
#
# perf report -D
<SNIP>
3 2028902078892 0x115140 [0xa0]: PERF_RECORD_NAMESPACES 14783/14783 - nr_namespaces: 7
[0/net: 3/0xf0000081, 1/uts: 3/0xeffffffe, 2/ipc: 3/0xefffffff, 3/pid: 3/0xeffffffc,
4/user: 3/0xeffffffd, 5/mnt: 3/0xf0000000, 6/cgroup: 3/0xeffffffb]

0x1151e0 [0x30]: event: 9
.
. ... raw event: size 48 bytes
. 0000: 09 00 00 00 02 00 30 00 c4 71 82 68 0c 7f 00 00 ......0..q.h....
. 0010: a9 39 00 00 a9 39 00 00 94 28 fe 63 d8 01 00 00 .9...9...(.c....
. 0020: 03 00 00 00 00 00 00 00 ce c4 02 00 00 00 00 00 ................
<SNIP>
NAMESPACES events: 1
<SNIP>
#

Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sargun Dhillon <sargun@sargun.me>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/148891930386.25309.18412039920746995488.stgit@hbathini.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Hari Bathini and committed by
Arnaldo Carvalho de Melo
f3b3614a e4222673

+296 -4
+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 };
+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
+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 },
+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",
+6
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) ··· 1500 1497 .fork = perf_event__process_fork, 1501 1498 .exit = perf_event__process_exit, 1502 1499 .comm = perf_event__process_comm, 1500 + .namespaces = perf_event__process_namespaces, 1503 1501 .mmap = perf_event__process_mmap, 1504 1502 .mmap2 = perf_event__process_mmap2, 1505 1503 .ordered_events = true, ··· 1615 1611 "opts", "AUX area tracing Snapshot Mode", ""), 1616 1612 OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout, 1617 1613 "per thread proc mmap processing timeout in ms"), 1614 + OPT_BOOLEAN(0, "namespaces", &record.opts.record_namespaces, 1615 + "Record namespaces events"), 1618 1616 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1619 1617 "Record context switch events"), 1620 1618 OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
+1
tools/perf/builtin-report.c
··· 700 700 .mmap = perf_event__process_mmap, 701 701 .mmap2 = perf_event__process_mmap2, 702 702 .comm = perf_event__process_comm, 703 + .namespaces = perf_event__process_namespaces, 703 704 .exit = perf_event__process_exit, 704 705 .fork = perf_event__process_fork, 705 706 .lost = perf_event__process_lost,
+1
tools/perf/builtin-sched.c
··· 3272 3272 .tool = { 3273 3273 .sample = perf_sched__process_tracepoint_sample, 3274 3274 .comm = perf_event__process_comm, 3275 + .namespaces = perf_event__process_namespaces, 3275 3276 .lost = perf_event__process_lost, 3276 3277 .fork = perf_sched__process_fork_event, 3277 3278 .ordered_events = true,
+1
tools/perf/builtin-script.c
··· 2097 2097 .mmap = perf_event__process_mmap, 2098 2098 .mmap2 = perf_event__process_mmap2, 2099 2099 .comm = perf_event__process_comm, 2100 + .namespaces = perf_event__process_namespaces, 2100 2101 .exit = perf_event__process_exit, 2101 2102 .fork = perf_event__process_fork, 2102 2103 .attr = process_attr,
+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/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
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 },
+56
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, ··· 1026 1008 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); 1027 1009 } 1028 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 + 1029 1038 int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 1030 1039 union perf_event *event, 1031 1040 struct perf_sample *sample, 1032 1041 struct machine *machine) 1033 1042 { 1034 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); 1035 1052 } 1036 1053 1037 1054 int perf_event__process_lost(struct perf_tool *tool __maybe_unused, ··· 1248 1195 break; 1249 1196 case PERF_RECORD_MMAP: 1250 1197 ret += perf_event__fprintf_mmap(event, fp); 1198 + break; 1199 + case PERF_RECORD_NAMESPACES: 1200 + ret += perf_event__fprintf_namespaces(event, fp); 1251 1201 break; 1252 1202 case PERF_RECORD_MMAP2: 1253 1203 ret += perf_event__fprintf_mmap2(event, fp);
+13
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, ··· 665 653 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); 666 654 size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); 667 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); 668 657 size_t perf_event__fprintf(union perf_event *event, FILE *fp); 669 658 670 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
+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 */
+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 }
+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 */