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