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