Extension:PhpTags/Performance
The PhpTags extension is designed to obtain the best possible MediaWiki extensions performance without using any additional components (only pure PHP code).
This is achieved by using the concept of Magic expressions instead of Magic words. Although PhpTags himself uses the technology Magic words, but it allows to reduces to a minimum overhead of usage other extensions.
Time that takes PhpTags consists of:
- analysis of expression
- execution of instructions
- data transfer between extensions
- time spent by the extensions
Types of costs | Expensiveness | Costs | Comments |
---|---|---|---|
Analysis of expression | Relatively expensive | OK OK Using the cache allows not take into account this time | PhpTags produces a compilation in simple instructions (bytecode) that run very quickly and easily cached |
Execution of instructions | Inexpensive | OK OK Quickly (0.00001 sec/instr) | |
Data transfer between extensions | Cheapest | OK OK Directly | Direct transfer of data obtained from one function of the extension to the next |
Time spent by the extensions | Less | OK OK Savings on parsing the parameters | Extension does not have to worry about parsing the parameters from the text, it gets them ready-made as an array or object |
PhpTags works so rapidly that when used under the concept of the magic expressions the run time is negligible or it is not possible to measure.
- File:OOjs UI icon lightbulb-yellow.svg <translate> Note:</translate> The main part of the code should be in the extensions, and in the PhpTags placed instructions which features of these extensions, and in what order to use.
Of course, you can use this application as you wish, and in order to find out the effectiveness (as possible) this solution, I ran some tests using MediaWiki 1.23.1 and PhpTags 3.0.0.
- File:OOjs UI icon lightbulb-yellow.svg <translate> Note:</translate> All of these tests can give only a general overview of performance since they use completely different approaches and technologies.
Compared to Magic Words
For comparison I took two nested loops of 20 loops each, a total of 420 loops.
PhpTags [1] | Magic words (Loops, Variables and ParserFunctions) |
---|---|
<phptag>
$r = 1;
$i = 1;
while ( $i <= 20 ) {
$i++;
$j = 1;
while ( $j <= 20 ) {
$j++;
$r = ($r + ($i * $j) % 100) % 47;
}
}
</phptag>
|
{{ #vardefine: r | 1 }}{{ #vardefine: i | 1 }}{{ #while: | {{ #ifexpr: {{ #var: i }} <= 20 | true }} | {{ #vardefine: i | {{ #expr: {{ #var: i }} + 1 }} }} {{ #vardefine: j | 1 }} {{ #while: | {{ #ifexpr: {{ #var: j }} <= 20 | true }} | {{ #vardefine: j | {{ #expr: {{ #var: j }} + 1 }} }} {{ #vardefine: r | {{ #expr: ({{ #var: r }} + ( {{ #var: i }} * {{ #var: j }} ) % 100 ) % 47 }} }} }} }} |
NewPP limit report CPU time usage: 0.069 seconds Real time usage: 0.069 seconds Preprocessor visited node count: 4/1000000 Preprocessor generated node count: 24/1000000 Post‐expand include size: 0/2097152 bytes Template argument size: 0/2097152 bytes Highest expansion depth: 2/40 Expensive parser function count: 0/100 PhpTags time usage: 0.059 sec Compiler: 0.007 sec Runtime: 0.052 sec |
NewPP limit report: CPU time usage: 5.950 seconds Real time usage: 5.966 seconds Preprocessor visited node count: 6309/1000000 Preprocessor generated node count: 284/1000000 Post‐expand include size: 91309/2097152 bytes Template argument size: 0/2097152 bytes Highest expansion depth: 6/40 Expensive parser function count: 0/100 ExtLoops count: 420/100000 |
MediaWiki with PhpTags faster Magic words in more 86 times. ( 5.950 / 0.069 = 86.232 ) The next time bytecode will be taken from the cache, and PhpTags will be faster more 95 times. ( 5.950 / (0.069-0.007) = 95.968 )
Compared to pure PHP
For a more accurate measurement I increased the number of cycles up to 100100
$r = 1; // 1 = 1
$i = 1; // 1 = 1
while ( $i <= 100 ) { // 3 * 101 = 303
$i++; // 2 * 100 = 200
$j = 1; // 1 * 100 = 100
while ( $j <= 1000 ) { // 3 * 1001 * 100 = 300300
$j++; // 2 * 1000 * 100 = 200000
$r = ($r + ($i * $j) % 100) % 47; // 8 * 1000 * 100 = 800000
} // 1 * 1000 = 1000
} // 1 * 100 = 100
// _______________________
// 1302005
- File:OOjs UI icon lightbulb-yellow.svg <translate> Note:</translate> The comments indicate the number of instructions that PhpTags has executed.
Test Results:
PhpTags: 11.462 secs PHP: 0.029 secs PhpTags/PHP: 394.573
As it can be seen PhpTags in this test is slower pure PHP almost in 400 times. But PhpTags has executed 1 302 005 instructions per 11.462 seconds and one instruction took the less 0.00001 second.
I'm sure PHP uses some hack for cycles, so I did another test where few cycles and a lot of code.
Test Results:
PhpTags time usage: 0.332 sec Compiler: 0.272 sec Runtime: 0.060 sec Pure PHP: 0.00235 sec PhpTags/PHP without compiler cache: 0.332 / 0.00235 = 141 PhpTags/PHP with compiler cache: 0.060 / 0.00235 = 25
Since the runtime also includes the initialization of the PhpTags Functions classes I did another test where this code is duplicated ten times. Initialization occurs only once therefore I divide the runtime by 10 and get more accurate results where the initialization is less significant role.
Runtime: 0.484 / 10 = 0.0484 sec Pure PHP: 0.00235 sec PhpTags/PHP: 0.0484 / 0.00235 = 20.6
Well, something like that. You should try not to use loops with PhpTags if you want to get the best performance.
Compared to Scribunto (Lua)
It would seem what can be compared here? It is well known that Lua is due to the simple implementation works several times faster than PHP. In the test cycles given above PHP took 0.029 second and Lua takes only 0.008 second. It turns out that this is the fastest solution, and this is the best that can be used to increase performance Mediawiki.
In practice, this is not quite true.
Even if you move away from the concept of Magic expressions and will use PhpTags for writing scripts in the same way as is done in Scribunto, MediaWiki with PhpTags is still runs faster in two or more times than Scribunto. Perhaps this is due to the fact that the Scribunto requires some resources to initialize Lua, while PhpTags has no such overhead.
For testing, I used a ready-made module drawing markers on the map. I tried to rewrite it in the same manner but using PhpTags (Template:Location_map).
So here's what I got in the end:
Tasks | Scribunto (Lua) | PhpTags | Сonclusion |
---|---|---|---|
displaying of 4 maps | English Wikipedia
NewPP limit report Parsed by mw1082 CPU time usage: 0.428 seconds Real time usage: 0.467 seconds Preprocessor visited node count: 384/1000000 Preprocessor generated node count: 1122/1500000 Post‐expand include size: 20066/2048000 bytes Template argument size: 75/2048000 bytes Highest expansion depth: 5/40 Expensive parser function count: 3/500 Lua time usage: 0.139/10.000 seconds Lua memory usage: 1.17 MB/50 MB |
test.foxway.org
NewPP limit report CPU time usage: 0.124 seconds Real time usage: 0.131 seconds Preprocessor visited node count: 116/1000000 Preprocessor generated node count: 400/1000000 Post‐expand include size: 600/2097152 bytes Template argument size: 0/2097152 bytes Highest expansion depth: 4/40 Expensive parser function count: 0/100 PhpTags time usage: 0.024 sec Compiler: 0.004 sec Runtime: 0.020 sec |
MW with Scribunto took CPU time 3.45 times longer ( 0.428 / 0.124 ) Scribunto / PhpTags = 0.139 / 0.020 = 6.95 |
displaying of 40 maps | English Wikipedia
NewPP limit report Parsed by mw1169 CPU time usage: 2.124 seconds Real time usage: 2.258 seconds Preprocessor visited node count: 2548/1000000 Preprocessor generated node count: 10818/1500000 Post‐expand include size: 200510/2048000 bytes Template argument size: 75/2048000 bytes Highest expansion depth: 5/40 Expensive parser function count: 3/500 Lua time usage: 0.614/10.000 seconds Lua memory usage: 1.47 MB/50 MB |
test.foxway.org
NewPP limit report CPU time usage: 0.964 seconds Real time usage: 0.968 seconds Preprocessor visited node count: 1271/1000000 Preprocessor generated node count: 3956/1000000 Post‐expand include size: 6150/2097152 bytes Template argument size: 0/2097152 bytes Highest expansion depth: 4/40 Expensive parser function count: 0/100 PhpTags time usage: 0.280 sec Compiler: 0.012 sec Runtime: 0.268 sec |
MW with Scribunto took CPU time 2.2 times longer ( 2.124 / 0.964 ) Scribunto / PhpTags = 0.614 / 0.268 = 2.29 |