source: branches/port5/SOURCE_TOOLS/profile_annotate.pl

Last change on this file was 5273, checked in by westram, 17 years ago
  • dont die, just warn on invalid total
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 5.7 KB
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6# --------------------------------------------------------------------------------
7
8sub scanLine($) {
9  my ($line) = @_;
10  if ($line =~ /^[ ]*([0-9,]+) [ ]*/o) {
11    my ($num,$rest) = ($1,$');
12    $num =~ s/,//ig;
13    return ($num,$rest);
14  }
15  return (undef,undef);
16}
17
18sub prefix_percent($$$) {
19  my ($line,$total,$partial) = @_;
20  if ($partial>$total) { print "Invalid partial=$partial (total=$total)\n"; }
21  my $percent = int($partial/$total*1000+0.5)/10;
22  return sprintf("%5.1f",$percent).'% | '.$line;
23}
24
25sub percentize($$) {
26  my ($line,$totals) = @_;
27  my ($num,$rest) = scanLine($line);
28  if (defined $num) {
29    (prefix_percent($line,$totals,$num),$rest);
30  }
31  else {
32    ($line,$rest);
33  }
34}
35
36sub percentize_cluster(\@$) {
37  my ($cluster_r, $cluster_total) = @_;
38
39  eval {
40    if (defined $cluster_total) {
41      my @new = ();
42      foreach (@$cluster_r) {
43        if (/ \| /o) {
44          my ($prefix,$orgline) = ($`.$&, $');
45          my ($size,$rest) = scanLine($orgline);
46
47          push @new, prefix_percent($_,$cluster_total,$size);
48        }
49      }
50
51      @$cluster_r = @new;
52    }
53  };
54  if ($@) {
55    print "Error: $@\nat cluster:\n";
56    foreach (@$cluster_r) {
57      print "'$_'\n";
58    }
59  }
60}
61
62sub add_percentages(\@) {
63  my ($lines_r) = @_;
64
65  my @out       = ();
66  my $nr        = 0;
67  my $maxnr     = scalar(@$lines_r);
68  my $totals    = undef;
69  my $dummy;
70  my $seperator = undef;
71
72  while (not defined $totals && $nr<$maxnr) {
73    my $line = $$lines_r[$nr++];
74    push @out, $line;
75    if ($line =~ /PROGRAM TOTALS$/o) {
76      ($totals,$dummy) = scanLine($line);
77    }
78    elsif (not defined $seperator) {
79      if ($line =~ /^-+$/o) { $seperator = $line; }
80    }
81  }
82
83  if (not defined $totals) { die "Could not parse PROGRAM TOTALS"; }
84  if (not defined $seperator) { die "No separator found"; }
85
86  my $last_line = pop @out;
87  ($last_line,$dummy) = percentize($last_line,$totals);
88  push @out, $last_line;
89  push @out, "";
90
91  my @rest          = ();
92  my @cluster       = ();
93  my $cluster_total = undef;
94  my $percentize_cluster = 1;
95
96  while ($nr<$maxnr) {
97    my $line = $$lines_r[$nr++];
98    my ($pline,$rest) = percentize($line,$totals);
99    if (defined $rest) { # percentage added
100      if ($rest =~ /^\*/o) {
101        push @out, $pline;
102        if ($pline =~ /\| /o) {
103          ($cluster_total,$dummy) = scanLine($');
104        }
105      }
106      push @cluster, $pline;
107    }
108    else {
109      if (scalar(@cluster)) {
110        if ($percentize_cluster==1) { percentize_cluster(@cluster,$cluster_total); }
111        push @rest, @cluster;
112        @cluster       = ();
113        $cluster_total = undef;
114      }
115
116      if ($line =~ /Auto-annotated source/o) { $percentize_cluster = 0; }
117      push @rest, $pline;
118    }
119  }
120
121  if (scalar(@cluster)) {
122    if ($percentize_cluster==1) { percentize_cluster(@cluster,$cluster_total); }
123    push @rest, @cluster;
124  }
125
126  @$lines_r = @out;
127  push @$lines_r, @rest;
128}
129
130# --------------------------------------------------------------------------------
131
132sub setModtime($$) {
133  my ($file,$modtime) = @_;
134  utime($modtime,$modtime,$file) || die "can't set modtime of '$file' (Reason: $!)";
135}
136
137sub getModtime($) {
138  my ($fileOrDir) = @_;
139  my $modtime = (stat($fileOrDir))[9];
140  return $modtime;
141}
142
143sub annotate_one($$$) {
144  my ($outfile,$force,$dir) = @_;
145  if (not -f $outfile) { die "No such file '$outfile'"; }
146  if (not $outfile =~ /^callgrind\.out\./o) {
147    die "Illegal name (expected 'callgrind.out.xxx' not '$outfile')";
148  }
149
150  my $annotated   = 'callgrind.annotated.'.$';
151  my $perform     = $force;
152  my $modtime_out = getModtime($outfile);
153
154  if (not -f $annotated) { $perform = 1; }
155  elsif ($modtime_out>getModtime($annotated)) { $perform = 1; }
156
157  if ($perform==1) {
158    print "* Updating $annotated\n";
159
160    my $command = "callgrind_annotate --tree=both --inclusive=yes ";
161    if (defined $dir) { $command .= '--auto=yes --include=./'.$dir.' '; }
162    $command .= $outfile;
163    my $line;
164    my @lines  = ();
165
166    open(CMD, $command.'|') || die "can't execute '$command' (Reason: $!)";
167    while (defined ($line=<CMD>)) {
168      chomp($line);
169      push @lines, $line;
170    }
171    close(CMD);
172
173    add_percentages(@lines);
174
175    open(ANNO,'>'.$annotated) || die "can't write '$annotated' (Reason: $!)";
176    print ANNO "Command was '$command'\n\n";
177    foreach (@lines) {
178      print ANNO $_."\n";
179    }
180    close(ANNO);
181    # setModtime($annotated,$modtime_out+2);
182  }
183}
184
185sub annotate_all() {
186  opendir(DIR,".") || die "can't read directory '.' (Reason: $!)";
187  foreach (readdir(DIR)) {
188    if (/^callgrind\.out\./o) {
189      annotate_one($_,0, undef);
190    }
191    elsif (/^callgrind\.annotate\./o) {
192      my $out = 'callgrind.out.'.$';
193      if (not -f $out) {
194        print "* $out disappeared => remove $_\n";
195        unlink($_) || die "Can't unlink '$_' (Reason: $!)";
196      }
197    }
198  }
199  closedir(DIR);
200}
201
202# --------------------------------------------------------------------------------
203
204sub die_usage($) {
205  my ($err) = @_;
206
207  die("Usage: profile_annotate.pl  all | callgrind.out.xxx [DIR]\n".
208      "       Annotates all or one callgrind.out.xxx\n".
209      "       Annotations are written to callgrind.annotated.xxx\n".
210      "       If 'all' is specified, all callgrind.annotated.xxx files without source get deleted.\n".
211      "       If DIR is given it's used for auto source annotation.\n".
212      "Error: $err\n"
213       );
214}
215
216sub main() {
217  my $args = scalar(@ARGV);
218  if ($args<1 || $args>2) { die_usage "Wrong number of arguments"; }
219
220  my $arg = $ARGV[0];
221  if ($arg eq 'all') { annotate_all(); }
222  elsif (-f $arg) {
223    my $dir = undef;
224    if ($args==2) {
225      $dir = $ARGV[1];
226      if (not -d $dir) { die "No such directory '$dir'"; }
227    }
228    annotate_one($arg,1,$dir);
229  }
230  else { die_usage("No such file '$arg'"); }
231}
232
233main();
234
235
Note: See TracBrowser for help on using the repository browser.