if (he == NULL)
return -ENOMEM;
- return hist_entry__inc_addr_samples(he, al->addr);
+ if (he->ms.sym != NULL) {
+ /*
+ * All aggregated on the first sym_hist.
+ */
+ struct annotation *notes = symbol__annotation(he->ms.sym);
+ if (notes->histograms == NULL && symbol__alloc_hist(he->ms.sym, 1) < 0)
+ return -ENOMEM;
+
+ return hist_entry__inc_addr_samples(he, 0, al->addr);
+ }
+
+ return 0;
}
static int process_sample_event(union perf_event *event,
return 0;
}
-static int hist_entry__tty_annotate(struct hist_entry *he)
+static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
{
- return symbol__tty_annotate(he->ms.sym, he->ms.map,
+ return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
print_line, full_paths);
}
goto find_next;
notes = symbol__annotation(he->ms.sym);
- if (notes->histogram == NULL) {
+ if (notes->histograms == NULL) {
find_next:
if (key == KEY_LEFT)
nd = rb_prev(nd);
}
if (use_browser > 0) {
- key = hist_entry__tui_annotate(he);
+ /* For now all is aggregated on the first */
+ key = hist_entry__tui_annotate(he, 0);
switch (key) {
case KEY_RIGHT:
next = rb_next(nd);
if (next != NULL)
nd = next;
} else {
- hist_entry__tty_annotate(he);
+ /* For now all is aggregated on the first */
+ hist_entry__tty_annotate(he, 0);
nd = rb_next(nd);
/*
* Since we have a hist_entry per IP for the same
* symbol, free he->ms.sym->histogram to signal we already
* processed this symbol.
*/
- free(notes->histogram);
- notes->histogram = NULL;
+ free(notes->histograms);
+ notes->histograms = NULL;
}
}
}
* so we don't allocated the extra space needed because the stdio
* code will not use it.
*/
- if (use_browser > 0)
- err = hist_entry__inc_addr_samples(he, al->addr);
+ if (al->sym != NULL && use_browser > 0) {
+ /*
+ * All aggregated on the first sym_hist.
+ */
+ struct annotation *notes = symbol__annotation(he->ms.sym);
+ if (notes->histograms == NULL &&
+ symbol__alloc_hist(he->ms.sym, 1) < 0)
+ err = -ENOMEM;
+ else
+ err = hist_entry__inc_addr_samples(he, 0, al->addr);
+ }
return err;
}
}
if (use_browser > 0)
- hists__tui_browse_tree(&session->hists_tree, help);
+ hists__tui_browse_tree(&session->hists_tree, help, 0);
else
hists__tty_browse_tree(&session->hists_tree, help);
#include "debug.h"
#include "annotate.h"
-static int symbol__alloc_hist(struct symbol *sym)
+int symbol__alloc_hist(struct symbol *sym, int nevents)
{
struct annotation *notes = symbol__annotation(sym);
- const int size = (sizeof(*notes->histogram) +
- (sym->end - sym->start) * sizeof(u64));
- notes->histogram = zalloc(size);
- return notes->histogram == NULL ? -1 : 0;
+ notes->sizeof_sym_hist = (sizeof(*notes->histograms) +
+ (sym->end - sym->start) * sizeof(u64));
+ notes->histograms = calloc(nevents, notes->sizeof_sym_hist);
+ return notes->histograms == NULL ? -1 : 0;
}
-int symbol__inc_addr_samples(struct symbol *sym, struct map *map, u64 addr)
+int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
+ int evidx, u64 addr)
{
- unsigned int sym_size, offset;
+ unsigned offset;
struct annotation *notes;
struct sym_hist *h;
- if (!sym || !map)
- return 0;
-
notes = symbol__annotation(sym);
- if (notes->histogram == NULL && symbol__alloc_hist(sym) < 0)
+ if (notes->histograms == NULL)
return -ENOMEM;
- sym_size = sym->end - sym->start;
- offset = addr - sym->start;
-
pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
- if (offset >= sym_size)
+ if (addr >= sym->end)
return 0;
- h = notes->histogram;
+ offset = addr - sym->start;
+ h = annotation__histogram(notes, evidx);
h->sum++;
h->addr[offset]++;
pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
- "] => %" PRIu64 "\n", sym->start, sym->name,
- addr, addr - sym->start, h->addr[offset]);
+ ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
+ addr, addr - sym->start, evidx, h->addr[offset]);
return 0;
}
}
static void objdump_line__print(struct objdump_line *oline,
- struct list_head *head,
- struct symbol *sym, u64 len)
+ struct list_head *head, struct symbol *sym,
+ int evidx, u64 len)
{
static const char *prev_line;
static const char *prev_color;
const char *color;
struct annotation *notes = symbol__annotation(sym);
struct source_line *src_line = notes->src_line;
- struct sym_hist *h = notes->histogram;
+ struct sym_hist *h = annotation__histogram(notes, evidx);
s64 offset = oline->offset;
struct objdump_line *next = objdump__get_next_ip_line(head, oline);
/* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map,
- struct rb_root *root, int len,
+ int evidx, struct rb_root *root, int len,
const char *filename)
{
u64 start;
char cmd[PATH_MAX * 2];
struct source_line *src_line;
struct annotation *notes = symbol__annotation(sym);
- struct sym_hist *h = notes->histogram;
+ struct sym_hist *h = annotation__histogram(notes, evidx);
if (!h->sum)
return 0;
}
}
-static void symbol__annotate_hits(struct symbol *sym)
+static void symbol__annotate_hits(struct symbol *sym, int evidx)
{
struct annotation *notes = symbol__annotation(sym);
- struct sym_hist *h = notes->histogram;
+ struct sym_hist *h = annotation__histogram(notes, evidx);
u64 len = sym->end - sym->start, offset;
for (offset = 0; offset < len; ++offset)
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
}
-int symbol__tty_annotate(struct symbol *sym, struct map *map, bool print_lines,
- bool full_paths)
+int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
+ bool print_lines, bool full_paths)
{
struct dso *dso = map->dso;
const char *filename = dso->long_name, *d_filename;
len = sym->end - sym->start;
if (print_lines) {
- symbol__get_source_line(sym, map, &source_line, len, filename);
+ symbol__get_source_line(sym, map, evidx, &source_line,
+ len, filename);
print_summary(&source_line, filename);
}
printf("------------------------------------------------\n");
if (verbose)
- symbol__annotate_hits(sym);
+ symbol__annotate_hits(sym, evidx);
list_for_each_entry_safe(pos, n, &head, node) {
- objdump_line__print(pos, &head, sym, len);
+ objdump_line__print(pos, &head, sym, evidx, len);
list_del(&pos->node);
objdump_line__free(pos);
}
char *path;
};
+/** struct annotation - symbols with hits have this attached as in sannotation
+ *
+ * @histogram: Array of addr hit histograms per event being monitored
+ * @src_line: If 'print_lines' is specified, per source code line percentages
+ *
+ * src_line is allocated, percentages calculated and all sorted by percentage
+ * when the annotation is about to be presented, so the percentages are for
+ * one of the entries in the histogram array, i.e. for the event/counter being
+ * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate
+ * returns.
+ */
struct annotation {
- struct sym_hist *histogram;
struct source_line *src_line;
+ struct sym_hist *histograms;
+ int sizeof_sym_hist;
};
struct sannotation {
struct symbol symbol;
};
+static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
+{
+ return ((void *)notes->histograms) + (notes->sizeof_sym_hist * idx);
+}
+
static inline struct annotation *symbol__annotation(struct symbol *sym)
{
struct sannotation *a = container_of(sym, struct sannotation, symbol);
return &a->annotation;
}
-int symbol__inc_addr_samples(struct symbol *sym, struct map *map, u64 addr);
+int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
+ int evidx, u64 addr);
+int symbol__alloc_hist(struct symbol *sym, int nevents);
int symbol__annotate(struct symbol *sym, struct map *map,
struct list_head *head, size_t privsize);
-int symbol__tty_annotate(struct symbol *sym, struct map *map,
+int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
bool print_lines, bool full_paths);
#ifdef NO_NEWT_SUPPORT
static inline int symbol__tui_annotate(symbol *sym __used,
- struct map *map __used)
+ struct map *map __used, int evidx __used)
{
return 0;
}
#else
-int symbol__tui_annotate(struct symbol *sym, struct map *map);
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx);
#endif
#endif /* __PERF_ANNOTATE_H */
}
}
-int hist_entry__inc_addr_samples(struct hist_entry *he, u64 ip)
+int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
{
- return symbol__inc_addr_samples(he->ms.sym, he->ms.map, ip);
+ return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
}
int hist_entry__annotate(struct hist_entry *he, struct list_head *head,
size_t hists__fprintf(struct hists *self, struct hists *pair,
bool show_displacement, FILE *fp);
-int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip);
+int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
size_t privsize);
#ifdef NO_NEWT_SUPPORT
static inline int hists__browse(struct hists *self __used,
const char *helpline __used,
- const char *ev_name __used)
+ const char *ev_name __used, int evidx __used)
{
return 0;
}
static inline int hists__tui_browse_tree(struct rb_root *self __used,
- const char *help __used)
+ const char *help __used,
+ int evidx __used)
{
return 0;
}
-static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
+static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
+ int evidx __used)
{
return 0;
}
#else
#include <newt.h>
int hists__browse(struct hists *self, const char *helpline,
- const char *ev_name);
-int hist_entry__tui_annotate(struct hist_entry *self);
+ const char *ev_name, int evidx);
+int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
#define KEY_LEFT NEWT_KEY_LEFT
#define KEY_RIGHT NEWT_KEY_RIGHT
-int hists__tui_browse_tree(struct rb_root *self, const char *help);
+int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx);
#endif
unsigned int hists__sort_list_width(struct hists *self);
static double objdump_line__calc_percent(struct objdump_line *self,
struct list_head *head,
- struct symbol *sym)
+ struct symbol *sym, int evidx)
{
double percent = 0.0;
unsigned int hits = 0;
struct annotation *notes = symbol__annotation(sym);
struct source_line *src_line = notes->src_line;
- struct sym_hist *h = notes->histogram;
+ struct sym_hist *h = annotation__histogram(notes, evidx);
s64 offset = self->offset;
struct objdump_line *next = objdump__get_next_ip_line(head, self);
return key;
}
-int hist_entry__tui_annotate(struct hist_entry *he)
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
{
- return symbol__tui_annotate(he->ms.sym, he->ms.map);
+ return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx);
}
-int symbol__tui_annotate(struct symbol *sym, struct map *map)
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx)
{
struct objdump_line *pos, *n;
struct objdump_line_rb_node *rbpos;
browser.b.width = line_len;
rbpos = objdump_line__rb(pos);
rbpos->idx = browser.b.nr_entries++;
- rbpos->percent = objdump_line__calc_percent(pos, &head, sym);
+ rbpos->percent = objdump_line__calc_percent(pos, &head, sym, evidx);
if (rbpos->percent < 0.01)
continue;
objdump__insert_line(&browser.entries, rbpos);
return printed;
}
-int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
+int hists__browse(struct hists *self, const char *helpline,
+ const char *ev_name, int evidx)
{
struct hist_browser *browser = hist_browser__new(self);
struct pstack *fstack;
if (he == NULL)
continue;
- hist_entry__tui_annotate(he);
+ hist_entry__tui_annotate(he, evidx);
} else if (choice == browse_map)
map__browse(browser->selection->map);
else if (choice == zoom_dso) {
return key;
}
-int hists__tui_browse_tree(struct rb_root *self, const char *help)
+int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx)
{
struct rb_node *first = rb_first(self), *nd = first, *next;
int key = 0;
struct hists *hists = rb_entry(nd, struct hists, rb_node);
const char *ev_name = __event_name(hists->type, hists->config);
- key = hists__browse(hists, help, ev_name);
+ key = hists__browse(hists, help, ev_name, evidx);
switch (key) {
case NEWT_KEY_TAB:
next = rb_next(nd);