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