mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-05-09 21:42:09 +02:00
046fd8206d
`make check` will run sparse on the perf code base. A frequent warning is "warning: symbol '...' was not declared. Should it be static?" Go through and make global definitions without declarations static. In some cases it is deliberate due to dlsym accessing the symbol, this change doesn't clean up the missing declarations for perf test suites. Sometimes things can opportunistically be made const. Making somethings static exposed unused functions warnings, so restructuring of ifdefs was necessary for that. These changes reduce the size of the perf binary by 568 bytes. Committer notes: Refreshed the patch, the original one fell thru the cracks, updated the size reduction. Remove the trace-event-scripting.c changes, break the build, noticed with container builds and with sashiko: https://sashiko.dev/#/patchset/20260401215306.2152898-1-acme%40kernel.org Also make two variables static to address another sashiko review comment: https://sashiko.dev/#/patchset/20260402001740.2220481-1-acme%40kernel.org Signed-off-by: Ian Rogers <irogers@google.com> Acked-by: Ankur Arora <ankur.a.arora@oracle.com> Acked-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Alexandre Ghiti <alex@ghiti.fr> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Guo Ren <guoren@kernel.org> Cc: Howard Chu <howardchu95@gmail.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Leo Yan <leo.yan@arm.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Palmer Dabbelt <palmer@dabbelt.com> Cc: Paul Walmsley <pjw@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Yujie Liu <yujie.liu@intel.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
333 lines
6.9 KiB
C
333 lines
6.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include "block-range.h"
|
|
#include "annotate.h"
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
static struct {
|
|
struct rb_root root;
|
|
u64 blocks;
|
|
} block_ranges;
|
|
|
|
static void block_range__debug(void)
|
|
{
|
|
#ifndef NDEBUG
|
|
struct rb_node *rb;
|
|
u64 old = 0; /* NULL isn't executable */
|
|
|
|
for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
|
|
struct block_range *entry = rb_entry(rb, struct block_range, node);
|
|
|
|
assert(old < entry->start);
|
|
assert(entry->start <= entry->end); /* single instruction block; jump to a jump */
|
|
|
|
old = entry->end;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
struct block_range *block_range__find(u64 addr)
|
|
{
|
|
struct rb_node **p = &block_ranges.root.rb_node;
|
|
struct rb_node *parent = NULL;
|
|
struct block_range *entry;
|
|
|
|
while (*p != NULL) {
|
|
parent = *p;
|
|
entry = rb_entry(parent, struct block_range, node);
|
|
|
|
if (addr < entry->start)
|
|
p = &parent->rb_left;
|
|
else if (addr > entry->end)
|
|
p = &parent->rb_right;
|
|
else
|
|
return entry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
|
|
{
|
|
struct rb_node **p = &node->rb_left;
|
|
while (*p) {
|
|
node = *p;
|
|
p = &node->rb_right;
|
|
}
|
|
rb_link_node(left, node, p);
|
|
}
|
|
|
|
static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
|
|
{
|
|
struct rb_node **p = &node->rb_right;
|
|
while (*p) {
|
|
node = *p;
|
|
p = &node->rb_left;
|
|
}
|
|
rb_link_node(right, node, p);
|
|
}
|
|
|
|
/**
|
|
* block_range__create
|
|
* @start: branch target starting this basic block
|
|
* @end: branch ending this basic block
|
|
*
|
|
* Create all the required block ranges to precisely span the given range.
|
|
*/
|
|
struct block_range_iter block_range__create(u64 start, u64 end)
|
|
{
|
|
struct rb_node **p = &block_ranges.root.rb_node;
|
|
struct rb_node *n, *parent = NULL;
|
|
struct block_range *next, *entry = NULL;
|
|
struct block_range_iter iter = { NULL, NULL };
|
|
|
|
while (*p != NULL) {
|
|
parent = *p;
|
|
entry = rb_entry(parent, struct block_range, node);
|
|
|
|
if (start < entry->start)
|
|
p = &parent->rb_left;
|
|
else if (start > entry->end)
|
|
p = &parent->rb_right;
|
|
else
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Didn't find anything.. there's a hole at @start, however @end might
|
|
* be inside/behind the next range.
|
|
*/
|
|
if (!*p) {
|
|
if (!entry) /* tree empty */
|
|
goto do_whole;
|
|
|
|
/*
|
|
* If the last node is before, advance one to find the next.
|
|
*/
|
|
n = parent;
|
|
if (entry->end < start) {
|
|
n = rb_next(n);
|
|
if (!n)
|
|
goto do_whole;
|
|
}
|
|
next = rb_entry(n, struct block_range, node);
|
|
|
|
if (next->start <= end) { /* add head: [start...][n->start...] */
|
|
struct block_range *head = malloc(sizeof(struct block_range));
|
|
if (!head)
|
|
return iter;
|
|
|
|
*head = (struct block_range){
|
|
.start = start,
|
|
.end = next->start - 1,
|
|
.is_target = 1,
|
|
.is_branch = 0,
|
|
};
|
|
|
|
rb_link_left_of_node(&head->node, &next->node);
|
|
rb_insert_color(&head->node, &block_ranges.root);
|
|
block_range__debug();
|
|
|
|
iter.start = head;
|
|
goto do_tail;
|
|
}
|
|
|
|
do_whole:
|
|
/*
|
|
* The whole [start..end] range is non-overlapping.
|
|
*/
|
|
entry = malloc(sizeof(struct block_range));
|
|
if (!entry)
|
|
return iter;
|
|
|
|
*entry = (struct block_range){
|
|
.start = start,
|
|
.end = end,
|
|
.is_target = 1,
|
|
.is_branch = 1,
|
|
};
|
|
|
|
rb_link_node(&entry->node, parent, p);
|
|
rb_insert_color(&entry->node, &block_ranges.root);
|
|
block_range__debug();
|
|
|
|
iter.start = entry;
|
|
iter.end = entry;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* We found a range that overlapped with ours, split if needed.
|
|
*/
|
|
if (entry->start < start) { /* split: [e->start...][start...] */
|
|
struct block_range *head = malloc(sizeof(struct block_range));
|
|
if (!head)
|
|
return iter;
|
|
|
|
*head = (struct block_range){
|
|
.start = entry->start,
|
|
.end = start - 1,
|
|
.is_target = entry->is_target,
|
|
.is_branch = 0,
|
|
|
|
.coverage = entry->coverage,
|
|
.entry = entry->entry,
|
|
};
|
|
|
|
entry->start = start;
|
|
entry->is_target = 1;
|
|
entry->entry = 0;
|
|
|
|
rb_link_left_of_node(&head->node, &entry->node);
|
|
rb_insert_color(&head->node, &block_ranges.root);
|
|
block_range__debug();
|
|
|
|
} else if (entry->start == start)
|
|
entry->is_target = 1;
|
|
|
|
iter.start = entry;
|
|
|
|
do_tail:
|
|
/*
|
|
* At this point we've got: @iter.start = [@start...] but @end can still be
|
|
* inside or beyond it.
|
|
*/
|
|
entry = iter.start;
|
|
for (;;) {
|
|
/*
|
|
* If @end is inside @entry, split.
|
|
*/
|
|
if (end < entry->end) { /* split: [...end][...e->end] */
|
|
struct block_range *tail = malloc(sizeof(struct block_range));
|
|
if (!tail)
|
|
return iter;
|
|
|
|
*tail = (struct block_range){
|
|
.start = end + 1,
|
|
.end = entry->end,
|
|
.is_target = 0,
|
|
.is_branch = entry->is_branch,
|
|
|
|
.coverage = entry->coverage,
|
|
.taken = entry->taken,
|
|
.pred = entry->pred,
|
|
};
|
|
|
|
entry->end = end;
|
|
entry->is_branch = 1;
|
|
entry->taken = 0;
|
|
entry->pred = 0;
|
|
|
|
rb_link_right_of_node(&tail->node, &entry->node);
|
|
rb_insert_color(&tail->node, &block_ranges.root);
|
|
block_range__debug();
|
|
|
|
iter.end = entry;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* If @end matches @entry, done
|
|
*/
|
|
if (end == entry->end) {
|
|
entry->is_branch = 1;
|
|
iter.end = entry;
|
|
goto done;
|
|
}
|
|
|
|
next = block_range__next(entry);
|
|
if (!next)
|
|
goto add_tail;
|
|
|
|
/*
|
|
* If @end is in beyond @entry but not inside @next, add tail.
|
|
*/
|
|
if (end < next->start) { /* add tail: [...e->end][...end] */
|
|
struct block_range *tail;
|
|
add_tail:
|
|
tail = malloc(sizeof(struct block_range));
|
|
if (!tail)
|
|
return iter;
|
|
|
|
*tail = (struct block_range){
|
|
.start = entry->end + 1,
|
|
.end = end,
|
|
.is_target = 0,
|
|
.is_branch = 1,
|
|
};
|
|
|
|
rb_link_right_of_node(&tail->node, &entry->node);
|
|
rb_insert_color(&tail->node, &block_ranges.root);
|
|
block_range__debug();
|
|
|
|
iter.end = tail;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* If there is a hole between @entry and @next, fill it.
|
|
*/
|
|
if (entry->end + 1 != next->start) {
|
|
struct block_range *hole = malloc(sizeof(struct block_range));
|
|
if (!hole)
|
|
return iter;
|
|
|
|
*hole = (struct block_range){
|
|
.start = entry->end + 1,
|
|
.end = next->start - 1,
|
|
.is_target = 0,
|
|
.is_branch = 0,
|
|
};
|
|
|
|
rb_link_left_of_node(&hole->node, &next->node);
|
|
rb_insert_color(&hole->node, &block_ranges.root);
|
|
block_range__debug();
|
|
}
|
|
|
|
entry = next;
|
|
}
|
|
|
|
done:
|
|
assert(iter.start->start == start && iter.start->is_target);
|
|
assert(iter.end->end == end && iter.end->is_branch);
|
|
|
|
block_ranges.blocks++;
|
|
|
|
return iter;
|
|
}
|
|
|
|
|
|
/*
|
|
* Compute coverage as:
|
|
*
|
|
* br->coverage / br->sym->max_coverage
|
|
*
|
|
* This ensures each symbol has a 100% spot, to reflect that each symbol has a
|
|
* most covered section.
|
|
*
|
|
* Returns [0-1] for coverage and -1 if we had no data what so ever or the
|
|
* symbol does not exist.
|
|
*/
|
|
double block_range__coverage(struct block_range *br)
|
|
{
|
|
struct symbol *sym;
|
|
struct annotated_branch *branch;
|
|
|
|
if (!br) {
|
|
if (block_ranges.blocks)
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
sym = br->sym;
|
|
if (!sym)
|
|
return -1;
|
|
|
|
branch = symbol__annotation(sym)->branch;
|
|
if (!branch)
|
|
return -1;
|
|
|
|
return (double)br->coverage / branch->max_coverage;
|
|
}
|