Page MenuHomePhabricator

Improve performance of Title::isMainPage
Open, Needs TriagePublic

Description

Title::isMainPage is run once for every link on a page to determine what the localURL should be (and apparently 3 times for each file on a page, but that's a story for later). It's also used pretty frequently by hooks like onGetLocalURLInternal, and a moderately sized page can easily have 1000-2000 calls to it.

Despite this, it's a surprisingly expensive call, because it calls Title::newMainPage() every time. This doesn't technically create a new Title object every time due to the newFromText cache, but the expensive part is where it gets the "mainpage" message from the MessageCache. It's not outrageously expensive, but 20-30 μs for each call adds up if it's called 1000-2000 times per page.

Since Title::newMainPage() is a static method, can we just cache the result when it's called from Title::isMainPage? Here's some example code that I'm sure could be improved (I'm fairly new to MediaWiki perf stuff):

Change from

public function isMainPage() {
        return $this->equals( self::newMainPage() );
}

to

public function isMainPage() {
        if (isset(self::$mainPage)) {
                return $this->equals( self::$mainPage );
        }
        self::$mainPage = self::newMainPage();
        return $this->equals( self::$mainPage );
}

I can't speak for the general case, but for runescape.wiki this little change reduces the average parse time of pages by about 8%.

Event Timeline

A little more investigation suggests that this is mainly an issue for wikis with $wgMainPageIsDomainRoot = true, which is not the case for WMF.

Instance caching newMainPage() seems reasonable to me. You might need to guard it on !defined( 'MW_PHPUNIT_TEST' ) but that's a pretty common pattern.