MediaWiki REL1_37
benchmarkParse.php
Go to the documentation of this file.
1<?php
25require_once __DIR__ . '/../Maintenance.php';
26
31
40 private $templateTimestamp = null;
41
42 private $clearLinkCache = false;
43
47 private $linkCache;
48
50 private $idCache = [];
51
52 public function __construct() {
53 parent::__construct();
54 $this->addDescription( 'Benchmark parse operation' );
55 $this->addArg( 'title', 'The name of the page to parse' );
56 $this->addOption( 'warmup', 'Repeat the parse operation this number of times to warm the cache',
57 false, true );
58 $this->addOption( 'loops', 'Number of times to repeat parse operation post-warmup',
59 false, true );
60 $this->addOption( 'page-time',
61 'Use the version of the page which was current at the given time',
62 false, true );
63 $this->addOption( 'tpl-time',
64 'Use templates which were current at the given time (except that moves and ' .
65 'deletes are not handled properly)',
66 false, true );
67 $this->addOption( 'reset-linkcache', 'Reset the LinkCache after every parse.',
68 false, false );
69 }
70
71 public function execute() {
72 if ( $this->hasOption( 'tpl-time' ) ) {
73 $this->templateTimestamp = wfTimestamp( TS_MW, strtotime( $this->getOption( 'tpl-time' ) ) );
74 Hooks::register( 'BeforeParserFetchTemplateRevisionRecord', [ $this, 'onFetchTemplate' ] );
75 }
76
77 $this->clearLinkCache = $this->hasOption( 'reset-linkcache' );
78 // Set as a member variable to avoid function calls when we're timing the parse
79 $this->linkCache = MediaWikiServices::getInstance()->getLinkCache();
80
81 $title = Title::newFromText( $this->getArg( 0 ) );
82 if ( !$title ) {
83 $this->fatalError( "Invalid title" );
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->fatalError( "The page did not exist at that time" );
92 }
93
94 $revision = $revLookup->getRevisionById( $id );
95 } else {
96 $revision = $revLookup->getRevisionByTitle( $title );
97 }
98
99 if ( !$revision ) {
100 $this->fatalError( "Unable to load revision, incorrect title?" );
101 }
102
103 $warmup = $this->getOption( 'warmup', 1 );
104 for ( $i = 0; $i < $warmup; $i++ ) {
105 $this->runParser( $revision );
106 }
107
108 $loops = $this->getOption( 'loops', 1 );
109 if ( $loops < 1 ) {
110 $this->fatalError( 'Invalid number of loops specified' );
111 }
112 $startUsage = getrusage();
113 $startTime = microtime( true );
114 for ( $i = 0; $i < $loops; $i++ ) {
115 $this->runParser( $revision );
116 }
117 $endUsage = getrusage();
118 $endTime = microtime( true );
119
120 printf( "CPU time = %.3f s, wall clock time = %.3f s\n",
121 // CPU time
122 ( $endUsage['ru_utime.tv_sec'] + $endUsage['ru_utime.tv_usec'] * 1e-6
123 - $startUsage['ru_utime.tv_sec'] - $startUsage['ru_utime.tv_usec'] * 1e-6 ) / $loops,
124 // Wall clock time
125 ( $endTime - $startTime ) / $loops
126 );
127 }
128
136 private function getRevIdForTime( Title $title, $timestamp ) {
137 $dbr = $this->getDB( DB_REPLICA );
138
139 $id = $dbr->selectField(
140 [ 'revision', 'page' ],
141 'rev_id',
142 [
143 'page_namespace' => $title->getNamespace(),
144 'page_title' => $title->getDBkey(),
145 'rev_timestamp <= ' . $dbr->addQuotes( $timestamp )
146 ],
147 __METHOD__,
148 [ 'ORDER BY' => 'rev_timestamp DESC' ],
149 [ 'revision' => [ 'JOIN', 'rev_page=page_id' ] ]
150 );
151
152 return $id;
153 }
154
160 private function runParser( RevisionRecord $revision ) {
161 $content = $revision->getContent( SlotRecord::MAIN );
162 $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
163
164 $content->getParserOutput( $title, $revision->getId() );
165 if ( $this->clearLinkCache ) {
166 $this->linkCache->clear();
167 }
168 }
169
180 private function onFetchTemplate(
181 ?LinkTarget $contextTitle,
182 LinkTarget $titleTarget,
183 bool &$skip,
184 ?RevisionRecord &$revRecord
185 ): bool {
186 $title = Title::castFromLinkTarget( $titleTarget );
187
188 $pdbk = $title->getPrefixedDBkey();
189 if ( !isset( $this->idCache[$pdbk] ) ) {
190 $proposedId = $this->getRevIdForTime( $title, $this->templateTimestamp );
191 $this->idCache[$pdbk] = $proposedId;
192 }
193 if ( $this->idCache[$pdbk] !== false ) {
194 $revLookup = MediaWikiServices::getInstance()->getRevisionLookup();
195 $revRecord = $revLookup->getRevisionById( $this->idCache[$pdbk] );
196 }
197
198 return true;
199 }
200}
201
202$maintClass = BenchmarkParse::class;
203require_once RUN_MAINTENANCE_IF_MAIN;
getDB()
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$maintClass
Maintenance script to benchmark how long it takes to parse a given title at an optionally specified t...
LinkCache $linkCache
onFetchTemplate(?LinkTarget $contextTitle, LinkTarget $titleTarget, bool &$skip, ?RevisionRecord &$revRecord)
Hook into the parser's revision ID fetcher.
getRevIdForTime(Title $title, $timestamp)
Fetch the ID of the revision of a Title that occurred.
__construct()
Default constructor.
runParser(RevisionRecord $revision)
Parse the text from a given RevisionRecord.
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:41
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
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, Authority $performer=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.
getId( $wikiId=self::LOCAL)
Get revision ID.
Value object representing a content slot associated with a page revision.
Represents a title within MediaWiki.
Definition Title.php:48
getPrefixedDBkey()
Get the prefixed database key form.
Definition Title.php:1909
const DB_REPLICA
Definition defines.php:25
$content
Definition router.php:76