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