Created
October 26, 2011 03:23
-
-
Save revmischa/1315330 to your computer and use it in GitHub Desktop.
Compare branches vs. branch mispredictions in libav profiling output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
# This script takes two files with profiling information about branch | |
# misprediction as input. It outputs the percentage of branch | |
# mispredictions per instruction address | |
use strict; | |
use warnings; | |
my $stats = compute_branch_misprediction_stats(); | |
print $stats . "\n"; | |
sub usage { | |
qq/Usage: $0 branch_count_file misprediction_count_file | |
/; | |
} | |
sub compute_branch_misprediction_stats { | |
# get input files | |
my ($branch_count_file, $misprediction_count_file) = @ARGV; | |
die usage() unless $branch_count_file && $misprediction_count_file; | |
# slurp files | |
my $branches = slurp($branch_count_file); | |
die "Could not read profile information from $branch_count_file" unless $branches && @$branches; | |
my $mispredictions = slurp($misprediction_count_file); | |
die "Could not read profile information from $misprediction_count_file" unless $mispredictions && @$mispredictions; | |
# parse files | |
my $branch_stats = parse_profile_info($branches); | |
my $misprediction_stats = parse_profile_info($mispredictions); | |
# merge stats | |
my @stats; | |
foreach my $addr (keys %$branch_stats) { | |
my $hit = $branch_stats->{$addr}; | |
my $miss = $misprediction_stats->{$addr}; | |
# ignore addrs not in both files | |
next unless $hit && $miss; | |
# get miss percentage | |
my $hit_total = $hit->{count}; | |
my $miss_total = $miss->{count}; | |
if (! defined $hit_total || ! defined $miss_total) { | |
warn "Did not get counts for addr $addr"; | |
next; | |
} | |
my $miss_pct = sprintf("%0.2f", ( $miss_total / ($hit_total + $miss_total) ) * 100); | |
push @stats, { addr => $addr, miss => $miss_total, hit => $hit_total, miss_pct => $miss_pct, file => $hit->{file}, line => $hit->{line} }; | |
} | |
# sort by miss pct | |
@stats = sort { $b->{miss} <=> $a->{miss} } @stats; | |
# format output | |
my $output = "Addr\t\tMiss\tHit\tMiss%\tFile:Line\n"; | |
foreach my $stat (@stats) { | |
my $addr = $stat->{addr}; | |
my $miss = $stat->{miss}; | |
my $hit = $stat->{hit}; | |
my $miss_pct = $stat->{miss_pct}; | |
my $file = $stat->{file}; | |
my $line = $stat->{line}; | |
# format output line | |
$output .= "$addr\t$miss\t$hit\t$miss_pct\%\t$file:$line\n"; | |
} | |
return $output; | |
} | |
# takes arrayref of lines as input, returns: | |
# { address => { line => $line, count => $count, file => $file, line => $line } } | |
sub parse_profile_info { | |
my ($info_lines) = @_; | |
my %ret; | |
foreach my $info_line (@$info_lines) { | |
# sample line: 00477f67 25 29.0698 /home/gaikai/x264-devel/encoder/cabac.c:106 | |
my ($addr, $count, $pct, $file, $line) = $info_line =~ m/ | |
^ | |
\s*([0-9A-Fa-f]+) # addr | |
\s+(\d+) # count | |
\s+([0-9\.]+) # pct | |
\s+([^:]+): # file: | |
(\d+)\s* # line | |
$ | |
/x; | |
next unless $addr && defined $count && $file && $line; | |
$ret{$addr} = { | |
count => $count, | |
file => $file, | |
line => $line, | |
}; | |
} | |
return \%ret; | |
} | |
# read file in | |
sub slurp { | |
my ($file) = @_; | |
die "$file does not exist" unless -e $file; | |
my $fh; | |
my @lines; | |
open $fh, "<$file" or die $!; | |
{ | |
local $/; | |
@lines = split("\n", <$fh>); | |
} | |
close $fh; | |
return \@lines; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment