os/graphics/fbs/fontandbitmapserver/utils/fbsbitmap_memory.pl
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/fbs/fontandbitmapserver/utils/fbsbitmap_memory.pl	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,318 @@
     1.4 +#!/usr/local/bin/perl
     1.5 +#
     1.6 +# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
     1.7 +# All rights reserved.
     1.8 +# This component and the accompanying materials are made available
     1.9 +# under the terms of "Eclipse Public License v1.0"
    1.10 +# which accompanies this distribution, and is available
    1.11 +# at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.12 +#
    1.13 +# Initial Contributors:
    1.14 +# Nokia Corporation - initial contribution.
    1.15 +#
    1.16 +# Contributors:
    1.17 +#
    1.18 +# Description:
    1.19 +#  This script parses trace data produced by OST from FBS, using the the FBSCLI, 
    1.20 +#  FBSERV and Symbian BTrace Hooks OST dictionaries, to produce a CSV output of
    1.21 +#  the amount of bitmap memory used per-thread over a user-definable time
    1.22 +#  granularity, since the start of the trace.
    1.23 +# 
    1.24 +#  To use, enable SYMBIAN_KERNEL_THREAD_IDENTIFICATION trace group in Symbian
    1.25 +#  BTrace Hooks OST dictionary, GRAPHICS_RESOURCE_MANAGEMENT_SEMANTICS in FBSERV
    1.26 +#  OST dictionary, and GRAPHICS_RESOURCE_MANAGEMENT_SEMANTICS, 
    1.27 +#  GRAPHICS_RESOURCE_MANAGEMENT_FUNCTIONS and GRAPHICS_CONTROL_FUNCTIONS in
    1.28 +#  FBSCLI OST dictionary. Once tracing is gathered, save trace output as ascii 
    1.29 +#  and run this script against it. The resulting file can then be imported into
    1.30 +#  a spreadsheet application to be visually processed.
    1.31 +#  
    1.32 +#  KNOWN DEFECTS:
    1.33 +#  Once the log time goes beyond midnight, snapshots will stop being taken.
    1.34 +#
    1.35 +
    1.36 +use strict;
    1.37 +
    1.38 +# Sanity checking of the command line parameters...
    1.39 +if ($#ARGV == -1 || $ARGV[0] eq "help" || $ARGV[0] eq "/?")
    1.40 +{
    1.41 +   print "\nusage: $0 filename [-h]\n";
    1.42 +   print "where\n";
    1.43 +   print " -h : Specifies the heartbeat in millisecs (default=10000)\n";
    1.44 +   exit;
    1.45 +}
    1.46 +
    1.47 +
    1.48 +## Modifiable constants...
    1.49 +my $CSV_DELIMITER = ',';
    1.50 +
    1.51 +# Time after start to take first snapshot, in millisecs
    1.52 +my $firstHeartBeatTimeMS = 1000;
    1.53 +
    1.54 +# Default heartbeat in millisecs if none specified.
    1.55 +my $heartBeatMS = 10000;
    1.56 +
    1.57 +
    1.58 +##
    1.59 +## Internal structures...
    1.60 +##
    1.61 +my $heartBeatCount = 0;
    1.62 +my $nextHeartBeatMS = -1;
    1.63 +
    1.64 +# A hash of thread names to the amount of bitmap memory they 
    1.65 +# have used since the start of the trace.
    1.66 +my %bmpMemoryPerThread = ();
    1.67 +
    1.68 +# A hash of bitmaps fully qualified by the session they belong to,
    1.69 +# and their local handle (because bitmaps can have the same local
    1.70 +# handle in different threads), mapped to their size in bytes.
    1.71 +my %bmpMemoryByServerHandle = ();
    1.72 +
    1.73 +# Hash of FbsSessions to thread IDs.
    1.74 +my %SessionThreadMap = ();
    1.75 +
    1.76 +# Array of the above hashes, one hash per heartbeat.
    1.77 +my @arrayOfSnapshots;
    1.78 +
    1.79 +# Hashes of thread and process names to IDs.
    1.80 +my %ThreadNames;
    1.81 +my %ProcessNames;
    1.82 +
    1.83 +
    1.84 +##
    1.85 +## Command line options parsing...
    1.86 +## First arg is assumed to be the filename.
    1.87 +##
    1.88 +for my $i (1..$#ARGV)
    1.89 +{
    1.90 +   my $cma = $ARGV[$i];
    1.91 +   if ($cma =~ m/-h(\d*)/)
    1.92 +   {
    1.93 +      $heartBeatMS = $1;
    1.94 +   }
    1.95 +   else
    1.96 +   {
    1.97 +      print "Unrecognised parameter: $cma , ignoring...\n";
    1.98 +   }
    1.99 +}
   1.100 +
   1.101 +## Read from the file.
   1.102 +## Read the log into an array line by line.
   1.103 +my $TRACE_FILENAME = $ARGV[0];
   1.104 +open(INPUT_FILE, $TRACE_FILENAME) or die $!;
   1.105 +my @traceLines = <INPUT_FILE>;
   1.106 +
   1.107 +
   1.108 +##
   1.109 +## Parse each line sequentially...
   1.110 +##
   1.111 +foreach my $line (@traceLines)
   1.112 +{
   1.113 +   my $timeFromMidnightMS;
   1.114 +
   1.115 +   ## 
   1.116 +   ## If this line is about a new process, make a note of the name and the
   1.117 +   ## associated process id, so that FbsSessions can be mapped to their 
   1.118 +   ## thread by name.
   1.119 +   ##
   1.120 +   if ($line =~ /^.*Thread:Process name assigned;NThread:(.*);DProcess:(.*);Name:(.*)$/i)
   1.121 +   {
   1.122 +      my $threadId  = $1;
   1.123 +      my $processId = $2;
   1.124 +      my $processName = $3;
   1.125 +      $ProcessNames{$processId} = $processName ;
   1.126 +   }
   1.127 +
   1.128 +   ## 
   1.129 +   ## If this line is about a new process, make a note of the name and the
   1.130 +   ## associated process id, so that FbsSessions can be mapped to their 
   1.131 +   ## thread by name when the csv is generated.
   1.132 +   ##
   1.133 +   if (($line =~ /^.*Thread:Thread created;NThread:(.*);DProcess:(.*);Name:(.*)$/i) ||
   1.134 +      ($line =~ /^.*Thread:Thread name assigned;NThread:(.*);DProcess:(.*);Name:(.*)$/i))
   1.135 +      {
   1.136 +      my $threadId  = $1;
   1.137 +      my $processId = $2;
   1.138 +      my $threadName = $3;
   1.139 +      my $fullThreadName = $ProcessNames{$processId} . ":" . $threadName;
   1.140 +      $ThreadNames{$threadId} = $fullThreadName;
   1.141 +   }
   1.142 +
   1.143 +   ##
   1.144 +   ## Determine timestamp. If this time is beyond the heartbeat, 
   1.145 +   ## take a snapshot and 
   1.146 +   ##
   1.147 +   if ($line =~ /^(\d\d):(\d\d):(\d\d)\.(\d{3})/)
   1.148 +   {
   1.149 +      $timeFromMidnightMS = ((($1 * 3600) + ($2 * 60) + $3) * 1000) + $4;
   1.150 +      # Set up the time for the first snapshot.
   1.151 +      if ($nextHeartBeatMS == -1) 
   1.152 +      {
   1.153 +         $nextHeartBeatMS = $timeFromMidnightMS + $firstHeartBeatTimeMS;
   1.154 +      }
   1.155 +   }
   1.156 +
   1.157 +   ##
   1.158 +   ## If heartbeat reached, take snapshot of bmp memory per thread
   1.159 +   ## and set next heartbeat time.
   1.160 +   ##
   1.161 +   while ($timeFromMidnightMS >= $nextHeartBeatMS)
   1.162 +   {
   1.163 +      $nextHeartBeatMS += $heartBeatMS;
   1.164 +      # take a snapshot of the current bitmap memory usage per thread
   1.165 +      while ((my $thread, my $bmpMemory) = each(%bmpMemoryPerThread))
   1.166 +      {
   1.167 +           $arrayOfSnapshots[$heartBeatCount]{$thread} = $bmpMemory;
   1.168 +      }
   1.169 +      $heartBeatCount++;
   1.170 +   }
   1.171 +
   1.172 +   ## FBS Client-side traces.
   1.173 +   if ($line =~ m/\tFBSCLI: /)
   1.174 +   {
   1.175 +      ##
   1.176 +      ## If this line is an FBSCLI trace, and it contains iSSH then
   1.177 +      ## it gives a chance to map a client thread ID to a session handle.
   1.178 +      ## 
   1.179 +      if ( $line =~ m/iSSH=(\w*);.*Thread ID:(.*)$/)
   1.180 +      {
   1.181 +         my $ServerSessionHandle = $1;
   1.182 +         my $thread = $2;
   1.183 +         if ($thread ne "0x00000000")
   1.184 +         {
   1.185 +            $SessionThreadMap{$ServerSessionHandle} = $thread;
   1.186 +         }
   1.187 +      }
   1.188 +   }
   1.189 +
   1.190 +   ## 
   1.191 +   ## FBS Server-side traces.
   1.192 +   ##
   1.193 +   if ($line =~ m/\tFBSERV: /)
   1.194 +   {
   1.195 +      ## The line must have a s= parameter to be useful - the session server handle.
   1.196 +      ## Any FBSERV line without this is not considered for parsing.
   1.197 +      if ($line =~ m/; iSSH=(\w*);/)
   1.198 +      {
   1.199 +         my $FbsSessionHandle = $1;
   1.200 +         my $thread = "Unknown Thread [Session=$FbsSessionHandle]";
   1.201 +         if (defined($SessionThreadMap{$FbsSessionHandle}))
   1.202 +         {
   1.203 +            $thread = $SessionThreadMap{$FbsSessionHandle};
   1.204 +         }
   1.205 +         if ($line =~ m/# Server resource destroyed; .*iH=(\w*);/)
   1.206 +         {
   1.207 +            my $bmpHandle = $1;
   1.208 +            my $bmpIdentifier = "$FbsSessionHandle:$bmpHandle";
   1.209 +            if (defined($bmpMemoryByServerHandle{$bmpIdentifier}))
   1.210 +            {
   1.211 +               $bmpMemoryPerThread{$thread} -= $bmpMemoryByServerHandle{$bmpIdentifier};
   1.212 +               delete $bmpMemoryByServerHandle{$bmpIdentifier};
   1.213 +            }
   1.214 +         }
   1.215 +         if ($line =~ m/# Server bitmap resized; .*iOldH=(\w*); iNewH=(\w*); newbytes=(\d*);/)
   1.216 +         {
   1.217 +            # When a bitmap is resized, the amount of memory held by the bitmap may change
   1.218 +            # and the bitmap localhandle will change.
   1.219 +            my $oldBmpHandle = $1;
   1.220 +            my $newBmpHandle = $2;
   1.221 +            my $newBmpBytes = $3;
   1.222 +            my $oldBmpIdentifier = "$FbsSessionHandle:$oldBmpHandle";
   1.223 +            my $newBmpIdentifier = "$FbsSessionHandle:$newBmpHandle";
   1.224 +            if (defined($bmpMemoryByServerHandle{$oldBmpIdentifier}))
   1.225 +            {
   1.226 +               $bmpMemoryPerThread{$thread} -= $bmpMemoryByServerHandle{$oldBmpIdentifier};
   1.227 +               delete $bmpMemoryByServerHandle{$oldBmpIdentifier};
   1.228 +            }
   1.229 +            $bmpMemoryPerThread{$thread} += $newBmpBytes;
   1.230 +            $bmpMemoryByServerHandle{$newBmpIdentifier} = $newBmpBytes;           
   1.231 +         }
   1.232 +         elsif ($line =~ m/#.*iOldH=(\w*); iNewH=(\w*);/)
   1.233 +         {
   1.234 +            # When a bitmap is compressed, cleaned or resized, the bitmap local handle changes
   1.235 +            my $oldBmpHandle = $1;
   1.236 +            my $newBmpHandle = $2;
   1.237 +            my $oldBmpIdentifier = "$FbsSessionHandle:$oldBmpHandle";
   1.238 +            my $newBmpIdentifier = "$FbsSessionHandle:$newBmpHandle";
   1.239 +            if (defined($bmpMemoryByServerHandle{$oldBmpIdentifier}))
   1.240 +            {
   1.241 +               my $bytes = $bmpMemoryByServerHandle{$oldBmpIdentifier};
   1.242 +               delete $bmpMemoryByServerHandle{$oldBmpIdentifier};
   1.243 +               $bmpMemoryByServerHandle{$newBmpIdentifier} = $bytes;
   1.244 +            }
   1.245 +         }
   1.246 +         elsif ($line =~ m/#.*iH=(\w*);.*bytes=(\d+);/)
   1.247 +         {
   1.248 +            # Duplication of a bitmap typically. When a bitmap is duplicated,
   1.249 +            # the memory is 'owned' by all threads that duplicate it.
   1.250 +            my $bmpHandle = $1;
   1.251 +            my $bmpBytes = $2;
   1.252 +            my $bmpIdentifier = "$FbsSessionHandle:$bmpHandle";
   1.253 +            $bmpMemoryPerThread{$thread} += $bmpBytes;
   1.254 +            $bmpMemoryByServerHandle{$bmpIdentifier} = $bmpBytes;
   1.255 +         }
   1.256 +      }
   1.257 +   }
   1.258 +}
   1.259 +
   1.260 +close (INPUT_FILE);
   1.261 +
   1.262 +
   1.263 +##
   1.264 +## Make a map of unique threads across all snapshots
   1.265 +## This is so only one occurrence of each thread will appear
   1.266 +## in the csv file.
   1.267 +##
   1.268 +my %uniqueThreads = ();
   1.269 +for my $i (0..$#arrayOfSnapshots)
   1.270 +{
   1.271 +   for my $thread (keys %{$arrayOfSnapshots[$i]})
   1.272 +   {
   1.273 +      $uniqueThreads{$thread} = 1;
   1.274 +   }
   1.275 +}
   1.276 +
   1.277 +##
   1.278 +## Start writing to file.
   1.279 +## First row, which contains the heartbeat number column headings...
   1.280 +##
   1.281 +my $OUTPUT_FILENAME = sprintf("%s.csv", $TRACE_FILENAME);
   1.282 +open(OUTPUT_FILE,">$OUTPUT_FILENAME") or die $!;
   1.283 +print OUTPUT_FILE "Session$CSV_DELIMITER";
   1.284 +for my $i (0..$heartBeatCount)
   1.285 +{
   1.286 +    print OUTPUT_FILE "$i$CSV_DELIMITER";
   1.287 +}
   1.288 +
   1.289 +##
   1.290 +## For each subsequent row, print the first thread and the
   1.291 +## memory at each snapshot...
   1.292 +##
   1.293 +print OUTPUT_FILE "\n";
   1.294 +while ((my $thread, my $dummy) = each(%uniqueThreads))
   1.295 +{
   1.296 +    # Resolve the thread to its full name...
   1.297 +    print OUTPUT_FILE "$thread";
   1.298 +    if (defined($ThreadNames{$thread}) )
   1.299 +    {
   1.300 +       my $threadName = $ThreadNames{$thread};
   1.301 +       print OUTPUT_FILE ":$threadName";
   1.302 +    }
   1.303 +    print OUTPUT_FILE "$CSV_DELIMITER";
   1.304 +
   1.305 +    # print the memory use per thread, for each snapshot...
   1.306 +    for my $i (0..$#arrayOfSnapshots)
   1.307 +    {
   1.308 +       my %snapshot = %{$arrayOfSnapshots[$i]};
   1.309 +       while ((my $snapshotThread, my $bmpMemory) = each(%snapshot))
   1.310 +       {
   1.311 +           if ($snapshotThread eq $thread) 
   1.312 +           {
   1.313 +              print OUTPUT_FILE "$bmpMemory";
   1.314 +           }
   1.315 +       }
   1.316 +       print OUTPUT_FILE "$CSV_DELIMITER";
   1.317 +    }
   1.318 +    print OUTPUT_FILE "\n";
   1.319 +}
   1.320 +close (OUTPUT_FILE);
   1.321 +