Aaron Schulz has uploaded a new change for review.
https://gerrit.wikimedia.org/r/172813
Change subject: Move request-only template profiling to an always-on parser
report
......................................................................
Move request-only template profiling to an always-on parser report
Change-Id: I0660c8d6cac0dadab648eac9736504b7939320f3
---
M includes/AutoLoader.php
M includes/parser/Parser.php
A includes/profiler/ExplicitProfiler.php
M includes/profiler/ProfilerStandard.php
4 files changed, 141 insertions(+), 11 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/13/172813/1
diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index af86c99..ef9ce26 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
@@ -878,6 +878,7 @@
'EncryptedPassword' => 'includes/password/EncryptedPassword.php',
# includes/profiler
+ 'ExplicitProfiler' => 'includes/profiler/ExplicitProfiler.php',
'Profiler' => 'includes/profiler/Profiler.php',
'ProfilerSimpleDB' => 'includes/profiler/ProfilerSimpleDB.php',
'ProfilerSimpleText' => 'includes/profiler/ProfilerSimpleText.php',
diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php
index cd804b5..fa6d366 100644
--- a/includes/parser/Parser.php
+++ b/includes/parser/Parser.php
@@ -224,6 +224,9 @@
*/
public $mInParse = false;
+ /** @var ExplicitProfiler */
+ protected $mProfiler;
+
/**
* @param array $conf
*/
@@ -364,6 +367,8 @@
if ( isset( $this->mPreprocessor ) &&
$this->mPreprocessor->parser !== $this ) {
$this->mPreprocessor = null;
}
+
+ $this->mProfiler = new ExplicitProfiler();
wfRunHooks( 'ParserClearState', array( &$this ) );
wfProfileOut( __METHOD__ );
@@ -525,6 +530,19 @@
// which looks much like the problematic '-'.
$limitReport = str_replace( array( '-', '&' ), array(
'‐', '&' ), $limitReport );
$text .= "\n<!-- \n$limitReport-->\n";
+
+ // Add on template profiling data
+ $dataByFunc = $this->mProfiler->getRawData();
+ uasort( $dataByFunc, function( $a, $b ) {
+ return $a['elapsed'] < $b['elapsed']; //
descending order
+ } );
+ $profileReport = "Top template expansion time report
(%,ms,calls,template)\n";
+ foreach ( array_slice( $dataByFunc, 0, 10 ) as $item ) {
+ $profileReport .= sprintf( "%6.2f%% %3.6f %6d -
%s\n",
+ $item['percent'], $item['elapsed'],
$item['calls'],
+ htmlspecialchars($item['name'] ) );
+ }
+ $text .= "\n<!-- \n$profileReport-->\n";
if ( $this->mGeneratedPPNodeCount >
$this->mOptions->getMaxGeneratedPPNodeCount() / 10 ) {
wfDebugLog( 'generated-pp-node-count',
$this->mGeneratedPPNodeCount . ' ' .
@@ -3473,7 +3491,7 @@
$args = ( null == $piece['parts'] ) ? array() : $piece['parts'];
wfProfileOut( __METHOD__ . '-setup' );
- $titleProfileIn = null; // profile templates
+ $profileSection = null; // profile templates
# SUBST
wfProfileIn( __METHOD__ . '-modifiers' );
@@ -3594,11 +3612,7 @@
# Load from database
if ( !$found && $title ) {
- if ( !Profiler::instance()->isPersistent() ) {
- # Too many unique items can kill profiling
DBs/collectors
- $titleProfileIn = __METHOD__ . "-title-" .
$title->getPrefixedDBkey();
- wfProfileIn( $titleProfileIn ); // template in
- }
+ $profileSection = $this->mProfiler->scopedProfileIn(
$title->getPrefixedDBkey() );
wfProfileIn( __METHOD__ . '-loadtpl' );
if ( !$title->isExternal() ) {
if ( $title->isSpecialPage()
@@ -3680,8 +3694,8 @@
# Recover the source wikitext and return it
if ( !$found ) {
$text = $frame->virtualBracketedImplode( '{{', '|',
'}}', $titleWithSpaces, $args );
- if ( $titleProfileIn ) {
- wfProfileOut( $titleProfileIn ); // template out
+ if ( $profileSection ) {
+ $this->mProfiler->scopedProfileOut(
$profileSection );
}
wfProfileOut( __METHOD__ );
return array( 'object' => $text );
@@ -3707,8 +3721,8 @@
$isLocalObj = false;
}
- if ( $titleProfileIn ) {
- wfProfileOut( $titleProfileIn ); // template out
+ if ( $profileSection ) {
+ $this->mProfiler->scopedProfileOut( $profileSection );
}
# Replace raw HTML by a placeholder
diff --git a/includes/profiler/ExplicitProfiler.php
b/includes/profiler/ExplicitProfiler.php
new file mode 100644
index 0000000..e510bc5
--- /dev/null
+++ b/includes/profiler/ExplicitProfiler.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Arbitrary section name based PHP profiling.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Profiler
+ * @author Aaron Schulz
+ */
+
+/**
+ * Custom PHP profiler for parser/DB type section names that xhprof/xdebug
can't handle
+ *
+ * @TODO: refactor implementation by moving Profiler code to here when
non-automatic
+ * profiler support is dropped.
+ *
+ * @since 1.25
+ */
+class ExplicitProfiler {
+ /** @var ProfilerStandard */
+ protected $profiler;
+
+ public function __construct() {
+ // This does *not* care about PHP request start time
+ $this->profiler = new ProfilerStandard( array( 'initTotal' =>
false ) );
+ }
+
+ /**
+ * @param string $section
+ * @return ScopedCallback
+ */
+ public function scopedProfileIn( $section ) {
+ $that = $this;
+ $sc = new ScopedCallback( function() use ( $that, $section ) {
+ $that->scopedProfileOut( $section );
+ } );
+ $this->profiler->profileIn( $section );
+
+ return $sc;
+ }
+
+ /**
+ * @param ScopedCallback|string $section
+ */
+ public function scopedProfileOut( &$section = null ) {
+ if ( is_string( $section ) ) {
+ $this->profiler->profileOut( $section );
+ } else {
+ $section = null;
+ }
+ }
+
+ /**
+ * Get the raw and collated breakdown data for each method
+ *
+ * The percent time for each time is based on the current "total" time
+ * used is based on all methods so far. This method can therefore be
+ * called several times in between several profiling calls without the
+ * delays in usage of the profiler skewing the results. A "-total" entry
+ * is always included in the results.
+ *
+ * @return array List of method entries arrays, each having:
+ * - name : method name
+ * - calls : the number of method calls
+ * - elapsed : real time ellapsed (ms)
+ * - percent : percent real time
+ * - memory : memory used (bytes)
+ * - min : min real time of all calls (ms)
+ * - max : max real time of all calls (ms)
+ */
+ public function getRawData() {
+ $data = $this->profiler->getRawData();
+
+ $memoryTotal = 0;
+ $elapsedTotal = 0;
+ foreach ( $data as $item ) {
+ $memoryTotal += $item['memory'];
+ $elapsedTotal += $item['elapsed'];
+ }
+
+ foreach ( $data as &$item ) {
+ $item['percent'] = $item['elapsed'] / $elapsedTotal *
100;
+ }
+ unset( $item );
+
+ $data[] = array(
+ 'name' => '-total',
+ 'calls' => 1,
+ 'elapsed' => $elapsedTotal,
+ 'percent' => 100,
+ 'memory' => $memoryTotal,
+ 'min' => $elapsedTotal,
+ 'max' => $elapsedTotal
+ );
+
+ return $data;
+ }
+}
diff --git a/includes/profiler/ProfilerStandard.php
b/includes/profiler/ProfilerStandard.php
index 4825f7a..d75ae9e 100644
--- a/includes/profiler/ProfilerStandard.php
+++ b/includes/profiler/ProfilerStandard.php
@@ -47,11 +47,14 @@
/**
* @param array $params
+ * - initTotal : set to false to omit -total/-setup entries (which
use request start time)
*/
public function __construct( array $params ) {
parent::__construct( $params );
- $this->addInitialStack();
+ if ( !isset( $params['initTotal'] ) || $params['initTotal'] ) {
+ $this->addInitialStack();
+ }
}
/**
--
To view, visit https://gerrit.wikimedia.org/r/172813
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0660c8d6cac0dadab648eac9736504b7939320f3
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits