OSDN Git Service

perf branch: Extend branch type classification
authorAnshuman Khandual <anshuman.khandual@arm.com>
Wed, 24 Aug 2022 04:48:20 +0000 (10:18 +0530)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 4 Oct 2022 11:55:20 +0000 (08:55 -0300)
This updates the perf tool with generic branch type classification with new
ABI extender place holder i.e PERF_BR_EXTEND_ABI, the new 4 bit branch type
field i.e perf_branch_entry.new_type, new generic page fault related branch
types and some arch specific branch types as added earlier in the kernel.

Committer note:

Add an extra entry to the branch_type_name array to cope with
PERF_BR_EXTEND_ABI, to address build warnings on some compiler/systems,
like:

  75     8.89 ubuntu:20.04-x-powerpc64el    : FAIL gcc version 10.3.0 (Ubuntu 10.3.0-1ubuntu1~20.04)
        inlined from 'branch_type_stat_display' at util/branch.c:152:4:
    /usr/powerpc64le-linux-gnu/include/bits/stdio2.h:100:10: error: '%8s' directive argument is null [-Werror=format-overflow=]
      100 |   return __fprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt,
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      101 |    __va_arg_pack ());
          |    ~~~~~~~~~~~~~~~~~

Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20220824044822.70230-7-anshuman.khandual@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/include/uapi/linux/perf_event.h
tools/perf/builtin-script.c
tools/perf/util/branch.c
tools/perf/util/branch.h
tools/perf/util/session.c

index 146c137..0f7c7ce 100644 (file)
@@ -255,9 +255,22 @@ enum {
        PERF_BR_IRQ             = 12,   /* irq */
        PERF_BR_SERROR          = 13,   /* system error */
        PERF_BR_NO_TX           = 14,   /* not in transaction */
+       PERF_BR_EXTEND_ABI      = 15,   /* extend ABI */
        PERF_BR_MAX,
 };
 
+enum {
+       PERF_BR_NEW_FAULT_ALGN          = 0,    /* Alignment fault */
+       PERF_BR_NEW_FAULT_DATA          = 1,    /* Data fault */
+       PERF_BR_NEW_FAULT_INST          = 2,    /* Inst fault */
+       PERF_BR_NEW_ARCH_1              = 3,    /* Architecture specific */
+       PERF_BR_NEW_ARCH_2              = 4,    /* Architecture specific */
+       PERF_BR_NEW_ARCH_3              = 5,    /* Architecture specific */
+       PERF_BR_NEW_ARCH_4              = 6,    /* Architecture specific */
+       PERF_BR_NEW_ARCH_5              = 7,    /* Architecture specific */
+       PERF_BR_NEW_MAX,
+};
+
 #define PERF_SAMPLE_BRANCH_PLM_ALL \
        (PERF_SAMPLE_BRANCH_USER|\
         PERF_SAMPLE_BRANCH_KERNEL|\
@@ -1375,7 +1388,8 @@ struct perf_branch_entry {
                abort:1,    /* transaction abort */
                cycles:16,  /* cycle count to last branch */
                type:4,     /* branch type */
-               reserved:40;
+               new_type:4, /* additional branch type */
+               reserved:36;
 };
 
 union perf_sample_weight {
index 029b433..886f53c 100644 (file)
@@ -882,7 +882,7 @@ static int print_bstack_flags(FILE *fp, struct branch_entry *br)
                       br->flags.in_tx ? 'X' : '-',
                       br->flags.abort ? 'A' : '-',
                       br->flags.cycles,
-                      br->flags.type ? branch_type_name(br->flags.type) : "-");
+                      get_branch_type(br));
 }
 
 static int perf_sample__fprintf_brstack(struct perf_sample *sample,
index abc6733..675cbbe 100644 (file)
@@ -21,7 +21,10 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
        if (flags->type == PERF_BR_UNKNOWN || from == 0)
                return;
 
-       st->counts[flags->type]++;
+       if (flags->type == PERF_BR_EXTEND_ABI)
+               st->new_counts[flags->new_type]++;
+       else
+               st->counts[flags->type]++;
 
        if (flags->type == PERF_BR_COND) {
                if (to > from)
@@ -36,6 +39,25 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
                st->cross_4k++;
 }
 
+const char *branch_new_type_name(int new_type)
+{
+       const char *branch_new_names[PERF_BR_NEW_MAX] = {
+               "FAULT_ALGN",
+               "FAULT_DATA",
+               "FAULT_INST",
+               "ARCH_1",
+               "ARCH_2",
+               "ARCH_3",
+               "ARCH_4",
+               "ARCH_5"
+       };
+
+       if (new_type >= 0 && new_type < PERF_BR_NEW_MAX)
+               return branch_new_names[new_type];
+
+       return NULL;
+}
+
 const char *branch_type_name(int type)
 {
        const char *branch_names[PERF_BR_MAX] = {
@@ -53,7 +75,8 @@ const char *branch_type_name(int type)
                "ERET",
                "IRQ",
                "SERROR",
-               "NO_TX"
+               "NO_TX",
+               "", // Needed for PERF_BR_EXTEND_ABI that ends up triggering some compiler warnings about NULL deref
        };
 
        if (type >= 0 && type < PERF_BR_MAX)
@@ -62,6 +85,17 @@ const char *branch_type_name(int type)
        return NULL;
 }
 
+const char *get_branch_type(struct branch_entry *e)
+{
+       if (e->flags.type == PERF_BR_UNKNOWN)
+               return "";
+
+       if (e->flags.type == PERF_BR_EXTEND_ABI)
+               return branch_new_type_name(e->flags.new_type);
+
+       return branch_type_name(e->flags.type);
+}
+
 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
 {
        u64 total = 0;
@@ -108,6 +142,15 @@ void branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
                                100.0 *
                                (double)st->counts[i] / (double)total);
        }
+
+       for (i = 0; i < PERF_BR_NEW_MAX; i++) {
+               if (st->new_counts[i] > 0)
+                       fprintf(fp, "\n%8s: %5.1f%%",
+                               branch_new_type_name(i),
+                               100.0 *
+                               (double)st->new_counts[i] / (double)total);
+       }
+
 }
 
 static int count_str_scnprintf(int idx, const char *str, char *bf, int size)
@@ -123,6 +166,9 @@ int branch_type_str(struct branch_type_stat *st, char *bf, int size)
        for (i = 0; i < PERF_BR_MAX; i++)
                total += st->counts[i];
 
+       for (i = 0; i < PERF_BR_NEW_MAX; i++)
+               total += st->new_counts[i];
+
        if (total == 0)
                return 0;
 
@@ -140,6 +186,11 @@ int branch_type_str(struct branch_type_stat *st, char *bf, int size)
                        printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed);
        }
 
+       for (i = 0; i < PERF_BR_NEW_MAX; i++) {
+               if (st->new_counts[i] > 0)
+                       printed += count_str_scnprintf(j++, branch_new_type_name(i), bf + printed, size - printed);
+       }
+
        if (st->cross_4k > 0)
                printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed);
 
index 17b2ccc..8d251b3 100644 (file)
@@ -24,7 +24,8 @@ struct branch_flags {
                        u64 abort:1;
                        u64 cycles:16;
                        u64 type:4;
-                       u64 reserved:40;
+                       u64 new_type:4;
+                       u64 reserved:36;
                };
        };
 };
@@ -72,6 +73,7 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl
 struct branch_type_stat {
        bool    branch_to;
        u64     counts[PERF_BR_MAX];
+       u64     new_counts[PERF_BR_NEW_MAX];
        u64     cond_fwd;
        u64     cond_bwd;
        u64     cross_4k;
@@ -82,6 +84,8 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
                       u64 from, u64 to);
 
 const char *branch_type_name(int type);
+const char *branch_new_type_name(int new_type);
+const char *get_branch_type(struct branch_entry *e);
 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st);
 int branch_type_str(struct branch_type_stat *st, char *bf, int bfsize);
 
index 192c927..47d5a50 100644 (file)
@@ -1180,7 +1180,7 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack)
                                e->flags.abort ? "A" : " ",
                                e->flags.in_tx ? "T" : " ",
                                (unsigned)e->flags.reserved,
-                               e->flags.type ? branch_type_name(e->flags.type) : "");
+                               get_branch_type(e));
                } else {
                        if (i == 0) {
                                printf("..... %2"PRIu64": %016" PRIx64 "\n"