annotate.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "../browser.h"
  2. #include "../helpline.h"
  3. #include "../libslang.h"
  4. #include "../../hist.h"
  5. #include "../../sort.h"
  6. #include "../../symbol.h"
  7. static void ui__error_window(const char *fmt, ...)
  8. {
  9. va_list ap;
  10. va_start(ap, fmt);
  11. newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
  12. va_end(ap);
  13. }
  14. struct annotate_browser {
  15. struct ui_browser b;
  16. struct rb_root entries;
  17. };
  18. struct objdump_line_rb_node {
  19. struct rb_node rb_node;
  20. double percent;
  21. u32 idx;
  22. };
  23. static inline
  24. struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
  25. {
  26. return (struct objdump_line_rb_node *)(self + 1);
  27. }
  28. static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
  29. {
  30. struct objdump_line *ol = rb_entry(entry, struct objdump_line, node);
  31. bool current_entry = ui_browser__is_current_entry(self, row);
  32. int width = self->width;
  33. if (ol->offset != -1) {
  34. struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
  35. int color = ui_browser__percent_color(olrb->percent, current_entry);
  36. SLsmg_set_color(color);
  37. slsmg_printf(" %7.2f ", olrb->percent);
  38. if (!current_entry)
  39. SLsmg_set_color(HE_COLORSET_CODE);
  40. } else {
  41. int color = ui_browser__percent_color(0, current_entry);
  42. SLsmg_set_color(color);
  43. slsmg_write_nstring(" ", 9);
  44. }
  45. SLsmg_write_char(':');
  46. slsmg_write_nstring(" ", 8);
  47. if (!*ol->line)
  48. slsmg_write_nstring(" ", width - 18);
  49. else
  50. slsmg_write_nstring(ol->line, width - 18);
  51. }
  52. static double objdump_line__calc_percent(struct objdump_line *self,
  53. struct list_head *head,
  54. struct symbol *sym)
  55. {
  56. double percent = 0.0;
  57. if (self->offset != -1) {
  58. int len = sym->end - sym->start;
  59. unsigned int hits = 0;
  60. struct sym_priv *priv = symbol__priv(sym);
  61. struct sym_ext *sym_ext = priv->ext;
  62. struct sym_hist *h = priv->hist;
  63. s64 offset = self->offset;
  64. struct objdump_line *next = objdump__get_next_ip_line(head, self);
  65. while (offset < (s64)len &&
  66. (next == NULL || offset < next->offset)) {
  67. if (sym_ext) {
  68. percent += sym_ext[offset].percent;
  69. } else
  70. hits += h->ip[offset];
  71. ++offset;
  72. }
  73. if (sym_ext == NULL && h->sum)
  74. percent = 100.0 * hits / h->sum;
  75. }
  76. return percent;
  77. }
  78. static void objdump__insert_line(struct rb_root *self,
  79. struct objdump_line_rb_node *line)
  80. {
  81. struct rb_node **p = &self->rb_node;
  82. struct rb_node *parent = NULL;
  83. struct objdump_line_rb_node *l;
  84. while (*p != NULL) {
  85. parent = *p;
  86. l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
  87. if (line->percent < l->percent)
  88. p = &(*p)->rb_left;
  89. else
  90. p = &(*p)->rb_right;
  91. }
  92. rb_link_node(&line->rb_node, parent, p);
  93. rb_insert_color(&line->rb_node, self);
  94. }
  95. int hist_entry__tui_annotate(struct hist_entry *self)
  96. {
  97. struct newtExitStruct es;
  98. struct objdump_line *pos, *n;
  99. struct objdump_line_rb_node *rbpos;
  100. struct rb_node *nd;
  101. LIST_HEAD(head);
  102. struct annotate_browser browser = {
  103. .b = {
  104. .entries = &head,
  105. .refresh = ui_browser__list_head_refresh,
  106. .seek = ui_browser__list_head_seek,
  107. .write = annotate_browser__write,
  108. .priv = self,
  109. },
  110. };
  111. int ret;
  112. if (self->ms.sym == NULL)
  113. return -1;
  114. if (self->ms.map->dso->annotate_warned)
  115. return -1;
  116. if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) {
  117. ui__error_window(ui_helpline__last_msg);
  118. return -1;
  119. }
  120. ui_helpline__push("Press <- or ESC to exit");
  121. list_for_each_entry(pos, &head, node) {
  122. size_t line_len = strlen(pos->line);
  123. if (browser.b.width < line_len)
  124. browser.b.width = line_len;
  125. rbpos = objdump_line__rb(pos);
  126. rbpos->idx = browser.b.nr_entries++;
  127. rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
  128. if (rbpos->percent < 0.01)
  129. continue;
  130. objdump__insert_line(&browser.entries, rbpos);
  131. }
  132. /*
  133. * Position the browser at the hottest line.
  134. */
  135. nd = rb_last(&browser.entries);
  136. if (nd != NULL) {
  137. unsigned back;
  138. ui_browser__refresh_dimensions(&browser.b);
  139. back = browser.b.height / 2;
  140. rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
  141. pos = ((struct objdump_line *)rbpos) - 1;
  142. browser.b.top_idx = browser.b.index = rbpos->idx;
  143. while (browser.b.top_idx != 0 && back != 0) {
  144. pos = list_entry(pos->node.prev, struct objdump_line, node);
  145. --browser.b.top_idx;
  146. --back;
  147. }
  148. browser.b.top = pos;
  149. }
  150. browser.b.width += 18; /* Percentage */
  151. ui_browser__show(&browser.b, self->ms.sym->name);
  152. ret = ui_browser__run(&browser.b, &es);
  153. newtFormDestroy(browser.b.form);
  154. newtPopWindow();
  155. list_for_each_entry_safe(pos, n, &head, node) {
  156. list_del(&pos->node);
  157. objdump_line__free(pos);
  158. }
  159. ui_helpline__pop();
  160. return ret;
  161. }