Linux 4.19-rc7
[linux-2.6/btrfs-unstable.git] / tools / perf / util / block-range.c
blobf1451c987eec8e4b96cfb825f48b93dd4c155700
1 // SPDX-License-Identifier: GPL-2.0
2 #include "block-range.h"
3 #include "annotate.h"
5 struct {
6 struct rb_root root;
7 u64 blocks;
8 } block_ranges;
10 static void block_range__debug(void)
13 * XXX still paranoid for now; see if we can make this depend on
14 * DEBUG=1 builds.
16 #if 1
17 struct rb_node *rb;
18 u64 old = 0; /* NULL isn't executable */
20 for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
21 struct block_range *entry = rb_entry(rb, struct block_range, node);
23 assert(old < entry->start);
24 assert(entry->start <= entry->end); /* single instruction block; jump to a jump */
26 old = entry->end;
28 #endif
31 struct block_range *block_range__find(u64 addr)
33 struct rb_node **p = &block_ranges.root.rb_node;
34 struct rb_node *parent = NULL;
35 struct block_range *entry;
37 while (*p != NULL) {
38 parent = *p;
39 entry = rb_entry(parent, struct block_range, node);
41 if (addr < entry->start)
42 p = &parent->rb_left;
43 else if (addr > entry->end)
44 p = &parent->rb_right;
45 else
46 return entry;
49 return NULL;
52 static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
54 struct rb_node **p = &node->rb_left;
55 while (*p) {
56 node = *p;
57 p = &node->rb_right;
59 rb_link_node(left, node, p);
62 static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
64 struct rb_node **p = &node->rb_right;
65 while (*p) {
66 node = *p;
67 p = &node->rb_left;
69 rb_link_node(right, node, p);
72 /**
73 * block_range__create
74 * @start: branch target starting this basic block
75 * @end: branch ending this basic block
77 * Create all the required block ranges to precisely span the given range.
79 struct block_range_iter block_range__create(u64 start, u64 end)
81 struct rb_node **p = &block_ranges.root.rb_node;
82 struct rb_node *n, *parent = NULL;
83 struct block_range *next, *entry = NULL;
84 struct block_range_iter iter = { NULL, NULL };
86 while (*p != NULL) {
87 parent = *p;
88 entry = rb_entry(parent, struct block_range, node);
90 if (start < entry->start)
91 p = &parent->rb_left;
92 else if (start > entry->end)
93 p = &parent->rb_right;
94 else
95 break;
99 * Didn't find anything.. there's a hole at @start, however @end might
100 * be inside/behind the next range.
102 if (!*p) {
103 if (!entry) /* tree empty */
104 goto do_whole;
107 * If the last node is before, advance one to find the next.
109 n = parent;
110 if (entry->end < start) {
111 n = rb_next(n);
112 if (!n)
113 goto do_whole;
115 next = rb_entry(n, struct block_range, node);
117 if (next->start <= end) { /* add head: [start...][n->start...] */
118 struct block_range *head = malloc(sizeof(struct block_range));
119 if (!head)
120 return iter;
122 *head = (struct block_range){
123 .start = start,
124 .end = next->start - 1,
125 .is_target = 1,
126 .is_branch = 0,
129 rb_link_left_of_node(&head->node, &next->node);
130 rb_insert_color(&head->node, &block_ranges.root);
131 block_range__debug();
133 iter.start = head;
134 goto do_tail;
137 do_whole:
139 * The whole [start..end] range is non-overlapping.
141 entry = malloc(sizeof(struct block_range));
142 if (!entry)
143 return iter;
145 *entry = (struct block_range){
146 .start = start,
147 .end = end,
148 .is_target = 1,
149 .is_branch = 1,
152 rb_link_node(&entry->node, parent, p);
153 rb_insert_color(&entry->node, &block_ranges.root);
154 block_range__debug();
156 iter.start = entry;
157 iter.end = entry;
158 goto done;
162 * We found a range that overlapped with ours, split if needed.
164 if (entry->start < start) { /* split: [e->start...][start...] */
165 struct block_range *head = malloc(sizeof(struct block_range));
166 if (!head)
167 return iter;
169 *head = (struct block_range){
170 .start = entry->start,
171 .end = start - 1,
172 .is_target = entry->is_target,
173 .is_branch = 0,
175 .coverage = entry->coverage,
176 .entry = entry->entry,
179 entry->start = start;
180 entry->is_target = 1;
181 entry->entry = 0;
183 rb_link_left_of_node(&head->node, &entry->node);
184 rb_insert_color(&head->node, &block_ranges.root);
185 block_range__debug();
187 } else if (entry->start == start)
188 entry->is_target = 1;
190 iter.start = entry;
192 do_tail:
194 * At this point we've got: @iter.start = [@start...] but @end can still be
195 * inside or beyond it.
197 entry = iter.start;
198 for (;;) {
200 * If @end is inside @entry, split.
202 if (end < entry->end) { /* split: [...end][...e->end] */
203 struct block_range *tail = malloc(sizeof(struct block_range));
204 if (!tail)
205 return iter;
207 *tail = (struct block_range){
208 .start = end + 1,
209 .end = entry->end,
210 .is_target = 0,
211 .is_branch = entry->is_branch,
213 .coverage = entry->coverage,
214 .taken = entry->taken,
215 .pred = entry->pred,
218 entry->end = end;
219 entry->is_branch = 1;
220 entry->taken = 0;
221 entry->pred = 0;
223 rb_link_right_of_node(&tail->node, &entry->node);
224 rb_insert_color(&tail->node, &block_ranges.root);
225 block_range__debug();
227 iter.end = entry;
228 goto done;
232 * If @end matches @entry, done
234 if (end == entry->end) {
235 entry->is_branch = 1;
236 iter.end = entry;
237 goto done;
240 next = block_range__next(entry);
241 if (!next)
242 goto add_tail;
245 * If @end is in beyond @entry but not inside @next, add tail.
247 if (end < next->start) { /* add tail: [...e->end][...end] */
248 struct block_range *tail;
249 add_tail:
250 tail = malloc(sizeof(struct block_range));
251 if (!tail)
252 return iter;
254 *tail = (struct block_range){
255 .start = entry->end + 1,
256 .end = end,
257 .is_target = 0,
258 .is_branch = 1,
261 rb_link_right_of_node(&tail->node, &entry->node);
262 rb_insert_color(&tail->node, &block_ranges.root);
263 block_range__debug();
265 iter.end = tail;
266 goto done;
270 * If there is a hole between @entry and @next, fill it.
272 if (entry->end + 1 != next->start) {
273 struct block_range *hole = malloc(sizeof(struct block_range));
274 if (!hole)
275 return iter;
277 *hole = (struct block_range){
278 .start = entry->end + 1,
279 .end = next->start - 1,
280 .is_target = 0,
281 .is_branch = 0,
284 rb_link_left_of_node(&hole->node, &next->node);
285 rb_insert_color(&hole->node, &block_ranges.root);
286 block_range__debug();
289 entry = next;
292 done:
293 assert(iter.start->start == start && iter.start->is_target);
294 assert(iter.end->end == end && iter.end->is_branch);
296 block_ranges.blocks++;
298 return iter;
303 * Compute coverage as:
305 * br->coverage / br->sym->max_coverage
307 * This ensures each symbol has a 100% spot, to reflect that each symbol has a
308 * most covered section.
310 * Returns [0-1] for coverage and -1 if we had no data what so ever or the
311 * symbol does not exist.
313 double block_range__coverage(struct block_range *br)
315 struct symbol *sym;
317 if (!br) {
318 if (block_ranges.blocks)
319 return 0;
321 return -1;
324 sym = br->sym;
325 if (!sym)
326 return -1;
328 return (double)br->coverage / symbol__annotation(sym)->max_coverage;