Extension:PhpTags/Performance

Outdated. Last version of PhpTags works several times faster.

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 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 Quickly (0.00001 sec/instr)
Data transfer between extensions Cheapest  OK Directly Direct transfer of data obtained from one function of the extension to the next
Time spent by the extensions Less  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.

Note Note: 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.

Note Note: All of these tests can give only a general overview of performance since they use completely different approaches and technologies.

Compared to Magic Words edit

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 edit

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
  Note: 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) edit

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