Skip to content

Instantly share code, notes, and snippets.

@revmischa
Created October 26, 2011 03:23
Show Gist options
  • Save revmischa/1315330 to your computer and use it in GitHub Desktop.
Save revmischa/1315330 to your computer and use it in GitHub Desktop.
Compare branches vs. branch mispredictions in libav profiling output
#!/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