os/graphics/fbs/fontandbitmapserver/utils/fbsbitmap_memory.pl
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
#!/usr/local/bin/perl
sl@0
     2
#
sl@0
     3
# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     4
# All rights reserved.
sl@0
     5
# This component and the accompanying materials are made available
sl@0
     6
# under the terms of "Eclipse Public License v1.0"
sl@0
     7
# which accompanies this distribution, and is available
sl@0
     8
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     9
#
sl@0
    10
# Initial Contributors:
sl@0
    11
# Nokia Corporation - initial contribution.
sl@0
    12
#
sl@0
    13
# Contributors:
sl@0
    14
#
sl@0
    15
# Description:
sl@0
    16
#  This script parses trace data produced by OST from FBS, using the the FBSCLI, 
sl@0
    17
#  FBSERV and Symbian BTrace Hooks OST dictionaries, to produce a CSV output of
sl@0
    18
#  the amount of bitmap memory used per-thread over a user-definable time
sl@0
    19
#  granularity, since the start of the trace.
sl@0
    20
# 
sl@0
    21
#  To use, enable SYMBIAN_KERNEL_THREAD_IDENTIFICATION trace group in Symbian
sl@0
    22
#  BTrace Hooks OST dictionary, GRAPHICS_RESOURCE_MANAGEMENT_SEMANTICS in FBSERV
sl@0
    23
#  OST dictionary, and GRAPHICS_RESOURCE_MANAGEMENT_SEMANTICS, 
sl@0
    24
#  GRAPHICS_RESOURCE_MANAGEMENT_FUNCTIONS and GRAPHICS_CONTROL_FUNCTIONS in
sl@0
    25
#  FBSCLI OST dictionary. Once tracing is gathered, save trace output as ascii 
sl@0
    26
#  and run this script against it. The resulting file can then be imported into
sl@0
    27
#  a spreadsheet application to be visually processed.
sl@0
    28
#  
sl@0
    29
#  KNOWN DEFECTS:
sl@0
    30
#  Once the log time goes beyond midnight, snapshots will stop being taken.
sl@0
    31
#
sl@0
    32
sl@0
    33
use strict;
sl@0
    34
sl@0
    35
# Sanity checking of the command line parameters...
sl@0
    36
if ($#ARGV == -1 || $ARGV[0] eq "help" || $ARGV[0] eq "/?")
sl@0
    37
{
sl@0
    38
   print "\nusage: $0 filename [-h]\n";
sl@0
    39
   print "where\n";
sl@0
    40
   print " -h : Specifies the heartbeat in millisecs (default=10000)\n";
sl@0
    41
   exit;
sl@0
    42
}
sl@0
    43
sl@0
    44
sl@0
    45
## Modifiable constants...
sl@0
    46
my $CSV_DELIMITER = ',';
sl@0
    47
sl@0
    48
# Time after start to take first snapshot, in millisecs
sl@0
    49
my $firstHeartBeatTimeMS = 1000;
sl@0
    50
sl@0
    51
# Default heartbeat in millisecs if none specified.
sl@0
    52
my $heartBeatMS = 10000;
sl@0
    53
sl@0
    54
sl@0
    55
##
sl@0
    56
## Internal structures...
sl@0
    57
##
sl@0
    58
my $heartBeatCount = 0;
sl@0
    59
my $nextHeartBeatMS = -1;
sl@0
    60
sl@0
    61
# A hash of thread names to the amount of bitmap memory they 
sl@0
    62
# have used since the start of the trace.
sl@0
    63
my %bmpMemoryPerThread = ();
sl@0
    64
sl@0
    65
# A hash of bitmaps fully qualified by the session they belong to,
sl@0
    66
# and their local handle (because bitmaps can have the same local
sl@0
    67
# handle in different threads), mapped to their size in bytes.
sl@0
    68
my %bmpMemoryByServerHandle = ();
sl@0
    69
sl@0
    70
# Hash of FbsSessions to thread IDs.
sl@0
    71
my %SessionThreadMap = ();
sl@0
    72
sl@0
    73
# Array of the above hashes, one hash per heartbeat.
sl@0
    74
my @arrayOfSnapshots;
sl@0
    75
sl@0
    76
# Hashes of thread and process names to IDs.
sl@0
    77
my %ThreadNames;
sl@0
    78
my %ProcessNames;
sl@0
    79
sl@0
    80
sl@0
    81
##
sl@0
    82
## Command line options parsing...
sl@0
    83
## First arg is assumed to be the filename.
sl@0
    84
##
sl@0
    85
for my $i (1..$#ARGV)
sl@0
    86
{
sl@0
    87
   my $cma = $ARGV[$i];
sl@0
    88
   if ($cma =~ m/-h(\d*)/)
sl@0
    89
   {
sl@0
    90
      $heartBeatMS = $1;
sl@0
    91
   }
sl@0
    92
   else
sl@0
    93
   {
sl@0
    94
      print "Unrecognised parameter: $cma , ignoring...\n";
sl@0
    95
   }
sl@0
    96
}
sl@0
    97
sl@0
    98
## Read from the file.
sl@0
    99
## Read the log into an array line by line.
sl@0
   100
my $TRACE_FILENAME = $ARGV[0];
sl@0
   101
open(INPUT_FILE, $TRACE_FILENAME) or die $!;
sl@0
   102
my @traceLines = <INPUT_FILE>;
sl@0
   103
sl@0
   104
sl@0
   105
##
sl@0
   106
## Parse each line sequentially...
sl@0
   107
##
sl@0
   108
foreach my $line (@traceLines)
sl@0
   109
{
sl@0
   110
   my $timeFromMidnightMS;
sl@0
   111
sl@0
   112
   ## 
sl@0
   113
   ## If this line is about a new process, make a note of the name and the
sl@0
   114
   ## associated process id, so that FbsSessions can be mapped to their 
sl@0
   115
   ## thread by name.
sl@0
   116
   ##
sl@0
   117
   if ($line =~ /^.*Thread:Process name assigned;NThread:(.*);DProcess:(.*);Name:(.*)$/i)
sl@0
   118
   {
sl@0
   119
      my $threadId  = $1;
sl@0
   120
      my $processId = $2;
sl@0
   121
      my $processName = $3;
sl@0
   122
      $ProcessNames{$processId} = $processName ;
sl@0
   123
   }
sl@0
   124
sl@0
   125
   ## 
sl@0
   126
   ## If this line is about a new process, make a note of the name and the
sl@0
   127
   ## associated process id, so that FbsSessions can be mapped to their 
sl@0
   128
   ## thread by name when the csv is generated.
sl@0
   129
   ##
sl@0
   130
   if (($line =~ /^.*Thread:Thread created;NThread:(.*);DProcess:(.*);Name:(.*)$/i) ||
sl@0
   131
      ($line =~ /^.*Thread:Thread name assigned;NThread:(.*);DProcess:(.*);Name:(.*)$/i))
sl@0
   132
      {
sl@0
   133
      my $threadId  = $1;
sl@0
   134
      my $processId = $2;
sl@0
   135
      my $threadName = $3;
sl@0
   136
      my $fullThreadName = $ProcessNames{$processId} . ":" . $threadName;
sl@0
   137
      $ThreadNames{$threadId} = $fullThreadName;
sl@0
   138
   }
sl@0
   139
sl@0
   140
   ##
sl@0
   141
   ## Determine timestamp. If this time is beyond the heartbeat, 
sl@0
   142
   ## take a snapshot and 
sl@0
   143
   ##
sl@0
   144
   if ($line =~ /^(\d\d):(\d\d):(\d\d)\.(\d{3})/)
sl@0
   145
   {
sl@0
   146
      $timeFromMidnightMS = ((($1 * 3600) + ($2 * 60) + $3) * 1000) + $4;
sl@0
   147
      # Set up the time for the first snapshot.
sl@0
   148
      if ($nextHeartBeatMS == -1) 
sl@0
   149
      {
sl@0
   150
         $nextHeartBeatMS = $timeFromMidnightMS + $firstHeartBeatTimeMS;
sl@0
   151
      }
sl@0
   152
   }
sl@0
   153
sl@0
   154
   ##
sl@0
   155
   ## If heartbeat reached, take snapshot of bmp memory per thread
sl@0
   156
   ## and set next heartbeat time.
sl@0
   157
   ##
sl@0
   158
   while ($timeFromMidnightMS >= $nextHeartBeatMS)
sl@0
   159
   {
sl@0
   160
      $nextHeartBeatMS += $heartBeatMS;
sl@0
   161
      # take a snapshot of the current bitmap memory usage per thread
sl@0
   162
      while ((my $thread, my $bmpMemory) = each(%bmpMemoryPerThread))
sl@0
   163
      {
sl@0
   164
           $arrayOfSnapshots[$heartBeatCount]{$thread} = $bmpMemory;
sl@0
   165
      }
sl@0
   166
      $heartBeatCount++;
sl@0
   167
   }
sl@0
   168
sl@0
   169
   ## FBS Client-side traces.
sl@0
   170
   if ($line =~ m/\tFBSCLI: /)
sl@0
   171
   {
sl@0
   172
      ##
sl@0
   173
      ## If this line is an FBSCLI trace, and it contains iSSH then
sl@0
   174
      ## it gives a chance to map a client thread ID to a session handle.
sl@0
   175
      ## 
sl@0
   176
      if ( $line =~ m/iSSH=(\w*);.*Thread ID:(.*)$/)
sl@0
   177
      {
sl@0
   178
         my $ServerSessionHandle = $1;
sl@0
   179
         my $thread = $2;
sl@0
   180
         if ($thread ne "0x00000000")
sl@0
   181
         {
sl@0
   182
            $SessionThreadMap{$ServerSessionHandle} = $thread;
sl@0
   183
         }
sl@0
   184
      }
sl@0
   185
   }
sl@0
   186
sl@0
   187
   ## 
sl@0
   188
   ## FBS Server-side traces.
sl@0
   189
   ##
sl@0
   190
   if ($line =~ m/\tFBSERV: /)
sl@0
   191
   {
sl@0
   192
      ## The line must have a s= parameter to be useful - the session server handle.
sl@0
   193
      ## Any FBSERV line without this is not considered for parsing.
sl@0
   194
      if ($line =~ m/; iSSH=(\w*);/)
sl@0
   195
      {
sl@0
   196
         my $FbsSessionHandle = $1;
sl@0
   197
         my $thread = "Unknown Thread [Session=$FbsSessionHandle]";
sl@0
   198
         if (defined($SessionThreadMap{$FbsSessionHandle}))
sl@0
   199
         {
sl@0
   200
            $thread = $SessionThreadMap{$FbsSessionHandle};
sl@0
   201
         }
sl@0
   202
         if ($line =~ m/# Server resource destroyed; .*iH=(\w*);/)
sl@0
   203
         {
sl@0
   204
            my $bmpHandle = $1;
sl@0
   205
            my $bmpIdentifier = "$FbsSessionHandle:$bmpHandle";
sl@0
   206
            if (defined($bmpMemoryByServerHandle{$bmpIdentifier}))
sl@0
   207
            {
sl@0
   208
               $bmpMemoryPerThread{$thread} -= $bmpMemoryByServerHandle{$bmpIdentifier};
sl@0
   209
               delete $bmpMemoryByServerHandle{$bmpIdentifier};
sl@0
   210
            }
sl@0
   211
         }
sl@0
   212
         if ($line =~ m/# Server bitmap resized; .*iOldH=(\w*); iNewH=(\w*); newbytes=(\d*);/)
sl@0
   213
         {
sl@0
   214
            # When a bitmap is resized, the amount of memory held by the bitmap may change
sl@0
   215
            # and the bitmap localhandle will change.
sl@0
   216
            my $oldBmpHandle = $1;
sl@0
   217
            my $newBmpHandle = $2;
sl@0
   218
            my $newBmpBytes = $3;
sl@0
   219
            my $oldBmpIdentifier = "$FbsSessionHandle:$oldBmpHandle";
sl@0
   220
            my $newBmpIdentifier = "$FbsSessionHandle:$newBmpHandle";
sl@0
   221
            if (defined($bmpMemoryByServerHandle{$oldBmpIdentifier}))
sl@0
   222
            {
sl@0
   223
               $bmpMemoryPerThread{$thread} -= $bmpMemoryByServerHandle{$oldBmpIdentifier};
sl@0
   224
               delete $bmpMemoryByServerHandle{$oldBmpIdentifier};
sl@0
   225
            }
sl@0
   226
            $bmpMemoryPerThread{$thread} += $newBmpBytes;
sl@0
   227
            $bmpMemoryByServerHandle{$newBmpIdentifier} = $newBmpBytes;           
sl@0
   228
         }
sl@0
   229
         elsif ($line =~ m/#.*iOldH=(\w*); iNewH=(\w*);/)
sl@0
   230
         {
sl@0
   231
            # When a bitmap is compressed, cleaned or resized, the bitmap local handle changes
sl@0
   232
            my $oldBmpHandle = $1;
sl@0
   233
            my $newBmpHandle = $2;
sl@0
   234
            my $oldBmpIdentifier = "$FbsSessionHandle:$oldBmpHandle";
sl@0
   235
            my $newBmpIdentifier = "$FbsSessionHandle:$newBmpHandle";
sl@0
   236
            if (defined($bmpMemoryByServerHandle{$oldBmpIdentifier}))
sl@0
   237
            {
sl@0
   238
               my $bytes = $bmpMemoryByServerHandle{$oldBmpIdentifier};
sl@0
   239
               delete $bmpMemoryByServerHandle{$oldBmpIdentifier};
sl@0
   240
               $bmpMemoryByServerHandle{$newBmpIdentifier} = $bytes;
sl@0
   241
            }
sl@0
   242
         }
sl@0
   243
         elsif ($line =~ m/#.*iH=(\w*);.*bytes=(\d+);/)
sl@0
   244
         {
sl@0
   245
            # Duplication of a bitmap typically. When a bitmap is duplicated,
sl@0
   246
            # the memory is 'owned' by all threads that duplicate it.
sl@0
   247
            my $bmpHandle = $1;
sl@0
   248
            my $bmpBytes = $2;
sl@0
   249
            my $bmpIdentifier = "$FbsSessionHandle:$bmpHandle";
sl@0
   250
            $bmpMemoryPerThread{$thread} += $bmpBytes;
sl@0
   251
            $bmpMemoryByServerHandle{$bmpIdentifier} = $bmpBytes;
sl@0
   252
         }
sl@0
   253
      }
sl@0
   254
   }
sl@0
   255
}
sl@0
   256
sl@0
   257
close (INPUT_FILE);
sl@0
   258
sl@0
   259
sl@0
   260
##
sl@0
   261
## Make a map of unique threads across all snapshots
sl@0
   262
## This is so only one occurrence of each thread will appear
sl@0
   263
## in the csv file.
sl@0
   264
##
sl@0
   265
my %uniqueThreads = ();
sl@0
   266
for my $i (0..$#arrayOfSnapshots)
sl@0
   267
{
sl@0
   268
   for my $thread (keys %{$arrayOfSnapshots[$i]})
sl@0
   269
   {
sl@0
   270
      $uniqueThreads{$thread} = 1;
sl@0
   271
   }
sl@0
   272
}
sl@0
   273
sl@0
   274
##
sl@0
   275
## Start writing to file.
sl@0
   276
## First row, which contains the heartbeat number column headings...
sl@0
   277
##
sl@0
   278
my $OUTPUT_FILENAME = sprintf("%s.csv", $TRACE_FILENAME);
sl@0
   279
open(OUTPUT_FILE,">$OUTPUT_FILENAME") or die $!;
sl@0
   280
print OUTPUT_FILE "Session$CSV_DELIMITER";
sl@0
   281
for my $i (0..$heartBeatCount)
sl@0
   282
{
sl@0
   283
    print OUTPUT_FILE "$i$CSV_DELIMITER";
sl@0
   284
}
sl@0
   285
sl@0
   286
##
sl@0
   287
## For each subsequent row, print the first thread and the
sl@0
   288
## memory at each snapshot...
sl@0
   289
##
sl@0
   290
print OUTPUT_FILE "\n";
sl@0
   291
while ((my $thread, my $dummy) = each(%uniqueThreads))
sl@0
   292
{
sl@0
   293
    # Resolve the thread to its full name...
sl@0
   294
    print OUTPUT_FILE "$thread";
sl@0
   295
    if (defined($ThreadNames{$thread}) )
sl@0
   296
    {
sl@0
   297
       my $threadName = $ThreadNames{$thread};
sl@0
   298
       print OUTPUT_FILE ":$threadName";
sl@0
   299
    }
sl@0
   300
    print OUTPUT_FILE "$CSV_DELIMITER";
sl@0
   301
sl@0
   302
    # print the memory use per thread, for each snapshot...
sl@0
   303
    for my $i (0..$#arrayOfSnapshots)
sl@0
   304
    {
sl@0
   305
       my %snapshot = %{$arrayOfSnapshots[$i]};
sl@0
   306
       while ((my $snapshotThread, my $bmpMemory) = each(%snapshot))
sl@0
   307
       {
sl@0
   308
           if ($snapshotThread eq $thread) 
sl@0
   309
           {
sl@0
   310
              print OUTPUT_FILE "$bmpMemory";
sl@0
   311
           }
sl@0
   312
       }
sl@0
   313
       print OUTPUT_FILE "$CSV_DELIMITER";
sl@0
   314
    }
sl@0
   315
    print OUTPUT_FILE "\n";
sl@0
   316
}
sl@0
   317
close (OUTPUT_FILE);
sl@0
   318