lkml.org 
[lkml]   [2017]   [Feb]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH v6 2/3] perf tool: add PERF_RECORD_NAMESPACES to include namespaces related info
    From
    Date
    This patch updates perf tool to examine PERF_RECORD_NAMESPACES events
    emitted by the kernel when fork, clone, setns or unshare are invoked.
    Also, it synthesizes PERF_RECORD_NAMESPACES events for processes that
    were running prior to invocation of perf record, the data for which
    is taken from /proc/$PID/ns. These changes make way for analyzing
    events with regard to namespaces.

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

    diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
    index c66a485..ee60f54 100644
    --- a/tools/include/uapi/linux/perf_event.h
    +++ b/tools/include/uapi/linux/perf_event.h
    @@ -344,7 +344,8 @@ struct perf_event_attr {
    use_clockid : 1, /* use @clockid for time fields */
    context_switch : 1, /* context switch data */
    write_backward : 1, /* Write ring buffer from end to beginning */
    - __reserved_1 : 36;
    + namespaces : 1, /* include namespaces data */
    + __reserved_1 : 35;

    union {
    __u32 wakeup_events; /* wakeup every n events */
    @@ -610,6 +611,29 @@ struct perf_event_header {
    __u16 size;
    };

    +/*
    + * The maximum size of the name of each namespace
    + */
    +#define NS_NAME_SIZE 8
    +
    +struct perf_ns_link_info {
    + char name[NS_NAME_SIZE];
    + __u64 dev;
    + __u64 ino;
    +};
    +
    +enum {
    + NET_NS_INDEX = 0,
    + UTS_NS_INDEX = 1,
    + IPC_NS_INDEX = 2,
    + PID_NS_INDEX = 3,
    + USER_NS_INDEX = 4,
    + MNT_NS_INDEX = 5,
    + CGROUP_NS_INDEX = 6,
    +
    + NAMESPACES_MAX, /* maximum available namespaces */
    +};
    +
    enum perf_event_type {

    /*
    @@ -862,6 +886,18 @@ enum perf_event_type {
    */
    PERF_RECORD_SWITCH_CPU_WIDE = 15,

    + /*
    + * struct {
    + * struct perf_event_header header;
    + * u32 pid;
    + * u32 tid;
    + * u32 nr_namespaces;
    + * struct namespace_link_info link_info[NAMESPACES_MAX];
    + * struct sample_id sample_id;
    + * };
    + */
    + PERF_RECORD_NAMESPACES = 16,
    +
    PERF_RECORD_MAX, /* non-ABI */
    };

    diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
    index ebb6283..1b63dc4 100644
    --- a/tools/perf/builtin-annotate.c
    +++ b/tools/perf/builtin-annotate.c
    @@ -393,6 +393,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
    .comm = perf_event__process_comm,
    .exit = perf_event__process_exit,
    .fork = perf_event__process_fork,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    .ordering_requires_timestamps = true,
    },
    diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
    index 933aeec..37cfbaa 100644
    --- a/tools/perf/builtin-diff.c
    +++ b/tools/perf/builtin-diff.c
    @@ -354,6 +354,7 @@ static struct perf_tool tool = {
    .exit = perf_event__process_exit,
    .fork = perf_event__process_fork,
    .lost = perf_event__process_lost,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    .ordering_requires_timestamps = true,
    };
    diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
    index b9bc7e3..c5ddc73 100644
    --- a/tools/perf/builtin-inject.c
    +++ b/tools/perf/builtin-inject.c
    @@ -333,6 +333,19 @@ static int perf_event__repipe_comm(struct perf_tool *tool,
    return err;
    }

    +static int perf_event__repipe_namespaces(struct perf_tool *tool,
    + union perf_event *event,
    + struct perf_sample *sample,
    + struct machine *machine)
    +{
    + int err;
    +
    + err = perf_event__process_namespaces(tool, event, sample, machine);
    + perf_event__repipe(tool, event, sample, machine);
    +
    + return err;
    +}
    +
    static int perf_event__repipe_exit(struct perf_tool *tool,
    union perf_event *event,
    struct perf_sample *sample,
    @@ -660,6 +673,7 @@ static int __cmd_inject(struct perf_inject *inject)
    session->itrace_synth_opts = &inject->itrace_synth_opts;
    inject->itrace_synth_opts.inject = true;
    inject->tool.comm = perf_event__repipe_comm;
    + inject->tool.namespaces = perf_event__repipe_namespaces;
    inject->tool.exit = perf_event__repipe_exit;
    inject->tool.id_index = perf_event__repipe_id_index;
    inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
    diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
    index 29f4751..1b53852 100644
    --- a/tools/perf/builtin-kmem.c
    +++ b/tools/perf/builtin-kmem.c
    @@ -964,6 +964,7 @@ static struct perf_tool perf_kmem = {
    .comm = perf_event__process_comm,
    .mmap = perf_event__process_mmap,
    .mmap2 = perf_event__process_mmap2,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    };

    diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
    index 08fa88f..18e6c38 100644
    --- a/tools/perf/builtin-kvm.c
    +++ b/tools/perf/builtin-kvm.c
    @@ -1044,6 +1044,7 @@ static int read_events(struct perf_kvm_stat *kvm)
    struct perf_tool eops = {
    .sample = process_sample_event,
    .comm = perf_event__process_comm,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    };
    struct perf_data_file file = {
    @@ -1348,6 +1349,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
    kvm->tool.exit = perf_event__process_exit;
    kvm->tool.fork = perf_event__process_fork;
    kvm->tool.lost = process_lost_event;
    + kvm->tool.namespaces = perf_event__process_namespaces;
    kvm->tool.ordered_events = true;
    perf_tool__fill_defaults(&kvm->tool);

    diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
    index ce3bfb4..d750cca 100644
    --- a/tools/perf/builtin-lock.c
    +++ b/tools/perf/builtin-lock.c
    @@ -858,6 +858,7 @@ static int __cmd_report(bool display_info)
    struct perf_tool eops = {
    .sample = process_sample_event,
    .comm = perf_event__process_comm,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    };
    struct perf_data_file file = {
    diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
    index cd7bc4d..430656c 100644
    --- a/tools/perf/builtin-mem.c
    +++ b/tools/perf/builtin-mem.c
    @@ -342,6 +342,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
    .lost = perf_event__process_lost,
    .fork = perf_event__process_fork,
    .build_id = perf_event__process_build_id,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    },
    .input_name = "perf.data",
    diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
    index ffac8ca..1946a17 100644
    --- a/tools/perf/builtin-record.c
    +++ b/tools/perf/builtin-record.c
    @@ -875,6 +875,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
    signal(SIGTERM, sig_handler);
    signal(SIGSEGV, sigsegv_handler);

    + if (rec->opts.record_namespaces)
    + tool->namespace_events = true;
    +
    if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) {
    signal(SIGUSR2, snapshot_sig_handler);
    if (rec->opts.auxtrace_snapshot_mode)
    @@ -982,6 +985,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
    */
    if (forks) {
    union perf_event *event;
    + pid_t tgid;

    event = malloc(sizeof(event->comm) + machine->id_hdr_size);
    if (event == NULL) {
    @@ -995,10 +999,28 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
    * cannot see a correct process name for those events.
    * Synthesize COMM event to prevent it.
    */
    - perf_event__synthesize_comm(tool, event,
    - rec->evlist->workload.pid,
    - process_synthesized_event,
    - machine);
    + tgid = perf_event__synthesize_comm(tool, event,
    + rec->evlist->workload.pid,
    + process_synthesized_event,
    + machine);
    + free(event);
    +
    + if (tgid == -1)
    + goto out_child;
    +
    + event = malloc(sizeof(event->namespaces) + machine->id_hdr_size);
    + if (event == NULL) {
    + err = -ENOMEM;
    + goto out_child;
    + }
    +
    + /*
    + * Synthesize NAMESPACES event for the command specified.
    + */
    + perf_event__synthesize_namespaces(tool, event,
    + rec->evlist->workload.pid,
    + tgid, process_synthesized_event,
    + machine);
    free(event);

    perf_evlist__start_workload(rec->evlist);
    @@ -1496,6 +1518,7 @@ static struct record record = {
    .fork = perf_event__process_fork,
    .exit = perf_event__process_exit,
    .comm = perf_event__process_comm,
    + .namespaces = perf_event__process_namespaces,
    .mmap = perf_event__process_mmap,
    .mmap2 = perf_event__process_mmap2,
    .ordered_events = true,
    @@ -1610,6 +1633,8 @@ static struct option __record_options[] = {
    "opts", "AUX area tracing Snapshot Mode", ""),
    OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
    "per thread proc mmap processing timeout in ms"),
    + OPT_BOOLEAN(0, "namespaces", &record.opts.record_namespaces,
    + "Record namespaces events"),
    OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
    "Record context switch events"),
    OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
    diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
    index dbd7fa0..5c92c75 100644
    --- a/tools/perf/builtin-report.c
    +++ b/tools/perf/builtin-report.c
    @@ -694,6 +694,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
    .mmap = perf_event__process_mmap,
    .mmap2 = perf_event__process_mmap2,
    .comm = perf_event__process_comm,
    + .namespaces = perf_event__process_namespaces,
    .exit = perf_event__process_exit,
    .fork = perf_event__process_fork,
    .lost = perf_event__process_lost,
    diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
    index daceb32..109baf6 100644
    --- a/tools/perf/builtin-sched.c
    +++ b/tools/perf/builtin-sched.c
    @@ -3272,6 +3272,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
    .tool = {
    .sample = perf_sched__process_tracepoint_sample,
    .comm = perf_event__process_comm,
    + .namespaces = perf_event__process_namespaces,
    .lost = perf_event__process_lost,
    .fork = perf_sched__process_fork_event,
    .ordered_events = true,
    diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
    index c0783b4..b0672cc 100644
    --- a/tools/perf/builtin-script.c
    +++ b/tools/perf/builtin-script.c
    @@ -830,6 +830,7 @@ struct perf_script {
    bool show_task_events;
    bool show_mmap_events;
    bool show_switch_events;
    + bool show_namespaces_events;
    bool allocated;
    struct cpu_map *cpus;
    struct thread_map *threads;
    @@ -1118,6 +1119,41 @@ static int process_comm_event(struct perf_tool *tool,
    return ret;
    }

    +static int process_namespaces_event(struct perf_tool *tool,
    + union perf_event *event,
    + struct perf_sample *sample,
    + struct machine *machine)
    +{
    + struct thread *thread;
    + struct perf_script *script = container_of(tool, struct perf_script, tool);
    + struct perf_session *session = script->session;
    + struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
    + int ret = -1;
    +
    + thread = machine__findnew_thread(machine, event->namespaces.pid,
    + event->namespaces.tid);
    + if (thread == NULL) {
    + pr_debug("problem processing NAMESPACES event, skipping it.\n");
    + return -1;
    + }
    +
    + if (perf_event__process_namespaces(tool, event, sample, machine) < 0)
    + goto out;
    +
    + if (!evsel->attr.sample_id_all) {
    + sample->cpu = 0;
    + sample->time = 0;
    + sample->tid = event->namespaces.tid;
    + sample->pid = event->namespaces.pid;
    + }
    + print_sample_start(sample, thread, evsel);
    + perf_event__fprintf(event, stdout);
    + ret = 0;
    +out:
    + thread__put(thread);
    + return ret;
    +}
    +
    static int process_fork_event(struct perf_tool *tool,
    union perf_event *event,
    struct perf_sample *sample,
    @@ -1293,6 +1329,8 @@ static int __cmd_script(struct perf_script *script)
    }
    if (script->show_switch_events)
    script->tool.context_switch = process_switch_event;
    + if (script->show_namespaces_events)
    + script->tool.namespaces = process_namespaces_event;

    ret = perf_session__process_events(script->session);

    @@ -2097,6 +2135,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
    .mmap = perf_event__process_mmap,
    .mmap2 = perf_event__process_mmap2,
    .comm = perf_event__process_comm,
    + .namespaces = perf_event__process_namespaces,
    .exit = perf_event__process_exit,
    .fork = perf_event__process_fork,
    .attr = process_attr,
    @@ -2180,6 +2219,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
    "Show the mmap events"),
    OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events,
    "Show context switch events (if recorded)"),
    + OPT_BOOLEAN('\0', "show-namespaces-events", &script.show_namespaces_events,
    + "Show namespaces events (if recorded)"),
    OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
    OPT_BOOLEAN(0, "ns", &nanosecs,
    "Use 9 decimal places when displaying time"),
    diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
    index 40ef9b2..0bcd32f 100644
    --- a/tools/perf/builtin-trace.c
    +++ b/tools/perf/builtin-trace.c
    @@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace)
    trace->tool.exit = perf_event__process_exit;
    trace->tool.fork = perf_event__process_fork;
    trace->tool.attr = perf_event__process_attr;
    - trace->tool.tracing_data = perf_event__process_tracing_data;
    + trace->tool.tracing_data = perf_event__process_tracing_data;
    trace->tool.build_id = perf_event__process_build_id;
    + trace->tool.namespaces = perf_event__process_namespaces;

    trace->tool.ordered_events = true;
    trace->tool.ordering_requires_timestamps = true;
    diff --git a/tools/perf/perf.h b/tools/perf/perf.h
    index 1c27d94..806c216 100644
    --- a/tools/perf/perf.h
    +++ b/tools/perf/perf.h
    @@ -50,6 +50,7 @@ struct record_opts {
    bool running_time;
    bool full_auxtrace;
    bool auxtrace_snapshot_mode;
    + bool record_namespaces;
    bool record_switch_events;
    bool all_kernel;
    bool all_user;
    diff --git a/tools/perf/util/Build b/tools/perf/util/Build
    index 5da376b..2ea5ee1 100644
    --- a/tools/perf/util/Build
    +++ b/tools/perf/util/Build
    @@ -42,6 +42,7 @@ libperf-y += pstack.o
    libperf-y += session.o
    libperf-$(CONFIG_AUDIT) += syscalltbl.o
    libperf-y += ordered-events.o
    +libperf-y += namespaces.o
    libperf-y += comm.o
    libperf-y += thread.o
    libperf-y += thread_map.o
    diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
    index 4e6cbc9..3b408f7 100644
    --- a/tools/perf/util/data-convert-bt.c
    +++ b/tools/perf/util/data-convert-bt.c
    @@ -1468,6 +1468,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
    .lost = perf_event__process_lost,
    .tracing_data = perf_event__process_tracing_data,
    .build_id = perf_event__process_build_id,
    + .namespaces = perf_event__process_namespaces,
    .ordered_events = true,
    .ordering_requires_timestamps = true,
    },
    @@ -1479,6 +1480,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
    c.tool.comm = process_comm_event;
    c.tool.exit = process_exit_event;
    c.tool.fork = process_fork_event;
    + c.tool.namespaces = process_namespaces_event;
    }

    err = perf_config(convert__config, &c);
    diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
    index 8ab0d7d..0ac1a8d 100644
    --- a/tools/perf/util/event.c
    +++ b/tools/perf/util/event.c
    @@ -31,6 +31,7 @@ static const char *perf_event__names[] = {
    [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES",
    [PERF_RECORD_SWITCH] = "SWITCH",
    [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE",
    + [PERF_RECORD_NAMESPACES] = "NAMESPACES",
    [PERF_RECORD_HEADER_ATTR] = "ATTR",
    [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
    [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
    @@ -203,6 +204,74 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
    return tgid;
    }

    +static void perf_event__get_ns_link_info(pid_t pid, const char *ns,
    + struct perf_ns_link_info *ns_link_info)
    +{
    + struct stat64 st;
    + char proc_ns[128];
    +
    + snprintf(ns_link_info->name, NS_NAME_SIZE, "%s", ns);
    +
    + sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
    + if (stat64(proc_ns, &st) == 0) {
    + ns_link_info->dev = st.st_dev;
    + ns_link_info->ino = st.st_ino;
    + }
    +}
    +
    +int perf_event__synthesize_namespaces(struct perf_tool *tool,
    + union perf_event *event,
    + pid_t pid, pid_t tgid,
    + perf_event__handler_t process,
    + struct machine *machine)
    +{
    + struct perf_ns_link_info *ns_link_info;
    +
    + if (!tool->namespace_events)
    + return 0;
    +
    + memset(&event->namespaces, 0,
    + sizeof(event->namespaces) + machine->id_hdr_size);
    +
    + event->namespaces.pid = tgid;
    + event->namespaces.tid = pid;
    +
    + event->namespaces.nr_namespaces = NAMESPACES_MAX;
    +
    + ns_link_info = event->namespaces.link_info;
    +
    + perf_event__get_ns_link_info(pid, "mnt",
    + &ns_link_info[MNT_NS_INDEX]);
    +
    + perf_event__get_ns_link_info(pid, "net",
    + &ns_link_info[NET_NS_INDEX]);
    +
    + perf_event__get_ns_link_info(pid, "uts",
    + &ns_link_info[UTS_NS_INDEX]);
    +
    + perf_event__get_ns_link_info(pid, "ipc",
    + &ns_link_info[IPC_NS_INDEX]);
    +
    + perf_event__get_ns_link_info(pid, "pid",
    + &ns_link_info[PID_NS_INDEX]);
    +
    + perf_event__get_ns_link_info(pid, "user",
    + &ns_link_info[USER_NS_INDEX]);
    +
    + perf_event__get_ns_link_info(pid, "cgroup",
    + &ns_link_info[CGROUP_NS_INDEX]);
    +
    + event->namespaces.header.type = PERF_RECORD_NAMESPACES;
    +
    + event->namespaces.header.size = (sizeof(event->namespaces) +
    + machine->id_hdr_size);
    +
    + if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
    + return -1;
    +
    + return 0;
    +}
    +
    static int perf_event__synthesize_fork(struct perf_tool *tool,
    union perf_event *event,
    pid_t pid, pid_t tgid, pid_t ppid,
    @@ -434,8 +503,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
    static int __event__synthesize_thread(union perf_event *comm_event,
    union perf_event *mmap_event,
    union perf_event *fork_event,
    + union perf_event *namespaces_event,
    pid_t pid, int full,
    - perf_event__handler_t process,
    + perf_event__handler_t process,
    struct perf_tool *tool,
    struct machine *machine,
    bool mmap_data,
    @@ -455,6 +525,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
    if (tgid == -1)
    return -1;

    + if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,
    + tgid, process, machine) < 0)
    + return -1;
    +
    +
    return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
    process, machine, mmap_data,
    proc_map_timeout);
    @@ -488,6 +563,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
    if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
    ppid, process, machine) < 0)
    break;
    +
    + if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
    + tgid, process, machine) < 0)
    + break;
    +
    /*
    * Send the prepared comm event
    */
    @@ -516,6 +596,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
    unsigned int proc_map_timeout)
    {
    union perf_event *comm_event, *mmap_event, *fork_event;
    + union perf_event *namespaces_event;
    int err = -1, thread, j;

    comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
    @@ -530,10 +611,15 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
    if (fork_event == NULL)
    goto out_free_mmap;

    + namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
    + machine->id_hdr_size);
    + if (namespaces_event == NULL)
    + goto out_free_fork;
    +
    err = 0;
    for (thread = 0; thread < threads->nr; ++thread) {
    if (__event__synthesize_thread(comm_event, mmap_event,
    - fork_event,
    + fork_event, namespaces_event,
    thread_map__pid(threads, thread), 0,
    process, tool, machine,
    mmap_data, proc_map_timeout)) {
    @@ -559,7 +645,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
    /* if not, generate events for it */
    if (need_leader &&
    __event__synthesize_thread(comm_event, mmap_event,
    - fork_event,
    + fork_event, namespaces_event,
    comm_event->comm.pid, 0,
    process, tool, machine,
    mmap_data, proc_map_timeout)) {
    @@ -568,6 +654,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
    }
    }
    }
    + free(namespaces_event);
    +out_free_fork:
    free(fork_event);
    out_free_mmap:
    free(mmap_event);
    @@ -587,6 +675,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
    char proc_path[PATH_MAX];
    struct dirent *dirent;
    union perf_event *comm_event, *mmap_event, *fork_event;
    + union perf_event *namespaces_event;
    int err = -1;

    if (machine__is_default_guest(machine))
    @@ -604,11 +693,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
    if (fork_event == NULL)
    goto out_free_mmap;

    + namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
    + machine->id_hdr_size);
    + if (namespaces_event == NULL)
    + goto out_free_fork;
    +
    snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
    proc = opendir(proc_path);

    if (proc == NULL)
    - goto out_free_fork;
    + goto out_free_namespaces;

    while ((dirent = readdir(proc)) != NULL) {
    char *end;
    @@ -620,13 +714,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
    * We may race with exiting thread, so don't stop just because
    * one thread couldn't be synthesized.
    */
    - __event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
    - 1, process, tool, machine, mmap_data,
    + __event__synthesize_thread(comm_event, mmap_event, fork_event,
    + namespaces_event, pid, 1, process,
    + tool, machine, mmap_data,
    proc_map_timeout);
    }

    err = 0;
    closedir(proc);
    +out_free_namespaces:
    + free(namespaces_event);
    out_free_fork:
    free(fork_event);
    out_free_mmap:
    @@ -1008,6 +1105,29 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
    return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
    }

    +size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
    +{
    + size_t ret = 0;
    + struct perf_ns_link_info *ns_link_info;
    + u32 nr_namespaces, idx;
    +
    + ns_link_info = event->namespaces.link_info;
    + nr_namespaces = event->namespaces.nr_namespaces;
    +
    + ret += fprintf(fp, " %d/%d - nr_namespaces: %u [",
    + event->namespaces.pid,
    + event->namespaces.tid,
    + nr_namespaces);
    +
    + for (idx = 0; idx < nr_namespaces; idx++)
    + ret += fprintf(fp, "%s: %lu/0x%lx%s", ns_link_info[idx].name,
    + (u64)ns_link_info[idx].dev,
    + (u64)ns_link_info[idx].ino,
    + ((idx + 1) != nr_namespaces) ? ", " : "]\n\n");
    +
    + return ret;
    +}
    +
    int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
    union perf_event *event,
    struct perf_sample *sample,
    @@ -1016,6 +1136,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
    return machine__process_comm_event(machine, event, sample);
    }

    +int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused,
    + union perf_event *event,
    + struct perf_sample *sample,
    + struct machine *machine)
    +{
    + return machine__process_namespaces_event(machine, event, sample);
    +}
    +
    int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
    union perf_event *event,
    struct perf_sample *sample,
    @@ -1196,6 +1324,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
    case PERF_RECORD_MMAP:
    ret += perf_event__fprintf_mmap(event, fp);
    break;
    + case PERF_RECORD_NAMESPACES:
    + ret += perf_event__fprintf_namespaces(event, fp);
    + break;
    case PERF_RECORD_MMAP2:
    ret += perf_event__fprintf_mmap2(event, fp);
    break;
    diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
    index c735c53..09fde83 100644
    --- a/tools/perf/util/event.h
    +++ b/tools/perf/util/event.h
    @@ -39,6 +39,13 @@ struct comm_event {
    char comm[16];
    };

    +struct namespaces_event {
    + struct perf_event_header header;
    + u32 pid, tid;
    + u32 nr_namespaces;
    + struct perf_ns_link_info link_info[NAMESPACES_MAX];
    +};
    +
    struct fork_event {
    struct perf_event_header header;
    u32 pid, ppid;
    @@ -485,6 +492,7 @@ union perf_event {
    struct mmap_event mmap;
    struct mmap2_event mmap2;
    struct comm_event comm;
    + struct namespaces_event namespaces;
    struct fork_event fork;
    struct lost_event lost;
    struct lost_samples_event lost_samples;
    @@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool,
    union perf_event *event,
    struct perf_sample *sample,
    struct machine *machine);
    +int perf_event__process_namespaces(struct perf_tool *tool,
    + union perf_event *event,
    + struct perf_sample *sample,
    + struct machine *machine);
    int perf_event__process_mmap(struct perf_tool *tool,
    union perf_event *event,
    struct perf_sample *sample,
    @@ -636,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
    perf_event__handler_t process,
    struct machine *machine);

    +int perf_event__synthesize_namespaces(struct perf_tool *tool,
    + union perf_event *event,
    + pid_t pid, pid_t tgid,
    + perf_event__handler_t process,
    + struct machine *machine);
    +
    int perf_event__synthesize_mmap_events(struct perf_tool *tool,
    union perf_event *event,
    pid_t pid, pid_t tgid,
    @@ -653,6 +671,7 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
    size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
    size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
    size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
    +size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
    size_t perf_event__fprintf(union perf_event *event, FILE *fp);

    u64 kallsyms__get_function_start(const char *kallsyms_filename,
    diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
    index 04e536a..e94f807 100644
    --- a/tools/perf/util/evsel.c
    +++ b/tools/perf/util/evsel.c
    @@ -932,6 +932,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
    attr->mmap2 = track && !perf_missing_features.mmap2;
    attr->comm = track;

    + if (opts->record_namespaces)
    + attr->namespaces = track;
    +
    if (opts->record_switch_events)
    attr->context_switch = track;

    diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
    index 747a034..ecdf1f0 100644
    --- a/tools/perf/util/machine.c
    +++ b/tools/perf/util/machine.c
    @@ -13,6 +13,7 @@
    #include <symbol/kallsyms.h>
    #include "unwind.h"
    #include "linux/hash.h"
    +#include "asm/bug.h"

    static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);

    @@ -501,6 +502,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
    return err;
    }

    +int machine__process_namespaces_event(struct machine *machine __maybe_unused,
    + union perf_event *event,
    + struct perf_sample *sample __maybe_unused)
    +{
    + struct thread *thread = machine__findnew_thread(machine,
    + event->namespaces.pid,
    + event->namespaces.tid);
    + int err = 0;
    +
    + WARN_ONCE(event->namespaces.nr_namespaces > NAMESPACES_MAX,
    + "\nWARNING: kernel seems to support more namespaces than perf"
    + " tool.\nTry updating the perf tool..\n\n");
    +
    + WARN_ONCE(event->namespaces.nr_namespaces < NAMESPACES_MAX,
    + "\nWARNING: perf tool seems to support more namespaces than"
    + " the kernel.\nTry updating the kernel..\n\n");
    +
    + if (dump_trace)
    + perf_event__fprintf_namespaces(event, stdout);
    +
    + if (thread == NULL ||
    + thread__set_namespaces(thread, sample->time, &event->namespaces)) {
    + dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
    + err = -1;
    + }
    +
    + thread__put(thread);
    +
    + return err;
    +}
    +
    int machine__process_lost_event(struct machine *machine __maybe_unused,
    union perf_event *event, struct perf_sample *sample __maybe_unused)
    {
    @@ -1538,6 +1570,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
    ret = machine__process_comm_event(machine, event, sample); break;
    case PERF_RECORD_MMAP:
    ret = machine__process_mmap_event(machine, event, sample); break;
    + case PERF_RECORD_NAMESPACES:
    + ret = machine__process_namespaces_event(machine, event, sample); break;
    case PERF_RECORD_MMAP2:
    ret = machine__process_mmap2_event(machine, event, sample); break;
    case PERF_RECORD_FORK:
    diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
    index a283050..3cdb134 100644
    --- a/tools/perf/util/machine.h
    +++ b/tools/perf/util/machine.h
    @@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine,
    union perf_event *event);
    int machine__process_switch_event(struct machine *machine,
    union perf_event *event);
    +int machine__process_namespaces_event(struct machine *machine,
    + union perf_event *event,
    + struct perf_sample *sample);
    int machine__process_mmap_event(struct machine *machine, union perf_event *event,
    struct perf_sample *sample);
    int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
    diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
    new file mode 100644
    index 0000000..3134c00
    --- /dev/null
    +++ b/tools/perf/util/namespaces.c
    @@ -0,0 +1,35 @@
    +/*
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License, version 2, as
    + * published by the Free Software Foundation.
    + *
    + * Copyright (C) 2017 Hari Bathini, IBM Corporation
    + */
    +
    +#include "namespaces.h"
    +#include "util.h"
    +#include "event.h"
    +#include <stdlib.h>
    +#include <stdio.h>
    +
    +struct namespaces *namespaces__new(struct namespaces_event *event)
    +{
    + struct namespaces *namespaces = zalloc(sizeof(*namespaces));
    +
    + if (!namespaces)
    + return NULL;
    +
    + namespaces->end_time = -1;
    +
    + if (event) {
    + memcpy(namespaces->link_info, event->link_info,
    + sizeof(namespaces->link_info));
    + }
    +
    + return namespaces;
    +}
    +
    +void namespaces__free(struct namespaces *namespaces)
    +{
    + free(namespaces);
    +}
    diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
    new file mode 100644
    index 0000000..e42487e
    --- /dev/null
    +++ b/tools/perf/util/namespaces.h
    @@ -0,0 +1,26 @@
    +/*
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License, version 2, as
    + * published by the Free Software Foundation.
    + *
    + * Copyright (C) 2017 Hari Bathini, IBM Corporation
    + */
    +
    +#ifndef __PERF_NAMESPACES_H
    +#define __PERF_NAMESPACES_H
    +
    +#include "../perf.h"
    +#include <linux/list.h>
    +
    +struct namespaces_event;
    +
    +struct namespaces {
    + struct list_head list;
    + u64 end_time;
    + struct perf_ns_link_info link_info[NAMESPACES_MAX];
    +};
    +
    +struct namespaces *namespaces__new(struct namespaces_event *event);
    +void namespaces__free(struct namespaces *namespaces);
    +
    +#endif /* __PERF_NAMESPACES_H */
    diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
    index 349c681..d868661 100644
    --- a/tools/perf/util/session.c
    +++ b/tools/perf/util/session.c
    @@ -1239,6 +1239,8 @@ static int machines__deliver_event(struct machines *machines,
    return tool->mmap2(tool, event, sample, machine);
    case PERF_RECORD_COMM:
    return tool->comm(tool, event, sample, machine);
    + case PERF_RECORD_NAMESPACES:
    + return tool->namespaces(tool, event, sample, machine);
    case PERF_RECORD_FORK:
    return tool->fork(tool, event, sample, machine);
    case PERF_RECORD_EXIT:
    @@ -1494,6 +1496,11 @@ int perf_session__register_idle_thread(struct perf_session *session)
    err = -1;
    }

    + if (thread == NULL || thread__set_namespaces(thread, 0, NULL)) {
    + pr_err("problem inserting idle task.\n");
    + err = -1;
    + }
    +
    /* machine__findnew_thread() got the thread, so put it */
    thread__put(thread);
    return err;
    diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
    index f5af87f..b9fe432 100644
    --- a/tools/perf/util/thread.c
    +++ b/tools/perf/util/thread.c
    @@ -7,6 +7,7 @@
    #include "thread-stack.h"
    #include "util.h"
    #include "debug.h"
    +#include "namespaces.h"
    #include "comm.h"
    #include "unwind.h"

    @@ -40,6 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
    thread->tid = tid;
    thread->ppid = -1;
    thread->cpu = -1;
    + INIT_LIST_HEAD(&thread->namespaces_list);
    INIT_LIST_HEAD(&thread->comm_list);

    comm_str = malloc(32);
    @@ -66,7 +68,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)

    void thread__delete(struct thread *thread)
    {
    - struct comm *comm, *tmp;
    + struct namespaces *namespaces, *tmp_namespaces;
    + struct comm *comm, *tmp_comm;

    BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));

    @@ -76,7 +79,12 @@ void thread__delete(struct thread *thread)
    map_groups__put(thread->mg);
    thread->mg = NULL;
    }
    - list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
    + list_for_each_entry_safe(namespaces, tmp_namespaces,
    + &thread->namespaces_list, list) {
    + list_del(&namespaces->list);
    + namespaces__free(namespaces);
    + }
    + list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
    list_del(&comm->list);
    comm__free(comm);
    }
    @@ -104,6 +112,38 @@ void thread__put(struct thread *thread)
    }
    }

    +struct namespaces *thread__namespaces(const struct thread *thread)
    +{
    + if (list_empty(&thread->namespaces_list))
    + return NULL;
    +
    + return list_first_entry(&thread->namespaces_list, struct namespaces, list);
    +}
    +
    +int thread__set_namespaces(struct thread *thread, u64 timestamp,
    + struct namespaces_event *event)
    +{
    + struct namespaces *new, *curr = thread__namespaces(thread);
    +
    + new = namespaces__new(event);
    + if (!new)
    + return -ENOMEM;
    +
    + list_add(&new->list, &thread->namespaces_list);
    +
    + if (timestamp && curr) {
    + /*
    + * setns syscall must have changed few or all the namespaces
    + * of this thread. Update end time for the namespaces
    + * previously used.
    + */
    + curr = list_next_entry(new, list);
    + curr->end_time = timestamp;
    + }
    +
    + return 0;
    +}
    +
    struct comm *thread__comm(const struct thread *thread)
    {
    if (list_empty(&thread->comm_list))
    diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
    index 99263cb..b18b5a2 100644
    --- a/tools/perf/util/thread.h
    +++ b/tools/perf/util/thread.h
    @@ -28,6 +28,7 @@ struct thread {
    bool comm_set;
    int comm_len;
    bool dead; /* if set thread has exited */
    + struct list_head namespaces_list;
    struct list_head comm_list;
    u64 db_id;

    @@ -40,6 +41,7 @@ struct thread {
    };

    struct machine;
    +struct namespaces;
    struct comm;

    struct thread *thread__new(pid_t pid, pid_t tid);
    @@ -62,6 +64,10 @@ static inline void thread__exited(struct thread *thread)
    thread->dead = true;
    }

    +struct namespaces *thread__namespaces(const struct thread *thread);
    +int thread__set_namespaces(struct thread *thread, u64 timestamp,
    + struct namespaces_event *event);
    +
    int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
    bool exec);
    static inline int thread__set_comm(struct thread *thread, const char *comm,
    diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
    index ac2590a..829471a 100644
    --- a/tools/perf/util/tool.h
    +++ b/tools/perf/util/tool.h
    @@ -40,6 +40,7 @@ struct perf_tool {
    event_op mmap,
    mmap2,
    comm,
    + namespaces,
    fork,
    exit,
    lost,
    @@ -66,6 +67,7 @@ struct perf_tool {
    event_op3 auxtrace;
    bool ordered_events;
    bool ordering_requires_timestamps;
    + bool namespace_events;
    };

    #endif /* __PERF_TOOL_H */
    \
     
     \ /
      Last update: 2017-02-08 09:33    [W:3.350 / U:0.740 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site