<?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>Блоги &#187; Marat Dukhan (Intel)</title>
	<atom:link href="http://software.intel.com/ru-ru/blogs/author/marat-dukhan/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/ru-ru/blogs</link>
	<description></description>
	<lastBuildDate>Thu, 24 May 2012 12:16:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Поговорим о производительности</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/07/06/2001646/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/07/06/2001646/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 12:02:10 +0000</pubDate>
		<dc:creator>Marat Dukhan (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Microsoft* Visual Studio]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/07/06/2001646/</guid>
		<description><![CDATA[Когда на ISN речь заходит о производительности, обычно имеют в виду производительность процессора, памяти или видеокарты. Но этот пост будет о другой производительности&#160;&#8212; о производительности программиста. Я хочу рассказать о паре полезных "фич" Visual Studio, которые, как мне кажется, не слишком известны, но весьма полезны для программистов. Первая полезная фича Visual Studio, появившаяся ни то [...]]]></description>
			<content:encoded><![CDATA[<p>Когда на ISN речь заходит о производительности, обычно имеют в виду производительность процессора, памяти или видеокарты. Но этот пост будет о другой производительности&nbsp;&mdash; о производительности программиста. Я хочу рассказать о паре полезных "фич" Visual Studio, которые, как мне кажется, не слишком известны, но весьма полезны для программистов.<br />
Первая полезная фича Visual Studio, появившаяся ни то в 2003, ни то в 2005 версии&nbsp;&mdash; это автоматическое форматирование исходного текста. Работает просто: выделяем кусок кода, нажимаем Ctrl+K и, не отпуская клавишу Ctrl, тут же Ctrl+F (можно также выбрать из меню Edit-&gt;Advanced-&gt;Format Selection, но это слишком долго). В результате выделенный кусок кода приводится к удобочитаемому виду. Особенно полезна эта фича для чтения созданного кодогенератором кода.<br />
Другая полезная фича,&nbsp;&mdash; макросы. Про макросы слышали, пожалуй, все программисты, а вот реально их используют&nbsp;&mdash; лишь немногие. И это очень зря! Допустим, у нас есть кусок кода следующего содержания:</p>
<pre>std::cout &lt;&lt; "VariableA = " &lt;&lt; variableA &lt;&lt; std::endl;
std::cout &lt;&lt; "VariableB = " &lt;&lt; variableB &lt;&lt; std::endl;
std::cout &lt;&lt; "VariableC = " &lt;&lt; variableC &lt;&lt; std::endl;
...</pre>
<p>И в какой-то момент времени нам захотелось выводить не только значение переменной, но и её тип. Сложный способ добиться этого&nbsp;&mdash; вручную изменить каждую строку и при этом постараться не сделать ошибок, которые не выловит компилятор. Простой способ заключается в использовании макросов. Сначала нужно установить курсор на начало первой строки. Как-то так:</p>
<pre><b>I</b>std::cout &lt;&lt; "VariableA = " &lt;&lt; variableA &lt;&lt; std::endl;
...</pre>
<p>Теперь нужно нажать магическую комбинацию клавиш Ctrl+Shift+R (или выбрать в меню Tools-&gt;Macros-&gt;Record Temporary Macro). Теперь Visual Studio будет запоминать всё, что вы будете делать. Затем, с помощью обычного Copy &amp; Paste нужно привести первую строчку к желаемому виду, например такому:</p>
<pre>std::cout &lt;&lt; &quot;VariableA = &quot; &lt;&lt; variableA &lt;&lt; &quot;, typeof VariableA is " &lt;&lt; typeid( VariableA ).name() &lt;&lt;<b>I</b> std::endl;
...</pre>
<p>Обратите внимание, что имя переменной VariableA нужно не набирать с клавиатуры, а копировать из другого места этой строки. Для навигации внутри строки лучше пользоваться не обычными стрелками на клавиатуре, а комбинацией Ctrl+стрелка&nbsp;&mdash; в этом случае курсор будет перемещаться сразу на следующее слово. Когда первая строка преобразована к нужному виду, нужно переместить курсор на начало второй строки и снова нажать магическую комбинацию клавиш Ctrl+Shift+R, чтобы завершить запись макроса.</p>
<pre>std::cout &lt;&lt; &quot;VariableA = &quot; &lt;&lt; variableA &lt;&lt; &quot;, typeof VariableA is " &lt;&lt; typeid( VariableA ).name() &lt;&lt; std::endl;
<b>I</b>std::cout &lt;&lt; "VariableB = " &lt;&lt; variableB &lt;&lt; std::endl;
std::cout &lt;&lt; "VariableC = " &lt;&lt; variableC &lt;&lt; std::endl;
...</pre>
<p>Теперь достаточно нажать Ctrl+Shift+P и&nbsp;&mdash; вуаля&nbsp;&mdash; Visual Studio повторит всё, что вы делали для первой строки со второй строкой, а затем переместит курсор на начало третьей строки. Таким образом, любой исходник, сколь бы большим он ни был, можно обработать за десяток секунд.</p>
<p>А как повышаете свою производительность вы?</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/07/06/2001646/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Грабли wcscmp</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/07/06/wcscmp/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/07/06/wcscmp/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 10:59:22 +0000</pubDate>
		<dc:creator>Marat Dukhan (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Unicode]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/07/06/wcscmp/</guid>
		<description><![CDATA[На первый взгляд может показаться, что внутренность if'а if( wcscmp( someString, anotherString ) == 0 ) { &#160;&#160;&#160;&#160;// do something } будет выполняться всегда, если someString&#160;&#8212; это та же строка, что и anotherString. В реальности же вполне может получится ситуация, когда вы в отладчике видите, что строки абсолютно одинаковые, а wcscmp всё равно упорно не [...]]]></description>
			<content:encoded><![CDATA[<p>На первый взгляд может показаться, что внутренность if'а<br />
<code>if( wcscmp( someString, anotherString ) == 0 ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// do something<br />
}</code><br />
будет выполняться всегда, если someString&nbsp;&mdash; это та же строка, что и anotherString. В реальности же вполне может получится ситуация, когда вы в отладчике видите, что строки абсолютно одинаковые, а wcscmp всё равно упорно не хочет возвращать 0. А дело всё в том, что Unicode строки могут быть представлены по-разному. Скажем, польская буква ó (o kreskowane) может быть записана как один Unicode-символ ó (U+00F3&nbsp;&mdash; Latin Small Letter O With Acute) или как два Unicode-символа o (U+006F&nbsp;&mdash; Latin Small Letter O) и ́´ (U+0301&nbsp;&mdash; Combining Acute Accent). Первый вид называется нормализованной формой, а второй&nbsp;&mdash; денормализованной. С точки зрения стандарта Unicode обе записи представляют собой одну и ту же букву, и на экране она будет рисоваться совершенно одинаково, но с точки зрения wcscmp они различны.<br />
Но постойте, почему бы нам сразу (например, в конструкторе вашего класса String) не преобразовывать все строки в какую-то единую форму, чтобы быть уверенными, что их граблебезопасно сравнивать через wcscmp? Некоторые так и делают: Mac OS X, например, всегда сохраняет имена файлов в денормализованном виде. К сожалению, в большинстве случаев такой подход нельзя использовать: в мире уже есть огромное количество кода, который работает с Unicode-строками как с обычными массивами из wchar_t и нам с этим кодом придётся взаимодействовать. Такой код,&nbsp;&mdash; о ужас!&nbsp;&mdash; встречается даже в ОС. Так, в Windows XP (на других версиях я не проверял) вы можете создать два файла с одинаковыми с точки зрения Unicode именами, которые система будет считать разными. Да, École.txt (Latin Capital Letter E With Acute, ...) и École.txt (Latin Capital Letter E, Combining Acute Accent, ...) будут считаться разными файлами! Поэтому если ваша программа будет всегда преобразовывать Unicode-строки в денормализованную форму, вместо первого файла она всегда будет открывать второй (ну или не всегда, а только под Windows, что с точки зрения отладки ещё хуже).<br />
Вот и получается, что с одной стороны, программа должна работать с Unicode-строками правильно, а с другой стороны, работать с библиотеками, которые работают с Unicode-строками неправильно. И нет спасения от этой напасти!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/07/06/wcscmp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Петафлопс и петабайт</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/06/08/2001481/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/06/08/2001481/#comments</comments>
		<pubDate>Mon, 08 Jun 2009 13:47:53 +0000</pubDate>
		<dc:creator>Marat Dukhan (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/06/08/2001481/</guid>
		<description><![CDATA[На прошлой неделе Дмитрий Оганезов задался актуальным вопросом: чем загрузить сегодняшний суперкомпьютер, который завтра будет вмещаться под корпусом мобильника. Действительно, для настольных компьютеров уже сегодня терафлопс вычислительной мощи не кажется чем-то запредельным, а будущая архитектура CPU, Larrabee и поколение DirectX-11 GPU продвинут стандарт вычислительной мощи ещё дальше. Так, шаг за шагом мы приближаемся к новому [...]]]></description>
			<content:encoded><![CDATA[<p>На прошлой неделе Дмитрий Оганезов <a href="http://software.intel.com/ru-ru/blogs/2009/06/03/2001472/">задался</a> актуальным вопросом: чем загрузить сегодняшний суперкомпьютер, который завтра будет вмещаться под корпусом мобильника. Действительно, для настольных компьютеров уже сегодня терафлопс вычислительной мощи не кажется чем-то запредельным, а <a href="http://en.wikipedia.org/wiki/Intel_Sandy_Bridge_(microarchitecture)">будущая архитектура CPU</a>, Larrabee и поколение DirectX-11 GPU продвинут стандарт вычислительной мощи ещё дальше. Так, шаг за шагом мы приближаемся к новому замечательному пределу производительности в 1 Петафлопс или 1000&nbsp;000&nbsp;000&nbsp;000&nbsp;000 операций с плавающей точкой в секунду.<br />
На первый взгляд кажется, что такая вычислительная мощность ни кому и не нужна. Но, если покапаться глубже, можно найти кучу алгоритмов, которые до сих пор были слишком медленными, чтобы их использовать. В играх наконец-то появится действительно реалистичная графика (кажется, эту фраза появляется в печати с завидным постоянством, но тем не менее). С переходом 3d-графики на raytracing графика в играх засияет, как спецэффекты в голливудских фильмах. Вообще говоря, <a href="http://software.intel.com/en-us/articles/quake-wars-gets-ray-traced/">использовать raytracing можно уже сегодня, но для этого вам понадобится 4 6-ядерных Xeon'а</a>. Кроме графики, в играх ещё есть физика, и чем ближе мы будем приближаться к петафлопсу, тем больше мир за монитором будет напоминать мир перед ним. Думаю, мы ещё дождёмся времени, когда профессора в университетах будут показывать физические опыты на примере какой-нибудь модной компьютерной игрушки.<br />
Впрочем, довольно об играх. У нас хватит и более серьёзных задач на один петафлопс. Вы часто управляете компьютером голосом? Врядли. Хотя программ для этой задачи предостаточно, у них у всех есть два общих недостатка: компьютер понимает только простые команды и он не отличает, говорите вы с ним и с приятелем по телефону. Но когда у нас будет петафлопс...когда у нас будет петафлопс производительности и петабайт памяти, мы сможем делать семантический разбор того, что говорит пользователь. Компьютер сможет не просто сопоставлять слова пользователя с набором из десяти фраз, а разбивать предложения на слова, сопоставлять их с контектом, и делать именно то, что вам нужно. А ещё с петафлопсом производительности мы сможем распознавать, что же заснято на картинку (например, с HD-вебкамеры). Сегодня компьютеры умеют распознавать лица на фотографиях, но делать полное распознавание всех объектов на картинке компьютер пока не может. Хм..наверное, это потому, что у нас ещё нет петафлопса! Ведь для этого во-первых нужна колоссальная база данных с изображениями разных предметов, а во-вторых компьютер должен уметь выполнять астрономическое число операций за сотые доли секунды. И вот когда петафлопсовый компьютер научиться распознавать, смотрите вы на него или нет, когда вы говорите, и научиться понимать, что вы ему говорите, с ним станет удобно общаться голосом.<br />
А какие новшества ожидают программистов? Вот сегодня программист пишет программу, потом запускает её билд и идёт пить кофе. Понятно, что такой путь разработки, во-первых вреден для здоровья (ибо нельзя столько кофе пить), а во-вторых не лучшим образом использует время программиста. Так что пусть программа потихоньку компилируется, оптимизируется и линкуется пока программист её пишет. Программист изменил строчку в функции&nbsp;&mdash; она быстро перекомпилировалась без оптимизации и начала потихоньку оптимизироваться в фоне. А программист продолжает работу над следующей функцией. А потом программист нажимает F5&nbsp;&mdash; и программа тут же запускается.<br />
И ещё. Есть такая вещь&nbsp;&mdash; Image-based Rendering. Это когда у вас есть много фотографий одного и того же места с разных сторон и вы из них восстанавливаете 3D-модель. Вычислений это требует тьму. Но когда у нас будет петафлопс...вы любите футбол? Тогда вам понравятся трансляции футбола в 3D! Зрелищность хлынет через край: можно будет сделать виртуальный облёт камеры вокруг Аршавина перед тем самым ударом или даже посмотреть на этот гол с точки зрения мяча.<br />
Итак, ждём петафлопс!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/06/08/2001481/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>В помощь тестирующим</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/05/05/2001174/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/05/05/2001174/#comments</comments>
		<pubDate>Tue, 05 May 2009 08:49:20 +0000</pubDate>
		<dc:creator>Marat Dukhan (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/05/05/2001174/</guid>
		<description><![CDATA[Необходимость покрывать код unit-тестами сегодня мало у кого вызывает сомнения. Но, если ваши библиотеки классов развиваются достаточно интенсивно, проверка того, что они покрыты тестами может сама по себе превратится в проблему. В этом случае вам поможет отличная утилита codecov.exe из состава Intel C++ Compiler 11. Для примера возьмём минибиблиотеку из одного класса RandomGenerator, включающую один [...]]]></description>
			<content:encoded><![CDATA[<p>Необходимость покрывать код unit-тестами сегодня мало у кого вызывает сомнения. Но, если ваши библиотеки классов развиваются достаточно интенсивно, проверка того, что они покрыты тестами может сама по себе превратится в проблему. В этом случае вам поможет отличная утилита codecov.exe из состава Intel C++ Compiler 11.<br />
Для примера возьмём минибиблиотеку из одного класса RandomGenerator, включающую один заголовочный файл lib.h<br />
<code>#pragma once</p>
<p>class RandomGenerator {<br />
public:<br />
&nbsp;&nbsp;&nbsp;&nbsp;RandomGenerator();<br />
&nbsp;&nbsp;&nbsp;&nbsp;RandomGenerator( unsigned int seed );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;unsigned int next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;void reset( unsigned int seed );<br />
private:<br />
&nbsp;&nbsp;&nbsp;&nbsp;unsigned int seed;<br />
};<br />
</code><br />
и файл с реализацией этого класса lib.cpp<br />
<code>#include "lib.h"<br />
#include &lt;stdlib.h&gt;<br />
#include &lt;intrin.h&gt;<br />
#include &lt;exception&gt;</p>
<p>RandomGenerator::RandomGenerator() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;seed = (unsigned int)__rdtsc();<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( seed == 0 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;seed = 1;<br />
}</p>
<p>RandomGenerator::RandomGenerator( unsigned int seed ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;reset( seed );<br />
}</p>
<p>// Алгоритм <a href="http://www.jstatsoft.org/v08/i14/paper">XorShift</a><br />
unsigned int RandomGenerator::next() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;seed ^= seed &lt;&lt; 13;<br />
&nbsp;&nbsp;&nbsp;&nbsp;seed ^= seed &gt;&gt; 17;<br />
&nbsp;&nbsp;&nbsp;&nbsp;seed ^= seed &lt;&lt; 5;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return seed;<br />
}</p>
<p>void RandomGenerator::reset( unsigned int seed ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( seed == 0 )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw std::exception( "Bad seed" );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;this-&gt;seed = seed;<br />
}<br />
</code><br />
Как и полагается всякой приличной библиотеке, она покрыта тестом<br />
</code>#include "lib.h"<br />
#include &lt;stdio.h&gt;</p>
<p>int main() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RandomGenerator random;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf( "Random number: %d\n", random.next() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;} catch( ... ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf( "Exception\n" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<code></p>
<p>Чтобы узнать, какая часть библиотеки реально покрыта тестом, нужно сначала скомплировать её Intel C++ Compiler'ом с параметром /Qprof-gen:srcpos<br />
<code>icl /nologo /c /Qprof-gen:srcpos /EHsc lib.cpp</code><br />
в результате кроме объектного файла lib.obj компилятор создаст также файл pgopti.spi<br />
Сам тест можно компилировать и без /Qprof-gen:srcpos<br />
<code>icl /nologo /c /EHsc test.cpp</code><br />
Линкуем как обычно<br />
<code>xilink /SUBSYSTEM:CONSOLE test.obj lib.obj</code><br />
Запускаем получившийся файл test.exe и получаем файл со страшным именем и расширением .dyn&nbsp;&mdash; в нём содержится информация о том, какие кусочки библиотеки реально выполнялись. Можно запустить несколько тестов (или запустить один и тот же тест несколько раз с разными параметрами), и получить несколько разных .dyn-файлов. Когда вы решите, что .dyn-файлов вам уже хватит, объедините их в один утилитой profmerge:<br />
<code>profmerge 49fff6de_04680.dyn</code><br />
Эта утилита создаст один файл pgopti.dpi, объединяющий все данные из dyn-файлов<br />
И последний шаг&nbsp;&mdash; запускаем утилиту codecov.<br />
<code>codecov</code><br />
Она создаёт набор HTML-страниц, с интересующей нас статистикой.<br />
<a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/stat.bmp"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/stat.bmp" alt="Summary по файлам" class="alignnone size-full wp-image-2001181" /></a><br />
Более того, можно даже посмотреть, какие именно строки кода остались непротестированными:<br />
<a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/codecov.bmp"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/codecov.bmp" alt="" class="alignnone size-medium wp-image-2001182" /></a><br />
А для любителей всё настраивать под себя утилита codecov предлагает множество опций, в том числе вывод результатов в формате XML.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/05/05/2001174/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Быстрое умножение для __int64</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/04/21/int64/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/04/21/int64/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 11:54:13 +0000</pubDate>
		<dc:creator>Marat Dukhan (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/04/21/int64/</guid>
		<description><![CDATA[Знаете ли вы, во что компилятор обычно компилирует следующий код: ... __int64 a = ..., b =...; __int64 c = a * b; Если программа компилируется в Visual C++ под архитектуру x86, для умножения двух __int64 чисел будет вызвана специальная функция _allmul. Вот её прототип: extern "C" __int64 __stdcall _allmul( __int64 a, __int 64 b);, [...]]]></description>
			<content:encoded><![CDATA[<p>Знаете ли вы, во что компилятор обычно компилирует следующий код:<br />
<code><br />
...<br />
__int64 a = ..., b =...;<br />
__int64 c = a * b;<br />
</code><br />
Если программа компилируется в Visual C++ под архитектуру x86, для умножения двух __int64 чисел будет вызвана специальная функция _allmul. Вот её прототип:<br />
<code>extern "C" __int64 __stdcall _allmul( __int64 a, __int 64 b);</code>,<br />
а реализацию вы сможете найти в файле %VCINSTALLDIR%\crt\src\intel\llmul.asm. Как видно из названия файла, эта функция написана на ассемблере, что в данном случае ведёт к падению производительности. Дело в том, что компилятор Visual C++ не может заинлайнить эту функцию, ведь она компилируется другой программой&nbsp;&mdash; Masm'ом. Таким образом, умножение двух __int64 чисел выливается в самый настоящий вызов функции. Для такой пустяковой операции как умножение это значительные накладные расходы. Избежать их можно, написав свою реализацию умножения __int64 чисел на инлайн-ассемблере или прямо на C/C++. Например, так:<br />
<code><br />
typedef unsigned __int64 uint64;<br />
typedef unsigned __int32 uint32;<br />
typedef signed __int64 int64;</p>
<p>// Вспомогательные функции<br />
__forceinline uint32 LowDword( uint64 qword ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return (uint32)qword;<br />
}</p>
<p>__forceinline uint32 HighDword( uint64 qword ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return (uint32)( ( qword &gt;&gt; 32 ) &amp; 0xFFFFFFFFU );<br />
}</p>
<p>__forceinline uint64 MakeQword( uint32 lowDword, uint32 highDword ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return ( (uint64)highDword &lt;&lt; 32 ) | ( uint64 )lowDword;<br />
}</p>
<p>// Собственно, сами функции быстрого умножения<br />
__forceinline uint64 FastMul( uint64 a, uint64 b ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// <a href="http://msdn.microsoft.com/en-us/library/d2s81xt0(VS.80).aspx">__emulu</a>&nbsp;&mdash; intrinsic-функция, описана в файле intrin.h<br />
&nbsp;&nbsp;&nbsp;&nbsp;uint64 lowPartProd = __emulu( LowDword( a ), LowDword( b ) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;return MakeQword( LowDword( lowPartProd ), HighDword( lowPartProd ) + LowDword( a ) * HighDword( b ) + HighDword( a ) * LowDword( b ) );<br />
}</p>
<p>__forceinline int64 FastMul( int64 a, int64 b ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return (int64)FastMul( (uint64)a, (uint64)b );<br />
}<br />
</code></p>
<p>На Core2Duo/Merom тест<br />
<code><br />
for( int i = 0; i &lt; 1000000000; i++ ) {<br />
#ifdef FAST_MUL<br />
&nbsp;&nbsp;&nbsp;&nbsp;result = FastMul( result, mult );<br />
#else<br />
&nbsp;&nbsp;&nbsp;&nbsp;result *= mult;<br />
#endif<br />
}<br />
</code><br />
выполняется за 4.2 секунды с FAST_MUL и за 7.7 секунд без него.</p>
<p>Замечу, что на архитектуре Intel64 (aka x86-64) для умножения 64-битных чисел используется отдельная команда процессора, так что такой проблемы там нет.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/04/21/int64/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Кое-что о Unicode character</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/04/20/unicode-character/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/04/20/unicode-character/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 12:35:11 +0000</pubDate>
		<dc:creator>Marat Dukhan (Intel)</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Unicode]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/04/20/unicode-character/</guid>
		<description><![CDATA[Редкий стандарт умудряется обрасти таким количеством мифов, как Unicode. Даже базовые понятия этого стандарта зачастую воспринимаются неверно. Например, популярный миф гласит, что Unicode character'ы, в отличие от character'ов других кодировок, занимает 2 байта. Возможно, это объясняется тем, что в языке Java и компиляторах C++ под Windows, sizeof(wchar_t) == 2. Заблуждение, что Unicode character занимает 2 [...]]]></description>
			<content:encoded><![CDATA[<p>Редкий стандарт умудряется обрасти таким количеством мифов, как Unicode. Даже базовые понятия этого стандарта зачастую воспринимаются неверно. Например, популярный миф гласит, что Unicode character'ы, в отличие от character'ов других кодировок, занимает 2 байта. Возможно, это объясняется тем, что в языке Java и компиляторах C++ под Windows, sizeof(wchar_t) == 2. Заблуждение, что Unicode character занимает 2 байта настолько популярно, что даже используется в документации, например в MSDN или документации к Intel IPP. Не все, однако, пишут под Windows. В GCC под Linux sizeof(wchar_t) == 4, отчего берёт начало другой миф, будто бы Unicode character это character, который занимает 4 байта.</p>
<p>Чтобы окончательно разобраться, придётся заглянуть в <a href="http://www.unicode.org/versions/Unicode5.0.0/bookmarks.html">Стандарт Unicode</a>. По стандарту, character это некий абстрактный символ, например "маленькая кириллическая буква а" или "римская цифра Ⅰ". Каждому character'у приписан некий номер — code point (для "маленькой кириллической буквы а" это число 0x430). Code point это число в диапазоне от 0 до 0x1FFFFF, однако большинству таких чисел не соответствует никакого character'а. Способ хранить эти code point'ы в памяти называется кодировкой, самые популярные кодировки для Unicode code point'ов — UTF-32, UTF-16 и UTF-8.</p>
<p>UTF-32 наиболее проста: каждый code point записывается как 32-битное число. Упомянутая "римская цифра Ⅰ" (не путать с "большой латинской буквой I") с code point 0x2160 будет записана как DWORD 0x00002160. Т.к. DWORD'ы записываются по-разному на Big Endian и Little Endian системах, вместо одной кодировки UTF-32 получаются уже две: UTF-32-BE (Big Endian) и UTF-32-LE (Little Endian). wchar_t в GCC/Linux представляет собой code point как раз в UTF-32 кодировке.</p>
<p>Более популярная кодировка UTF-16 использует для записи code point'а одно или два 16-битных слова. В первых версиях стандартах Unicode не было code point'ов больших, чем 0xFFFF. Программисты, заметив это, обрадовались, и решили, что раз любой code point влезает в 16 бит, то пусть отныне и во веки веков sizeof(wchar_t) = 2. Назвали эту кодировку UTF-16. Наша "римская цифра Ⅰ" записывалась в ней как 0x2160, и все были довольны. Но радоваться предстояло недолго: в скором времени оказалось, что за свою историю человечество придумало больше, чем 65536 символов, так что 16 бит явно не хватает. Тогда первые 65536 code point'ов назвали Basic Multingual Plane, а для новых character'ов добавили ещё 16 таких же plane'ов. Чтобы старые программы было легче адаптировать к этим нововведениям, придумали записывать code point'ы из новых 16 plane'ов так: если code point больше, чем 0xFFFF, то из него вычитается 0x10000 и в результате получается 20-битное число в диапазоне от 0 до 0xFFFFF. Это число разбивается на две половинки по 10 бит каждая. Затем старшая половинка этого числа дополняется слева последовательностью бит 0b110110, а младшая — 0b110111. Два получившихся 16-битных слова называются суррогатной парой, и представляют собой запись нужного code point в кодировке UTF-16. Например, "готическая буква манна" имеет code point 0x1033C. После вычитания 0x10000 остаётся число 0x33C = 0b00000000001100111100. Разбиваем на две половинки: 0b0000000000 и 0b1100111100. Дополняем старшую половинку последовательностью 0b110110, а младшую последовательностью 0b110111; получается 0b1101100000000000 = 0xD800 и 0b1101111100111100 = 0xDF3C. Таким образом, "готическая буква манна" представляется в кодировке UTF-16 суррогатной парой 0xD800 0xDF3C.</p>
<p>Определить, является ли слово в кодировке UTF-16 само по себе code point'ом или частью суррогатной пары можно по первым его битам: если слово начинается с последовательности 0x11011, то оно часть суррогатной пары, иначе — целый code point. При редактировании UTF-16 строки нужно учитавать, что сначала всегда должен идти High Surrogate (включающий старшие разряды 20-битного числа), а затем Low Surrogate (с младшими 10-ю разрядами). Если пренебречь этим правилом, можно получить очень интересные, но редко проявляющиеся баги. К сожалению, такие баги есть не только в пользовательском ПО, но встречаются и в системных библиотеках. Так, функция _wcsrev из msvcrt меняет местами нижний и верхний суррогаты в суррогатной паре. Но это уже совсем другая история.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/04/20/unicode-character/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

