From e1e6e89bd8e573434f0b2d1c613614c95bb7e141 Mon Sep 17 00:00:00 2001 From: Bart Wiegmans Date: Fri, 28 Aug 2020 13:04:55 +0200 Subject: [PATCH] [dtrace-perf-map] Use binary rather than linear search Linear search was very slow on a decently-sized perf map, but with sorting + binary search it's rather faster. --- bin/dtrace-perf-map.pl | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/bin/dtrace-perf-map.pl b/bin/dtrace-perf-map.pl index 0c6588e..c60b178 100755 --- a/bin/dtrace-perf-map.pl +++ b/bin/dtrace-perf-map.pl @@ -4,8 +4,7 @@ no warnings 'portable'; use strict; -my $num_args = $#ARGV + 1; -if ($num_args != 1) { +if (@ARGV != 1) { print "\nUsage: $0 perf-*.map\n"; exit; } @@ -22,30 +21,35 @@ my $address = hex($parts[0]); my $size = hex($parts[1]); my $method = $parts[2]; - my @entry = (); - - push @entry, $address; - push @entry, $size; - push @entry, $method; - push @map_entries, [@entry]; + push @map_entries, [$address, $size, $method]; } +# Sort to allow for binary search +@map_entries = sort { $a->[0] <=> $b->[0] } @map_entries; + # Process STDIN and replace unkown methods with these provided by the perf-*.map file. while (my $row = ) { chomp $row; if ($row =~ "^ 0x(.+)") { my $addr = hex($1); my $size = -1; - foreach my $e (@map_entries) { - my $entry_addr = $e->[0]; - my $entry_size = $e->[1]; - - # First check if we had a match before that had a smaller entry_size. If so its a better match and we should just continue. - if (($size == -1 || $entry_size < $size) && $addr >= $entry_addr && $addr <= ($entry_addr + $entry_size)) { - $row = " $e->[2]"; - $size = $entry_size; - } - } + # binary search map entries + my ($l, $h) = (0, 0 + @map_entries); + while (($h - $l) > 1) { + my $m = int(($h + $l) / 2); + my $entry_addr = $map_entries[$m][0]; + if ($entry_addr < $addr) { + $l = $m; + } else { + $h = $m; + } + } + my $entry_addr = $map_entries[$l][0]; + my $entry_size = $map_entries[$l][1]; + my $method = $map_entries[$l][2]; + if ($addr >= $entry_addr && $addr <= ($entry_addr + $entry_size)) { + $row = " $method"; + } } print "$row\n"; }