<?php

/**
 * DooBechmark class file.
 * @package doo.helper
 * @author Zohaib Sibt-e-Hassan <zohaib.hassan@gmail.com>
 * @link http://www.doophp.com/
 * @copyright Copyright &copy; 2009 Zohaib Sibt-e-Hassan
 * @license http://www.doophp.com/license
 */

/**
* DooBenchmark class, for benchmarking memory and time of particular code segment
*
* @author Zohaib Sibt-e-Hassan <zohaib.hassan@gmail.com>
* @copyright &copy; 2009 Zohaib Sibt-e-Hassan
* @license http://www.doophp.com/license
*/

class DooBenchmark {
    /**
    * Associative array of marked label as key and value of microtime
    * 
    * @var array
    */
    protected static $timeArr = array();
    
    /**
    * Associative array of marked label as key and value of memory used
    * 
    * @var array
    */
    protected static $memoArr = array();
    
    /**
    * Associative array of saved points that can be fetched later on and displayed
    * Keys are mark names and values are objects carrying the 
    * @var array
    */
    
    protected static $savedPoints = array();
    
    /**
    * Mark current position with given name
    * 
    * @param string $name
    */
    
    public static function mark($name){
        self::$timeArr[$name] = microtime();
        self::$memoArr[$name] = self::getMemUsage();
    }
    
    /**
    * Finish the bechmarking process and return the total memory
    * and time consumed as obj->time and obj->memory
    * 
    * @param string $name
    * @param int $decimals
    * @return Object (time and memory containing elapsed values)
    */
    public static function get($name){
        list($startMic, $startSec) = explode(' ', self::$timeArr[$name]);
        list($endMic, $endSec) = explode(' ', microtime());
        
        $mem = null;
        if(isset(self::$memoArr[$name]) && self::$memoArr[$name])
            $mem = self::getMemUsage() - self::$memoArr[$name];
        
        $tm = (float)($endMic + $endSec) - (float)($startMic + $startSec);
        
        $ret=new DooBenchmark();
        $ret->memory = $mem;
        $ret->time = $tm;
        
        return $ret;
    }
    
    /**
    * Retrieve memory usage. Use memory_get_usage() if available.
    * 
    * @return false|int Bytes of memory consumed. Returns False if failed to retrieve memory usage
    */
    protected static function getMemUsage(){
        $mmus = false;
        if(function_exists('memory_get_usage')){
            $mmus =  memory_get_usage();
        }
        else{
            $output=array();
            if(strncmp(PHP_OS,'WIN',3)===0){
                exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST',$output);
                $mmus =  isset($output[5])?preg_replace('/[\D]/','',$output[5])*1024 : 0;
            }
            else{
                $pid=getmypid();
                exec("ps -eo%mem,rss,pid | grep $pid", $output);
                $output=explode("  ",$output[0]);
                $mmus =  isset($output[1]) ? $output[1]*1024 : 0;
            }
        }
        
        return $mmus;
    }
    
    /**
    * Save all the unsaved benchmarks
    * This subroutine will look up for any benchmarks that were marked with DooBenchmark::mark
    * And for all unsaved 
    * 
    * @param int $decimals number of decimal precisions as place
    */
    
    public static function saveAllMarks(){
        list($em, $es) = explode(' ', microtime());
		
		$mmus = self::getMemUsage();
        
        foreach(self::$memoArr as $k => &$val){
            if( !isset(self::$savedPoints[$k]) ){
                list($sm, $ss) = explode(' ', self::$timeArr[$k]);
                $tm = (float)($em + $es) - (float)($sm + $ss);
                
                $mem = null;
                if(isset(self::$memoArr[$k]) && self::$memoArr[$k])
                    $mem =  $mmus - self::$memoArr[$k];
                
                $ret=new DooBenchmark();
                $ret->memory = $mem;
                $ret->time = $tm;
                
                self::$savedPoints[$k] = $ret;
                
            }
        }
    }
    
    /**
    * Save current bechmark associateed with its name
    * 
    * @param string $name name of bencmark item marked with mark function previously
    */
    
    public static function saveMark($name){
        self::$savedPoints[$name] = self::get($name, $decimal);
    }
    
    /**
    * Get all the saved points
    * 
    */
    
    public static function getAll(){
        return self::$savedPoints;
    }
}
