MediaWiki  master
profileinfo.php
Go to the documentation of this file.
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>