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