// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-annotate.c, see those files for further * copyright notes. */ #include <errno.h>#include <inttypes.h>#include <stdlib.h>#include "util.h" // hex_width()#include "ui/ui.h"#include "sort.h"#include "build-id.h"#include "color.h"#include "config.h"#include "disasm.h"#include "dso.h"#include "env.h"#include "map.h"#include "maps.h"#include "symbol.h"#include "srcline.h"#include "units.h"#include "debug.h"#include "debuginfo.h"#include "annotate.h"#include "annotate-data.h"#include "evsel.h"#include "evlist.h"#include "bpf-event.h"#include "bpf-utils.h"#include "block-range.h"#include "string2.h"#include "dwarf-regs.h"#include "util/event.h"#include "util/sharded_mutex.h"#include "arch/common.h"#include "namespaces.h"#include "thread.h"#include "hashmap.h"#include "strbuf.h"#include <regex.h>#include <linux/bitops.h>#include <linux/err.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/zalloc.h>#include <subcmd/parse-options.h>#include <subcmd/run-command.h>#include <math.h> /* FIXME: For the HE_COLORSET */#include "ui/browser.h" /* * FIXME: Using the same values as slang.h, * but that header may not be available everywhere */#define LARROW_CHAR ((unsigned char)',')#define RARROW_CHAR ((unsigned char)'+')#define DARROW_CHAR ((unsigned char)'.')#define UARROW_CHAR ((unsigned char)'-') #include <linux/ctype.h> /* global annotation options */struct annotation_options annotate_opts; /* Data type collection debug statistics */struct annotated_data_stat ann_data_stat;LIST_HEAD(ann_insn_stat); /* Pseudo data types */struct annotated_data_type stackop_type = { .self = { .type_name = (char *)"(stack operation)", .children = LIST_HEAD_INIT(stackop_type.self.children), },}; struct annotated_data_type canary_type = { .self = { .type_name = (char *)"(stack canary)", .children = LIST_HEAD_INIT(canary_type.self.children), },}; #define NO_TYPE ((struct annotated_data_type *)-1UL) /* symbol histogram: key = offset << 16 | evsel->core.idx */static size_t sym_hist_hash(long key, void *ctx __maybe_unused){ return (key >> 16) + (key & 0xffff);} static bool sym_hist_equal(long key1, long key2, void *ctx __maybe_unused){ return key1 == key2;} static struct annotated_source *annotated_source__new(void){ struct annotated_source *src = zalloc(sizeof(*src)); if (src != NULL) INIT_LIST_HEAD(&src->source); return src;} static __maybe_unused void annotated_source__delete(struct annotated_source *src){ struct hashmap_entry *cur; size_t bkt; if (src == NULL) return; if (src->samples) { hashmap__for_each_entry(src->samples, cur, bkt) zfree(&cur->pvalue); hashmap__free(src->samples); } zfree(&src->histograms); free(src);} static int annotated_source__alloc_histograms(struct annotated_source *src, int nr_hists){ src->nr_histograms = nr_hists; src->histograms = calloc(nr_hists, sizeof(*src->histograms)); if (src->histograms == NULL) return -1; src->samples = hashmap__new(sym_hist_hash, sym_hist_equal, NULL); if (IS_ERR(src->samples)) { zfree(&src->histograms); src->samples = NULL; } return src->histograms ? 0 : -1;} void symbol__annotate_zero_histograms(struct symbol *sym){ struct annotation *notes = symbol__annotation(sym); annotation__lock(notes); if (notes->src != NULL) { memset(notes->src->histograms, 0, notes->src->nr_histograms * sizeof(*notes->src->histograms)); hashmap__clear(notes->src->samples); } if (notes->branch && notes->branch->cycles_hist) { memset(notes->branch->cycles_hist, 0, symbol__size(sym) * sizeof(struct cyc_hist)); } annotation__unlock(notes);} static int __symbol__account_cycles(struct cyc_hist *ch, u64 start, unsigned offset, unsigned cycles, unsigned have_start){ /* * For now we can only account one basic block per * final jump. But multiple could be overlapping. * Always account the longest one. So when * a shorter one has been already seen throw it away. * * We separately always account the full cycles. */ ch[offset].num_aggr++; ch[offset].cycles_aggr += cycles; if (cycles > ch[offset].cycles_max) ch[offset].cycles_max = cycles; if (ch[offset].cycles_min) { if (cycles && cycles < ch[offset].cycles_min) ch[offset].cycles_min = cycles; } else ch[offset].cycles_min = cycles; if (!have_start && ch[offset].have_start) return 0; if (ch[offset].num) { if (have_start && (!ch[offset].have_start || ch[offset].start > start)) { ch[offset].have_start = 0; ch[offset].cycles = 0; ch[offset].num = 0; if (ch[offset].reset < 0xffff) ch[offset].reset++; } else if (have_start && ch[offset].start < start) return 0; } if (ch[offset].num < NUM_SPARKS) ch[offset].cycles_spark[ch[offset].num] = cycles; ch[offset].have_start = have_start; ch[offset].start = start; ch[offset].cycles += cycles; ch[offset].num++; return 0;} static int __symbol__inc_addr_samples(struct map_symbol *ms, struct annotated_source *src, u64 addr, struct perf_sample *sample){ struct evsel *evsel = sample->evsel; struct symbol *sym = ms->sym; long hash_key; u64 offset; struct sym_hist *h; struct sym_hist_entry *entry; pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map__unmap_ip(ms->map, addr)); if ((addr < sym->start || addr >= sym->end) && (addr != sym->end || sym->start != sym->end)) { pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, __LINE__, sym->name, sym->start, addr, sym->end); return -ERANGE; } offset = addr - sym->start; h = annotated_source__histogram(src, evsel); if (h == NULL) { pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n", __func__, __LINE__, sym->name, sym->start, addr, sym->end, symbol__type(sym) == STT_FUNC); return -ENOMEM; } hash_key = offset << 16 | evsel->core.idx; if (!hashmap__find(src->samples, hash_key, &entry)) { entry = zalloc(sizeof(*entry)); if (entry == NULL) return -ENOMEM; if (hashmap__add(src->samples, hash_key, entry) < 0) return -ENOMEM; } h->nr_samples++; h->period += sample->period; entry->nr_samples++; entry->period += sample->period; pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n", sym->start, sym->name, addr, addr - sym->start, evsel->core.idx, entry->nr_samples, entry->period); return 0;} struct annotated_branch *annotation__get_branch(struct annotation *notes){ if (notes == NULL) return NULL; if (notes->branch == NULL) notes->branch = zalloc(sizeof(*notes->branch)); return notes->branch;} static struct annotated_branch *symbol__find_branch_hist(struct symbol *sym, unsigned int br_cntr_nr){ struct annotation *notes = symbol__annotation(sym); struct annotated_branch *branch; const size_t size = symbol__size(sym); branch = annotation__get_branch(notes); if (branch == NULL) return NULL; if (branch->cycles_hist == NULL) { branch->cycles_hist = calloc(size, sizeof(struct cyc_hist)); if (!branch->cycles_hist) return NULL; } if (br_cntr_nr && branch->br_cntr == NULL) { branch->br_cntr = calloc(br_cntr_nr * size, sizeof(u64)); if (!branch->br_cntr) return NULL; } return branch;} struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists){ struct annotation *notes = symbol__annotation(sym); if (notes->src == NULL) { notes->src = annotated_source__new(); if (notes->src == NULL) return NULL; goto alloc_histograms; } if (notes->src->histograms == NULL) {alloc_histograms: annotated_source__alloc_histograms(notes->src, nr_hists); } return notes->src;} static int symbol__inc_addr_samples(struct map_symbol *ms, u64 addr, struct perf_sample *sample){ struct symbol *sym = ms->sym; struct annotated_source *src; if (sym == NULL) return 0; src = symbol__hists(sym, evlist__nr_entries(sample->evsel->evlist)); return src ? __symbol__inc_addr_samples(ms, src, addr, sample) : 0;} static int symbol__account_br_cntr(struct annotated_branch *branch, struct evsel *evsel, unsigned offset, u64 br_cntr){ unsigned int br_cntr_nr = evsel__leader(evsel)->br_cntr_nr; unsigned int base = evsel__leader(evsel)->br_cntr_idx; unsigned int off = offset * evlist__nr_br_cntr(evsel->evlist); u64 *branch_br_cntr = branch->br_cntr; unsigned int i, mask, width; if (!br_cntr || !branch_br_cntr) return 0; perf_env__find_br_cntr_info(evsel__env(evsel), NULL, &width); mask = (1L << width) - 1; for (i = 0; i < br_cntr_nr; i++) { u64 cntr = (br_cntr >> i * width) & mask; branch_br_cntr[off + i + base] += cntr; if (cntr == mask) branch_br_cntr[off + i + base] |= ANNOTATION__BR_CNTR_SATURATED_FLAG; } return 0;} static int symbol__account_cycles(u64 addr, u64 start, struct symbol *sym, unsigned cycles, struct evsel *evsel, u64 br_cntr){ struct annotated_branch *branch; unsigned offset; int ret; if (sym == NULL) return 0; branch = symbol__find_branch_hist(sym, evlist__nr_br_cntr(evsel->evlist)); if (!branch) return -ENOMEM; if (addr < sym->start || addr >= sym->end) return -ERANGE; if (start) { if (start < sym->start || start >= sym->end) return -ERANGE; if (start >= addr) start = 0; } offset = addr - sym->start; ret = __symbol__account_cycles(branch->cycles_hist, start ? start - sym->start : 0, offset, cycles, !!start); if (ret) return ret; return symbol__account_br_cntr(branch, evsel, offset, br_cntr);} int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, struct addr_map_symbol *start, unsigned cycles, struct evsel *evsel, u64 br_cntr){ u64 saddr = 0; int err; if (!cycles) return 0; /* * Only set start when IPC can be computed. We can only * compute it when the basic block is completely in a single * function. * Special case the case when the jump is elsewhere, but * it starts on the function start. */ if (start && (start->ms.sym == ams->ms.sym || (ams->ms.sym && start->addr == ams->ms.sym->start + map__start(ams->ms.map)))) saddr = start->al_addr; if (saddr == 0) pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n", ams->addr, start ? start->addr : 0, ams->ms.sym ? ams->ms.sym->start + map__start(ams->ms.map) : 0, saddr); err = symbol__account_cycles(ams->al_addr, saddr, ams->ms.sym, cycles, evsel, br_cntr); if (err) pr_debug2("account_cycles failed %d\n", err); return err;} struct annotation_line *annotated_source__get_line(struct annotated_source *src, s64 offset){ struct annotation_line *al; list_for_each_entry(al, &src->source, node) { if (al->offset == offset) return al; } return NULL;} static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end){ struct annotation_line *al; unsigned n_insn = 0; al = annotated_source__get_line(notes->src, start); if (al == NULL) return 0; list_for_each_entry_from(al, ¬es->src->source, node) { if (al->offset == -1) continue; if ((u64)al->offset > end) break; n_insn++; } return n_insn;} static void annotated_branch__delete(struct annotated_branch *branch){ if (branch) { zfree(&branch->cycles_hist); free(branch->br_cntr); free(branch); }} static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch){ unsigned n_insn; unsigned int cover_insn = 0; n_insn = annotation__count_insn(notes, start, end); if (n_insn && ch->num && ch->cycles) { struct annotation_line *al; struct annotated_branch *branch; float ipc = n_insn / ((double)ch->cycles / (double)ch->num); /* Hide data when there are too many overlaps. */ if (ch->reset >= 0x7fff) return; al = annotated_source__get_line(notes->src, start); if (al == NULL) return; list_for_each_entry_from(al, ¬es->src->source, node) { if (al->offset == -1) continue; if ((u64)al->offset > end) break; if (al->cycles && al->cycles->ipc == 0.0) { al->cycles->ipc = ipc; cover_insn++; } }Lines 1–500 of 3228. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-annotate.c, see those files for further * copyright notes. */ #include <errno.h> #include <inttypes.h> #include <stdlib.h> #include "util.h" // hex_width() #include "ui/ui.h" #include "sort.h" #include "build-id.h" #include "color.h" #include "config.h" #include "disasm.h" #include "dso.h" #include "env.h" #include "map.h" #include "maps.h" #include "symbol.h" #include "srcline.h" #include "units.h" #include "debug.h" #include "debuginfo.h" #include "annotate.h" #include "annotate-data.h" #include "evsel.h" #include "evlist.h" #include "bpf-event.h" #include "bpf-utils.h" #include "block-range.h" #include "string2.h" #include "dwarf-regs.h" #include "util/event.h" #include "util/sharded_mutex.h" #include "arch/common.h" #include "namespaces.h" #include "thread.h" #include "hashmap.h" #include "strbuf.h" #include <regex.h> #include <linux/bitops.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/zalloc.h> #include <subcmd/parse-options.h> #include <subcmd/run-command.h> #include <math.h> /* FIXME: For the HE_COLORSET */ #include "ui/browser.h" /* * FIXME: Using the same values as slang.h, * but that header may not be available everywhere */ #define LARROW_CHAR ((unsigned char)',') #define RARROW_CHAR ((unsigned char)'+') #define DARROW_CHAR ((unsigned char)'.') #define UARROW_CHAR ((unsigned char)'-') #include <linux/ctype.h> /* global annotation options */ struct annotation_options annotate_opts; /* Data type collection debug statistics */ struct annotated_data_stat ann_data_stat; LIST_HEAD(ann_insn_stat); /* Pseudo data types */ struct annotated_data_type stackop_type = { .self = { .type_name = (char *)"(stack operation)", .children = LIST_HEAD_INIT(stackop_type.self.children), }, }; struct annotated_data_type canary_type = { .self = { .type_name = (char *)"(stack canary)", .children = LIST_HEAD_INIT(canary_type.self.children), }, }; #define NO_TYPE ((struct annotated_data_type *)-1UL) /* symbol histogram: key = offset << 16 | evsel->core.idx */ static size_t sym_hist_hash(long key, void *ctx __maybe_unused) { return (key >> 16) + (key & 0xffff); } static bool sym_hist_equal(long key1, long key2, void *ctx __maybe_unused) { return key1 == key2; } static struct annotated_source *annotated_source__new(void) { struct annotated_source *src = zalloc(sizeof(*src)); if (src != NULL) INIT_LIST_HEAD(&src->source); return src; } static __maybe_unused void annotated_source__delete(struct annotated_source *src) { struct hashmap_entry *cur; size_t bkt; if (src == NULL) return; if (src->samples) { hashmap__for_each_entry(src->samples, cur, bkt) zfree(&cur->pvalue); hashmap__free(src->samples); } zfree(&src->histograms); free(src); } static int annotated_source__alloc_histograms(struct annotated_source *src, int nr_hists) { src->nr_histograms = nr_hists; src->histograms = calloc(nr_hists, sizeof(*src->histograms)); if (src->histograms == NULL) return -1; src->samples = hashmap__new(sym_hist_hash, sym_hist_equal, NULL); if (IS_ERR(src->samples)) { zfree(&src->histograms); src->samples = NULL; } return src->histograms ? 0 : -1; } void symbol__annotate_zero_histograms(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); annotation__lock(notes); if (notes->src != NULL) { memset(notes->src->histograms, 0, notes->src->nr_histograms * sizeof(*notes->src->histograms)); hashmap__clear(notes->src->samples); } if (notes->branch && notes->branch->cycles_hist) { memset(notes->branch->cycles_hist, 0, symbol__size(sym) * sizeof(struct cyc_hist)); } annotation__unlock(notes); } static int __symbol__account_cycles(struct cyc_hist *ch, u64 start, unsigned offset, unsigned cycles, unsigned have_start) { /* * For now we can only account one basic block per * final jump. But multiple could be overlapping. * Always account the longest one. So when * a shorter one has been already seen throw it away. * * We separately always account the full cycles. */ ch[offset].num_aggr++; ch[offset].cycles_aggr += cycles; if (cycles > ch[offset].cycles_max) ch[offset].cycles_max = cycles; if (ch[offset].cycles_min) { if (cycles && cycles < ch[offset].cycles_min) ch[offset].cycles_min = cycles; } else ch[offset].cycles_min = cycles; if (!have_start && ch[offset].have_start) return 0; if (ch[offset].num) { if (have_start && (!ch[offset].have_start || ch[offset].start > start)) { ch[offset].have_start = 0; ch[offset].cycles = 0; ch[offset].num = 0; if (ch[offset].reset < 0xffff) ch[offset].reset++; } else if (have_start && ch[offset].start < start) return 0; } if (ch[offset].num < NUM_SPARKS) ch[offset].cycles_spark[ch[offset].num] = cycles; ch[offset].have_start = have_start; ch[offset].start = start; ch[offset].cycles += cycles; ch[offset].num++; return 0; } static int __symbol__inc_addr_samples(struct map_symbol *ms, struct annotated_source *src, u64 addr, struct perf_sample *sample) { struct evsel *evsel = sample->evsel; struct symbol *sym = ms->sym; long hash_key; u64 offset; struct sym_hist *h; struct sym_hist_entry *entry; pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map__unmap_ip(ms->map, addr)); if ((addr < sym->start || addr >= sym->end) && (addr != sym->end || sym->start != sym->end)) { pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, __LINE__, sym->name, sym->start, addr, sym->end); return -ERANGE; } offset = addr - sym->start; h = annotated_source__histogram(src, evsel); if (h == NULL) { pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n", __func__, __LINE__, sym->name, sym->start, addr, sym->end, symbol__type(sym) == STT_FUNC); return -ENOMEM; } hash_key = offset << 16 | evsel->core.idx; if (!hashmap__find(src->samples, hash_key, &entry)) { entry = zalloc(sizeof(*entry)); if (entry == NULL) return -ENOMEM; if (hashmap__add(src->samples, hash_key, entry) < 0) return -ENOMEM; } h->nr_samples++; h->period += sample->period; entry->nr_samples++; entry->period += sample->period; pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n", sym->start, sym->name, addr, addr - sym->start, evsel->core.idx, entry->nr_samples, entry->period); return 0; } struct annotated_branch *annotation__get_branch(struct annotation *notes) { if (notes == NULL) return NULL; if (notes->branch == NULL) notes->branch = zalloc(sizeof(*notes->branch)); return notes->branch; } static struct annotated_branch *symbol__find_branch_hist(struct symbol *sym, unsigned int br_cntr_nr) { struct annotation *notes = symbol__annotation(sym); struct annotated_branch *branch; const size_t size = symbol__size(sym); branch = annotation__get_branch(notes); if (branch == NULL) return NULL; if (branch->cycles_hist == NULL) { branch->cycles_hist = calloc(size, sizeof(struct cyc_hist)); if (!branch->cycles_hist) return NULL; } if (br_cntr_nr && branch->br_cntr == NULL) { branch->br_cntr = calloc(br_cntr_nr * size, sizeof(u64)); if (!branch->br_cntr) return NULL; } return branch; } struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) { struct annotation *notes = symbol__annotation(sym); if (notes->src == NULL) { notes->src = annotated_source__new(); if (notes->src == NULL) return NULL; goto alloc_histograms; } if (notes->src->histograms == NULL) { alloc_histograms: annotated_source__alloc_histograms(notes->src, nr_hists); } return notes->src; } static int symbol__inc_addr_samples(struct map_symbol *ms, u64 addr, struct perf_sample *sample) { struct symbol *sym = ms->sym; struct annotated_source *src; if (sym == NULL) return 0; src = symbol__hists(sym, evlist__nr_entries(sample->evsel->evlist)); return src ? __symbol__inc_addr_samples(ms, src, addr, sample) : 0; } static int symbol__account_br_cntr(struct annotated_branch *branch, struct evsel *evsel, unsigned offset, u64 br_cntr) { unsigned int br_cntr_nr = evsel__leader(evsel)->br_cntr_nr; unsigned int base = evsel__leader(evsel)->br_cntr_idx; unsigned int off = offset * evlist__nr_br_cntr(evsel->evlist); u64 *branch_br_cntr = branch->br_cntr; unsigned int i, mask, width; if (!br_cntr || !branch_br_cntr) return 0; perf_env__find_br_cntr_info(evsel__env(evsel), NULL, &width); mask = (1L << width) - 1; for (i = 0; i < br_cntr_nr; i++) { u64 cntr = (br_cntr >> i * width) & mask; branch_br_cntr[off + i + base] += cntr; if (cntr == mask) branch_br_cntr[off + i + base] |= ANNOTATION__BR_CNTR_SATURATED_FLAG; } return 0; } static int symbol__account_cycles(u64 addr, u64 start, struct symbol *sym, unsigned cycles, struct evsel *evsel, u64 br_cntr) { struct annotated_branch *branch; unsigned offset; int ret; if (sym == NULL) return 0; branch = symbol__find_branch_hist(sym, evlist__nr_br_cntr(evsel->evlist)); if (!branch) return -ENOMEM; if (addr < sym->start || addr >= sym->end) return -ERANGE; if (start) { if (start < sym->start || start >= sym->end) return -ERANGE; if (start >= addr) start = 0; } offset = addr - sym->start; ret = __symbol__account_cycles(branch->cycles_hist, start ? start - sym->start : 0, offset, cycles, !!start); if (ret) return ret; return symbol__account_br_cntr(branch, evsel, offset, br_cntr); } int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, struct addr_map_symbol *start, unsigned cycles, struct evsel *evsel, u64 br_cntr) { u64 saddr = 0; int err; if (!cycles) return 0; /* * Only set start when IPC can be computed. We can only * compute it when the basic block is completely in a single * function. * Special case the case when the jump is elsewhere, but * it starts on the function start. */ if (start && (start->ms.sym == ams->ms.sym || (ams->ms.sym && start->addr == ams->ms.sym->start + map__start(ams->ms.map)))) saddr = start->al_addr; if (saddr == 0) pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n", ams->addr, start ? start->addr : 0, ams->ms.sym ? ams->ms.sym->start + map__start(ams->ms.map) : 0, saddr); err = symbol__account_cycles(ams->al_addr, saddr, ams->ms.sym, cycles, evsel, br_cntr); if (err) pr_debug2("account_cycles failed %d\n", err); return err; } struct annotation_line *annotated_source__get_line(struct annotated_source *src, s64 offset) { struct annotation_line *al; list_for_each_entry(al, &src->source, node) { if (al->offset == offset) return al; } return NULL; } static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end) { struct annotation_line *al; unsigned n_insn = 0; al = annotated_source__get_line(notes->src, start); if (al == NULL) return 0; list_for_each_entry_from(al, ¬es->src->source, node) { if (al->offset == -1) continue; if ((u64)al->offset > end) break; n_insn++; } return n_insn; } static void annotated_branch__delete(struct annotated_branch *branch) { if (branch) { zfree(&branch->cycles_hist); free(branch->br_cntr); free(branch); } } static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch) { unsigned n_insn; unsigned int cover_insn = 0; n_insn = annotation__count_insn(notes, start, end); if (n_insn && ch->num && ch->cycles) { struct annotation_line *al; struct annotated_branch *branch; float ipc = n_insn / ((double)ch->cycles / (double)ch->num); /* Hide data when there are too many overlaps. */ if (ch->reset >= 0x7fff) return; al = annotated_source__get_line(notes->src, start); if (al == NULL) return; list_for_each_entry_from(al, ¬es->src->source, node) { if (al->offset == -1) continue; if ((u64)al->offset > end) break; if (al->cycles && al->cycles->ipc == 0.0) { al->cycles->ipc = ipc; cover_insn++; } }