]>
pere.pagekite.me Git - homepage.git/blob - linux/gprof-callgraph/gprof-callgraph.pl-20010101
3 # Author: Petter Reinholdtsen <pere@td.org.uit.no>
6 # Parse output from gprof, and generate graph output for daVinci or xvcg.
8 # This is alpha quality code, and indended as proof of consept. The
9 # idea is based on the C++ implementation cg by ? (look up name).
12 # - Encode # calls and time used into graph (color, edge width, dashed, etc)
13 # - Add daVinci output mode
14 # - Detect non-GNU gprof, and correct flags for this case
16 # - Use getopt to choose output mode and if unused functions should be
20 # 2000-12-30 Petter Reinholdtsen <pere@td.org.uit.no>
21 # Changed to skip unused functions.
25 my $url = "http://www.student.uit.no/~pere/linux/";
30 my $gprofopt = "-c -z";
32 # Which program to profile
35 # Only show called functions (flag) [dont work yet]
38 # Map from function name, to list of funcion calling this function
41 # Map from function name, to list of function called
44 # Map from function id to function name
51 parse_gnu_gprof
($program);
61 # Flag set when parsing gprof call graph output
64 open(GPROF
, "gprof $gprofopt $program |") || die "Unable to run gprof";
68 $ingraph = 1 if (/Call graph/);
69 $ingraph = 0 if (/This table describes the call tree/);
72 if (/^-+$/) { # End of current entry
73 debugmsg
(1, "Registering \"$current\"\n") if defined $current;
76 $pre{$current} = [@parents] if (@parents);
77 $post{$current}= [@children] if (@children);
79 debugmsg
(1, "No current func!\n");
89 $current = parse_current_func
($_);
92 # Match the parent and child functions. Examples:
93 # 2 get_ll_tempfile <cycle 3> [36]
94 # 0.00 0.00 0/5 __getproperty [891]
96 parse_parent_or_child
($current, $_);
103 return $func{$a} cmp $func{$b}
106 # Match current function, ie lines like these (notice the GNU
107 # gprof bug in the last line):
108 # Skip unused functions.
110 # [1] 0.0 0.00 0.00 0 <cycle 1 as a whole> [1]
111 # [4] 0.0 0.00 0.00 9 incache [4]
112 # [10000 0.0 0.00 0.00 9 incache [10000
113 # [10] 0.0 0.00 0.00 7 fndentry [10]
114 # [11] 0.0 0.00 0.00 7 get_property <cycle 3> [11]
115 sub parse_current_func
{
117 if(/^\[(\d+)\]?\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d\+]*)\s+(.+)\s+\[(\d+)\]$/) {
118 # Name the extracted variables
119 my ($id, $ptime, $selftime, $chtime, $called, $name, $index) =
120 ($1, $2, $3, $4, $5, $6, $7);
122 # I'm not quite sure if this would ever happen
123 print "Bad index or id: $id != $index\n " if ($id != $index);
125 # If this function wasn't called, skip to the next one
126 return undef if ($used_only && !$called);
128 if ($name =~ m/^\<.+\>$/) {
129 # cycle, not a function
130 debugmsg
(1, "Cycle \"$name\" index $index\n");
133 return save_func_name
($name, $id);
135 debugmsg
(0, "Bad formatting of line \"$line\"\n");
141 # Match parents and child of the current function.
142 # Skip unused functions.
144 sub parse_parent_or_child
146 my ($current, $line) = @_;
147 my ($selftime, $chtime, $countinfo, $name, $index) = $line =~
148 m
%^\s
+([\d
.]*)\s
+([\d
.]*)\s
+([\d
/\
+]+)\s
+(.+)\s\
[(\d
+)\
]$%;
149 if (!defined $name) {
150 debugmsg
(0, "Unable to parse \"$_\"\n");
154 # Check if this function was called at all
156 my ($this, $total) = split(/\//, $countinfo);
157 return unless (defined $total && 0 < $this);
160 debugmsg
(1, "Called: $countinfo\n");
162 $name = save_func_name
($name, $index);
165 push(@children, $name);
167 push(@parents, $name);
172 # Store decoded function name in hash with the function index as key
175 my ($name, $id) = @_;
178 # Remove cycle information
179 $current =~ s/\s*\<.+\>//;
181 $func{$id} = $current;
182 debugmsg
(1, "Name: \"$name\" -> \"$current\"\n");
186 # Output current graph database
190 for $current (sort sort_func_name
keys %func) {
191 my $name = $func{$current};
192 print "Func: \"" . $name . "\" [$current]\n";
195 if (defined $pre{$current}) {
197 for $f (sort sort_func_name
@{$pre{$current}}) {
198 print " " . $func{$f} . " [$f] -> \"$name\"\n";
203 if (defined $post{$current}) {
205 for $f (sort sort_func_name
@{$post{$current}}) {
206 print " \"$name\" -> \"" . $func{$f} . "\" [$f]\n";
214 my ($src, $dst, $thickness, $comment) = @_;
215 my $buffer = " edge: {".
216 " sourcename: \"$src\"".
217 " targetname: \"$dst\"" .
218 " thickness: $thickness }";
219 $buffer .= " /* $comment */\n" if ($comment);
224 # Output current graph database in vcg format
233 * VCG formatted call graph for program "$program" based on gprof output.
235 * Check <URL:$url> for more information.
239 title: "Profiling $program"
240 orientation: left_to_right
244 # First print all the nodes
245 for $current (sort sort_func_name
keys %func) {
246 my $name = $func{$current};
247 print " node: { title: \"$current\" label: \"$name\" borderwidth: 0}\n"
252 # Then print all the edges
253 for $current (sort sort_func_name
keys %func) {
254 my $name = $func{$current};
256 if (defined $pre{$current}) {
258 my $buffer = " /* \"$name\" callers */\n";
260 for $f (sort sort_func_name
@{$pre{$current}}) {
261 if (!exists $printed{"$f:$current"}) {
262 my $prename = $func{$f};
264 $buffer .= vcg_edge
($f, $current, $thickness, $prename);
265 $printed{"$f:$current"} = 1;
270 print $buffer if (0 < $content);
273 if (defined $post{$current}) {
275 my $buffer = " /* \"$name\" called */\n";
277 for $f (sort sort_func_name
@{$post{$current}}) {
278 if (!exists $printed{"$current:$f"}) {
279 my $postname = $func{$f};
281 $buffer .= vcg_edge
($current, $f, $thickness, $postname);
282 $printed{"$current:$f"} = 1;
287 print $buffer if (0 < $content);
295 # Output current graph database in daVinci format
297 sub dump_graph_daVinci
{
304 # First print all the nodes
305 for $current (sort sort_func_name
keys %func) {
306 my $name = $func{$current};
307 print " l(\"$current\",n(\"$name\",[],[\n";
309 if (defined $pre{$current}) {
311 for $f (sort sort_func_name
@{$pre{$current}}) {
312 print "l(\"$f\"->\"$current\",e(\"B\",[],";
316 print " edge: { sourcename: \"$f\" targetname: \"$current\"" .
322 if (defined $post{$current}) {
324 for $f (sort sort_func_name
@{$post{$current}}) {
325 print " edge: { sourcename: \"$current\" targetname: \"$f\"" .
337 my ($level, $msg) = @_;
338 print STDERR
$msg if ($level <= $debug);