perf annotate: Honor output options with --data-type

For data type profiling output, it should be in sync with normal output
so make it display percentage for each field.  Also use coloring scheme
for users to identify fields with big overhead easily.

Users can use --show-total-period or --show-nr-samples to change the
output style like in the normal perf annotate output.

Before:

  $ perf annotate --data-type
  Annotate type: 'struct task_struct' in [kernel.kallsyms] (34 samples):
  ============================================================================
      samples     offset       size  field
           34          0       9792  struct task_struct    {
            2          0         24      struct thread_info       thread_info {
            0          0          8          long unsigned int    flags;
            1          8          8          long unsigned int    syscall_work;
            0         16          4          u32  status;
            1         20          4          u32  cpu;
                                         };

After:

  $ perf annotate --data-type
  Annotate type: 'struct task_struct' in [kernel.kallsyms] (34 samples):
  ============================================================================
   Percent     offset       size  field
    100.00          0       9792  struct task_struct       {
      3.55          0         24      struct thread_info  thread_info {
      0.00          0          8          long unsigned int       flags;
      1.63          8          8          long unsigned int       syscall_work;
      0.00         16          4          u32     status;
      1.91         20          4          u32     cpu;
                                      };

Committer testing:

First collect a suitable perf.data file for use with 'perf annotate --data-type':

  root@number:~# perf mem record -a sleep 1s
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 11.047 MB perf.data (3466 samples) ]
  root@number:~#

Then, before:

  root@number:~# perf annotate --data-type
  Annotate type: 'union ' in /usr/lib64/libc.so.6 (6 samples):
  ============================================================================
      samples     offset       size  field
            6          0         40  union         {
            6          0         40      struct __pthread_mutex_s __data {
            2          0          4          int  __lock;
            0          4          4          unsigned int __count;
            0          8          4          int  __owner;
            1         12          4          unsigned int __nusers;
            2         16          4          int  __kind;
            1         20          2          short int    __spins;
            0         22          2          short int    __elision;
            0         24         16          __pthread_list_t     __list {
            0         24          8              struct __pthread_internal_list*  __prev;
            0         32          8              struct __pthread_internal_list*  __next;
                                             };
                                         };
            0          0          0      char*    __size;
            2          0          8      long int __align;
                                     };
  <SNIP>

And after:

  Annotate type: 'union ' in /usr/lib64/libc.so.6 (6 samples):
  ============================================================================
   Percent     offset       size  field
    100.00          0         40  union    {
    100.00          0         40      struct __pthread_mutex_s    __data {
     31.27          0          4          int     __lock;
      0.00          4          4          unsigned int    __count;
      0.00          8          4          int     __owner;
      7.67         12          4          unsigned int    __nusers;
     53.10         16          4          int     __kind;
      7.96         20          2          short int       __spins;
      0.00         22          2          short int       __elision;
      0.00         24         16          __pthread_list_t        __list {
      0.00         24          8              struct __pthread_internal_list*     __prev;
      0.00         32          8              struct __pthread_internal_list*     __next;
                                          };
                                      };
      0.00          0          0      char*       __size;
     31.27          0          8      long int    __align;
                                  };
  <SNIP>

The lines with percentages >= 7.67 have its percentages red colored.

Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240322224313.423181-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Namhyung Kim 2024-03-22 15:43:13 -07:00 committed by Arnaldo Carvalho de Melo
parent 374af9f1f0
commit bdeaf6ffec

View File

@ -42,6 +42,7 @@
#include <errno.h>
#include <linux/bitmap.h>
#include <linux/err.h>
#include <inttypes.h>
struct perf_annotate {
struct perf_tool tool;
@ -332,6 +333,8 @@ static void print_annotated_data_header(struct hist_entry *he, struct evsel *evs
struct dso *dso = map__dso(he->ms.map);
int nr_members = 1;
int nr_samples = he->stat.nr_events;
int width = 7;
const char *val_hdr = "Percent";
if (evsel__is_group_event(evsel)) {
struct hist_entry *pair;
@ -353,8 +356,30 @@ static void print_annotated_data_header(struct hist_entry *he, struct evsel *evs
nr_members = evsel->core.nr_members;
}
if (symbol_conf.show_total_period) {
width = 11;
val_hdr = "Period";
} else if (symbol_conf.show_nr_samples) {
width = 7;
val_hdr = "Samples";
}
printf("============================================================================\n");
printf("%*s %10s %10s %s\n", 11 * nr_members, "samples", "offset", "size", "field");
printf("%*s %10s %10s %s\n", (width + 1) * nr_members, val_hdr,
"offset", "size", "field");
}
static void print_annotated_data_value(struct type_hist *h, u64 period, int nr_samples)
{
double percent = h->period ? (100.0 * period / h->period) : 0;
const char *color = get_percent_color(percent);
if (symbol_conf.show_total_period)
color_fprintf(stdout, color, " %11" PRIu64, period);
else if (symbol_conf.show_nr_samples)
color_fprintf(stdout, color, " %7d", nr_samples);
else
color_fprintf(stdout, color, " %7.2f", percent);
}
static void print_annotated_data_type(struct annotated_data_type *mem_type,
@ -364,10 +389,14 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type,
struct annotated_member *child;
struct type_hist *h = mem_type->histograms[evsel->core.idx];
int i, nr_events = 1, samples = 0;
u64 period = 0;
int width = symbol_conf.show_total_period ? 11 : 7;
for (i = 0; i < member->size; i++)
for (i = 0; i < member->size; i++) {
samples += h->addr[member->offset + i].nr_samples;
printf(" %10d", samples);
period += h->addr[member->offset + i].period;
}
print_annotated_data_value(h, period, samples);
if (evsel__is_group_event(evsel)) {
struct evsel *pos;
@ -376,9 +405,12 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type,
h = mem_type->histograms[pos->core.idx];
samples = 0;
for (i = 0; i < member->size; i++)
period = 0;
for (i = 0; i < member->size; i++) {
samples += h->addr[member->offset + i].nr_samples;
printf(" %10d", samples);
period += h->addr[member->offset + i].period;
}
print_annotated_data_value(h, period, samples);
}
nr_events = evsel->core.nr_members;
}
@ -394,7 +426,7 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type,
print_annotated_data_type(mem_type, child, evsel, indent + 4);
if (!list_empty(&member->children))
printf("%*s}", 11 * nr_events + 24 + indent, "");
printf("%*s}", (width + 1) * nr_events + 24 + indent, "");
printf(";\n");
}