scripts: get_abi.pl: add a graph to speedup the undefined algorithm
Searching for symlinks is an expensive operation with the current logic, as it is at the order of O(n^3). In practice, running the check spends 2-3 minutes to check all symbols. Fix it by storing the directory tree into a graph, and using a Breadth First Search (BFS) to find the links for each sysfs node. With such improvement, it can now report issues with ~11 seconds on my machine. It comes with a price, though: there are more symbols reported as undefined after this change. I suspect it is due to some sysfs circular loops that are dropped by BFS. Despite such increase, it seems that the reports are now more coherent. Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> Link: https://lore.kernel.org/r/f5c1e7b14a27132821c08f0459ba9aea3ed69028.1631957565.git.mchehab+huawei@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
0b87a1b81b
commit
ca8e055c22
1 changed files with 127 additions and 61 deletions
|
@ -546,6 +546,73 @@ sub dont_parse_special_attributes {
|
||||||
my %leaf;
|
my %leaf;
|
||||||
my %aliases;
|
my %aliases;
|
||||||
my @files;
|
my @files;
|
||||||
|
my %root;
|
||||||
|
|
||||||
|
sub graph_add_file {
|
||||||
|
my $file = shift;
|
||||||
|
my $type = shift;
|
||||||
|
|
||||||
|
my $dir = $file;
|
||||||
|
$dir =~ s,^(.*/).*,$1,;
|
||||||
|
$file =~ s,.*/,,;
|
||||||
|
|
||||||
|
my $name;
|
||||||
|
my $file_ref = \%root;
|
||||||
|
foreach my $edge(split "/", $dir) {
|
||||||
|
$name .= "$edge/";
|
||||||
|
if (!defined ${$file_ref}{$edge}) {
|
||||||
|
${$file_ref}{$edge} = { };
|
||||||
|
}
|
||||||
|
$file_ref = \%{$$file_ref{$edge}};
|
||||||
|
${$file_ref}{"__name"} = [ $name ];
|
||||||
|
}
|
||||||
|
$name .= "$file";
|
||||||
|
${$file_ref}{$file} = {
|
||||||
|
"__name" => [ $name ]
|
||||||
|
};
|
||||||
|
|
||||||
|
return \%{$$file_ref{$file}};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub graph_add_link {
|
||||||
|
my $file = shift;
|
||||||
|
my $link = shift;
|
||||||
|
|
||||||
|
# Traverse graph to find the reference
|
||||||
|
my $file_ref = \%root;
|
||||||
|
foreach my $edge(split "/", $file) {
|
||||||
|
$file_ref = \%{$$file_ref{$edge}} || die "Missing node!";
|
||||||
|
}
|
||||||
|
|
||||||
|
# do a BFS
|
||||||
|
|
||||||
|
my @queue;
|
||||||
|
my %seen;
|
||||||
|
my $base_name;
|
||||||
|
my $st;
|
||||||
|
|
||||||
|
push @queue, $file_ref;
|
||||||
|
$seen{$start}++;
|
||||||
|
|
||||||
|
while (@queue) {
|
||||||
|
my $v = shift @queue;
|
||||||
|
my @child = keys(%{$v});
|
||||||
|
|
||||||
|
foreach my $c(@child) {
|
||||||
|
next if $seen{$$v{$c}};
|
||||||
|
next if ($c eq "__name");
|
||||||
|
|
||||||
|
# Add new name
|
||||||
|
my $name = @{$$v{$c}{"__name"}}[0];
|
||||||
|
if ($name =~ s#^$file/#$link/#) {
|
||||||
|
push @{$$v{$c}{"__name"}}, $name;
|
||||||
|
}
|
||||||
|
# Add child to the queue and mark as seen
|
||||||
|
push @queue, $$v{$c};
|
||||||
|
$seen{$c}++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
my $escape_symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x29\x2b-\x2d\x3a-\x40\x7b-\xfe]) }x;
|
my $escape_symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x29\x2b-\x2d\x3a-\x40\x7b-\xfe]) }x;
|
||||||
sub parse_existing_sysfs {
|
sub parse_existing_sysfs {
|
||||||
|
@ -568,19 +635,50 @@ sub parse_existing_sysfs {
|
||||||
return if (defined($data{$file}));
|
return if (defined($data{$file}));
|
||||||
return if (defined($data{$abs_file}));
|
return if (defined($data{$abs_file}));
|
||||||
|
|
||||||
push @files, $abs_file;
|
push @files, graph_add_file($abs_file, "file");
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_leave($)
|
||||||
|
{
|
||||||
|
my $what = shift;
|
||||||
|
my $leave;
|
||||||
|
|
||||||
|
my $l = $what;
|
||||||
|
my $stop = 1;
|
||||||
|
|
||||||
|
$leave = $l;
|
||||||
|
$leave =~ s,/$,,;
|
||||||
|
$leave =~ s,.*/,,;
|
||||||
|
$leave =~ s/[\(\)]//g;
|
||||||
|
|
||||||
|
# $leave is used to improve search performance at
|
||||||
|
# check_undefined_symbols, as the algorithm there can seek
|
||||||
|
# for a small number of "what". It also allows giving a
|
||||||
|
# hint about a leave with the same name somewhere else.
|
||||||
|
# However, there are a few occurences where the leave is
|
||||||
|
# either a wildcard or a number. Just group such cases
|
||||||
|
# altogether.
|
||||||
|
if ($leave =~ m/^\.\*/ || $leave eq "" || $leave =~ /^\d+$/) {
|
||||||
|
$leave = "others";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_undefined_symbols {
|
sub check_undefined_symbols {
|
||||||
foreach my $file (sort @files) {
|
foreach my $file_ref (sort @files) {
|
||||||
|
my @names = @{$$file_ref{"__name"}};
|
||||||
|
my $file = $names[0];
|
||||||
|
|
||||||
my $defined = 0;
|
my $defined = 0;
|
||||||
my $exact = 0;
|
my $exact = 0;
|
||||||
my $whats = "";
|
|
||||||
my $found_string;
|
my $found_string;
|
||||||
|
|
||||||
my $leave = $file;
|
my $leave = get_leave($file);
|
||||||
$leave =~ s,.*/,,;
|
if (!defined($leaf{$leave})) {
|
||||||
|
$leave = "others";
|
||||||
|
}
|
||||||
|
my $what = $leaf{$leave};
|
||||||
|
|
||||||
my $path = $file;
|
my $path = $file;
|
||||||
$path =~ s,(.*/).*,$1,;
|
$path =~ s,(.*/).*,$1,;
|
||||||
|
@ -590,41 +688,12 @@ sub check_undefined_symbols {
|
||||||
$found_string = 1;
|
$found_string = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($leave =~ /^\d+$/ || !defined($leaf{$leave})) {
|
foreach my $a (@names) {
|
||||||
$leave = "others";
|
print "--> $a\n" if ($found_string && $hint);
|
||||||
}
|
foreach my $w (split /\xac/, $what) {
|
||||||
|
if ($a =~ m#^$w$#) {
|
||||||
print "--> $file\n" if ($found_string && $hint);
|
$exact = 1;
|
||||||
my $what = $leaf{$leave};
|
last;
|
||||||
$whats .= " $what" if (!($whats =~ m/$what/));
|
|
||||||
|
|
||||||
foreach my $w (split / /, $what) {
|
|
||||||
if ($file =~ m#^$w$#) {
|
|
||||||
$exact = 1;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Check for aliases
|
|
||||||
#
|
|
||||||
# TODO: this algorithm is O(w * n²). It can be
|
|
||||||
# improved in the future in order to handle it
|
|
||||||
# faster, by changing parse_existing_sysfs to
|
|
||||||
# store the sysfs inside a tree, at the expense
|
|
||||||
# on making the code less readable and/or using some
|
|
||||||
# additional perl library.
|
|
||||||
foreach my $a (keys %aliases) {
|
|
||||||
my $new = $aliases{$a};
|
|
||||||
my $len = length($new);
|
|
||||||
|
|
||||||
if (substr($file, 0, $len) eq $new) {
|
|
||||||
my $newf = $a . substr($file, $len);
|
|
||||||
|
|
||||||
print " $newf\n" if ($found_string && $hint);
|
|
||||||
foreach my $w (split / /, $what) {
|
|
||||||
if ($newf =~ m#^$w$#) {
|
|
||||||
$exact = 1;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,8 +710,13 @@ sub check_undefined_symbols {
|
||||||
# is not easily parseable.
|
# is not easily parseable.
|
||||||
next if ($file =~ m#/parameters/#);
|
next if ($file =~ m#/parameters/#);
|
||||||
|
|
||||||
if ($hint && $defined && $leave ne "others") {
|
if ($hint && $defined && (!$search_string || $found_string)) {
|
||||||
print "$leave at $path might be one of:$whats\n" if (!$search_string || $found_string);
|
$what =~ s/\xac/\n\t/g;
|
||||||
|
if ($leave ne "others") {
|
||||||
|
print " more likely regexes:\n\t$what\n";
|
||||||
|
} else {
|
||||||
|
print " tested regexes:\n\t$what\n";
|
||||||
|
}
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
print "$file not found.\n" if (!$search_string || $found_string);
|
print "$file not found.\n" if (!$search_string || $found_string);
|
||||||
|
@ -656,8 +730,10 @@ sub undefined_symbols {
|
||||||
no_chdir => 1
|
no_chdir => 1
|
||||||
}, $sysfs_prefix);
|
}, $sysfs_prefix);
|
||||||
|
|
||||||
|
$leaf{"others"} = "";
|
||||||
|
|
||||||
foreach my $w (sort keys %data) {
|
foreach my $w (sort keys %data) {
|
||||||
foreach my $what (split /\xac /,$w) {
|
foreach my $what (split /\xac/,$w) {
|
||||||
next if (!($what =~ m/^$sysfs_prefix/));
|
next if (!($what =~ m/^$sysfs_prefix/));
|
||||||
|
|
||||||
# Convert what into regular expressions
|
# Convert what into regular expressions
|
||||||
|
@ -700,19 +776,7 @@ sub undefined_symbols {
|
||||||
# (this happens on a few IIO definitions)
|
# (this happens on a few IIO definitions)
|
||||||
$what =~ s,\s*\=.*$,,;
|
$what =~ s,\s*\=.*$,,;
|
||||||
|
|
||||||
my $leave = $what;
|
my $leave = get_leave($what);
|
||||||
$leave =~ s,.*/,,;
|
|
||||||
|
|
||||||
# $leave is used to improve search performance at
|
|
||||||
# check_undefined_symbols, as the algorithm there can seek
|
|
||||||
# for a small number of "what". It also allows giving a
|
|
||||||
# hint about a leave with the same name somewhere else.
|
|
||||||
# However, there are a few occurences where the leave is
|
|
||||||
# either a wildcard or a number. Just group such cases
|
|
||||||
# altogether.
|
|
||||||
if ($leave =~ m/^\.\*/ || $leave eq "" || $leave =~ /^\d+$/) {
|
|
||||||
$leave = "others" ;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Escape all other symbols
|
# Escape all other symbols
|
||||||
$what =~ s/$escape_symbols/\\$1/g;
|
$what =~ s/$escape_symbols/\\$1/g;
|
||||||
|
@ -722,17 +786,14 @@ sub undefined_symbols {
|
||||||
|
|
||||||
$what =~ s/\xff/\\d+/g;
|
$what =~ s/\xff/\\d+/g;
|
||||||
|
|
||||||
|
|
||||||
# Special case: IIO ABI which a parenthesis.
|
# Special case: IIO ABI which a parenthesis.
|
||||||
$what =~ s/sqrt(.*)/sqrt\(.*\)/;
|
$what =~ s/sqrt(.*)/sqrt\(.*\)/;
|
||||||
|
|
||||||
$leave =~ s/[\(\)]//g;
|
|
||||||
|
|
||||||
my $added = 0;
|
my $added = 0;
|
||||||
foreach my $l (split /\|/, $leave) {
|
foreach my $l (split /\|/, $leave) {
|
||||||
if (defined($leaf{$l})) {
|
if (defined($leaf{$l})) {
|
||||||
next if ($leaf{$l} =~ m/$what/);
|
next if ($leaf{$l} =~ m/\b$what\b/);
|
||||||
$leaf{$l} .= " " . $what;
|
$leaf{$l} .= "\xac" . $what;
|
||||||
$added = 1;
|
$added = 1;
|
||||||
} else {
|
} else {
|
||||||
$leaf{$l} = $what;
|
$leaf{$l} = $what;
|
||||||
|
@ -745,6 +806,11 @@ sub undefined_symbols {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Take links into account
|
||||||
|
foreach my $link (keys %aliases) {
|
||||||
|
my $abs_file = $aliases{$link};
|
||||||
|
graph_add_link($abs_file, $link);
|
||||||
|
}
|
||||||
check_undefined_symbols;
|
check_undefined_symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue