<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ars Longa, Vita Brevis &#187; benchmark</title>
	<atom:link href="http://blog.sjinks.pro/tag/benchmark/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.sjinks.pro</link>
	<description>Quod scripsi, scripsi</description>
	<lastBuildDate>Mon, 06 Feb 2012 17:56:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>WP Super Cache vs MaxSite Cache: часть 1</title>
		<link>http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/</link>
		<comments>http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 23:17:34 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[MaxSite Cache]]></category>
		<category><![CDATA[WP Super Cache]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=689</guid>
		<description><![CDATA[Тест страничных кэшей на виртуальном сервере абсолютного чайника После того, как MAX’у не понравился тест с участием MaxSite Cache, я решил несколько видоизменить методику тестирования. На этот раз я тестировал только два кэша: WP Super Cache и MaxSite Cache Lite. Так как по словам MAX’а в реальности все ставится «из коробки», я взял виртуальный сервер [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Тест страничных кэшей на виртуальном сервере абсолютного чайника</em></h2>
<p>После того, как MAX’у не понравился <a href="http://blog.sjinks.pro/wordpress/683-wp-supercache-vs-hypercache-vs-w3-total-cache-vs-maxsite-cache/">тест с участием MaxSite Cache</a>, я решил несколько видоизменить методику тестирования.</p>
<p>На этот раз я тестировал только два кэша: <a href="http://blog.sjinks.pro/tag/wp-super-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WP Super Cache">WP Super Cache</a> и <a href="http://blog.sjinks.pro/tag/maxsite-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MaxSite Cache">MaxSite Cache</a> Lite.<span id="more-689"></span></p>
<p>Так как по словам <cite>MAX</cite>’а <q>в реальности все ставится «из коробки»</q>, я взял виртуальный сервер (512 MiB RAM, 10 GB HD, Intel Xeon X3320 (1 ядро), 2.5 GHz), на который поставил Ubuntu 8.04 LTS Server Edition. Затем поставил <a href="http://blog.sjinks.pro/tag/apache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Apache">Apache</a> (2.2.8-1ubuntu0), PHP (5.2.4-2ubuntu5.6) и MySQL (5.0.51a-3ubuntu5.4). Конфигурационные файлы брались «из коробки» (только для <a href="http://blog.sjinks.pro/tag/apache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Apache">Apache</a> пришлось включить mod_rewrite), в системной конфигурации абсолютно ничего не менялось. VDS абсолютного «чайника». Для мониторинга ресурсов системы установил munin (он рисует такие красивые графики).</p>
<p>Кому интересно, VDS конфигурировался так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p6892">
        <div class="code bash" id="p689code2">
<span class="kw2">wget</span> http:<span class="sy0">//</span>ubuntu-releases.eecs.wsu.edu<span class="sy0">/</span>hardy<span class="sy0">/</span>ubuntu-8.04.3-server-i386.iso<br />
VBoxManage registerimage dvd <span class="sy0">/</span>home<span class="sy0">/</span>user1<span class="sy0">/</span>ubuntu-8.04.3-server-i386.iso<br />
VBoxManage createhd <span class="re5">--filename</span> TestVDS-HD1 <span class="re5">--size</span> 10240 <span class="re5">--remember</span><br />
VBoxManage createvm <span class="re5">--name</span> TestVDS <span class="re5">--register</span><br />
VBoxManage modifyvm TestVDS \<br />
&nbsp; &nbsp; <span class="re5">--ostype</span> Ubuntu \<br />
&nbsp; &nbsp; <span class="re5">--memory</span> 512 <span class="re5">--vram</span> 1 \<br />
&nbsp; &nbsp; <span class="re5">--acpi</span> on <span class="re5">--ioapic</span> off <span class="re5">--pae</span> off <span class="re5">--hwvirtex</span> on <span class="re5">--nestedpaging</span> on \<br />
&nbsp; &nbsp; <span class="re5">--boot1</span> dvd \<br />
&nbsp; &nbsp; <span class="re5">--sata</span> on <span class="re5">--sataport1</span> TestVDS-HD1 \<br />
&nbsp; &nbsp; <span class="re5">--dvd</span> <span class="sy0">/</span>home<span class="sy0">/</span>user1<span class="sy0">/</span>ubuntu-8.04.3-server-i386.iso \<br />
&nbsp; &nbsp; <span class="re5">--floppy</span> disabled \<br />
&nbsp; &nbsp; <span class="re5">--nic1</span> nat \<br />
&nbsp; &nbsp; <span class="re5">--audio</span> none<br />
<br />
VBoxManage setextradata TestVDS <span class="st0">&quot;VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/Protocol&quot;</span> TCP<br />
VBoxManage setextradata TestVDS <span class="st0">&quot;VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/GuestPort&quot;</span> <span class="nu0">80</span><br />
VBoxManage setextradata TestVDS <span class="st0">&quot;VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/HostPort&quot;</span> <span class="nu0">8080</span>
        </div>
    </div>
</div>

<p>Затем я поставил <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> 2.8.5 с официального сайта, импортировал в блог порядка 800 статей среднего размера (авторство статей не моё, так что выложить не могу).</p>
<p>Вместо Apache Bench я использовал Siege, обращение производилось ко всем страницам сайта в случайном порядке (вероятность обращения к заданной странице задавалась количеством её повторений в файле с адресами). Тестирование каждого варианта (WP Super Cache и MaxSite Cache) проводилось по 45 минут — 30 минут при низкой нагрузке и 15 минут при высокой (увы, трафик не безлимитный, и раскидываться гигабайтами трафика для теста возможности пока нет). Это имитировало постепенный наплыв пользователей на сайт. Специфика теста такова, что новый запрос не выполнялся до тех пор, пока не завершался предыдущий.</p>
<p>Одновременно к страницам обращалось 30 пользователей (Apache просто больше не выдерживает). Между тестами системе перезагружалась (на всякий случай). Виртуальный сервер и сервер, с которого осуществлялось тестирование, были, естественно, разными; соединены гигабитным каналом.</p>
<p>Результаты получились очень интересными: MaxSite Cache Lite строит кэш несколько быстрее, чем WP Super Cache (у MaxSite Cache более простая логика работы). WP Super Cache создаёт более сильную нагрузку на диск (так как файлы разбрасываются по множеству каталогов, а не кидаются в один) и, за счёт этого, чуть большую нагрузку на процессор (если сравнивать по значению idle time). Но при этом у WP Super Cache больший коэффициент параллельности (обслуживает большее число запросов одновременно).</p>
<p>Но при отдаче кэша и с повышением нагрузки результат меняется: WP Super Cache отдаёт данные быстрее и, как результат, обслуживает большее количество клиентов. Потребление памяти при этом чуть меньше, но загрузка процессора чуть больше. Вообще картину очень сильно портил munin — нагрузка, им создаваемая, вносила существенные погрешности в измерения (было видно в <span class="codebox"><code class="bash">top</code></span>).</p>
<table class="bordered" cellspacing="0" cellpadding="0" rules="all">
<caption>Построение кэша</caption>
<thead>
<tr>
<th>&nbsp;</th>
<th><strong>WP Super Cache</strong></th>
<th><strong>MaxSite Cache</strong></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество транзакций</th>
<td>91,755</td>
<td>95,028</td>
</tr>
<tr>
<th scope="row">Объём данных, МБ</th>
<td>2,160.51</td>
<td>2,240.59</td>
</tr>
<tr>
<th scope="row">Среднее время ответа, с</th>
<td>0.05</td>
<td>0.04</td>
</tr>
<tr>
<th scope="row">Частота транзакций в секунду</th>
<td>50.97</td>
<td>52.79</td>
</tr>
<tr>
<th scope="row">Пропускная способность, МБ/с</th>
<td>1.20</td>
<td>1.24</td>
</tr>
<tr>
<th scope="row">Коэффициент параллельности</th>
<td>2.58</td>
<td>2.21</td>
</tr>
<tr>
<th scope="row">Максимальная длина транзакции, с</th>
<td>20.93</td>
<td>19.10</td>
</tr>
<tr>
<th scope="row">Минимальная длина транзакции, с</th>
<td>0.00</td>
<td>0.00</td>
</tr>
</tbody>
</table>
<table class="bordered" cellspacing="0" cellpadding="0" rules="all">
<caption>Использование кэша</caption>
<thead>
<tr>
<th>&nbsp;</th>
<th><strong>WP Super Cache</strong></th>
<th><strong>MaxSite Cache</strong></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество транзакций</th>
<td>219,761</td>
<td>206,949</td>
</tr>
<tr>
<th scope="row">Объём данных, МБ</th>
<td>5,129.06</td>
<td>4,880.30</td>
</tr>
<tr>
<th scope="row">Среднее время ответа, с</th>
<td>0.07</td>
<td>0.09</td>
</tr>
<tr>
<th scope="row">Частота транзакций в секунду</th>
<td>244.29</td>
<td>229.92</td>
</tr>
<tr>
<th scope="row">Пропускная способность, МБ/с</th>
<td>5.70</td>
<td>5.42</td>
</tr>
<tr>
<th scope="row">Коэффициент параллельности</th>
<td>27.89</td>
<td>21.58</td>
</tr>
<tr>
<th scope="row">Максимальная длина транзакции, с</th>
<td>21.96</td>
<td>21.58</td>
</tr>
<tr>
<th scope="row">Минимальная длина транзакции, с</th>
<td>0.00</td>
<td>0.00</td>
</tr>
</tbody>
</table>
<p><strong>Краткие выводы:</strong> в плане построения кэша <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a> у MaxSite Cache Lite выше, что объясняется простотой его логики. Но при  нагрузке и построенном кэше WP Super Cache обладает более высокой производительностью, так как web-сервер способен отдавать закэшированные данные без привлечения PHP. При одинаковом количестве запросов в секунду <em>под нагрузкой</em> WP Super Cache демонстрирует меньшее потребление памяти и нагрузку на процессор. При <em>средней</em> нагрузке на систему оба кэша ведут себя примерно одинаково — разница в потреблении памяти и нагрузке незаметна.</p>
<p><strong>В следующей части: <a href="http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/">тест WP Super Cache и MaxSite Cache на грамотно настроенном сервере</a>.</strong></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>OpenMP на многоядерном процессоре и криптография</title>
		<link>http://blog.sjinks.pro/openmp/522-openmp-on-multicore-cpu-and-cryptography/</link>
		<comments>http://blog.sjinks.pro/openmp/522-openmp-on-multicore-cpu-and-cryptography/#comments</comments>
		<pubDate>Sat, 04 Apr 2009 01:36:56 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[ECB]]></category>
		<category><![CDATA[криптография]]></category>
		<category><![CDATA[производительность]]></category>
		<category><![CDATA[шифрование]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=522</guid>
		<description><![CDATA[Практический пример использования OpenMP — это набор директив компилятора, библиотечных процедур и переменных окружения, которые предназначены для программирования многопоточных приложений на многопроцессорных системах с разделяемой памятью. OpenMP реализует параллельные вычисления с помощью многопоточности, в которой главный поток создает набор подчиненных потоков и задача распределяется между ними. Предполагается, что потоки выполняются параллельно на машине с несколькими процессорами. Использование [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/openmp/522-openmp-on-multicore-cpu-and-cryptography/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Практический пример использования</em></h2>
<p><a href="http://blog.sjinks.pro/tag/openmp/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  OpenMP">OpenMP</a> — это набор директив компилятора, библиотечных процедур и переменных окружения, которые предназначены для программирования многопоточных приложений на многопроцессорных системах с разделяемой памятью. <a href="http://blog.sjinks.pro/tag/openmp/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  OpenMP">OpenMP</a> реализует параллельные вычисления с помощью многопоточности, в которой главный поток создает набор подчиненных потоков и задача распределяется между ними. Предполагается, что потоки выполняются параллельно на машине с несколькими процессорами.</p>
<p>Использование OpenMP должно приводить к увеличению производительности за счет того, что программа (по крайней мере, её параллельные участки) выполняется не на одном процессоре, а на всех доступных. Процесс распределения потоков по процессорам можно <a href="http://blog.sjinks.pro/c-cpp/517-openmp-setting-cpu-affinity-mask-in-linux/">контролировать</a>.</p>
<p>В соответствии с законом Амдаля–Уэра (увеличение количества вычислителей приводит к ограничению роста производительности), имея четыре процессора, мы не получим четырёхкратное увеличение производительности. К тому же затраты на синхронизацию и управление потоками сказываются на производительности не лучшим образом. Да и увеличение вычислительной мощности в N раз не приводит к аналогичному росту скорости обращения к памяти.</p>
<p>Я решил проверить, каким будет прирост производительности параллельного шифрования в <a href="http://blog.sjinks.pro/security/18-data-encryption-modes-when-strong-cipher-doesnt-help/">режиме ECB</a> у алгоритма шифрования ГОСТ 28147—89 на четырёхядерном процессоре.<span id="more-522"></span></p>
<p>Операция зашифрования по ГОСТ 28147—89 сама по себе не может быть распараллелена (да и есть ли смысл?). Но так как в режиме <a href="http://blog.sjinks.pro/tag/ecb/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  ECB">ECB</a> операция зашифрования одного блока не зависит от остальных блоков, то процесс можно распараллелить.</p>
<p>Цикл зашифрования выглядит следующим образом (для краткости я не привожу вспомогательные таблицы):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52210">
        <div class="code c" id="p522code10">
uint_fast32_t gost_data_1<span class="br0">&#91;</span>256<span class="br0">&#93;</span><span class="sy0">;</span><br />
uint_fast32_t gost_data_2<span class="br0">&#91;</span>256<span class="br0">&#93;</span><span class="sy0">;</span><br />
uint_fast32_t gost_data_3<span class="br0">&#91;</span>256<span class="br0">&#93;</span><span class="sy0">;</span><br />
uint_fast32_t gost_data_4<span class="br0">&#91;</span>256<span class="br0">&#93;</span><span class="sy0">;</span><br />
<br />
<span class="kw4">union</span> gostrec_t <span class="br0">&#123;</span><br />
&nbsp; &nbsp; uint8_t x<span class="br0">&#91;</span>8<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; uint32_t y<span class="br0">&#91;</span>2<span class="br0">&#93;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
<br />
<span class="kw4">void</span> do_encode<span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span> buf<span class="sy0">,</span> <span class="kw4">const</span> uint32_t<span class="sy0">*</span> <span class="kw4">const</span> key<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> uint32_t<span class="sy0">*</span> k <span class="sy0">=</span> key<span class="sy0">;</span><br />
&nbsp; &nbsp; uint_fast32_t a <span class="sy0">=</span> buf<span class="sy0">-&gt;</span>y<span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; uint_fast32_t b <span class="sy0">=</span> buf<span class="sy0">-&gt;</span>y<span class="br0">&#91;</span>1<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; uint_fast32_t t<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>uint_fast32_t i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;=</span><span class="nu0">11</span><span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>0 <span class="sy0">==</span> <span class="br0">&#40;</span>i <span class="sy0">&amp;</span> 3<span class="br0">&#41;</span><span class="br0">&#41;</span> k <span class="sy0">=</span> key<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; t &nbsp;<span class="sy0">=</span> a <span class="sy0">+</span> k<span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; b <span class="sy0">^=</span> gost_data_1<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span>t<span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_2<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 8<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_3<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 16<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_4<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 24<span class="br0">&#41;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; t <span class="sy0">=</span> b <span class="sy0">+</span> k<span class="br0">&#91;</span>1<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; a <span class="sy0">^=</span> gost_data_1<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span>t<span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_2<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 8<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_3<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 16<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_4<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 24<span class="br0">&#41;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; k <span class="sy0">+=</span> <span class="nu0">2</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; k <span class="sy0">=</span> key <span class="sy0">+</span> <span class="nu0">8</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>uint_fast32_t i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;=</span><span class="nu0">3</span><span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; k <span class="sy0">-=</span> <span class="nu0">2</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; t &nbsp;<span class="sy0">=</span> a <span class="sy0">+</span> k<span class="br0">&#91;</span>1<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; b <span class="sy0">^=</span> gost_data_1<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span>t<span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_2<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 8<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_3<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 16<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_4<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 24<span class="br0">&#41;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; t <span class="sy0">=</span> b <span class="sy0">+</span> k<span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; a <span class="sy0">^=</span> gost_data_1<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span>t<span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_2<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 8<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_3<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 16<span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="sy0">^</span> gost_data_4<span class="br0">&#91;</span><span class="br0">&#40;</span>uint8_t<span class="br0">&#41;</span><span class="br0">&#40;</span>t <span class="sy0">&gt;&gt;</span> 24<span class="br0">&#41;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; buf<span class="sy0">-&gt;</span>y<span class="br0">&#91;</span>0<span class="br0">&#93;</span> <span class="sy0">=</span> <span class="br0">&#40;</span>uint32_t<span class="br0">&#41;</span>b<span class="sy0">;</span><br />
&nbsp; &nbsp; buf<span class="sy0">-&gt;</span>y<span class="br0">&#91;</span>1<span class="br0">&#93;</span> <span class="sy0">=</span> <span class="br0">&#40;</span>uint32_t<span class="br0">&#41;</span>a<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Зашифрование в режиме ECB выглядит так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52211">
        <div class="code c" id="p522code11">
<span class="kw4">void</span> encode<span class="br0">&#40;</span>uint8_t<span class="sy0">*</span> buf<span class="sy0">,</span> uint32_t len<span class="sy0">,</span> <span class="kw4">const</span> uint32_t<span class="sy0">*</span> key<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>int32_t i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="br0">&#40;</span>int32_t<span class="br0">&#41;</span>len<span class="sy0">;</span> i<span class="sy0">+=</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; do_encode<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span><span class="br0">&#41;</span><span class="br0">&#40;</span>buf<span class="sy0">+</span>i<span class="br0">&#41;</span><span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Длина явно приводится к знаковому типу для облегчения переноса на OpenMP (в спецификации есть требование, чтобы счетчики циклов были знаковыми).</p>
<p>Параллельная версия процедуры зашифрования будет выглядеть так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52212">
        <div class="code c" id="p522code12">
<span class="kw4">void</span> encode_omp<span class="br0">&#40;</span>uint8_t<span class="sy0">*</span> buf<span class="sy0">,</span> uint32_t len<span class="sy0">,</span> <span class="kw4">const</span> uint32_t<span class="sy0">*</span> key<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co2">#pragma omp parallel</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp for schedule(static) nowait</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>int32_t i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="br0">&#40;</span>int32_t<span class="br0">&#41;</span>len<span class="sy0">;</span> i<span class="sy0">+=</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_encode<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span><span class="br0">&#41;</span><span class="br0">&#40;</span>buf<span class="sy0">+</span>i<span class="br0">&#41;</span><span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Makefile:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52213">
        <div class="code make" id="p522code13">
CC<span class="sy0">=</span>gcc<br />
CFLAGS<span class="sy0">=-</span>O3 <span class="sy0">-</span>fopenmp <span class="sy0">-</span>march<span class="sy0">=</span>native <span class="sy0">-</span>fstrict<span class="sy0">-</span>aliasing <span class="sy0">-</span>std<span class="sy0">=</span>gnu99 <span class="sy0">-</span>Wall <span class="sy0">-</span>Wextra <span class="sy0">-</span>Wno<span class="sy0">-</span>unused<span class="sy0">-</span>parameter <span class="sy0">-</span>Wstrict<span class="sy0">-</span>aliasing<span class="sy0">=</span>1 <span class="sy0">-</span>Wdisabled<span class="sy0">-</span>optimization<br />
CFLAGS_PGEN<span class="sy0">=-</span>g3 <span class="sy0">-</span>pg <span class="sy0">-</span>fprofile<span class="sy0">-</span>arcs <span class="sy0">-</span>ftest<span class="sy0">-</span>coverage <span class="sy0">-</span>fprofile<span class="sy0">-</span>generate<br />
CFLAGS_PUSE<span class="sy0">=-</span>fomit<span class="sy0">-</span>frame<span class="sy0">-</span>pointer <span class="sy0">-</span>fprofile<span class="sy0">-</span>use<br />
LDFLAGS<span class="sy0">=-</span>fopenmp<br />
LDFLAGS_PGEN<span class="sy0">=-</span>fprofile<span class="sy0">-</span>generate<br />
<br />
all<span class="sy0">:</span> gost<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">./</span>gost<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CC</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CFLAGS</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">LDFLAGS</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CFLAGS_PUSE</span><span class="br0">&#41;</span> main<span class="sy0">.</span>c gost<span class="sy0">.</span>c <span class="sy0">-</span>o gost<br />
<br />
gost<span class="sy0">:</span> main<span class="sy0">.</span>o gost<span class="sy0">.</span>o<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CC</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">LDFLAGS</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">LDFLAGS_PGEN</span><span class="br0">&#41;</span> <span class="re0">$^</span> <span class="sy0">-</span>o <span class="re0">$@</span><br />
<br />
main<span class="sy0">.</span>o<span class="sy0">:</span> main<span class="sy0">.</span>c gost<span class="sy0">.</span>h<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CC</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CFLAGS</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CFLAGS_PGEN</span><span class="br0">&#41;</span> <span class="sy0">-</span>c <span class="re0">$*</span><span class="sy0">.</span>c<br />
<br />
gost<span class="sy0">.</span>o<span class="sy0">:</span> gost<span class="sy0">.</span>c gost<span class="sy0">.</span>h<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CC</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CFLAGS</span><span class="br0">&#41;</span> <span class="sy0">$</span><span class="br0">&#40;</span><span class="re2">CFLAGS_PGEN</span><span class="br0">&#41;</span> <span class="sy0">-</span>c <span class="re0">$*</span><span class="sy0">.</span>c<br />
<br />
clean<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">-</span>rm <span class="sy0">-</span>f <span class="sy0">*.</span>o gost <span class="sy0">*.</span>gcda <span class="sy0">*.</span>gcno<br />
<br />
<span class="kw2">.PHONY</span><span class="sy0">:</span> all clean
        </div>
    </div>
</div>

<p>Производительность измерялась путем многократного прогона операции зашифрования над стомегабайтным (точнее, стомебибайтным) буфером.</p>
<p><del datetime="2009-04-03T22:53:17+00:00">Получились весьма интересные результаты:</p>
<table cellpadding="2" cellspacing="1" class="bordered">
<thead>
<tr>
<th>&nbsp;</th>
<th>Min</th>
<th>Max</th>
<th>Avg</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" align="right">Parallel</th>
<td>1.43</td>
<td>1.46</td>
<td>1.44</td>
</tr>
<tr>
<th scope="row" align="right">Serial</th>
<td>1.39</td>
<td>1.42</td>
<td>1.41</td>
</tr>
</tbody>
</table>
<p>Параллельная версия алгоритма не только не даёт прироста в производительности, но еще и проигрывает последовательной версии!<br />
</del></p>
<p>Так бы и считал, если бы во время тестирования альтернативной версии не заметил, что параллельная версия выполняется быстрее. Мораль: читайте маны.</p>
<p>Дело в том, что время измерялось следующим образом:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52214">
        <div class="code c" id="p522code14">
&nbsp; &nbsp; start <span class="sy0">=</span> clock<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; func<span class="br0">&#40;</span>buf<span class="sy0">,</span> n<span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; stop <span class="sy0">=</span> clock<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; x <span class="sy0">=</span> <span class="br0">&#40;</span><span class="kw4">double</span><span class="br0">&#41;</span><span class="br0">&#40;</span>stop <span class="sy0">-</span> start<span class="br0">&#41;</span> <span class="sy0">/</span> CLOCKS_PER_SEC<span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Но <code>CLOCKS_PER_SEC</code> не учитывает, что у нас четыре ядра, а не одно. Или как раз-таки учитывает. И вообще <abbr title="зависит от реализации">хз</abbr>. Я так понял, что на выходе я получаю время, которое понадобилось бы процессору на выполнение задачи, если бы он был один. Тёмный лес.</p>
<p>UPD: <q cite="http://linux.die.net/man/3/clock">POSIX requires that CLOCKS_PER_SEC equals 1000000 <strong>independent of the actual resolution</strong></q>.</p>
<p>Как правильно:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52215">
        <div class="code c" id="p522code15">
&nbsp; &nbsp; gettimeofday<span class="br0">&#40;</span><span class="sy0">&amp;</span>start<span class="sy0">,</span> NULL<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; func<span class="br0">&#40;</span>buf<span class="sy0">,</span> n<span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; gettimeofday<span class="br0">&#40;</span><span class="sy0">&amp;</span>stop<span class="sy0">,</span> NULL<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; x <span class="sy0">=</span> <span class="br0">&#40;</span>1000000.0f<span class="sy0">*</span><span class="br0">&#40;</span>stop.<span class="me1">tv_sec</span> <span class="sy0">-</span> start.<span class="me1">tv_sec</span><span class="br0">&#41;</span> <span class="sy0">+</span> <span class="br0">&#40;</span>stop.<span class="me1">tv_usec</span> <span class="sy0">-</span> start.<span class="me1">tv_usec</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">/</span><span class="nu0">1000000</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Итак, что получилось на четырёх ядрах:</p>
<table cellpadding="2" cellspacing="1" class="bordered">
<thead>
<tr>
<th>&nbsp;</th>
<th>Min</th>
<th>Max</th>
<th>Avg</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" align="right">Parallel</th>
<td>0.365861</td>
<td>0.408662</td>
<td>0.371971</td>
</tr>
<tr>
<th scope="row" align="right">Serial</th>
<td>1.406327</td>
<td>1.418306</td>
<td>1.412239</td>
</tr>
</tbody>
</table>
<p>Что характерно, в случае с одним процессором оба способа измерения времени работают примерно одинаково, так что будем считать, что в статье <strong>"<a href="http://blog.sjinks.pro/c-cpp/519-practical-use-of-fast-types/">Практическая польза fast-типов</a>"</strong> я не сильно наврал со скоростью.</p>
<p>Когда я неудачно измерял время выполнения кода, я думал, что причина неудачи в том, что кэш процессора не резиновый: как-никак буфер для зашифрования 100 мебибайт, потоки берут код из совершенно разных участков памяти, процедура зашифрования активно использует 4 кибибайта таблиц…</p>
<p>Тогда я написал такую процедуру зашифрования, рассчитанную на четыре ядра:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p52216">
        <div class="code c" id="p522code16">
<span class="kw4">void</span> encode_omp<span class="br0">&#40;</span>uint8_t<span class="sy0">*</span> buf<span class="sy0">,</span> uint32_t len<span class="sy0">,</span> <span class="kw4">const</span> uint32_t<span class="sy0">*</span> key<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co2">#pragma omp parallel sections shared(buf, key, len)</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp section</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>int32_t i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="br0">&#40;</span>int32_t<span class="br0">&#41;</span>len<span class="sy0">;</span> i<span class="sy0">+=</span>4<span class="sy0">*</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_encode<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span><span class="br0">&#41;</span><span class="sy0">&amp;</span>buf<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp section</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>int32_t i<span class="sy0">=</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="br0">&#40;</span>int32_t<span class="br0">&#41;</span>len<span class="sy0">;</span> i<span class="sy0">+=</span>4<span class="sy0">*</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_encode<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span><span class="br0">&#41;</span><span class="sy0">&amp;</span>buf<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp section</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>int32_t i<span class="sy0">=</span>2<span class="sy0">*</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="br0">&#40;</span>int32_t<span class="br0">&#41;</span>len<span class="sy0">;</span> i<span class="sy0">+=</span>4<span class="sy0">*</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_encode<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span><span class="br0">&#41;</span><span class="sy0">&amp;</span>buf<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp section</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>int32_t i<span class="sy0">=</span>3<span class="sy0">*</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="br0">&#40;</span>int32_t<span class="br0">&#41;</span>len<span class="sy0">;</span> i<span class="sy0">+=</span>4<span class="sy0">*</span><span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_encode<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">union</span> gostrec_t<span class="sy0">*</span> <span class="kw4">const</span><span class="br0">&#41;</span><span class="sy0">&amp;</span>buf<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">,</span> key<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Идея в том, что если потоки выполняются с примерно одинаковой скоростью, возможно улучшить локальность данных в кэше процессора (код, скорее, представлял proof of concept, ибо не учитывает целый ряд факторов).</p>
<table cellpadding="2" cellspacing="1" class="bordered">
<thead>
<tr>
<th>&nbsp;</th>
<th>Min</th>
<th>Max</th>
<th>Avg</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" align="right">Parallel Sections</th>
<td>0.375868</td>
<td>0.404222</td>
<td>0.384918</td>
</tr>
</tbody>
</table>
<p>Результат с использованием секций получился чуть-чуть хуже.</p>
<p>Выигрыш в производительности на четырёх ядрах составил 380% — не так уж и плохо (особенно если считать, что основной целью статьи было показать, что параллельность — это не всегда хорошо).</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/openmp/522-openmp-on-multicore-cpu-and-cryptography/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/openmp/522-openmp-on-multicore-cpu-and-cryptography/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>MySQL и скорость выполнения INSERT для разных типов таблиц</title>
		<link>http://blog.sjinks.pro/mysql/44-mysql-insert-speed-for-different-storage-engines/</link>
		<comments>http://blog.sjinks.pro/mysql/44-mysql-insert-speed-for-different-storage-engines/#comments</comments>
		<pubDate>Thu, 20 Mar 2008 21:57:09 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[HEAP]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MyISAM]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[storage engine]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/mysql/44-mysql-insert-speed-for-different-storage-engines/</guid>
		<description><![CDATA[Сравнение скорости выполнения INSERT/INSERT DELAYED для таблиц типа HEAP (MEMORY), InnoDB и MyISAM Я сейчас работаю над очень интересным проектом, который, как надеется заказчик, составит серьёзную конкуренцию Google Analytics. Но речь не об этом. Разбираясь с архитектурой системы, я обнаружил весьма интересную деталь: 8&#160;гигабайт памяти сервера отдается под несколько таблиц типа HEAP. Так как HEAP-таблицы [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/mysql/44-mysql-insert-speed-for-different-storage-engines/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Сравнение скорости выполнения INSERT/INSERT DELAYED для таблиц типа <a href="http://blog.sjinks.pro/tag/heap/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HEAP">HEAP</a> (MEMORY), <a href="http://blog.sjinks.pro/tag/innodb/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  InnoDB">InnoDB</a> и <a href="http://blog.sjinks.pro/tag/myisam/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MyISAM">MyISAM</a></em></h2>
<p>Я сейчас работаю над очень интересным проектом, который, как надеется заказчик, составит серьёзную конкуренцию Google Analytics. Но речь не об этом. Разбираясь с архитектурой системы, я обнаружил весьма интересную деталь: 8&nbsp;гигабайт памяти сервера отдается под несколько таблиц типа HEAP. Так как HEAP-таблицы хранятся в исключительно в памяти, то операция вставки (INSERT) должна выполняться очень быстро, так как временн<em>ы</em>е затраты, связанные с перемещением головок диска и физической записью, отсутствуют. Я решил найти подтверждение этой теории. Google is your friend, и я довольно быстро нашел статью <a href="http://moncahier.canalblog.com/archives/2007/09/06/6119631.html">MySQL Engine INSERT speed</a>.<span id="more-44"></span></p>
<p>Меня несколько смутили результаты, приведённые автором:</p>
<ul>
<li><strong>MyISAM</strong> (с <code>DELAY_KEY_WRITE=ALL</code>): 33&nbsp;000&nbsp;INSERT/сек</li>
<li><strong>InnoDB</strong>: 24&nbsp;700&nbsp;INSERT/сек</li>
<li><strong>MEMORY</strong>: 64&nbsp;000&nbsp;INSERT/сек</li>
</ul>
<p>Смутило, в первую очередь, жуткое отставание InnoDB: хотя я не очень часто использовал данный тип таблиц, о его скорости я наслышан.</p>
<p>Первыми возникшими вопросами были:</p>
<ol>
<li>Какой тип вставки использовался для MyISAM/InnoDB-таблиц &mdash; <code>INSERT</code> или <code>INSERT DELAYED</code>?</li>
<li>Каким образом вставлялись данные &mdash; построчно или блочно (extended insert)?</li>
<li>Значение <code>AUTOCOMMIT</code> при работе с таблицей InnoDB.</li>
</ol>
<p>Об этом оставалось только гадать, поэтому я решил повторить этот эксперимент.</p>
<p><strong>Методика эксперимента:</strong><br />
Создаются три таблицы:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p4420">
        <div class="code mysql" id="p44code20">
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`test0`</span> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">`field`</span> <span class="kw4">INTEGER</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><br />
<span class="br0">&#41;</span> <span class="kw1">TYPE</span><span class="sy1">=</span>HEAP<span class="sy2">;</span><br />
<br />
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`test1`</span> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">`field`</span> <span class="kw4">INTEGER</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><br />
<span class="br0">&#41;</span> <span class="kw1">TYPE</span><span class="sy1">=</span><span class="kw1">InnoDB</span><span class="sy2">;</span><br />
<br />
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`test2`</span> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">`field`</span> <span class="kw4">INTEGER</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><br />
<span class="br0">&#41;</span> <span class="kw1">TYPE</span><span class="sy1">=</span>MyISAM <span class="kw6">DELAY_KEY_WRITE</span><span class="sy1">=</span><span class="nu0">1</span><span class="sy2">;</span>
        </div>
    </div>
</div>

<p>Перед началом эксперимента выполнялась команда</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p4421">
        <div class="code mysql" id="p44code21">
<span class="kw1">SET</span> AUTOCOMMIT<span class="sy1">=</span><span class="nu0">0</span>
        </div>
    </div>
</div>

<p>Затем в цикле в таблицу вставлялись случайно сгенерированные данные (компьютер, на котором проводился эксперимент, был слабый, поэтому я ограничился тридцатью тысячами записями). После цикла выполнялся COMMIT. Скрипт выполнялся 10 раз, бралось среднее время.</p>
<p>Исходный текст скрипта:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p4422">
        <div class="code php" id="p44code22">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw3">set_time_limit</span><span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">function</span> microtime_float<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">list</span><span class="br0">&#40;</span><span class="re0">$usec</span><span class="sy0">,</span> <span class="re0">$sec</span><span class="br0">&#41;</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="sy0">,</span> <span class="kw3">microtime</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span>float<span class="br0">&#41;</span><span class="re0">$usec</span> <span class="sy0">+</span> <span class="br0">&#40;</span>float<span class="br0">&#41;</span><span class="re0">$sec</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
<br />
&nbsp; &nbsp; <span class="re0">$link</span> <span class="sy0">=</span> <span class="kw3">mysql_connect</span><span class="br0">&#40;</span><span class="st_h">'localhost'</span><span class="sy0">,</span> <span class="st_h">'root'</span><span class="sy0">,</span> <span class="st_h">''</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw3">mysql_select_db</span><span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="re0">$link</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="re0">$schema</span> <span class="sy0">=</span> <span class="st0">&quot;CREATE TABLE `test` (`field` INTEGER UNSIGNED NOT NULL)&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$engines</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">' TYPE=HEAP'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">' TYPE=InnoDB'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">' DELAY_KEY_WRITE = 1 TYPE=MyISAM'</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="re0">$inserts</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'DELAYED'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="st0">&quot;DROP TABLE IF EXISTS `test0`, `test1`, `test2`&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="st0">&quot;SET AUTOCOMMIT=0&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="re0">$i</span><span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">&lt;</span>count<span class="br0">&#40;</span><span class="re0">$engines</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy0">++</span><span class="re0">$i</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">=</span> <span class="kw3">preg_replace</span><span class="br0">&#40;</span><span class="st_h">'/`test`/'</span><span class="sy0">,</span> <span class="st0">&quot;`test<span class="es4">{$i}</span>`&quot;</span><span class="sy0">,</span> <span class="re0">$schema</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="re0">$engines</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="st0">&quot;COMMIT&quot;</span><span class="sy0">,</span> <span class="re0">$link</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$start</span> <span class="sy0">=</span> microtime_float<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="re0">$j</span><span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$j</span><span class="sy0">&lt;</span><span class="nu0">30000</span><span class="sy0">;</span> <span class="sy0">++</span><span class="re0">$j</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$val</span> <span class="sy0">=</span> <span class="kw3">mt_rand</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="st0">&quot;INSERT {<span class="es4">$inserts</span>[<span class="es4">$i</span>]} INTO `test<span class="es4">{$i}</span>` (`field`) VALUES(<span class="es4">{$val}</span>)&quot;</span><span class="sy0">,</span> <span class="re0">$link</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="st0">&quot;COMMIT&quot;</span><span class="sy0">,</span> <span class="re0">$link</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$end</span> <span class="sy0">=</span> microtime_float<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="re0">$end</span> <span class="sy0">-</span> <span class="re0">$start</span> <span class="sy0">.</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw3">mysql_close</span><span class="br0">&#40;</span><span class="re0">$link</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>У меня получились такие результаты (я привожу относительную &mdash; относительно таблиц типа HEAP &mdash; скорость):</p>
<table class="bordered" cellpadding="2" cellspacing="1">
<thead>
<tr>
<th>&nbsp;</th>
<th>HEAP</th>
<th>InnoDB</th>
<th>MyISAM</th>
</tr>
</thead>
<tbody align="right">
<tr>
<th>INSERT</th>
<td rowspan="2">1.000</td>
<td>1.277</td>
<td>1.162</td>
</tr>
<tr>
<th>INSERT DELAYED</th>
<td>2.125</td>
<td>0.998</td>
</tr>
</tbody>
</table>
<p>Эксперимент показал, что разница по скорости между INSERT DELAYED для таблицы MyISAM и INSERT для таблицы HEAP очень незначительна. Таблицы InnoDB действительно оказались медленнее, но не сильно. Большую роль здесь могла сыграть &laquo;слабость&raquo; тестового компьютера и значение переменной <code>innodb_flush_log_at_trx_commit</code>.  Вдобавок, MyISAM был сконфигурирован очень даже хорошо, в то время как InnoDB использовал практически значения по умолчанию (мне редко приходится пользоваться таблицами InnoDB, поэтому тонкой настройкой я не занимался). Тем не менее, результаты проведенного мной эксперимента совсем не согласуются с данными, приведёнными в исходной статье. Кто же из нас прав?</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/mysql/44-mysql-insert-speed-for-different-storage-engines/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/mysql/44-mysql-insert-speed-for-different-storage-engines/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

