0001
0002 #include "block-range.h"
0003 #include "annotate.h"
0004 #include <assert.h>
0005 #include <stdlib.h>
0006
0007 struct {
0008 struct rb_root root;
0009 u64 blocks;
0010 } block_ranges;
0011
0012 static void block_range__debug(void)
0013 {
0014
0015
0016
0017
0018 #if 1
0019 struct rb_node *rb;
0020 u64 old = 0;
0021
0022 for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
0023 struct block_range *entry = rb_entry(rb, struct block_range, node);
0024
0025 assert(old < entry->start);
0026 assert(entry->start <= entry->end);
0027
0028 old = entry->end;
0029 }
0030 #endif
0031 }
0032
0033 struct block_range *block_range__find(u64 addr)
0034 {
0035 struct rb_node **p = &block_ranges.root.rb_node;
0036 struct rb_node *parent = NULL;
0037 struct block_range *entry;
0038
0039 while (*p != NULL) {
0040 parent = *p;
0041 entry = rb_entry(parent, struct block_range, node);
0042
0043 if (addr < entry->start)
0044 p = &parent->rb_left;
0045 else if (addr > entry->end)
0046 p = &parent->rb_right;
0047 else
0048 return entry;
0049 }
0050
0051 return NULL;
0052 }
0053
0054 static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
0055 {
0056 struct rb_node **p = &node->rb_left;
0057 while (*p) {
0058 node = *p;
0059 p = &node->rb_right;
0060 }
0061 rb_link_node(left, node, p);
0062 }
0063
0064 static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
0065 {
0066 struct rb_node **p = &node->rb_right;
0067 while (*p) {
0068 node = *p;
0069 p = &node->rb_left;
0070 }
0071 rb_link_node(right, node, p);
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081 struct block_range_iter block_range__create(u64 start, u64 end)
0082 {
0083 struct rb_node **p = &block_ranges.root.rb_node;
0084 struct rb_node *n, *parent = NULL;
0085 struct block_range *next, *entry = NULL;
0086 struct block_range_iter iter = { NULL, NULL };
0087
0088 while (*p != NULL) {
0089 parent = *p;
0090 entry = rb_entry(parent, struct block_range, node);
0091
0092 if (start < entry->start)
0093 p = &parent->rb_left;
0094 else if (start > entry->end)
0095 p = &parent->rb_right;
0096 else
0097 break;
0098 }
0099
0100
0101
0102
0103
0104 if (!*p) {
0105 if (!entry)
0106 goto do_whole;
0107
0108
0109
0110
0111 n = parent;
0112 if (entry->end < start) {
0113 n = rb_next(n);
0114 if (!n)
0115 goto do_whole;
0116 }
0117 next = rb_entry(n, struct block_range, node);
0118
0119 if (next->start <= end) {
0120 struct block_range *head = malloc(sizeof(struct block_range));
0121 if (!head)
0122 return iter;
0123
0124 *head = (struct block_range){
0125 .start = start,
0126 .end = next->start - 1,
0127 .is_target = 1,
0128 .is_branch = 0,
0129 };
0130
0131 rb_link_left_of_node(&head->node, &next->node);
0132 rb_insert_color(&head->node, &block_ranges.root);
0133 block_range__debug();
0134
0135 iter.start = head;
0136 goto do_tail;
0137 }
0138
0139 do_whole:
0140
0141
0142
0143 entry = malloc(sizeof(struct block_range));
0144 if (!entry)
0145 return iter;
0146
0147 *entry = (struct block_range){
0148 .start = start,
0149 .end = end,
0150 .is_target = 1,
0151 .is_branch = 1,
0152 };
0153
0154 rb_link_node(&entry->node, parent, p);
0155 rb_insert_color(&entry->node, &block_ranges.root);
0156 block_range__debug();
0157
0158 iter.start = entry;
0159 iter.end = entry;
0160 goto done;
0161 }
0162
0163
0164
0165
0166 if (entry->start < start) {
0167 struct block_range *head = malloc(sizeof(struct block_range));
0168 if (!head)
0169 return iter;
0170
0171 *head = (struct block_range){
0172 .start = entry->start,
0173 .end = start - 1,
0174 .is_target = entry->is_target,
0175 .is_branch = 0,
0176
0177 .coverage = entry->coverage,
0178 .entry = entry->entry,
0179 };
0180
0181 entry->start = start;
0182 entry->is_target = 1;
0183 entry->entry = 0;
0184
0185 rb_link_left_of_node(&head->node, &entry->node);
0186 rb_insert_color(&head->node, &block_ranges.root);
0187 block_range__debug();
0188
0189 } else if (entry->start == start)
0190 entry->is_target = 1;
0191
0192 iter.start = entry;
0193
0194 do_tail:
0195
0196
0197
0198
0199 entry = iter.start;
0200 for (;;) {
0201
0202
0203
0204 if (end < entry->end) {
0205 struct block_range *tail = malloc(sizeof(struct block_range));
0206 if (!tail)
0207 return iter;
0208
0209 *tail = (struct block_range){
0210 .start = end + 1,
0211 .end = entry->end,
0212 .is_target = 0,
0213 .is_branch = entry->is_branch,
0214
0215 .coverage = entry->coverage,
0216 .taken = entry->taken,
0217 .pred = entry->pred,
0218 };
0219
0220 entry->end = end;
0221 entry->is_branch = 1;
0222 entry->taken = 0;
0223 entry->pred = 0;
0224
0225 rb_link_right_of_node(&tail->node, &entry->node);
0226 rb_insert_color(&tail->node, &block_ranges.root);
0227 block_range__debug();
0228
0229 iter.end = entry;
0230 goto done;
0231 }
0232
0233
0234
0235
0236 if (end == entry->end) {
0237 entry->is_branch = 1;
0238 iter.end = entry;
0239 goto done;
0240 }
0241
0242 next = block_range__next(entry);
0243 if (!next)
0244 goto add_tail;
0245
0246
0247
0248
0249 if (end < next->start) {
0250 struct block_range *tail;
0251 add_tail:
0252 tail = malloc(sizeof(struct block_range));
0253 if (!tail)
0254 return iter;
0255
0256 *tail = (struct block_range){
0257 .start = entry->end + 1,
0258 .end = end,
0259 .is_target = 0,
0260 .is_branch = 1,
0261 };
0262
0263 rb_link_right_of_node(&tail->node, &entry->node);
0264 rb_insert_color(&tail->node, &block_ranges.root);
0265 block_range__debug();
0266
0267 iter.end = tail;
0268 goto done;
0269 }
0270
0271
0272
0273
0274 if (entry->end + 1 != next->start) {
0275 struct block_range *hole = malloc(sizeof(struct block_range));
0276 if (!hole)
0277 return iter;
0278
0279 *hole = (struct block_range){
0280 .start = entry->end + 1,
0281 .end = next->start - 1,
0282 .is_target = 0,
0283 .is_branch = 0,
0284 };
0285
0286 rb_link_left_of_node(&hole->node, &next->node);
0287 rb_insert_color(&hole->node, &block_ranges.root);
0288 block_range__debug();
0289 }
0290
0291 entry = next;
0292 }
0293
0294 done:
0295 assert(iter.start->start == start && iter.start->is_target);
0296 assert(iter.end->end == end && iter.end->is_branch);
0297
0298 block_ranges.blocks++;
0299
0300 return iter;
0301 }
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315 double block_range__coverage(struct block_range *br)
0316 {
0317 struct symbol *sym;
0318
0319 if (!br) {
0320 if (block_ranges.blocks)
0321 return 0;
0322
0323 return -1;
0324 }
0325
0326 sym = br->sym;
0327 if (!sym)
0328 return -1;
0329
0330 return (double)br->coverage / symbol__annotation(sym)->max_coverage;
0331 }