diff options
Diffstat (limited to 'src/boost/libs/asio/tools')
-rwxr-xr-x | src/boost/libs/asio/tools/handlerviz.pl | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/boost/libs/asio/tools/handlerviz.pl b/src/boost/libs/asio/tools/handlerviz.pl new file mode 100755 index 000000000..7e8de3df2 --- /dev/null +++ b/src/boost/libs/asio/tools/handlerviz.pl @@ -0,0 +1,299 @@ +#!/usr/bin/perl -w +# +# handlerviz.pl +# ~~~~~~~~~~~~~ +# +# A visualisation tool for post-processing the debug output generated by +# Asio-based programs. Programs write this output to the standard error stream +# when compiled with the define `BOOST_ASIO_ENABLE_HANDLER_TRACKING'. +# +# This tool generates output intended for use with the GraphViz tool `dot'. For +# example, to convert output to a PNG image, use: +# +# perl handlerviz.pl < output.txt | dot -Tpng > output.png +# +# To convert to a PDF file, use: +# +# perl handlerviz.pl < output.txt | dot -Tpdf > output.pdf +# +# Copyright (c) 2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +use strict; + +my %nodes = (); +my @edges = (); +my %anon_nodes = (); +my $anon_id = 0; +my %all_nodes = (); + +#------------------------------------------------------------------------------- +# Parse the debugging output and populate the nodes and edges. + +sub parse_debug_output() +{ + while (my $line = <>) + { + chomp($line); + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $timestamp = $1; + my $action = $2; + my $description = $3; + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + my $begin = $1; + my $end = $2; + my $label = $description; + $label =~ s/\./\\n/g; + + if ($begin eq "0") + { + $begin = "a" . $anon_id++; + $anon_nodes{$begin} = $timestamp; + $all_nodes{"$timestamp-$begin"} = $begin; + } + + my %edge = ( begin=>$begin, end=>$end, label=>$label ); + push(@edges, \%edge); + } + + # Begin handler invocation. + elsif ($action =~ /^>([0-9]+)$/) + { + my %new_node = ( label=>$description, entry=>$timestamp ); + $new_node{content} = (); + $nodes{$1} = \%new_node; + $all_nodes{"$timestamp-$1"} = $1; + } + + # End handler invocation. + elsif ($action =~ /^<([0-9]+)$/) + { + $nodes{$1}->{exit} = $timestamp; + } + + # Handler threw exception. + elsif ($action =~ /^!([0-9]+)$/) + { + push(@{$nodes{$1}->{content}}, "exception"); + } + + # Handler was destroyed without being invoked. + elsif ($action =~ /^~([0-9]+)$/) + { + my %new_node = ( label=>"$timestamp destroyed" ); + $new_node{content} = (); + $nodes{$1} = \%new_node; + $all_nodes{"$timestamp-$1"} = $1; + } + + # Handler performed some operation. + elsif ($action =~ /^([0-9]+)$/) + { + if ($1 eq "0") + { + my $id = "a" . $anon_id++; + $anon_nodes{$id} = "$timestamp\\l$description"; + $all_nodes{"$timestamp-$id"} = $id; + } + else + { + push(@{$nodes{$1}->{content}}, "$description"); + } + } + } + } +} + +#------------------------------------------------------------------------------- +# Helper function to convert a string to escaped HTML text. + +sub escape($) +{ + my $text = shift; + $text =~ s/&/\&\;/g; + $text =~ s/</\<\;/g; + $text =~ s/>/\>\;/g; + $text =~ s/\t/ /g; + return $text; +} + +#------------------------------------------------------------------------------- +# Templates for dot output. + +my $graph_header = <<"EOF"; +/* Generated by asioviz.pl */ +digraph G +{ +graph [ nodesep="1" ]; +node [ shape="box", fontsize="9" ]; +edge [ arrowtail="dot", fontsize="9" ]; +EOF + +my $graph_footer = <<"EOF"; +} +EOF + +my $node_header = <<"EOF"; +"%name%" +[ +label=<<table border="0" cellspacing="0"> +<tr><td align="left" bgcolor="gray" border="0">%label%</td></tr> +EOF + +my $node_footer = <<"EOF"; +</table>> +] +EOF + +my $node_content = <<"EOF"; +<tr><td align="left" bgcolor="white" border="0"> +<font face="mono" point-size="9">%content%</font> +</td></tr> +EOF + +my $anon_nodes_header = <<"EOF"; +{ +node [ shape="record" ]; +EOF + +my $anon_nodes_footer = <<"EOF"; +} +EOF + +my $anon_node = <<"EOF"; +"%name%" [ label="%label%", color="gray" ]; +EOF + +my $edges_header = <<"EOF"; +{ +edge [ style="dashed", arrowhead="open", weight="100" ]; +EOF + +my $edges_footer = <<"EOF"; +} +EOF + +my $edge = <<"EOF"; +"%begin%" -> "%end%" [ label="%label%" ] +EOF + +my $node_order_header = <<"EOF"; +{ +edge [ style="invis", weight="1" ]; +EOF + +my $node_order_footer = <<"EOF"; +} +EOF + +my $node_order = <<"EOF"; +"%begin%" -> "%end%" +EOF + +#------------------------------------------------------------------------------- +# Generate dot output from the nodes and edges. + +sub print_nodes() +{ + foreach my $name (sort keys %nodes) + { + my $node = $nodes{$name}; + my $entry = $node->{entry}; + my $exit = $node->{exit}; + my $label = escape($node->{label}); + my $header = $node_header; + $header =~ s/%name%/$name/g; + $header =~ s/%label%/$label/g; + print($header); + + my $line = $node_content; + my $content = $entry . " + " . sprintf("%.6f", $exit - $entry) . "s"; + $line =~ s/%content%/$content/g; + print($line); + + foreach my $content (@{$node->{content}}) + { + $content = escape($content); + $content = " " if length($content) == 0; + my $line = $node_content; + $line =~ s/%content%/$content/g; + print($line); + } + + print($node_footer); + } +} + +sub print_anon_nodes() +{ + print($anon_nodes_header); + foreach my $name (sort keys %anon_nodes) + { + my $label = $anon_nodes{$name}; + my $line = $anon_node; + $line =~ s/%name%/$name/g; + $line =~ s/%label%/$label/g; + print($line); + } + print($edges_footer); +} + +sub print_edges() +{ + print($edges_header); + foreach my $e (@edges) + { + my $begin = $e->{begin}; + my $end = $e->{end}; + my $label = $e->{label}; + my $line = $edge; + $line =~ s/%begin%/$begin/g; + $line =~ s/%end%/$end/g; + $line =~ s/%label%/$label/g; + print($line); + } + print($edges_footer); +} + +sub print_node_order() +{ + my $prev = ""; + print($node_order_header); + foreach my $name (sort keys %all_nodes) + { + if ($prev ne "") + { + my $begin = $prev; + my $end = $all_nodes{$name}; + my $line = $node_order; + $line =~ s/%begin%/$begin/g; + $line =~ s/%end%/$end/g; + print($line); + } + $prev = $all_nodes{$name}; + } + print($node_order_footer); +} + +sub generate_dot() +{ + print($graph_header); + print_nodes(); + print_anon_nodes(); + print_edges(); + print_node_order(); + print($graph_footer); +} + +#------------------------------------------------------------------------------- + +parse_debug_output(); +generate_dot(); |