396 lines
10 KiB
PHP
396 lines
10 KiB
PHP
<?php
|
|
/*
|
|
+--------------------------------------------------------------------------
|
|
| Invision Power Services Kernel [Application Profiling]
|
|
| Invision Power Board
|
|
| =============================================
|
|
| by Matthew Mecham
|
|
| (c) 2001 - 2006 Invision Power Services, Inc.
|
|
| http://www.invisionpower.com
|
|
| =============================================
|
|
| Web: http://www.invisionboard.com
|
|
+---------------------------------------------------------------------------
|
|
| THIS IS NOT FREE / OPEN SOURCE SOFTWARE
|
|
+---------------------------------------------------------------------------
|
|
|
|
|
| > Application Profiling
|
|
| > Module written by Brandon Farber
|
|
| > Date started: Monday 28th February 2005 16:46
|
|
|
|
|
| > Module Version Number: 1.0.0
|
|
+--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* IPS Kernel Pages: Application Profiling Layer [PHP5]
|
|
*
|
|
* @package IPS_KERNEL
|
|
* @subpackage ApplicationProfiling
|
|
* @author Brandon Farber
|
|
* @copyright Invision Power Services, Inc.
|
|
* @version 1.0
|
|
*/
|
|
|
|
/**
|
|
* Gateway for application profiling
|
|
*
|
|
* $a = new class_profiling();
|
|
* $a->output_results( true, false );
|
|
*/
|
|
|
|
//-----------------------------------------
|
|
// Define KERNEL_PATH if not
|
|
// defined - i.e. installation
|
|
//-----------------------------------------
|
|
|
|
if ( ! defined('KERNEL_PATH') )
|
|
{
|
|
if( defined('INS_KERNEL_PATH') )
|
|
{
|
|
define( 'KERNEL_PATH', INS_KERNEL_PATH );
|
|
}
|
|
else
|
|
{
|
|
define( 'KERNEL_PATH', str_replace( "//", "/", str_replace( "\\", "/", dirname( __FILE__ ) ) ) . "/" );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Define ROOT_PATH if not
|
|
//-----------------------------------------
|
|
|
|
if ( ! defined('ROOT_PATH') )
|
|
{
|
|
$path = str_replace( "//", "/", str_replace( "\\", "/", dirname( __FILE__ ) ) );
|
|
$path_bits = explode( "/", $path );
|
|
array_pop( $path_bits );
|
|
|
|
define( 'ROOT_PATH', implode( "/", $path_bits ) . "/" );
|
|
}
|
|
|
|
|
|
class class_profiling
|
|
{
|
|
var $start_time = array();
|
|
var $end_time = array();
|
|
var $running_time = array();
|
|
|
|
var $start_memory = array();
|
|
var $end_memory = array();
|
|
|
|
var $descriptions = array();
|
|
|
|
var $timer_stack = array();
|
|
var $internal_count = array();
|
|
var $stack_trace = null;
|
|
|
|
var $cur_timer = null;
|
|
var $init_time = 0;
|
|
|
|
var $init_memory = 0;
|
|
var $total_memory = 0;
|
|
var $peak_memory = 0;
|
|
|
|
|
|
function __construct( $start_apd = false )
|
|
{
|
|
$this->start_time = array();
|
|
$this->end_time = array();
|
|
$this->running_time = array();
|
|
|
|
$this->start_memory = array();
|
|
$this->end_memory = array();
|
|
|
|
$this->descriptions = array();
|
|
|
|
$this->timer_stack = array();
|
|
$this->internal_count = array();
|
|
$this->stack_trace = "Profiling Class Initialized\n";
|
|
|
|
$this->cur_timer = null;
|
|
$this->init_time = $this->get_micro_seconds();
|
|
|
|
$this->init_memory = $this->get_current_memory();
|
|
$this->total_memory = $this->init_memory;
|
|
$this->peak_memory = $this->init_memory;
|
|
|
|
if( $start_apd == true && function_exists( 'apd_set_pprof_trace' ) )
|
|
{
|
|
apd_set_pprof_trace();
|
|
}
|
|
|
|
$this->start_session( 'Overall' );
|
|
}
|
|
|
|
|
|
function start_session( $name, $desc='' )
|
|
{
|
|
$x = array_push( $this->timer_stack, $this->cur_timer );
|
|
|
|
if( isset($this->timer_stack[ $x - 1 ]) )
|
|
{
|
|
$this->_suspend_timer( $this->timer_stack[ $x - 1 ] );
|
|
}
|
|
|
|
$this->start_time[ $name ] = $this->get_micro_seconds();
|
|
$this->start_memory[ $name ] = $this->get_current_memory();
|
|
|
|
$this->cur_timer = $name;
|
|
|
|
$this->descriptions[ $name ] = $desc;
|
|
|
|
if( array_key_exists( $name, $this->internal_count ) )
|
|
{
|
|
$this->internal_count[ $name ]++;
|
|
}
|
|
else
|
|
{
|
|
$this->internal_count[ $name ] = 1;
|
|
}
|
|
|
|
$this->stack_trace .= "Started Session '{$name}'\n";
|
|
|
|
$backtrace = debug_backtrace();
|
|
|
|
if( is_array($backtrace) AND count($backtrace) )
|
|
{
|
|
$cnt = 0;
|
|
|
|
foreach( array_reverse( $backtrace ) as $trace )
|
|
{
|
|
$cnt++;
|
|
|
|
$this->stack_trace .= "\t{$cnt}. Function '{$trace['function']}' in {$trace['file']} (line {$trace['line']})\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function stop_session( $name )
|
|
{
|
|
$this->end_time[ $name ] = $this->get_micro_seconds();
|
|
$this->end_memory[ $name ] = $this->get_current_memory();
|
|
|
|
if( !array_key_exists( $name, $this->running_time ) )
|
|
{
|
|
$this->running_time[ $name ] = $this->get_elapsed_time( $name );
|
|
}
|
|
else
|
|
{
|
|
$this->running_time[ $name ] += $this->get_elapsed_time( $name );
|
|
}
|
|
|
|
$this->cur_timer = array_pop( $this->timer_stack );
|
|
|
|
$this->stack_trace .= "Stopped Session '{$name}'\n";
|
|
|
|
if( isset($this->cur_timer) )
|
|
{
|
|
$this->_resume_timer( $this->cur_timer );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function get_elapsed_time( $name )
|
|
{
|
|
if( !array_key_exists( $name, $this->start_time ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( array_key_exists( $name, $this->end_time ) )
|
|
{
|
|
return ( $this->end_time[ $name ] - $this->start_time[ $name ] );
|
|
}
|
|
else
|
|
{
|
|
return( $this->get_micro_seconds() - $this->start_time[ $name ] );
|
|
}
|
|
}
|
|
|
|
|
|
function get_total_time()
|
|
{
|
|
return ( $this->get_micro_seconds() - $this->init_time );
|
|
}
|
|
|
|
|
|
function get_peak_memory()
|
|
{
|
|
if( function_exists( 'memory_get_peak_usage' ) )
|
|
{
|
|
$this->peak_memory = memory_get_peak_usage();
|
|
}
|
|
else
|
|
{
|
|
if( count( $this->start_memory ) )
|
|
{
|
|
foreach( $this->start_memory as $mem_entry )
|
|
{
|
|
if( $mem_entry > $this->peak_memory )
|
|
{
|
|
$this->peak_memory = $mem_entry;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( count( $this->end_memory ) )
|
|
{
|
|
foreach( $this->end_memory as $mem_entry )
|
|
{
|
|
if( $mem_entry > $this->peak_memory )
|
|
{
|
|
$this->peak_memory = $mem_entry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $this->peak_memory;
|
|
}
|
|
|
|
|
|
function _resume_timer( $name )
|
|
{
|
|
$this->stack_trace .= "Resumed Session '{$name}'\n";
|
|
|
|
$this->start_time[ $name ] = $this->get_micro_seconds();
|
|
}
|
|
|
|
|
|
function _suspend_timer( $name )
|
|
{
|
|
$this->stack_trace .= "Suspended Session '{$name}'\n";
|
|
|
|
$this->end_time[ $name ] = $this->get_micro_seconds();
|
|
|
|
if( !array_key_exists( $name, $this->running_time ) )
|
|
{
|
|
$this->running_time[ $name ] = $this->get_elapsed_time( $name );
|
|
}
|
|
else
|
|
{
|
|
$this->running_time[ $name ] += $this->get_elapsed_time( $name );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function get_micro_seconds()
|
|
{
|
|
$tmp = explode( " ", microtime() );
|
|
|
|
return ( $tmp[0] + $tmp[1] );
|
|
}
|
|
|
|
|
|
function get_current_memory()
|
|
{
|
|
if( ! function_exists( 'memory_get_usage' ) )
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return memory_get_usage();
|
|
}
|
|
}
|
|
|
|
|
|
function format_memory( $val=0 )
|
|
{
|
|
if( $val >= 1048576 )
|
|
{
|
|
return ( round( ( $val / 1048576 * 100 ), 2 ) / 100 ) . 'MB';
|
|
}
|
|
else if( $val >= 1024 )
|
|
{
|
|
return ( round( ( $val / 1024 * 100 ), 2 ) / 100 ) . 'KB';
|
|
}
|
|
else
|
|
{
|
|
return intval( $val ) . 'b';
|
|
}
|
|
}
|
|
|
|
|
|
function output_results( $display_backtrace=true, $log=false )
|
|
{
|
|
$this->stop_session( 'Overall' );
|
|
$this->total_memory = $this->get_current_memory();
|
|
|
|
$timed_total = 0;
|
|
$percent_total = 0;
|
|
$output = null;
|
|
|
|
$overall_time = $this->get_total_time();
|
|
$overall_memory = $this->get_peak_memory();
|
|
|
|
if( $log == false )
|
|
{
|
|
print "<pre>\n";
|
|
}
|
|
|
|
ksort($this->descriptions);
|
|
|
|
$output = "============================================================================\n";
|
|
$output .= " PROFILER OUTPUT\n";
|
|
$output .= "============================================================================\n";
|
|
$output .= "Calls Time Memory Routine\n";
|
|
$output .= "----------------------------------------------------------------------------\n";
|
|
|
|
foreach( $this->descriptions as $key => $val )
|
|
{
|
|
$this_total = $this->running_time[$key];
|
|
$this_count = $this->internal_count[$key];
|
|
$this_percent = ( $this_total / $overall_time ) * 100;
|
|
$this_memory = $this->format_memory( $this->end_memory[ $key ] - $this->start_memory[ $key ] );
|
|
|
|
$timed_total += $this_total;
|
|
$percent_total += $this_percent;
|
|
$mem_total += $this->end_memory[ $key ] - $this->start_memory[ $key ];
|
|
|
|
$output .= sprintf( "%3d %3.4f ms (%3.2f %%) %s %s\n", $this_count, $this_total * 1000, $this_percent, $this_memory, $key);
|
|
}
|
|
|
|
$output .= "\n";
|
|
|
|
$missed_time = $overall_time - $timed_total;
|
|
$missed_percent = ( $missed_time / $overall_time ) * 100;
|
|
$percent_total += $missed_percent;
|
|
$missed_memory = $this->format_memory( $this->total_memory - $this->init_memory - $mem_total );
|
|
|
|
$output .= sprintf( " %3.4f ms (%3.2f %%) %s %s\n", $missed_time * 1000, $missed_percent, $missed_memory, 'Leaked' );
|
|
|
|
$output .= "============================================================================\n";
|
|
$output .= "Start Memory: " . $this->format_memory( $this->init_memory ) . "\n";
|
|
$output .= "Total Memory: " . $this->format_memory( $this->total_memory ) . "\n";
|
|
$output .= "Peak Memory: " . $this->format_memory( $this->peak_memory ) . "\n";
|
|
$output .= "============================================================================\n";
|
|
|
|
$output .= sprintf( " %3.4f ms (%3.2f %%) %s %s\n", $timed_total * 1000, $pecent_total, $this->format_memory( $this->total_memory ), 'OVERALL TIME' );
|
|
|
|
$output .= "============================================================================\n";
|
|
|
|
if( $display_backtrace == true )
|
|
{
|
|
$output .= "Backtrace\n";
|
|
$output .= $this->stack_trace;
|
|
}
|
|
|
|
if( $log == false )
|
|
{
|
|
print $output . '</pre>';
|
|
}
|
|
else
|
|
{
|
|
return $output;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|