block-range.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "block-range.h"
  3. #include "annotate.h"
  4. #include <assert.h>
  5. #include <stdlib.h>
  6. struct {
  7. struct rb_root root;
  8. u64 blocks;
  9. } block_ranges;
  10. static void block_range__debug(void)
  11. {
  12. #ifndef NDEBUG
  13. struct rb_node *rb;
  14. u64 old = 0; /* NULL isn't executable */
  15. for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
  16. struct block_range *entry = rb_entry(rb, struct block_range, node);
  17. assert(old < entry->start);
  18. assert(entry->start <= entry->end); /* single instruction block; jump to a jump */
  19. old = entry->end;
  20. }
  21. #endif
  22. }
  23. struct block_range *block_range__find(u64 addr)
  24. {
  25. struct rb_node **p = &block_ranges.root.rb_node;
  26. struct rb_node *parent = NULL;
  27. struct block_range *entry;
  28. while (*p != NULL) {
  29. parent = *p;
  30. entry = rb_entry(parent, struct block_range, node);
  31. if (addr < entry->start)
  32. p = &parent->rb_left;
  33. else if (addr > entry->end)
  34. p = &parent->rb_right;
  35. else
  36. return entry;
  37. }
  38. return NULL;
  39. }
  40. static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
  41. {
  42. struct rb_node **p = &node->rb_left;
  43. while (*p) {
  44. node = *p;
  45. p = &node->rb_right;
  46. }
  47. rb_link_node(left, node, p);
  48. }
  49. static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
  50. {
  51. struct rb_node **p = &node->rb_right;
  52. while (*p) {
  53. node = *p;
  54. p = &node->rb_left;
  55. }
  56. rb_link_node(right, node, p);
  57. }
  58. /**
  59. * block_range__create
  60. * @start: branch target starting this basic block
  61. * @end: branch ending this basic block
  62. *
  63. * Create all the required block ranges to precisely span the given range.
  64. */
  65. struct block_range_iter block_range__create(u64 start, u64 end)
  66. {
  67. struct rb_node **p = &block_ranges.root.rb_node;
  68. struct rb_node *n, *parent = NULL;
  69. struct block_range *next, *entry = NULL;
  70. struct block_range_iter iter = { NULL, NULL };
  71. while (*p != NULL) {
  72. parent = *p;
  73. entry = rb_entry(parent, struct block_range, node);
  74. if (start < entry->start)
  75. p = &parent->rb_left;
  76. else if (start > entry->end)
  77. p = &parent->rb_right;
  78. else
  79. break;
  80. }
  81. /*
  82. * Didn't find anything.. there's a hole at @start, however @end might
  83. * be inside/behind the next range.
  84. */
  85. if (!*p) {
  86. if (!entry) /* tree empty */
  87. goto do_whole;
  88. /*
  89. * If the last node is before, advance one to find the next.
  90. */
  91. n = parent;
  92. if (entry->end < start) {
  93. n = rb_next(n);
  94. if (!n)
  95. goto do_whole;
  96. }
  97. next = rb_entry(n, struct block_range, node);
  98. if (next->start <= end) { /* add head: [start...][n->start...] */
  99. struct block_range *head = malloc(sizeof(struct block_range));
  100. if (!head)
  101. return iter;
  102. *head = (struct block_range){
  103. .start = start,
  104. .end = next->start - 1,
  105. .is_target = 1,
  106. .is_branch = 0,
  107. };
  108. rb_link_left_of_node(&head->node, &next->node);
  109. rb_insert_color(&head->node, &block_ranges.root);
  110. block_range__debug();
  111. iter.start = head;
  112. goto do_tail;
  113. }
  114. do_whole:
  115. /*
  116. * The whole [start..end] range is non-overlapping.
  117. */
  118. entry = malloc(sizeof(struct block_range));
  119. if (!entry)
  120. return iter;
  121. *entry = (struct block_range){
  122. .start = start,
  123. .end = end,
  124. .is_target = 1,
  125. .is_branch = 1,
  126. };
  127. rb_link_node(&entry->node, parent, p);
  128. rb_insert_color(&entry->node, &block_ranges.root);
  129. block_range__debug();
  130. iter.start = entry;
  131. iter.end = entry;
  132. goto done;
  133. }
  134. /*
  135. * We found a range that overlapped with ours, split if needed.
  136. */
  137. if (entry->start < start) { /* split: [e->start...][start...] */
  138. struct block_range *head = malloc(sizeof(struct block_range));
  139. if (!head)
  140. return iter;
  141. *head = (struct block_range){
  142. .start = entry->start,
  143. .end = start - 1,
  144. .is_target = entry->is_target,
  145. .is_branch = 0,
  146. .coverage = entry->coverage,
  147. .entry = entry->entry,
  148. };
  149. entry->start = start;
  150. entry->is_target = 1;
  151. entry->entry = 0;
  152. rb_link_left_of_node(&head->node, &entry->node);
  153. rb_insert_color(&head->node, &block_ranges.root);
  154. block_range__debug();
  155. } else if (entry->start == start)
  156. entry->is_target = 1;
  157. iter.start = entry;
  158. do_tail:
  159. /*
  160. * At this point we've got: @iter.start = [@start...] but @end can still be
  161. * inside or beyond it.
  162. */
  163. entry = iter.start;
  164. for (;;) {
  165. /*
  166. * If @end is inside @entry, split.
  167. */
  168. if (end < entry->end) { /* split: [...end][...e->end] */
  169. struct block_range *tail = malloc(sizeof(struct block_range));
  170. if (!tail)
  171. return iter;
  172. *tail = (struct block_range){
  173. .start = end + 1,
  174. .end = entry->end,
  175. .is_target = 0,
  176. .is_branch = entry->is_branch,
  177. .coverage = entry->coverage,
  178. .taken = entry->taken,
  179. .pred = entry->pred,
  180. };
  181. entry->end = end;
  182. entry->is_branch = 1;
  183. entry->taken = 0;
  184. entry->pred = 0;
  185. rb_link_right_of_node(&tail->node, &entry->node);
  186. rb_insert_color(&tail->node, &block_ranges.root);
  187. block_range__debug();
  188. iter.end = entry;
  189. goto done;
  190. }
  191. /*
  192. * If @end matches @entry, done
  193. */
  194. if (end == entry->end) {
  195. entry->is_branch = 1;
  196. iter.end = entry;
  197. goto done;
  198. }
  199. next = block_range__next(entry);
  200. if (!next)
  201. goto add_tail;
  202. /*
  203. * If @end is in beyond @entry but not inside @next, add tail.
  204. */
  205. if (end < next->start) { /* add tail: [...e->end][...end] */
  206. struct block_range *tail;
  207. add_tail:
  208. tail = malloc(sizeof(struct block_range));
  209. if (!tail)
  210. return iter;
  211. *tail = (struct block_range){
  212. .start = entry->end + 1,
  213. .end = end,
  214. .is_target = 0,
  215. .is_branch = 1,
  216. };
  217. rb_link_right_of_node(&tail->node, &entry->node);
  218. rb_insert_color(&tail->node, &block_ranges.root);
  219. block_range__debug();
  220. iter.end = tail;
  221. goto done;
  222. }
  223. /*
  224. * If there is a hole between @entry and @next, fill it.
  225. */
  226. if (entry->end + 1 != next->start) {
  227. struct block_range *hole = malloc(sizeof(struct block_range));
  228. if (!hole)
  229. return iter;
  230. *hole = (struct block_range){
  231. .start = entry->end + 1,
  232. .end = next->start - 1,
  233. .is_target = 0,
  234. .is_branch = 0,
  235. };
  236. rb_link_left_of_node(&hole->node, &next->node);
  237. rb_insert_color(&hole->node, &block_ranges.root);
  238. block_range__debug();
  239. }
  240. entry = next;
  241. }
  242. done:
  243. assert(iter.start->start == start && iter.start->is_target);
  244. assert(iter.end->end == end && iter.end->is_branch);
  245. block_ranges.blocks++;
  246. return iter;
  247. }
  248. /*
  249. * Compute coverage as:
  250. *
  251. * br->coverage / br->sym->max_coverage
  252. *
  253. * This ensures each symbol has a 100% spot, to reflect that each symbol has a
  254. * most covered section.
  255. *
  256. * Returns [0-1] for coverage and -1 if we had no data what so ever or the
  257. * symbol does not exist.
  258. */
  259. double block_range__coverage(struct block_range *br)
  260. {
  261. struct symbol *sym;
  262. struct annotated_branch *branch;
  263. if (!br) {
  264. if (block_ranges.blocks)
  265. return 0;
  266. return -1;
  267. }
  268. sym = br->sym;
  269. if (!sym)
  270. return -1;
  271. branch = symbol__annotation(sym)->branch;
  272. if (!branch)
  273. return -1;
  274. return (double)br->coverage / branch->max_coverage;
  275. }