MediaWiki
master
|
00001 <?php 00028 ini_set( 'zlib.output_compression', 'off' ); 00029 00030 $wgEnableProfileInfo = $wgProfileToDatabase = false; 00031 if ( isset( $_SERVER['MW_COMPILED'] ) ) { 00032 require ( 'core/includes/WebStart.php' ); 00033 } else { 00034 require ( __DIR__ . '/includes/WebStart.php' ); 00035 } 00036 00037 00038 header( 'Content-Type: text/html; charset=utf-8' ); 00039 00040 ?> 00041 <!DOCTYPE html> 00042 <html> 00043 <head> 00044 <meta charset="UTF-8"> 00045 <title>Profiling data</title> 00046 <style> 00047 /* noc.wikimedia.org/base.css */ 00048 00049 * { 00050 margin: 0; 00051 padding: 0; 00052 } 00053 00054 body { 00055 padding: 0.5em 1em; 00056 background: #fff; 00057 font: 14px/1.6 sans-serif; 00058 color: #333; 00059 } 00060 00061 p, ul, ol, table { 00062 margin: 0.5em 0; 00063 } 00064 00065 a { 00066 color: #0645AD; 00067 text-decoration: none; 00068 } 00069 00070 a:hover { 00071 text-decoration: underline; 00072 } 00073 00084 table { 00085 max-width: 100%; 00086 background-color: transparent; 00087 border-collapse: collapse; 00088 border-spacing: 0; 00089 } 00090 00091 .table { 00092 width: 100%; 00093 margin-bottom: 20px; 00094 } 00095 00096 .table th, 00097 .table td { 00098 padding: 8px; 00099 line-height: 20px; 00100 text-align: left; 00101 vertical-align: top; 00102 border-top: 1px solid #ddd; 00103 } 00104 00105 .table th { 00106 font-weight: bold; 00107 } 00108 00109 .table thead th { 00110 vertical-align: bottom; 00111 } 00112 00113 .table thead:first-child tr:first-child th, 00114 .table thead:first-child tr:first-child td { 00115 border-top: 0; 00116 } 00117 00118 .table tbody + tbody { 00119 border-top: 2px solid #ddd; 00120 } 00121 00122 .table-condensed th, 00123 .table-condensed td { 00124 padding: 4px 5px; 00125 } 00126 00127 .table-striped tbody tr:nth-child(odd) td, 00128 .table-striped tbody tr:nth-child(odd) th { 00129 background-color: #f9f9f9; 00130 } 00131 00132 .table-hover tbody tr:hover td, 00133 .table-hover tbody tr:hover th { 00134 background-color: #f5f5f5; 00135 } 00136 00137 hr { 00138 margin: 20px 0; 00139 border: 0; 00140 border-top: 1px solid #eee; 00141 border-bottom: 1px solid #fff; 00142 } 00143 00144 </style> 00145 </head> 00146 <body> 00147 <?php 00148 00149 if ( !$wgEnableProfileInfo ) { 00150 echo '<p>Disabled</p>' 00151 . '</body></html>'; 00152 exit( 1 ); 00153 } 00154 00155 $dbr = wfGetDB( DB_SLAVE ); 00156 00157 if( !$dbr->tableExists( 'profiling' ) ) { 00158 echo '<p>No <code>profiling</code> table exists, so we can\'t show you anything.</p>' 00159 . '<p>If you want to log profiling data, create the table using ' 00160 . '<code>maintenance/archives/patch-profiling.sql</code> and enable ' 00161 . '<code>$wgProfileToDatabase</code>.</p>' 00162 . '</body></html>'; 00163 exit( 1 ); 00164 } 00165 00166 $expand = array(); 00167 if ( isset( $_REQUEST['expand'] ) ) 00168 foreach( explode( ',', $_REQUEST['expand'] ) as $f ) 00169 $expand[$f] = true; 00170 00171 class profile_point { 00172 var $name; 00173 var $count; 00174 var $time; 00175 var $children; 00176 00177 static $totaltime, $totalmemory, $totalcount; 00178 00179 function __construct( $name, $count, $time, $memory ) { 00180 $this->name = $name; 00181 $this->count = $count; 00182 $this->time = $time; 00183 $this->memory = $memory; 00184 $this->children = array(); 00185 } 00186 00187 function add_child( $child ) { 00188 $this->children[] = $child; 00189 } 00190 00191 function display( $expand, $indent = 0.0 ) { 00192 usort( $this->children, 'compare_point' ); 00193 00194 $ex = isset( $expand[$this->name()] ); 00195 00196 if ( !$ex ) { 00197 if ( count( $this->children ) ) { 00198 $url = getEscapedProfileUrl( false, false, $expand + array( $this->name() => true ) ); 00199 $extet = ' <a href="' . $url . '">[+]</a>'; 00200 } else { 00201 $extet = ''; 00202 } 00203 } else { 00204 $e = array(); 00205 foreach ( $expand as $name => $ep ) { 00206 if ( $name != $this->name() ) { 00207 $e += array( $name => $ep ); 00208 } 00209 } 00210 00211 $extet = ' <a href="' . getEscapedProfileUrl( false, false, $e ) . '">[–]</a>'; 00212 } 00213 ?> 00214 <tr> 00215 <th><div style="margin-left: <?php echo (int)$indent; ?>em;"> 00216 <?php echo htmlspecialchars( $this->name() ) . $extet ?> 00217 </div></th> 00218 <td class="mw-profileinfo-timep"><?php echo @wfPercent( $this->time() / self::$totaltime * 100 ); ?></td> 00219 <td class="mw-profileinfo-memoryp"><?php echo @wfPercent( $this->memory() / self::$totalmemory * 100 ); ?></td> 00220 <td class="mw-profileinfo-count"><?php echo $this->count(); ?></td> 00221 <td class="mw-profileinfo-cpr"><?php echo round( sprintf( '%.2f', $this->callsPerRequest() ), 2 ); ?></td> 00222 <td class="mw-profileinfo-tpc"><?php echo round( sprintf( '%.2f', $this->timePerCall() ), 2 ); ?></td> 00223 <td class="mw-profileinfo-mpc"><?php echo round( sprintf( '%.2f' ,$this->memoryPerCall() / 1024 ), 2 ); ?></td> 00224 <td class="mw-profileinfo-tpr"><?php echo @round( sprintf( '%.2f', $this->time() / self::$totalcount ), 2 ); ?></td> 00225 <td class="mw-profileinfo-mpr"><?php echo @round( sprintf( '%.2f' ,$this->memory() / self::$totalcount / 1024 ), 2 ); ?></td> 00226 </tr> 00227 <?php 00228 if ( $ex ) { 00229 foreach ( $this->children as $child ) { 00230 $child->display( $expand, $indent + 2 ); 00231 } 00232 } 00233 } 00234 00235 function name() { 00236 return $this->name; 00237 } 00238 00239 function count() { 00240 return $this->count; 00241 } 00242 00243 function time() { 00244 return $this->time; 00245 } 00246 00247 function memory() { 00248 return $this->memory; 00249 } 00250 00251 function timePerCall() { 00252 return @( $this->time / $this->count ); 00253 } 00254 00255 function memoryPerCall() { 00256 return @( $this->memory / $this->count ); 00257 } 00258 00259 function callsPerRequest() { 00260 return @( $this->count / self::$totalcount ); 00261 } 00262 00263 function timePerRequest() { 00264 return @( $this->time / self::$totalcount ); 00265 } 00266 00267 function memoryPerRequest() { 00268 return @( $this->memory / self::$totalcount ); 00269 } 00270 00271 function fmttime() { 00272 return sprintf( '%5.02f', $this->time ); 00273 } 00274 }; 00275 00276 function compare_point(profile_point $a, profile_point $b) { 00277 global $sort; 00278 switch ( $sort ) { 00279 case 'name': 00280 return strcmp( $a->name(), $b->name() ); 00281 case 'time': 00282 return $a->time() > $b->time() ? -1 : 1; 00283 case 'memory': 00284 return $a->memory() > $b->memory() ? -1 : 1; 00285 case 'count': 00286 return $a->count() > $b->count() ? -1 : 1; 00287 case 'time_per_call': 00288 return $a->timePerCall() > $b->timePerCall() ? -1 : 1; 00289 case 'memory_per_call': 00290 return $a->memoryPerCall() > $b->memoryPerCall() ? -1 : 1; 00291 case 'calls_per_req': 00292 return $a->callsPerRequest() > $b->callsPerRequest() ? -1 : 1; 00293 case 'time_per_req': 00294 return $a->timePerRequest() > $b->timePerRequest() ? -1 : 1; 00295 case 'memory_per_req': 00296 return $a->memoryPerRequest() > $b->memoryPerRequest() ? -1 : 1; 00297 } 00298 } 00299 00300 $sorts = array( 'time', 'memory', 'count', 'calls_per_req', 'name', 00301 'time_per_call', 'memory_per_call', 'time_per_req', 'memory_per_req' ); 00302 $sort = 'time'; 00303 if ( isset( $_REQUEST['sort'] ) && in_array( $_REQUEST['sort'], $sorts ) ) 00304 $sort = $_REQUEST['sort']; 00305 00306 $res = $dbr->select( 'profiling', '*', array(), 'profileinfo.php', array( 'ORDER BY' => 'pf_name ASC' ) ); 00307 00308 if (isset( $_REQUEST['filter'] ) ) 00309 $filter = $_REQUEST['filter']; 00310 else 00311 $filter = ''; 00312 00313 ?> 00314 <form method="get" action="profileinfo.php"> 00315 <p> 00316 <input type="text" name="filter" value="<?php echo htmlspecialchars($filter); ?>"> 00317 <input type="hidden" name="sort" value="<?php echo htmlspecialchars($sort); ?>"> 00318 <input type="hidden" name="expand" value="<?php echo htmlspecialchars(implode(",", array_keys($expand))); ?>"> 00319 <input type="submit" value="Filter"> 00320 </p> 00321 </form> 00322 00323 <table class="mw-profileinfo-table table table-striped table-hover"> 00324 <thead> 00325 <tr> 00326 <th><a href="<?php echo getEscapedProfileUrl( false, 'name' ); ?>">Name</a></th> 00327 <th><a href="<?php echo getEscapedProfileUrl( false, 'time' ); ?>">Time (%)</a></th> 00328 <th><a href="<?php echo getEscapedProfileUrl( false, 'memory' ); ?>">Memory (%)</a></th> 00329 <th><a href="<?php echo getEscapedProfileUrl( false, 'count' ); ?>">Count</a></th> 00330 <th><a href="<?php echo getEscapedProfileUrl( false, 'calls_per_req' ); ?>">Calls/req</a></th> 00331 <th><a href="<?php echo getEscapedProfileUrl( false, 'time_per_call' ); ?>">ms/call</a></th> 00332 <th><a href="<?php echo getEscapedProfileUrl( false, 'memory_per_call' ); ?>">kb/call</a></th> 00333 <th><a href="<?php echo getEscapedProfileUrl( false, 'time_per_req' ); ?>">ms/req</a></th> 00334 <th><a href="<?php echo getEscapedProfileUrl( false, 'memory_per_req' ); ?>">kb/req</a></th> 00335 </tr> 00336 </thead> 00337 <tbody> 00338 <?php 00339 profile_point::$totaltime = 0.0; 00340 profile_point::$totalcount = 0; 00341 profile_point::$totalmemory = 0.0; 00342 00343 function getEscapedProfileUrl( $_filter = false, $_sort = false, $_expand = false ) { 00344 global $filter, $sort, $expand; 00345 00346 if ( $_expand === false ) 00347 $_expand = $expand; 00348 00349 return htmlspecialchars( 00350 '?' . 00351 wfArrayToCGI( array( 00352 'filter' => $_filter ? $_filter : $filter, 00353 'sort' => $_sort ? $_sort : $sort, 00354 'expand' => implode( ',', array_keys( $_expand ) ) 00355 ) ) 00356 ); 00357 } 00358 00359 $points = array(); 00360 $queries = array(); 00361 $sqltotal = 0.0; 00362 00363 $last = false; 00364 foreach( $res as $o ) { 00365 $next = new profile_point( $o->pf_name, $o->pf_count, $o->pf_time, $o->pf_memory ); 00366 if( $next->name() == '-total' ) { 00367 profile_point::$totaltime = $next->time(); 00368 profile_point::$totalcount = $next->count(); 00369 profile_point::$totalmemory = $next->memory(); 00370 } 00371 if ( $last !== false ) { 00372 if ( preg_match( '/^'.preg_quote( $last->name(), '/' ).'/', $next->name() ) ) { 00373 $last->add_child($next); 00374 continue; 00375 } 00376 } 00377 $last = $next; 00378 if ( preg_match( '/^query: /', $next->name() ) || preg_match( '/^query-m: /', $next->name() ) ) { 00379 $sqltotal += $next->time(); 00380 $queries[] = $next; 00381 } else { 00382 $points[] = $next; 00383 } 00384 } 00385 00386 $s = new profile_point( 'SQL Queries', 0, $sqltotal, 0, 0 ); 00387 foreach ( $queries as $q ) 00388 $s->add_child($q); 00389 $points[] = $s; 00390 00391 usort( $points, 'compare_point' ); 00392 00393 foreach ( $points as $point ) { 00394 if ( strlen( $filter ) && !strstr( $point->name(), $filter ) ) 00395 continue; 00396 00397 $point->display( $expand ); 00398 } 00399 ?> 00400 </tbody> 00401 </table> 00402 <hr> 00403 <p>Total time: <code><?php printf('%5.02f', profile_point::$totaltime); ?></code></p> 00404 <p>Total memory: <code><?php printf('%5.02f', profile_point::$totalmemory / 1024 ); ?></code></p> 00405 <hr> 00406 </body> 00407 </html>