sbsv1/abld/memtrace/memtrace.pl
changeset 40 68f68128601f
equal deleted inserted replaced
39:fa9d7d89d3d6 40:68f68128601f
       
     1 # Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 #
       
    13 # Description:
       
    14 # Postprocess EPOC memory usage trace file
       
    15 # 
       
    16 #
       
    17 
       
    18 no strict 'vars';
       
    19 use English;
       
    20 # Standard Symbian boilerplate to find and load E32env library
       
    21 use FindBin;		# for FindBin::Bin
       
    22 use Getopt::Long;
       
    23 
       
    24 my $PerlLibPath;    # fully qualified pathname of the directory containing our Perl modules
       
    25 
       
    26 BEGIN {
       
    27 # check user has a version of perl that will cope
       
    28 	require 5.005_03;
       
    29 # establish the path to the Perl libraries: currently the same directory as this script
       
    30 	$PerlLibPath = $FindBin::Bin;	# X:/epoc32/tools
       
    31 	$PerlLibPath =~ s/\//\\/g;	# X:\epoc32\tools
       
    32 	$PerlLibPath .= "\\";
       
    33 }
       
    34 
       
    35 use lib $PerlLibPath;
       
    36 use Modload;
       
    37 Load_SetModulePath($PerlLibPath);
       
    38 
       
    39 my $tickperiod = 0;
       
    40 my $emulproc = quotemeta("epoc[00000000]0001::");
       
    41 my $apprun = quotemeta("apprun[10003a4b]");
       
    42 my $ramdrive = quotemeta("TheRamDriveChunk");
       
    43 
       
    44 my @chunknames;	# Array of chunk names, indexed by chunkid
       
    45 my @traces;		# Array of chunk traces, each trace being an array
       
    46 				# of (tick,chunkid,size) triples
       
    47 my @chunkgroup;	# Group that a chunk belongs to, indexed by chunkid
       
    48 my @groupnames;	# Array of chunk group names (normally a group==a process)
       
    49 my @groups;		# Array of chunk groups, each group being an array of chunkids
       
    50 
       
    51 my %opts;
       
    52 my $result = GetOptions (\%opts, "detailed", "help");
       
    53 if($result && ($opts{'help'} || $#ARGV<0))
       
    54 	{
       
    55 	&help;
       
    56 	exit 0;
       
    57 	}
       
    58 if(!$result || $#ARGV>0)
       
    59 	{
       
    60 	&usage;
       
    61 	exit 1;
       
    62 	}
       
    63 
       
    64 my $file = $ARGV[0];
       
    65 open TRACE,$file or die "Error: Can't open trace file \"$file\".\n";
       
    66 
       
    67 #
       
    68 # Parse trace file
       
    69 #
       
    70 my %current;	# chunkids hashed by DChunk address
       
    71 my $nextchunkid;
       
    72 while(<TRACE>)
       
    73 	{
       
    74 	if (/MT:P\s+(\d+)\s*$/)
       
    75 		{
       
    76 		$tickperiod = $1;
       
    77 		}
       
    78 	elsif (/MT:C\s+(\d+)\s+([0-9a-fA-F]+)\s+(.+)\s*$/)
       
    79 		{
       
    80 		$current{$2} = $nextchunkid++;
       
    81 		push @chunknames, $3;
       
    82 		}
       
    83 	elsif (my ($tick, $addr, $size, $name) =
       
    84 		   (/MT:A\s+(\d+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+(.+)\s*$/))
       
    85 		{
       
    86 		my $chunkid = $current{$addr};
       
    87 		die "Error: Parsing failure - is trace file complete ?"
       
    88 			unless (defined $chunkid);
       
    89 		push @traces, [0+$tick, $chunkid, hex($size)];
       
    90 
       
    91 		# Check whether chunk has been renamed to something more useful
       
    92 		$chunknames[$chunkid] = $name
       
    93 			if (($chunknames[$chunkid] =~ /^$emulproc/io) ||
       
    94 				($chunknames[$chunkid] =~ /^$apprun/io));
       
    95 		}
       
    96 	elsif (/MT:D\s+(\d+)\s+([0-9a-fA-F]+)\s+(.+)\s*$/)
       
    97 		{
       
    98 		die "Error: Parsing failure" unless (defined $current{$2});
       
    99 		push @traces, [0+$1, $current{$2}, 0];
       
   100 		delete $current{$2};
       
   101 		}
       
   102 	elsif (/(MT:.\s+.*)/)
       
   103 		{
       
   104 		printf "Warning: Unrecognised trace line \"$1\".\n";
       
   105 		}
       
   106 	}
       
   107 close TRACE;
       
   108 die "Error: File \"$file\" does not contain any memory traces.\n"
       
   109   unless ($#chunknames>0);
       
   110 
       
   111 
       
   112 #
       
   113 # Group chunks together by name
       
   114 #
       
   115 for (0..$#chunknames)
       
   116 	{
       
   117 	my $chunkid = $_;
       
   118 	my $name = $chunknames[$chunkid];
       
   119 	$name = $1 if ($name =~ /($ramdrive)$/i);	# Special handling for ramdrive
       
   120 	$name = $1 if ($name =~ /^$emulproc(.*)/i);	# Use thread names on Emulator
       
   121 	($name) = ($name =~ /([^:]+)/);				# otherwise strip thread name
       
   122 
       
   123 	# yuck! linear search
       
   124 	my $found = 0;
       
   125 	for (0..$#groupnames)
       
   126 		{
       
   127 		my $groupid = $_;
       
   128 		if ($groupnames[$groupid] eq $name)
       
   129 			{
       
   130 			$found = 1;
       
   131 			push @{$groups[$groupid]}, $chunkid;
       
   132 			$chunkgroup[$chunkid] = $groupid;
       
   133 			last;
       
   134 			}
       
   135 		}
       
   136 	
       
   137 	if (!$found)
       
   138 		{
       
   139 		push @groupnames, $name;
       
   140 		push @groups, [$chunkid];
       
   141 		$chunkgroup[$chunkid] = $#groups;
       
   142 		}
       
   143 	}
       
   144 
       
   145 # Strip instance number (if any) from group name for presentation
       
   146 for (0..$#groupnames)
       
   147 	{
       
   148 	$groupnames[$_] = $1 if ($groupnames[$_] =~ /^([^]]+]?)/);
       
   149 	}
       
   150 
       
   151 #
       
   152 # Output
       
   153 #
       
   154 my @chunksizes; # Array of chunk sizes, indexed by chunkid
       
   155 for (0..$#chunknames) { $chunksizes[$_] = 0 };
       
   156 	
       
   157 if ($opts{'detailed'})
       
   158 	{
       
   159 	# Detailed output
       
   160 
       
   161 	foreach my $name (@groupnames) { print ",\"$name\"" };
       
   162 	print "\n";
       
   163 
       
   164 	# if the tick size in microseconds hasn't been reported in the log with MT:P, take a guess
       
   165 	my $tickdiv = 0;
       
   166 	if ($tickperiod == 0)
       
   167 		{
       
   168 		# Uses hacky method to determine whether on Emulator or Target
       
   169 		$tickdiv = ($chunknames[0] =~ /^$emulproc/io) ? 10 : 64;
       
   170 		}
       
   171 	else
       
   172 		{
       
   173 		# tickperiod is number of microseconds 
       
   174 		$tickdiv = 1000000 / $tickperiod;
       
   175 		}
       
   176 
       
   177 	my ($oldtick, $minitick) = (0,0);
       
   178 	my @groupsizes;
       
   179 	for my $trace (@traces)
       
   180 		{
       
   181 		my ($tick, $chunkid, $size) = @$trace;
       
   182 		if ($oldtick != $tick)
       
   183 			{
       
   184 			$oldtick = $tick;
       
   185 			$minitick=0;
       
   186 			}
       
   187 
       
   188 		$chunksizes[$chunkid] = $size;
       
   189 		my $groupid=$chunkgroup[$chunkid];
       
   190 		my $groupsize = 0;
       
   191 		foreach $chunkid (@{$groups[$groupid]})
       
   192 			{
       
   193 			$groupsize += $chunksizes[$chunkid];
       
   194 			}
       
   195 		$groupsizes[$groupid] = $groupsize;
       
   196 
       
   197 		print $tick/$tickdiv + ($minitick++)/1000000;
       
   198 		foreach $groupsize (@groupsizes)
       
   199 			{
       
   200 			if ($groupsize)
       
   201 				{
       
   202 				printf ",%d", $groupsize/1024;
       
   203 				}
       
   204 			else
       
   205 				{
       
   206 				print ',';		# make output prettier by omitting 0s
       
   207 				}
       
   208 			}
       
   209 		print "\n";
       
   210 		}
       
   211 	}
       
   212 else
       
   213 	{
       
   214 	# Summary output
       
   215 
       
   216 	my @grouphighs;
       
   217 	for my $trace (@traces)
       
   218 		{
       
   219 		my ($tick, $chunkid, $size) = @$trace;
       
   220 		$chunksizes[$chunkid] = $size;
       
   221 		my $groupid=$chunkgroup[$chunkid];
       
   222 		my $groupsize = 0;
       
   223 		foreach $chunkid (@{$groups[$groupid]})
       
   224 			{
       
   225 			$groupsize += $chunksizes[$chunkid];
       
   226 			}
       
   227 		$grouphighs[$groupid] = $groupsize
       
   228 			if (!defined($grouphighs[$groupid]) ||
       
   229 				($grouphighs[$groupid] < $groupsize));
       
   230 	}
       
   231 
       
   232 	printf "\"Process\", Size [K]\n";
       
   233 	for (0..$#groupnames)
       
   234 		{
       
   235 		printf "\"$groupnames[$_]\", %d\n", $grouphighs[$_]/1024;
       
   236 		}
       
   237 	}
       
   238 exit 0;
       
   239 
       
   240 
       
   241 sub help ()
       
   242 	{
       
   243 	my $build;
       
   244 	
       
   245 	&Load_ModuleL('E32TPVER');
       
   246 	print "\nmemtrace - " .
       
   247 	  "Postprocess EPOC memory usage trace (Build ", &E32tpver, ")\n";
       
   248 	&usage;
       
   249 	}
       
   250 	
       
   251 sub usage ()
       
   252 	{
       
   253 	print <<EOF
       
   254 
       
   255 Usage:
       
   256   memtrace [-d] <logfile>
       
   257 
       
   258 Where:
       
   259   <logfile>     Memory usage trace file.
       
   260 
       
   261 Options:
       
   262   -d            Produce a detailed listing.
       
   263 EOF
       
   264 	;
       
   265 	}