root/tools/perf/util/block-range.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. block_range__debug
  2. block_range__find
  3. rb_link_left_of_node
  4. rb_link_right_of_node
  5. block_range__create
  6. block_range__coverage

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

/* [<][>][^][v][top][bottom][index][help] */