MediaWiki REL1_35
benchmarkParse.php
Go to the documentation of this file.
1<?php
25require __DIR__ . '/../Maintenance.php';
26
30
39 private $templateTimestamp = null;
40
41 private $clearLinkCache = false;
42
46 private $linkCache;
47
49 private $idCache = [];
50
51 public function __construct() {
52 parent::__construct();
53 $this->addDescription( 'Benchmark parse operation' );
54 $this->addArg( 'title', 'The name of the page to parse' );
55 $this->addOption( 'warmup', 'Repeat the parse operation this number of times to warm the cache',
56 false, true );
57 $this->addOption( 'loops', 'Number of times to repeat parse operation post-warmup',
58 false, true );
59 $this->addOption( 'page-time',
60 'Use the version of the page which was current at the given time',
61 false, true );
62 $this->addOption( 'tpl-time',
63 'Use templates which were current at the given time (except that moves and ' .
64 'deletes are not handled properly)',
65 false, true );
66 $this->addOption( 'reset-linkcache', 'Reset the LinkCache after every parse.',
67 false, false );
68 }
69
70 public function execute() {
71 if ( $this->hasOption( 'tpl-time' ) ) {
72 $this->templateTimestamp = wfTimestamp( TS_MW, strtotime( $this->getOption( 'tpl-time' ) ) );
73 Hooks::register( 'BeforeParserFetchTemplateAndtitle', [ $this, 'onFetchTemplate' ] );
74 }
75
76 $this->clearLinkCache = $this->hasOption( 'reset-linkcache' );
77 // Set as a member variable to avoid function calls when we're timing the parse
78 $this->linkCache = MediaWikiServices::getInstance()->getLinkCache();
79
80 $title = Title::newFromText( $this->getArg( 0 ) );
81 if ( !$title ) {
82 $this->error( "Invalid title" );
83 exit( 1 );
84 }
85
86 $revLookup = MediaWikiServices::getInstance()->getRevisionLookup();
87 if ( $this->hasOption( 'page-time' ) ) {
88 $pageTimestamp = wfTimestamp( TS_MW, strtotime( $this->getOption( 'page-time' ) ) );
89 $id = $this->getRevIdForTime( $title, $pageTimestamp );
90 if ( !$id ) {
91 $this->error( "The page did not exist at that time" );
92 exit( 1 );
93 }
94
95 $revision = $revLookup->getRevisionById( $id );
96 } else {
97 $revision = $revLookup->getRevisionByTitle( $title );
98 }
99
100 if ( !$revision ) {
101 $this->error( "Unable to load revision, incorrect title?" );
102 exit( 1 );
103 }
104
105 $warmup = $this->getOption( 'warmup', 1 );
106 for ( $i = 0; $i < $warmup; $i++ ) {
107 $this->runParser( $revision );
108 }
109
110 $loops = $this->getOption( 'loops', 1 );
111 if ( $loops < 1 ) {
112 $this->fatalError( 'Invalid number of loops specified' );
113 }
114 $startUsage = getrusage();
115 $startTime = microtime( true );
116 for ( $i = 0; $i < $loops; $i++ ) {
117 $this->runParser( $revision );
118 }
119 $endUsage = getrusage();
120 $endTime = microtime( true );
121
122 printf( "CPU time = %.3f s, wall clock time = %.3f s\n",
123 // CPU time
124 ( $endUsage['ru_utime.tv_sec'] + $endUsage['ru_utime.tv_usec'] * 1e-6
125 - $startUsage['ru_utime.tv_sec'] - $startUsage['ru_utime.tv_usec'] * 1e-6 ) / $loops,
126 // Wall clock time
127 ( $endTime - $startTime ) / $loops
128 );
129 }
130
138 private function getRevIdForTime( Title $title, $timestamp ) {
139 $dbr = $this->getDB( DB_REPLICA );
140
141 $id = $dbr->selectField(
142 [ 'revision', 'page' ],
143 'rev_id',
144 [
145 'page_namespace' => $title->getNamespace(),
146 'page_title' => $title->getDBkey(),
147 'rev_timestamp <= ' . $dbr->addQuotes( $timestamp )
148 ],
149 __METHOD__,
150 [ 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 1 ],
151 [ 'revision' => [ 'JOIN', 'rev_page=page_id' ] ]
152 );
153
154 return $id;
155 }
156
162 private function runParser( RevisionRecord $revision ) {
163 $content = $revision->getContent( SlotRecord::MAIN );
164 $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
165
166 $content->getParserOutput( $title, $revision->getId() );
167 if ( $this->clearLinkCache ) {
168 $this->linkCache->clear();
169 }
170 }
171
182 private function onFetchTemplate( Parser $parser, Title $title, &$skip, &$id ) {
183 $pdbk = $title->getPrefixedDBkey();
184 if ( !isset( $this->idCache[$pdbk] ) ) {
185 $proposedId = $this->getRevIdForTime( $title, $this->templateTimestamp );
186 $this->idCache[$pdbk] = $proposedId;
187 }
188 if ( $this->idCache[$pdbk] !== false ) {
189 $id = $this->idCache[$pdbk];
190 }
191
192 return true;
193 }
194}
195
196$maintClass = BenchmarkParse::class;
getDB()
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
const RUN_MAINTENANCE_IF_MAIN
$maintClass
Maintenance script to benchmark how long it takes to parse a given title at an optionally specified t...
LinkCache $linkCache
getRevIdForTime(Title $title, $timestamp)
Fetch the ID of the revision of a Title that occurred.
onFetchTemplate(Parser $parser, Title $title, &$skip, &$id)
Hook into the parser's revision ID fetcher.
__construct()
Default constructor.
runParser(RevisionRecord $revision)
Parse the text from a given Revision.
execute()
Do the actual work.
array $idCache
Cache that maps a Title DB key to revision ID for the requested timestamp.
string $templateTimestamp
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Cache for article titles (prefixed DB keys) and ids linked from one source.
Definition LinkCache.php:34
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
error( $err, $die=0)
Throw an error to the user.
addArg( $arg, $description, $required=true)
Add some args that are needed.
hasOption( $name)
Checks to see if a particular option was set.
getArg( $argId=0, $default=null)
Get an argument.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Page revision base class.
getContent( $role, $audience=self::FOR_PUBLIC, User $user=null)
Returns the Content of the given slot of this revision.
getPageAsLinkTarget()
Returns the title of the page this revision is associated with as a LinkTarget object.
Value object representing a content slot associated with a page revision.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:85
Represents a title within MediaWiki.
Definition Title.php:42
const DB_REPLICA
Definition defines.php:25
$content
Definition router.php:76