Before 2.1, iterating over a single Chunk can be done more efficiently like this:
<?php
$chunk = $modx->getObject('modChunk', array('name' => 'testSpeed'));
$chunk->setCacheable(false);
for ($i = 0; $i < 1000; $i++) {
$chunk->process();
}
This avoids having to load the Chunk object instance on each iteration, which is the major bottleneck you are exploring. This does not however, use the sourceCache and will generate a database query each time it is called, even if that chunk has been used before in the same request.
After 2.1, there is a parser method for working with single instances of any Element which directly uses an internal cache which is loaded by cached Resources without any db hits, and reused by the parser anytime the same element is called within the same request:
<?php
$chunk = $modx->getParser()->getElement('modChunk', 'testSpeed');
for ($i = 0; $i < 1000; $i++) {
$chunk->process();
}
Note that getChunk also uses the sourceCache, but does not avoid object instantiation, and thus is not good to use iteratively like this.
Future work on MODX will be focused on reducing the overhead of class loading, object instantiation, unnecessary parsing passes, and total code so that these bottlenecks can be more easily avoided, and using them is as efficient as including a simple file and parsing it.
Here are some additional benchmarks for comparison:
[2012-02-28 08:17:13] (INFO) Processed 1000 chunks using getObject — 0.3189 s
[2012-02-28 08:17:14] (INFO) Processed 1000 chunks using modParser::getElement — 0.2116 s
[2012-02-28 08:17:17] (INFO) Processed 1000 chunks using getChunk — 2.8757 s
[2012-02-28 08:17:17] (INFO) Processed 1000 iterations on included content using modParser::processElementTags — 0.0323 s
These benchmarks used the following script:
<?php
include 'config.core.php';
include MODX_CORE_PATH . 'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('web');
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');
$modx->setLogLevel(xPDO::LOG_LEVEL_INFO);
$tstart = $modx->getMicroTime();
$chunk = $modx->getObject('modChunk', array('name' => 'testSpeed'));
$chunk->setCacheable(false);
for ($i = 0; $i < 1000; $i++) {
$chunk->process();
}
$tend = $modx->getMicroTime();
$modx->log(modX::LOG_LEVEL_INFO, sprintf("Processed 1000 chunks using getObject — %2.4f s\n", $tend - $tstart));
$tstart = $modx->getMicroTime();
$chunk = $modx->getParser()->getElement('modChunk', 'testSpeed');
for ($i = 0; $i < 1000; $i++) {
$chunk->process();
}
$tend = $modx->getMicroTime();
$modx->log(modX::LOG_LEVEL_INFO, sprintf("Processed 1000 chunks using modParser::getElement — %2.4f s\n", $tend - $tstart));
$tstart = $modx->getMicroTime();
for ($i = 0; $i < 1000; $i++) {
$modx->getChunk('testSpeed');
}
$tend = $modx->getMicroTime();
$modx->log(modX::LOG_LEVEL_INFO, sprintf("Processed 1000 chunks using getChunk — %2.4f s\n", $tend - $tstart));
$tstart = $modx->getMicroTime();
$content = include 'test-content.php';
for ($i = 0; $i < 1000; $i++) {
$modx->getParser()->processElementTags('', $content);
}
$tend = $modx->getMicroTime();
$modx->log(modX::LOG_LEVEL_INFO, sprintf("Processed 1000 iterations on included content using modParser::processElementTags — %2.4f s\n", $tend - $tstart));
exit();