тестирование производительности template engines

ONK

Пассивист PHPСluba
Скачал для своих нужд этот тест http://template-bench.iliakantor.ru/

Погонял на нашем экстеншене, очень остался не доволен методикой измерения времени исполнения тестов. Чем больше итераций, тем менее предсказуемый результат с бОльшим разбросом и меньшей повторяемостью.

В связи с этим предложение отказаться от округления в 6-м знаке, и вычислять не устреднённое время выполнения тестов по всем итерациям, а минимальное время за все попытки для каждого теста. Это сокращает разброс на 50 итераций до менее одного процента.

Собcтвенно прелагаю вот такой код вместо аналогичного куска из index.php
PHP:
ob_start();

# first iteration ignored due to caching etc.
for ($n=0; $n<=$iterations; $n++) {

	foreach ($engine as $template_engine) {
		$path = "./$template_engine"; # for test functions

		$func = $template_engine.'_test';

		if ($n) {
			echo "$template_engine ";
		}

		$_begin = microtime();
		$res = $func();
		$_end = microtime();

		$_begin = explode(" ",$_begin);
		$_end = explode(" ",$_end);
		$diff = $_end[1] - $_begin[1] + $_end[0] - $_begin[0];

		if ($n) {
			if($timing[$template_engine] > $diff){
				$timing[$template_engine] = round($diff,8);
				$length[$template_engine] = $res;
			}
			echo "$diff $res <br>";
		}else{
			$timing[$template_engine] = round($diff,8);
			$length[$template_engine] = $res;
		}
	}

}

ob_end_clean();


# sort by time and output
asort($timing);


list(,$time_min) = each($timing);
 

ONK

Пассивист PHPСluba
Строку

# first iteration ignored due to caching etc.

имхо, убрать надо. )

-~{}~ 18.01.08 17:58:

korchasa, нет тест хоть и оторван от реальности, зато позволяет тестировать производительность именно шаблонизатора, без всяких довесок имитирующих "жизнь".

http://localhost/lebowski-bench/php/main.php - это совсем другой тест, он интересен по своему. Щас им займусь :)
 

fisher

накатила суть
ONK, это к algo ;) но я не думаю, что данная методика что-то поменяет - тест слишком простой.
 

ONK

Пассивист PHPСluba
fisher, изменения очень существенные. В копирайтах сказано что можно модифицировать свободно, к тому-же я уверен, что algo не будет против. ;)
 

fixxxer

К.О.
Партнер клуба
к реальной жизни даже lebowski bench имеет весьма далекое отношение

а подобные тесты это просто пузомерка =) сравнительные тесты можно делать но не более.

-~{}~ 19.01.08 12:05:

> позволяет тестировать производительность именно шаблонизатора, без всяких довесок имитирующих "жизнь"

для этого проще всего написать код использующий только вызовы template engine в достаточно длительном цикле, и запускать time php file.php, безо всяких mcirotime :)
 

ONK

Пассивист PHPСluba
fixxxer,

1. Имхо ты не прав хотя бы по одной причине, наличие возможности динамически играть параметрами очень полезная фича. Позволяет выявлять узкие места и оценивать вклад в производительность разных оптимизаций в коде. По крайней мере мне этот тест сейчас очень помог. )


2. а кто-же массивы данных ему будет готовить? )))

Это кстати самое узкое место. Если написать экстеншен шаблонизатора, работающий раза в 1,5 - 2 быстрее пхп интерпретатора реально, то вот инициализация в пхп массивов для него приводит к тому, что результирующий скрипт работает процентов на 10 медленнее (как с кешированием опкода так и без).
 

fisher

накатила суть
>>изменения очень существенные

может я чего не понимаю - как это на тестах сказывается - что, результаты начали отличаться, что-то неправильно считалось?
 

ONK

Пассивист PHPСluba
fisher, я уже писал, из-за округления до 6-го знака, последующего сложение всех итераций и деления на количество итераций получался очень нестабильный и не точный результат даже на совершенно не загруженном железе. Причём чем больше итераций тем, меньше стабильность и точность. Уже на 50 итерациях набиралась ошибка до 50% и более.

Предлагаемый метод очень сильно отличается.
Вопервых он регистрирует лучшее время из всех попыток для каждого теста, что позволяет получить адекватный результат даже на загруженных серверах. Помимо этого, Округление до 6-го знака для данного теста с учётом производительности современных процессоров уже не годится, т.к. само по себе вносит до 10% погрешности. Я добавил ещё пару разрядов, должно хватить лет на 10 :)))
 

fisher

накатила суть
слова я понял. покажите цифры и я поверю. я хотел бы увидеть цифры, которые вы намеряли, поскольку мне кажется, что хоть ошибки + абсолютные цифры могут и отличаться - на распределение кто быстрее и насколько это особенного не повлияет.

>>лучшее время из всех попыток для каждого теста
кстати, имхо это неправильно. стоимость владения - это интегральная характеристика
 

fixxxer

К.О.
Партнер клуба
позволил себе помодерастить, ибо blitz тут ну совсем сбоку.

про лучшее время сомнительно, ага. хотя все зависит от того, какие, собственно цели ставятся. я так понимаю что ONK тестирует свой движок в разных конфигурациях - тут наверное такой подход уместен.

-~{}~ 19.01.08 14:13:

>инициализация в пхп массивов для него приводит к тому, что результирующий скрипт работает процентов на 10 медленнее

то есть
static $set = array ( ... )

дает такое замедление при использовании акселератора? :O или все же сам вызов $Tmpl->set() ? ;)
 

korchasa

LIMB infected
Автор оригинала: fixxxer
к реальной жизни даже lebowski bench имеет весьма далекое отношение

а подобные тесты это просто пузомерка =) сравнительные тесты можно делать но не более.
Полностью согласен. Тестировать нужно на реальных страницах, причем так, как вы привыкли писать шаблоны, а не как они быстрее работают.

Ну не могу я представить себе написание шаблонов без враппинга и инклудов (можно, конечно, это перенести на стадию деплоя, но как то неудобно что ли).

Последние два дня занимался как раз бенчами шаблонизаторов. В итоге пришлось переделать lebowski под себя. Получилось 4 отдельных шаблона. У blitz осталось второе место, но не с таким уж большим отрывом, как на обычных примерах.
 

ONK

Пассивист PHPСluba
fisher, сделал тест старого и нового, в основном на распределение не повлияло, но в соотношениях есть существенные изменения.

Код:
old
1	ccsis_cached	0.000101	100%	52700	
2	ccsis2		0.000198	196%	52700	
3	ccsis			0.000225	223%	52700	
4	php			0.000314	311%	52700	
5	blitz			0.000377	373%	52700	
6	vsprintf		0.000769	761%	52700	
7	str_replace		0.001468	1453%	52700	
8	smarty		0.001612	1596%	52700	
9	phemplate		0.00208	2059%	52700	
10	fasttemplate	0.003079	3049%	52700	
11	madtemplate		0.004911	4862%	52700	
12	ultratemplate	0.006042	5982%	52700	
13	vtemplate		0.00636	6297%	52700	
14	templatepower	0.008657	8571%	52700	
15	tinybutstrong	0.013381	13249%	52700	
16	bugitemplate	0.014993	14845%	52700	
17	phplib		0.016901	16734%	52700	
18	xtemplate		0.03759	37218%	52700

new
1	ccsis_cached	9.2E-5	100%	52700	
2	ccsis2		0.000189	205%	52700	
3	ccsis			0.000218	237%	52700	
4	php			0.000288	313%	52700	
5	blitz			0.000296	322%	52700	
6	vsprintf		0.000648	704%	52700	
7	str_replace		0.001452	1578%	52700	
8	smarty		0.001516	1648%	52700	
9	phemplate		0.001958	2128%	52700	
10	fasttemplate	0.002988	3248%	52700	
11	ultratemplate	0.00592	6435%	52700	
12	vtemplate		0.006159	6695%	52700	
13	madtemplate		0.006797	7388%	52700	
14	templatepower	0.008504	9243%	52700	
15	tinybutstrong	0.013103	14242%	52700	
16	bugitemplate	0.014799	16086%	52700	
17	phplib		0.016772	18230%	52700	
18	xtemplate		0.037089	40314%	52700
По поводу второго пункта у меня нет слов. Для меня этот тест ценен именно возможностью определение теоретических характеристик движка, а не "усреднённой производительности этого движка соотнесённой с загруженностью процессора и дисковой подсистемы" :) На загруженном сервере результаты старой версии теста совершенно непредсказуемы.

-~{}~ 19.01.08 20:57:

fixxxer, причём тут static? Инициализация данных для шаблона происходит динамически. для понятности я просто приведу два кода.

первый
PHP:
<?php
include('../data.inc'); 
$T = new CCSIS_Template('test');
$aBlocks = array();
$aBlocks[] = array(0);
$random_keys =  array_rand($_DATA['ADVERTS'],3);
foreach($random_keys as $i) {
	$aBlocks[] = array(1,array('d0'=>$_DATA['ADVERTS'][$i][0],'d1'=>$_DATA['ADVERTS'][$i][1],'d2'=>$_DATA['ADVERTS'][$i][2]));
}
$aBlocks[] = array(2);
foreach($_DATA['SECTIONS'] AS $k => $v) {
	$aBlocks[] = array(3,array('d0'=>$v[0],'d1'=>$v[1],'d3'=>(($k%2) ? 'eeeeee' : 'dddddd'),'d2'=>($v[2])?array(4):''));
}
$aBlocks[] = array(5,array('d0'=>$_DATA['STAT']['TOTAL'],'d1'=>count($_DATA['STAT']['ONLINE'])));
foreach($_DATA['STAT']['ONLINE'] AS $v) { 
	$aBlocks[] = array(6,array('d0'=>$v[0],'d1'=>$v[1]));
}
$aBlocks[] = array(7,array('d0'=>$_POLL['TITLE'],'d1'=>$_POLL['QUESTION']));
foreach($_POLL['ANSWERS'] AS $v) {
	$aBlocks[] = array(8,array('d0'=>$v));
}
$aBlocks[] = array(9,array('d0'=>$_POLL['BUTTON']));
foreach($_NEWS AS $v) {
	$aBlocks[] = array(10,array('d0'=>$v[0],'d1'=>$v[1],'d2'=>$v[2],'d3'=>$v[3]));
} 
$aBlocks[] = array(11);
$T->assign($aBlocks);
echo $T->show();
?>
и второй

PHP:
<?php
include('../data.inc'); 
$T = new CCSIS_Template('test');
$T->add(0);
$random_keys =  array_rand($_DATA['ADVERTS'],3);
foreach($random_keys as $i) {
	$T->add(1,array('d0'=>$_DATA['ADVERTS'][$i][0],'d1'=>$_DATA['ADVERTS'][$i][1],'d2'=>$_DATA['ADVERTS'][$i][2]));
}
$T->add(2);
foreach($_DATA['SECTIONS'] AS $k => $v) {
	$T->add(3,array('d0'=>$v[0],'d1'=>$v[1],'d3'=>(($k%2) ? 'eeeeee' : 'dddddd'),'d2'=>($v[2])?array(4):''));
}
$T->add(5,array('d0'=>$_DATA['STAT']['TOTAL'],'d1'=>count($_DATA['STAT']['ONLINE'])));
foreach($_DATA['STAT']['ONLINE'] AS $v) { 
	$T->add(6,array('d0'=>$v[0],'d1'=>$v[1]));
}
$T->add(7,array('d0'=>$_POLL['TITLE'],'d1'=>$_POLL['QUESTION']));
foreach($_POLL['ANSWERS'] AS $v) {
	$T->add(8,array('d0'=>$v));
}
$T->add(9,array('d0'=>$_POLL['BUTTON']));
foreach($_NEWS AS $v) {
	$T->add(10,array('d0'=>$v[0],'d1'=>$v[1],'d2'=>$v[2],'d3'=>$v[3]));
} 
$T->add(11);
echo $T->show();
?>
А теперь угадай, какой из них быстрее?
 

fixxxer

К.О.
Партнер клуба
нуууу это уже совсем непонятно зачем все эти пляски.
по крайней мере я всегда собираю массив итераций заранее и делаю один-единственный set. это практически всегда будет гарантированно быстрее, и это удобно.
см. blitz-ctx-arr в lebowski bench

UPD: ага, ну приведенный пример как раз про это, дошло :D
 

fisher

накатила суть
>>в основном на распределение не повлияло
ONK, ну а теперь вспомним, что на самом деле тест можно юзать только для отделения быстрых от медленных - и только. с точки зрения эксплуатации реальной системы этот тест меряет хрен знает что. Вам кажется, будто это какие-то "теоретические пределы" шаблонизатора - ну сделайте чуть другой тест и получите совершенно другие цифры.

кстати, а почему бы не рассказать об этом загадочном ccsis? что он показывает на lebowski-bench? я вот считал, что мой движок самый быстрый, а тут глядишь окажется вдруг что это не так - всегда приятно узнавать что-то новое :) вряд ли движок шаблонов составляет ядро конкурентных преимуществ компании ;)
 

ONK

Пассивист PHPСluba
fixxxer, ты будеш удивлён, но многократные вызовы obj::add оказались ~ на 1% эффективнее, че заполнение массива $aBlocks и однократный вызов obj::assign Это сохраняется и при кэширования опкода. И дело не в тормознутости реализации метода assign (по сути это сишный итератор хэштаблицы массива, вызывающий то же код сборки блока что и add). Так что делаем выводы маи :).

fisher, с точки зрения реальных системы оба теста мерят хрен знает что.
Могу привести простой пример одно и тоже приложение, при использовании ПХП реализации шаблонного движка работает в среднем на 4% медленнее чем при подключении пхп экстеншена. Если включить кэширование опкода, разница возрастает до 10%. Хотя на простых скриптах генерирующих страницы, производительность может вырастать в разы. А теперь вопрос, как всё это соотносится с данными тестами? Правильно, - никак.
Тесты нужны комуто для выбора движка шаблонизатора, а комуто для анализа их производительности. В обоих случаях ИМХО, предпочтительнее получить информацию о производительности самого шаблонизатора, а не тестируемого аппаратно программного комплекса :) Вот моё предложение направлени именно на это.

По поводу lebowski-bench, если пользоваться предоставленным набором данных (по сути созданных под пхп версию теста), то из-за необходимости инициализировать массивы общая производительность теста на 7 - 10% хуже чем у пхп версии. Если массивы данных инициализировать в оптимальном для шаблонизатора виде, то думаю будет значительно быстрее, т.к. проблема откровенно в производительности самого пхп интепретатора. Могу даже ради интереса сделать тестик :).

По поводу самого экстеншена, он как раз в процессе разработки, на конечной стадии. Реализует проверенный временем и устоявшийся функционал простого шаблонизатора. Причина высокой скорости в особенности подхода к реализации подстановки переменных в блоки. Обычно это делается методом замены подстрок, у нас это делается методом композиции блока.
 

fisher

накатила суть
>>Если включить кэширование опкода, разница возрастает до 10%
эээ при этом нет никаких блокирующих операций и мы тупим по процу? 10% это как-то ОЧЕНЬ мало.
UPDATE: а, разница, понял

>>оба теста мерят хрен знает что
не соглашусь. то есть lebowski конечно далек от реальности. но есть всё-таки разница - переменные вставлять, или более менее реальную задачку решать. и сравнение результатов это очень хорошо показывает: нет смысла мерять отдельно какие-то операции, например, те же методы передачи данных в шаблон могут сильно повлиять на скорость (10-20% легко) - так что мерят надо на каких-то готовых страницах с данными, примерно похожими на правду. другое дело, что это можно сделать не через ab

>>общая производительность теста на 7 - 10% хуже чем у пхп
>>версии
я не совсем понял - ваш движок на lebowski bench на 7-10% медленее php mess?

>>методом композиции блока
это что за метод такой? разметили (сохранили массив указателей) а потом один раз собрали всё при парсинге?
 

fixxxer

К.О.
Партнер клуба
>но многократные вызовы obj::add оказались ~ на 1% эффективнее

окак... интересно тогда посмотреть на этот движок =)

-~{}~ 20.01.08 13:56:

> $T->add(10,array...

а вот это что за циферка, что она значит?
 

fisher

накатила суть
>>Доставьте туда Quicky + eAccelerator
если не просить, а прислать патч (в данном случае скачать тесты и сделать решение со своим шаблонизатором) - будет результат. акселератор у algo стоит кстати.
 
Сверху