perf tools: Basic support for CGROUP event
authorNamhyung Kim <namhyung@kernel.org>
Wed, 25 Mar 2020 12:45:30 +0000 (21:45 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 3 Apr 2020 12:37:55 +0000 (09:37 -0300)
Implement basic functionality to support cgroup tracking.  Each cgroup
can be identified by inode number which can be read from userspace too.
The actual cgroup processing will come in the later patch.

Reported-by: kernel test robot <rong.a.chen@intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
[ fix perf test failure on sampling parsing ]
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20200325124536.2800725-4-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
13 files changed:
tools/lib/perf/include/perf/event.h
tools/perf/builtin-diff.c
tools/perf/builtin-report.c
tools/perf/tests/sample-parsing.c
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/perf_event_attr_fprintf.c
tools/perf/util/session.c
tools/perf/util/synthetic-events.c
tools/perf/util/tool.h

index 18106899cb4eb19f28d1567858ee5229e146ab0b..69b44d2cc0f5001cb3098870555608c17c9f72b2 100644 (file)
@@ -105,6 +105,12 @@ struct perf_record_bpf_event {
        __u8                     tag[BPF_TAG_SIZE];  // prog tag
 };
 
+struct perf_record_cgroup {
+       struct perf_event_header header;
+       __u64                    id;
+       char                     path[PATH_MAX];
+};
+
 struct perf_record_sample {
        struct perf_event_header header;
        __u64                    array[];
@@ -352,6 +358,7 @@ union perf_event {
        struct perf_record_mmap2                mmap2;
        struct perf_record_comm                 comm;
        struct perf_record_namespaces           namespaces;
+       struct perf_record_cgroup               cgroup;
        struct perf_record_fork                 fork;
        struct perf_record_lost                 lost;
        struct perf_record_lost_samples         lost_samples;
index 5e697cd2224a5b0d4e70d1c907ad36048d8a1dcd..c94a002f295e007f05426d2edd6520cc3d3a4a37 100644 (file)
@@ -455,6 +455,7 @@ static struct perf_diff pdiff = {
                .fork   = perf_event__process_fork,
                .lost   = perf_event__process_lost,
                .namespaces = perf_event__process_namespaces,
+               .cgroup = perf_event__process_cgroup,
                .ordered_events = true,
                .ordering_requires_timestamps = true,
        },
index ea673b7eb3f43bc8f4393e2c60932093cf6adc5e..26d8fc27e427ef1a95d6dc84786b106712f769ca 100644 (file)
@@ -1105,6 +1105,7 @@ int cmd_report(int argc, const char **argv)
                        .mmap2           = perf_event__process_mmap2,
                        .comm            = perf_event__process_comm,
                        .namespaces      = perf_event__process_namespaces,
+                       .cgroup          = perf_event__process_cgroup,
                        .exit            = perf_event__process_exit,
                        .fork            = perf_event__process_fork,
                        .lost            = perf_event__process_lost,
index 14239e4721870804096c589967a7c3046fab6138..61865699c3f4fc62dc8090bbd126e1cdcab1eba6 100644 (file)
@@ -151,6 +151,9 @@ static bool samples_same(const struct perf_sample *s1,
        if (type & PERF_SAMPLE_PHYS_ADDR)
                COMP(phys_addr);
 
+       if (type & PERF_SAMPLE_CGROUP)
+               COMP(cgroup);
+
        if (type & PERF_SAMPLE_AUX) {
                COMP(aux_sample.size);
                if (memcmp(s1->aux_sample.data, s2->aux_sample.data,
@@ -230,6 +233,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
                        .regs   = regs,
                },
                .phys_addr      = 113,
+               .cgroup         = 114,
                .aux_sample     = {
                        .size   = sizeof(aux_data),
                        .data   = (void *)aux_data,
@@ -336,7 +340,7 @@ int test__sample_parsing(struct test *test __maybe_unused, int subtest __maybe_u
         * were added.  Please actually update the test rather than just change
         * the condition below.
         */
-       if (PERF_SAMPLE_MAX > PERF_SAMPLE_AUX << 1) {
+       if (PERF_SAMPLE_MAX > PERF_SAMPLE_CGROUP << 1) {
                pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
                return -1;
        }
index c5447ff516a2dec7067aeb619fc946bdaf87682c..824c038e5c33d5df23291286e71cc90ec372363c 100644 (file)
@@ -54,6 +54,7 @@ static const char *perf_event__names[] = {
        [PERF_RECORD_NAMESPACES]                = "NAMESPACES",
        [PERF_RECORD_KSYMBOL]                   = "KSYMBOL",
        [PERF_RECORD_BPF_EVENT]                 = "BPF_EVENT",
+       [PERF_RECORD_CGROUP]                    = "CGROUP",
        [PERF_RECORD_HEADER_ATTR]               = "ATTR",
        [PERF_RECORD_HEADER_EVENT_TYPE]         = "EVENT_TYPE",
        [PERF_RECORD_HEADER_TRACING_DATA]       = "TRACING_DATA",
@@ -180,6 +181,12 @@ size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
        return ret;
 }
 
+size_t perf_event__fprintf_cgroup(union perf_event *event, FILE *fp)
+{
+       return fprintf(fp, " cgroup: %" PRI_lu64 " %s\n",
+                      event->cgroup.id, event->cgroup.path);
+}
+
 int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
                             union perf_event *event,
                             struct perf_sample *sample,
@@ -196,6 +203,14 @@ int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused,
        return machine__process_namespaces_event(machine, event, sample);
 }
 
+int perf_event__process_cgroup(struct perf_tool *tool __maybe_unused,
+                              union perf_event *event,
+                              struct perf_sample *sample,
+                              struct machine *machine)
+{
+       return machine__process_cgroup_event(machine, event, sample);
+}
+
 int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
                             union perf_event *event,
                             struct perf_sample *sample,
@@ -417,6 +432,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
        case PERF_RECORD_NAMESPACES:
                ret += perf_event__fprintf_namespaces(event, fp);
                break;
+       case PERF_RECORD_CGROUP:
+               ret += perf_event__fprintf_cgroup(event, fp);
+               break;
        case PERF_RECORD_MMAP2:
                ret += perf_event__fprintf_mmap2(event, fp);
                break;
index 3cda40a2fafc9b90fc0af61ee9dbefb744c0e4de..b8289f160f070965eb40595e22a8aad1533d48c7 100644 (file)
@@ -135,6 +135,7 @@ struct perf_sample {
        u32 raw_size;
        u64 data_src;
        u64 phys_addr;
+       u64 cgroup;
        u32 flags;
        u16 insn_len;
        u8  cpumode;
@@ -322,6 +323,10 @@ int perf_event__process_namespaces(struct perf_tool *tool,
                                   union perf_event *event,
                                   struct perf_sample *sample,
                                   struct machine *machine);
+int perf_event__process_cgroup(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,
@@ -377,6 +382,7 @@ 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_cgroup(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf(union perf_event *event, FILE *fp);
index 15ccd193483f190be2e33a48433ee914e566c046..b766eb608b97765aaa6ae34aa1e032d96bd47b51 100644 (file)
@@ -2267,6 +2267,12 @@ int perf_evsel__parse_sample(struct evsel *evsel, union perf_event *event,
                array++;
        }
 
+       data->cgroup = 0;
+       if (type & PERF_SAMPLE_CGROUP) {
+               data->cgroup = *array;
+               array++;
+       }
+
        if (type & PERF_SAMPLE_AUX) {
                OVERFLOW_CHECK_u64(array);
                sz = *array++;
index fd14f1489802040b8b7f30e0724608ac3891dff5..399b4731b24608c8e8e8130d22e93c58356f511d 100644 (file)
@@ -654,6 +654,16 @@ int machine__process_namespaces_event(struct machine *machine __maybe_unused,
        return err;
 }
 
+int machine__process_cgroup_event(struct machine *machine __maybe_unused,
+                                 union perf_event *event,
+                                 struct perf_sample *sample __maybe_unused)
+{
+       if (dump_trace)
+               perf_event__fprintf_cgroup(event, stdout);
+
+       return 0;
+}
+
 int machine__process_lost_event(struct machine *machine __maybe_unused,
                                union perf_event *event, struct perf_sample *sample __maybe_unused)
 {
@@ -1878,6 +1888,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
                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_CGROUP:
+               ret = machine__process_cgroup_event(machine, event, sample); break;
        case PERF_RECORD_MMAP2:
                ret = machine__process_mmap2_event(machine, event, sample); break;
        case PERF_RECORD_FORK:
index be0a930eca8968df5297c08d769d93eac0c09609..fa1be9ea00fa88a7b1150448958e35191254272e 100644 (file)
@@ -128,6 +128,9 @@ int machine__process_switch_event(struct machine *machine,
 int machine__process_namespaces_event(struct machine *machine,
                                      union perf_event *event,
                                      struct perf_sample *sample);
+int machine__process_cgroup_event(struct machine *machine,
+                                 union perf_event *event,
+                                 struct perf_sample *sample);
 int machine__process_mmap_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample);
 int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
index 355d3458d4e6910a723a4803d0295068505df0d6..b94fa07f5d3264fbcc7798fb20899044d96c2b93 100644 (file)
@@ -35,6 +35,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
                bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
                bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
                bit_name(WEIGHT), bit_name(PHYS_ADDR), bit_name(AUX),
+               bit_name(CGROUP),
                { .name = NULL, }
        };
 #undef bit_name
@@ -132,6 +133,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
        PRINT_ATTRf(ksymbol, p_unsigned);
        PRINT_ATTRf(bpf_event, p_unsigned);
        PRINT_ATTRf(aux_output, p_unsigned);
+       PRINT_ATTRf(cgroup, p_unsigned);
 
        PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned);
        PRINT_ATTRf(bp_type, p_unsigned);
index 055b00abd56d855b343f852d2139f41d360d0f6a..0b0bfe5bef17cd8cb86029e6aca07f9dccc0c72b 100644 (file)
@@ -471,6 +471,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->comm = process_event_stub;
        if (tool->namespaces == NULL)
                tool->namespaces = process_event_stub;
+       if (tool->cgroup == NULL)
+               tool->cgroup = process_event_stub;
        if (tool->fork == NULL)
                tool->fork = process_event_stub;
        if (tool->exit == NULL)
@@ -1436,6 +1438,8 @@ static int machines__deliver_event(struct machines *machines,
                return tool->comm(tool, event, sample, machine);
        case PERF_RECORD_NAMESPACES:
                return tool->namespaces(tool, event, sample, machine);
+       case PERF_RECORD_CGROUP:
+               return tool->cgroup(tool, event, sample, machine);
        case PERF_RECORD_FORK:
                return tool->fork(tool, event, sample, machine);
        case PERF_RECORD_EXIT:
index 3f28af39f9c645f811da57378a90711f234d206b..f72d80999506420b8f5c02f1e9e81e0a693982cd 100644 (file)
@@ -1230,6 +1230,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
        if (type & PERF_SAMPLE_PHYS_ADDR)
                result += sizeof(u64);
 
+       if (type & PERF_SAMPLE_CGROUP)
+               result += sizeof(u64);
+
        if (type & PERF_SAMPLE_AUX) {
                result += sizeof(u64);
                result += sample->aux_sample.size;
@@ -1404,6 +1407,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
                array++;
        }
 
+       if (type & PERF_SAMPLE_CGROUP) {
+               *array = sample->cgroup;
+               array++;
+       }
+
        if (type & PERF_SAMPLE_AUX) {
                sz = sample->aux_sample.size;
                *array++ = sz;
index 2abbf668b8dec1a2293cce9e7b6600a06823dd37..472ef5eb406861770e8490c5c93eb4962996d823 100644 (file)
@@ -46,6 +46,7 @@ struct perf_tool {
                        mmap2,
                        comm,
                        namespaces,
+                       cgroup,
                        fork,
                        exit,
                        lost,