MediaWiki
REL1_24
|
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 // @codingStandardsIgnoreStart 00167 class profile_point { 00168 // @codingStandardsIgnoreEnd 00169 00170 public $name; 00171 public $count; 00172 public $time; 00173 public $children; 00174 00175 public static $totaltime, $totalmemory, $totalcount; 00176 00177 public function __construct( $name, $count, $time, $memory ) { 00178 $this->name = $name; 00179 $this->count = $count; 00180 $this->time = $time; 00181 $this->memory = $memory; 00182 $this->children = array(); 00183 } 00184 00185 public function add_child( $child ) { 00186 $this->children[] = $child; 00187 } 00188 00189 public function display( $expand, $indent = 0.0 ) { 00190 usort( $this->children, 'compare_point' ); 00191 00192 $ex = isset( $expand[$this->name()] ); 00193 00194 $anchor = str_replace( '"', '', $this->name() ); 00195 00196 if ( !$ex ) { 00197 if ( count( $this->children ) ) { 00198 $url = getEscapedProfileUrl( false, false, $expand + array( $this->name() => true ) ); 00199 $extet = " <a id=\"{$anchor}\" href=\"{$url}#{$anchor}\">[+]</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 $url = getEscapedProfileUrl( false, false, $e ); 00211 $extet = " <a id=\"{$anchor}\" href=\"{$url}#{$anchor}\">[–]</a>"; 00212 } 00213 ?> 00214 <tr> 00215 <th> 00216 <div style="margin-left: <?php echo (int)$indent; ?>em;"> 00217 <?php echo htmlspecialchars( str_replace( ',', ', ', $this->name() ) ) . $extet ?> 00218 </div> 00219 </th> 00220 <?php //@codingStandardsIgnoreStart ?> 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 <?php //@codingStandardsIgnoreEnd ?> 00230 </tr> 00231 <?php 00232 if ( $ex ) { 00233 foreach ( $this->children as $child ) { 00234 $child->display( $expand, $indent + 2 ); 00235 } 00236 } 00237 } 00238 00239 public function name() { 00240 return $this->name; 00241 } 00242 00243 public function count() { 00244 return $this->count; 00245 } 00246 00247 public function time() { 00248 return $this->time; 00249 } 00250 00251 public function memory() { 00252 return $this->memory; 00253 } 00254 00255 public function timePerCall() { 00256 // @codingStandardsIgnoreStart 00257 return @( $this->time / $this->count ); 00258 // @codingStandardsIgnoreEnd 00259 } 00260 00261 public function memoryPerCall() { 00262 // @codingStandardsIgnoreStart 00263 return @( $this->memory / $this->count ); 00264 // @codingStandardsIgnoreEnd 00265 } 00266 00267 public function callsPerRequest() { 00268 // @codingStandardsIgnoreStart 00269 return @( $this->count / self::$totalcount ); 00270 // @codingStandardsIgnoreEnd 00271 } 00272 00273 public function timePerRequest() { 00274 // @codingStandardsIgnoreStart 00275 return @( $this->time / self::$totalcount ); 00276 // @codingStandardsIgnoreEnd 00277 } 00278 00279 public function memoryPerRequest() { 00280 // @codingStandardsIgnoreStart 00281 return @( $this->memory / self::$totalcount ); 00282 // @codingStandardsIgnoreEnd 00283 } 00284 00285 public function fmttime() { 00286 return sprintf( '%5.02f', $this->time ); 00287 } 00288 }; 00289 00290 function compare_point( profile_point $a, profile_point $b ) { 00291 // @codingStandardsIgnoreStart 00292 global $sort; 00293 // @codingStandardsIgnoreEnd 00294 switch ( $sort ) { 00295 case 'name': 00296 return strcmp( $a->name(), $b->name() ); 00297 case 'time': 00298 return $a->time() > $b->time() ? -1 : 1; 00299 case 'memory': 00300 return $a->memory() > $b->memory() ? -1 : 1; 00301 case 'count': 00302 return $a->count() > $b->count() ? -1 : 1; 00303 case 'time_per_call': 00304 return $a->timePerCall() > $b->timePerCall() ? -1 : 1; 00305 case 'memory_per_call': 00306 return $a->memoryPerCall() > $b->memoryPerCall() ? -1 : 1; 00307 case 'calls_per_req': 00308 return $a->callsPerRequest() > $b->callsPerRequest() ? -1 : 1; 00309 case 'time_per_req': 00310 return $a->timePerRequest() > $b->timePerRequest() ? -1 : 1; 00311 case 'memory_per_req': 00312 return $a->memoryPerRequest() > $b->memoryPerRequest() ? -1 : 1; 00313 } 00314 } 00315 00316 $sorts = array( 'time', 'memory', 'count', 'calls_per_req', 'name', 00317 'time_per_call', 'memory_per_call', 'time_per_req', 'memory_per_req' ); 00318 $sort = 'time'; 00319 if ( isset( $_REQUEST['sort'] ) && in_array( $_REQUEST['sort'], $sorts ) ) { 00320 $sort = $_REQUEST['sort']; 00321 } 00322 00323 $res = $dbr->select( 'profiling', '*', array(), 'profileinfo.php', array( 'ORDER BY' => 'pf_name ASC' ) ); 00324 00325 if ( isset( $_REQUEST['filter'] ) ) { 00326 $filter = $_REQUEST['filter']; 00327 } else { 00328 $filter = ''; 00329 } 00330 00331 ?> 00332 <form method="get" action="profileinfo.php"> 00333 <p> 00334 <input type="text" name="filter" value="<?php echo htmlspecialchars( $filter ); ?>"> 00335 <input type="hidden" name="sort" value="<?php echo htmlspecialchars( $sort ); ?>"> 00336 <input type="hidden" name="expand" value="<?php echo htmlspecialchars( implode( ",", array_keys( $expand ) ) ); ?>"> 00337 <input type="submit" value="Filter"> 00338 </p> 00339 </form> 00340 00341 <table class="mw-profileinfo-table table table-striped table-hover"> 00342 <thead> 00343 <tr> 00344 <th><a href="<?php echo getEscapedProfileUrl( false, 'name' ); ?>">Name</a></th> 00345 <th><a href="<?php echo getEscapedProfileUrl( false, 'time' ); ?>">Time (%)</a></th> 00346 <th><a href="<?php echo getEscapedProfileUrl( false, 'memory' ); ?>">Memory (%)</a></th> 00347 <th><a href="<?php echo getEscapedProfileUrl( false, 'count' ); ?>">Count</a></th> 00348 <th><a href="<?php echo getEscapedProfileUrl( false, 'calls_per_req' ); ?>">Calls/req</a></th> 00349 <th><a href="<?php echo getEscapedProfileUrl( false, 'time_per_call' ); ?>">ms/call</a></th> 00350 <th><a href="<?php echo getEscapedProfileUrl( false, 'memory_per_call' ); ?>">kb/call</a></th> 00351 <th><a href="<?php echo getEscapedProfileUrl( false, 'time_per_req' ); ?>">ms/req</a></th> 00352 <th><a href="<?php echo getEscapedProfileUrl( false, 'memory_per_req' ); ?>">kb/req</a></th> 00353 </tr> 00354 </thead> 00355 <tbody> 00356 <?php 00357 profile_point::$totaltime = 0.0; 00358 profile_point::$totalcount = 0; 00359 profile_point::$totalmemory = 0.0; 00360 00361 function getEscapedProfileUrl( $_filter = false, $_sort = false, $_expand = false ) { 00362 // @codingStandardsIgnoreStart 00363 global $filter, $sort, $expand; 00364 // @codingStandardsIgnoreEnd 00365 00366 if ( $_expand === false ) { 00367 $_expand = $expand; 00368 } 00369 00370 return htmlspecialchars( 00371 '?' . 00372 wfArrayToCgi( array( 00373 'filter' => $_filter ? $_filter : $filter, 00374 'sort' => $_sort ? $_sort : $sort, 00375 'expand' => implode( ',', array_keys( $_expand ) ) 00376 ) ) 00377 ); 00378 } 00379 00380 $points = array(); 00381 $queries = array(); 00382 $sqltotal = 0.0; 00383 00384 $last = false; 00385 foreach ( $res as $o ) { 00386 $next = new profile_point( $o->pf_name, $o->pf_count, $o->pf_time, $o->pf_memory ); 00387 if ( $next->name() == '-total' ) { 00388 profile_point::$totaltime = $next->time(); 00389 profile_point::$totalcount = $next->count(); 00390 profile_point::$totalmemory = $next->memory(); 00391 } 00392 if ( $last !== false ) { 00393 if ( preg_match( '/^' . preg_quote( $last->name(), '/' ) . '/', $next->name() ) ) { 00394 $last->add_child( $next ); 00395 continue; 00396 } 00397 } 00398 $last = $next; 00399 if ( preg_match( '/^query: /', $next->name() ) || preg_match( '/^query-m: /', $next->name() ) ) { 00400 $sqltotal += $next->time(); 00401 $queries[] = $next; 00402 } else { 00403 $points[] = $next; 00404 } 00405 } 00406 00407 $s = new profile_point( 'SQL Queries', 0, $sqltotal, 0, 0 ); 00408 foreach ( $queries as $q ) { 00409 $s->add_child( $q ); 00410 } 00411 $points[] = $s; 00412 00413 usort( $points, 'compare_point' ); 00414 00415 foreach ( $points as $point ) { 00416 if ( strlen( $filter ) && !strstr( $point->name(), $filter ) ) { 00417 continue; 00418 } 00419 00420 $point->display( $expand ); 00421 } 00422 ?> 00423 </tbody> 00424 </table> 00425 <hr> 00426 <p>Total time: <code><?php printf( '%5.02f', profile_point::$totaltime ); ?></code></p> 00427 00428 <p>Total memory: <code><?php printf( '%5.02f', profile_point::$totalmemory / 1024 ); ?></code></p> 00429 <hr /> 00430 </body> 00431 </html>