#!/usr/local/bin/perl # # Script to read a file specifying the packages to which every function belongs # in VIS and then process the file output of purify and create a table of # memory usage per package. # # Abelardo Pardo # # Revision: [$Id: memoryaccount,v 1.8 1997/01/23 03:50:43 hsv Exp $] require 5.001; use Getopt::Long; $version = "1.8"; # Define option and default variables # $opt_f = 0; $opt_h = 0; $opt_p = 0; $opt_v = 0; $opt_u = 0; # Read the options # $optionResult = GetOptions("f=s","h","m=s","p","u=s","v"); # Read the result of the options # if ($opt_f) { $file = $opt_f; } else { $file = "purify.log"; } # Print the help message if required # if ($opt_h || !$optionResult) { goto usage; } if ($opt_u) { if ($opt_u eq "k") { $unit = "Kbytes"; $factor = 1000.0; $precission = 2; } if ($opt_u eq "m") { $unit = "Mbytes"; $factor = 1000000.0; $precission = 2; } if ($opt_u eq "g") { $unit = "Gbytes"; $factor = 1000000000.0; $precission = 2; } if ($opt_u eq "b") { $unit = "bytes"; $factor = 1.0; $precission = 0; } } else { $unit = "bytes"; $factor = 1.0; $precission = 0; } # Print the version if required # if ($opt_v) { print < ENDOFMESSAGE exit; } # Initial value of certain variables # $detectedmiu = 0; $totalchunks = 0; $totalmemory = 0; # Read in the function map files # if ($#ARGV == -1) { push(@ARGV, "./.fmap"); } foreach $filename (@ARGV) { if (open(INPUT, $filename)) { while () { @fields = split(/\s/,$_); $func2pkg{$fields[2]} = $fields[0]; $total{$fields[0]} = 0; } close(INPUT); } } # Open the input file # open(INPUT, $file) || die "Unable to open file $file\n"; while () { chop; # Detect the version of purify being executed if (/\s\s\*\sPurify\s([0-9\.]+)\s/) { $purifyVersion = $1; print "Memory Map of $pname at $pdate obtained with Purify $1\n"; if ($purifyVersion eq "3.2") { $totalMemoryExp = "^Memory\\sin\\-use:\\s([0-9]+)\\sbytes"; } if ($purifyVersion eq "4.0.1") { $totalMemoryExp = "^New\\smemory\\sin\\-use:\\s([0-9]+)\\sbytes"; } } # Detect the first line telling when this was executed if (/^\*\*\*\*\s\sPurify\sinstrumented\s(.+)\s\((.+)\sat\s(.+)\)/) { $pname = $2; $pdate = $3; } # Detecting when the data structure has to be flushed if (/^Purify:\sSearching\sfor\sall\smemory\sin\-use\.\.\.$/) { foreach $name (keys %total) { $total{$name} = 0; } $parsing = 1; } if ($parsing) { # Detect the line saying how much memory in use is visible if (/^Memory\sin\-use:\s([0-9]+)\sbytes\s+\(([0-9\.]+)%\s.+\)/) { $memInUse = $2; } # If we are inside a MIU statement if ($detectedmiu == 1) { # Detect end of MIU statement if ($_ eq "") { $detectedmiu = 0; if ($notallocatedyet == 1) { $total{"unclaimed"} += $portioninuse; } } else { # Obtain the function name of the allocation if ($notallocatedyet == 1) { if (/\s+([a-zA-Z0-9_]+)\s+\[(.+)\]/) { $function = $1; if (defined($func2pkg{$function})) { $pkg = $func2pkg{$function}; $total{$pkg} += $portioninuse; $notallocatedyet = 0; } } } } } if (/^MIU:\s([0-9]+)\sbytes/) { $detectedmiu = 1; $portioninuse = $1; $notallocatedyet = 1; } if (/^\s\s\s\s\sTotal\sAllocated\s+([0-9]+)\s+([0-9]+)/) { $totalchunks = $1; $totalmemory = $2; $parsing = 0; } } } close(INPUT); if ($memInUse ne "100") { print "Warning: The program is using $memInUse% of its allocated memory\n"; } print "Profile of the memory currently in use:\n"; foreach $name (sort keys %total) { if ($opt_p || $total{$name} != 0) { $tmemoryunits = $total{$name}/$factor; $percentage = 100.0*$total{$name}/$totalmemory; printf "%9s : %12.${precission}f %s %5.2f %%\n", $name, $tmemoryunits, $unit, $percentage; } } print "-------------------------------------------------------------------------------\n"; if ($totalchunks == 0) { print "No information found in file $file\n"; exit; } $memoryunits = $totalmemory/$factor; $memoryperchunk = $totalmemory/$totalchunks; printf "Total Memory Allocated = %12.${precission}f %s\n", $memoryunits, $unit; print "Memory allocated in $totalchunks portions. "; printf "Average %12.2f bytes per portion\n", $memoryperchunk; exit; usage: print <] [-h] [-p] [-v] [-u ] filenames Options: -f File to read the dump from. The default is "purify.log" -h Print this message -p Print also the packages that do not use any memory. -v Print the version -u Units to print the memory usage in. It may be "b" for bytes "k" for kilobytes, "m" for megabytes and "g" for gigabytes. The default is bytes. filenames Files containing the function map to be read. Default is ./.fmap Bugs: This script has been tested for purify versions 3.2 and 4.0.1. Since the parsing is sensitive to the messages written in the dump file, a new version of purify might have different messages that are not matched in the script. If this situation arises, chances are the results are completely bogus. Author: Abelardo Pardo ENDOFMESSAGE exit;