[RFC 10/11] perf annotate: Preparation for hazard

From: Ravi Bangoria
Date: Mon Mar 02 2020 - 00:25:06 EST


Introduce 'struct hazard_hist' that will contain hazard specific
information for annotate. Add Array of list of 'struct hazard_hist'
into 'struct annotated_source' where array length = symbol size and
each member of list contain hazard info from associated perf sample.
This information is prepared while parsing samples in perf report.
Also, this is just a preparation step for annotate and followup
patch does actual annotate ui changes.

Signed-off-by: Ravi Bangoria <ravi.bangoria@xxxxxxxxxxxxx>
---
tools/perf/builtin-report.c | 1 +
tools/perf/util/annotate.c | 75 +++++++++++++++++++++++++++++++++++++
tools/perf/util/annotate.h | 14 +++++++
tools/perf/util/hist.c | 13 +++++++
tools/perf/util/hist.h | 4 ++
tools/perf/util/machine.c | 6 +++
tools/perf/util/machine.h | 3 ++
7 files changed, 116 insertions(+)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index a47542a12da1..ff950ff8dd51 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -301,6 +301,7 @@ static int process_sample_event(struct perf_tool *tool,
hist__account_cycles(sample->branch_stack, &al, sample,
rep->nonany_branch_mode,
&rep->total_cycles);
+ hist__capture_haz_info(&al, sample, evsel);
}

ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 8aef60a6ffea..766934b0f36d 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -36,6 +36,7 @@
#include "string2.h"
#include "util/event.h"
#include "arch/common.h"
+#include "hazard.h"
#include <regex.h>
#include <pthread.h>
#include <linux/bitops.h>
@@ -800,6 +801,21 @@ static int symbol__alloc_hist_cycles(struct symbol *sym)
return 0;
}

+static int symbol__alloc_hist_hazard(struct symbol *sym)
+{
+ struct annotation *notes = symbol__annotation(sym);
+ const size_t size = symbol__size(sym);
+ size_t i;
+
+ notes->src->haz_hist = calloc(size, sizeof(struct hazard_hist));
+ if (notes->src->haz_hist == NULL)
+ return -1;
+
+ for (i = 0; i < size; i++)
+ INIT_LIST_HEAD(&notes->src->haz_hist[i].list);
+ return 0;
+}
+
void symbol__annotate_zero_histograms(struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
@@ -920,6 +936,25 @@ static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
return notes->src->cycles_hist;
}

+static struct hazard_hist *symbol__hazard_hist(struct symbol *sym)
+{
+ struct annotation *notes = symbol__annotation(sym);
+
+ if (notes->src == NULL) {
+ notes->src = annotated_source__new();
+ if (notes->src == NULL)
+ return NULL;
+ goto alloc_haz_hist;
+ }
+
+ if (!notes->src->haz_hist) {
+alloc_haz_hist:
+ symbol__alloc_hist_hazard(sym);
+ }
+
+ return notes->src->haz_hist;
+}
+
struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
{
struct annotation *notes = symbol__annotation(sym);
@@ -1014,6 +1049,46 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
return err;
}

+int symbol__capture_haz_info(struct addr_map_symbol *ams,
+ struct perf_sample *sample,
+ struct evsel *evsel)
+{
+ struct hazard_hist *hh, *tmp;
+ u64 offset;
+ const char *arch = perf_env__arch(perf_evsel__env(evsel));
+
+ if (ams->ms.sym == NULL)
+ return 0;
+
+ hh = symbol__hazard_hist(ams->ms.sym);
+ if (!hh)
+ return -ENOMEM;
+
+ if (ams->al_addr < ams->ms.sym->start || ams->al_addr >= ams->ms.sym->end)
+ return -ERANGE;
+
+ offset = ams->al_addr - ams->ms.sym->start;
+
+ tmp = zalloc(sizeof(*tmp));
+ if (!tmp)
+ return -ENOMEM;
+
+ tmp->icache = perf_haz__icache_str(sample->pipeline_haz->icache, arch);
+ tmp->haz_stage = perf_haz__hstage_str(sample->pipeline_haz->hazard_stage,
+ arch);
+ tmp->haz_reason = perf_haz__hreason_str(sample->pipeline_haz->hazard_stage,
+ sample->pipeline_haz->hazard_reason,
+ arch);
+ tmp->stall_stage = perf_haz__sstage_str(sample->pipeline_haz->stall_stage,
+ arch);
+ tmp->stall_reason = perf_haz__sreason_str(sample->pipeline_haz->stall_stage,
+ sample->pipeline_haz->stall_reason,
+ arch);
+
+ list_add(&tmp->list, &hh[offset].list);
+ return 0;
+}
+
static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end)
{
unsigned n_insn = 0;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 89839713d242..a3803f89b8fc 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -249,6 +249,15 @@ struct cyc_hist {
u16 reset;
};

+struct hazard_hist {
+ struct list_head list;
+ const char *icache;
+ const char *haz_stage;
+ const char *haz_reason;
+ const char *stall_stage;
+ const char *stall_reason;
+};
+
/** struct annotated_source - symbols with hits have this attached as in sannotation
*
* @histograms: Array of addr hit histograms per event being monitored
@@ -271,6 +280,7 @@ struct annotated_source {
int nr_histograms;
size_t sizeof_sym_hist;
struct cyc_hist *cycles_hist;
+ struct hazard_hist *haz_hist; /* Array of list. Array length = symbol size */
struct sym_hist *histograms;
};

@@ -343,6 +353,10 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
struct addr_map_symbol *start,
unsigned cycles);

+int symbol__capture_haz_info(struct addr_map_symbol *ams,
+ struct perf_sample *sample,
+ struct evsel *evsel);
+
int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
struct evsel *evsel, u64 addr);

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index d690d08b0f64..3cbfebb80f68 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -2702,6 +2702,19 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
}
}

+void hist__capture_haz_info(struct addr_location *al,
+ struct perf_sample *sample,
+ struct evsel *evsel)
+{
+ struct addr_map_symbol ams;
+
+ if (!sample->pipeline_haz)
+ return;
+
+ sample__resolve_haz(al, &ams, sample);
+ symbol__capture_haz_info(&ams, sample, evsel);
+}
+
size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp)
{
struct evsel *pos;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 063d65985a11..086c1dfde21f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -554,6 +554,10 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
struct perf_sample *sample, bool nonany_branch_mode,
u64 *total_cycles);

+void hist__capture_haz_info(struct addr_location *al,
+ struct perf_sample *sample,
+ struct evsel *evsel);
+
struct option;
int parse_filter_percentage(const struct option *opt, const char *arg, int unset);
int perf_hist_config(const char *var, const char *value);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index fb5c2cd44d30..e575488a1390 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -2094,6 +2094,12 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
return bi;
}

+void sample__resolve_haz(struct addr_location *al, struct addr_map_symbol *ams,
+ struct perf_sample *sample)
+{
+ ip__resolve_ams(al->thread, ams, sample->ip);
+}
+
static void save_iterations(struct iterations *iter,
struct branch_entry *be, int nr)
{
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index be0a930eca89..e9a298b5430c 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -173,6 +173,9 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
struct mem_info *sample__resolve_mem(struct perf_sample *sample,
struct addr_location *al);

+void sample__resolve_haz(struct addr_location *al, struct addr_map_symbol *ams,
+ struct perf_sample *sample);
+
struct callchain_cursor;

int thread__resolve_callchain(struct thread *thread,
--
2.21.1