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