summaryrefslogtreecommitdiffstats
path: root/lib/Webgrind/Preprocessor.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Webgrind/Preprocessor.php')
-rw-r--r--lib/Webgrind/Preprocessor.php100
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/Webgrind/Preprocessor.php b/lib/Webgrind/Preprocessor.php
new file mode 100644
index 0000000..3a9d033
--- /dev/null
+++ b/lib/Webgrind/Preprocessor.php
@@ -0,0 +1,100 @@
+<?php
+
+class Webgrind_Preprocessor{
+ const FILE_FORMAT_VERSION = 5;
+
+ const NR_FORMAT = 'V';
+ const NR_SIZE = 4;
+
+ const ENTRY_POINT = '{main}';
+
+ private $in, $out;
+
+ function __construct($inFile, $outFile){
+ $this->in = fopen($inFile, 'rb');
+ $this->out = fopen($outFile, 'w+b');
+ }
+
+
+ function parse(){
+ // Make local for faster access
+ $in = $this->in;
+ $out = $this->out;
+
+ $nextFuncNr = 0;
+ $functions = array();
+ $headers = array();
+
+
+ // Read information into memory
+ while(($line = fgets($in))){
+ if(substr($line,0,3)==='fl='){
+ list($function) = fscanf($in,"fn=%s");
+ if(!isset($functions[$function])){
+ $functions[$function] = array('filename'=>substr(trim($line),3), 'invocationCount'=>0,'nr'=>$nextFuncNr++,'count'=>0,'summedSelfCost'=>0,'summedInclusiveCost'=>0,'callInformation'=>array());
+ }
+ $functions[$function]['invocationCount']++;
+ // Special case for {main} - it contains summary header
+ if(self::ENTRY_POINT == $function){
+ fgets($in);
+ $headers[] = fgets($in);
+ fgets($in);
+ }
+ // Cost line
+ list($lnr, $cost) = fscanf($in,"%d %d");
+ $functions[$function]['summedSelfCost'] += $cost;
+ $functions[$function]['summedInclusiveCost'] += $cost;
+ } else if(substr($line,0,4)==='cfn=') {
+ $calledFunctionName = substr(trim($line),4);
+ // Skip call line
+ fgets($in);
+ // Cost line
+ list($lnr, $cost) = fscanf($in,"%d %d");
+
+ $functions[$function]['summedInclusiveCost'] += $cost;
+
+ if(!isset($functions[$calledFunctionName]['callInformation'][$function.':'.$lnr]))
+ $functions[$calledFunctionName]['callInformation'][$function.':'.$lnr] = array('functionNr'=>$functions[$function]['nr'],'line'=>$lnr,'callCount'=>0,'summedCallCost'=>0);
+ $functions[$calledFunctionName]['callInformation'][$function.':'.$lnr]['callCount']++;
+ $functions[$calledFunctionName]['callInformation'][$function.':'.$lnr]['summedCallCost'] += $cost;
+
+ } else if(strpos($line,': ')!==false){
+ $headers[] = $line;
+ }
+ }
+
+
+ // Write output
+ $functionCount = sizeof($functions);
+ fwrite($out, pack(self::NR_FORMAT.'*', self::FILE_FORMAT_VERSION, 0, $functionCount));
+ // Make room for function addresses
+ fseek($out,self::NR_SIZE*$functionCount, SEEK_CUR);
+ $functionAddresses = array();
+ foreach($functions as $functionName => $function){
+ $functionAddresses[] = ftell($out);
+ $calledFromCount = sizeof($function['callInformation']);
+ fwrite($out, pack(self::NR_FORMAT.'*', $function['summedSelfCost'], $function['summedInclusiveCost'], $function['invocationCount'], $calledFromCount));
+ // Write call information
+ foreach($function['callInformation'] as $call){
+ fwrite($out, pack(self::NR_FORMAT.'*', $call['functionNr'], $call['line'], $call['callCount'], $call['summedCallCost']));
+ }
+ fwrite($out, $function['filename']."\n".$functionName."\n");
+ }
+ $headersPos = ftell($this->out);
+ // Write headers
+ foreach($headers as $header){
+ fwrite($out,$header);
+ }
+
+ // Write addresses
+ fseek($out,self::NR_SIZE, SEEK_SET);
+ fwrite($out, pack(self::NR_FORMAT, $headersPos));
+ // Skip function count
+ fseek($out,self::NR_SIZE, SEEK_CUR);
+ foreach($functionAddresses as $address){
+ fwrite($out, pack(self::NR_FORMAT, $address));
+ }
+
+ }
+
+}