<?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; Yang Wang (Intel)</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/author/yang-wang/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Mon, 28 May 2012 14:23:20 +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>针对Vxworks的英特尔C++编译器</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/03/23/vxworksc/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/03/23/vxworksc/#comments</comments>
		<pubDate>Wed, 23 Mar 2011 06:10:45 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/03/23/vxworksc/</guid>
		<description><![CDATA[Vxworks 6.9  64bit RTOS Intel C++ Compiler for Vxworks, IPP library for Vxworks.]]></description>
			<content:encoded><![CDATA[<p>  日前， 风河宣布将发布世上首个也是唯一支持64位处理器的商用级实时操作系统， Vxworks 6.9. 该操作系统是首个完整支持32位和64位处理的实时操作系统。请参考： http://www.windriver.com/announces/vxworks6.9/<br />
  在最新的Vxworks6.9平台上， 同时发布的还有英特尔C++编译器（Intel(R) C++ Compiler for Vxworks）以及英特尔高性能多媒体函数库(the Intel® Integrated Performance Primitives for VxWorks (Intel® IPP library)). 这也是英特尔首次发布针对Vxworks操作系统的编译器。 对于使用英特尔处理器开发高性能Vxworks应用的开发者来说不妨尝试一下。参见： http://www.windriver.com/news/press/pr.html?ID=8881</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/03/23/vxworksc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用#pragma simd进行自动向量化</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/09/06/pragma-simd/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/09/06/pragma-simd/#comments</comments>
		<pubDate>Mon, 06 Sep 2010 05:25:20 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[Blog Challenge]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/09/06/pragma-simd/</guid>
		<description><![CDATA[使用#pragma simd进行自动向量化]]></description>
			<content:encoded><![CDATA[<p><strong><br />
#pragma simd<br />
</strong><br />
该编译指示(SIMD)是12.0编译器最新提供的功能。他可以强制性的让编译器做自动并行化。 对于其他编译指示比如#pragma ivdep来说， 如果编译器编译时发现用户提供的编译指示条件不满足， 那么编译器是不会根据编译指示来进行自动向量化的。也就是说， 编译器实际上还是会进行编译时的依赖关系检查。 而对于#pargam simd来说， 无论编译时条件如何， 编译器总是会进行自动向量化。这种情况下， 用户需要自己去保证被向量化的循环上语义的正确性， 需要自己保证被向量化变量之间的依赖关系的正确性。<br />
我们用一个例子来说明编译器的行为区别。</p>
<blockquote><p>File vec5.c<br />
void vec5(int* a, int n)<br />
{<br />
int i;<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i-1];<br />
}</p></blockquote>
<p>对上面这个例子， 由于存在flow-dependence关系， 程序中的循环明显是不能被向量化的。</p>
<p>vec5.c<br />
C:\test\vec5.c(6) (col. 2): remark: loop was not vectorized: existence of vector dependence.<br />
C:\test\vec5.c(7) (col. 3): remark: vector dependence: assumed FLOW dependence between a line 7 and a line 7.<br />
此时我们加上#pragma ivdep想让编译器忽略循环之间的依赖关系(当然这种操作是不符合原始语义的)。</p>
<blockquote><p>void vec5(int* a, int n)<br />
{<br />
int i;<br />
#pragma ivdep<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i-1];<br />
}</p></blockquote>
<p>这时编译该程序， 程序的输出与不加#pragma ivdep时相同。 编译器在进行编译的时候检查发现了循环之间不可避免的依赖关系， 即使有#pragma ivdep存在， 编译器也还是不会对该循环进行向量化。<br />
如果我们加上#pragma simd， 重新编译程序:</p>
<blockquote><p>void vec5(int* a, int n)<br />
{<br />
int i;<br />
#pragma simd<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i-1];<br />
}</p></blockquote>
<p>这时编译输出:</p>
<p>vec5.c<br />
C:\test\vec5.c(6) (col. 2): remark: SIMD LOOP WAS VECTORIZED.</p>
<p>程序中的循环被向量化了， 但是此时我们显然不会得到一个正确的结果。<br />
我们再看一个用SIMD的正确的例子。 比如下面这个程序：</p>
<blockquote><p>void vec5(int* a, int n, int m)<br />
{<br />
int i;<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i-m];<br />
}</p></blockquote>
<p>编译该程序: icl /O2 /c /Qvec_report:3, 编译器会报告该程序因为存在向量依赖关系而不能被向量化。在该程序中， 如果我们可以保证m大于等于4， 那么我们可以加入#pragma simd指示如下所示：</p>
<blockquote><p>void vec5(int* a, int n, int m)<br />
{<br />
int i;<br />
#prgama simd<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i-m];<br />
}</p></blockquote>
<p>此时编译该程序可以得到正确的自动向量化的代码。</p>
<p>SIMD的支持可以使得程序员可以更自由的控制程序中的向量化。 相比其他编译指示来说， SIMD提供更丰富的语法来满足程序员在各种条件下的向量化处理。 如果你发现现有的编译指示如法满足语义的需要或者向量化性能无法满足期望， 你可以尝试使用SIMD指示。 但是由于SIMD是有程序员来保证程序向量化语义的正确性， 在自由使用的同时，程序员需要很小心的检查程序的语义以保证程序的正确性。<br />
关于SIMD编译指示的详细使用， 请参考其他文档。</p>
<p>
<b>Optimization Notice</b><br />
Intel® Compiler includes compiler options that optimize for instruction sets that are available in both Intel® and non-Intel microprocessors (for example SIMD instruction sets), but do not optimize equally for non-Intel microprocessors. In addition, certain compiler options for Intel® Compiler are reserved for Intel microprocessors. For a detailed description of these compiler options, including the instruction sets they implicate, please refer to "Intel® Compiler User and Reference Guides &gt; Compiler Options". Many library routines that are part of Intel® Compiler are more highly optimized for Intel microprocessors than for other microprocessors. While the compilers and libraries in Intel® Compiler offer optimizations for both Intel and Intel-compatible microprocessors, depending on the options you select, your code and other factors, you likely will get extra performance on Intel microprocessors.</p>
<p>While the paragraph above describes the basic optimization approach for Intel® Compiler, with respect to Intel's compilers and associated libraries as a whole, Intel® Compiler may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include Intel® Streaming SIMD Extensions 2 (Intel® SSE2), Intel® Streaming SIMD Extensions 3 (Intel® SSE3), and Supplemental Streaming SIMD Extensions 3 (Intel® SSSE3) instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors.</p>
<p>Intel recommends that you evaluate other compilers to determine which best meet your requirements.<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/09/06/pragma-simd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用英特尔编译器进行自动向量化</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/09/06/400005000/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/09/06/400005000/#comments</comments>
		<pubDate>Mon, 06 Sep 2010 05:24:55 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[Blog Challenge]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[Auto Vectorization 自动向量化 SIMD SSE 编译指示]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/09/06/400005000/</guid>
		<description><![CDATA[自动向量化是英特尔编译器提供的一个可以自动的使用SIMD指示的功能。 使用编译器提供的自动向量化功能是提高程序性能的一个非常有效的手段。 使用编译器提供的对向量化的语言支持和编译指示还可以提高编译器向量化的效率， 提高程序执行的性能。本文使用一些具体的实例来演示这些编译指示对编译器优化的影响。
]]></description>
			<content:encoded><![CDATA[<p><strong>使用英特尔编译器进行自动向量化 </strong></p>
<p>自动向量化是英特尔编译器提供的一个可以自动的使用SIMD指示的功能。 在处理数据时， 编译器自动选择MMX™, Intel® Streaming SIMD 扩展（Intel® SSE, SSE2, SSE3 和SSE4）等指令集， 对数据进行并行的处理。 使用编译器提供的自动向量化功能是提高程序性能的一个非常有效的手段。自动向量化在IA-32和Intel® 64的平台上均提供很好的支持。</p>
<p>英特尔编译器提供的自动向量化相关的编译选项如下所示。”/Q”开头的选项是针对Windows平台的， “-“开头的选项是针对Linux*和Mac平台的。</p>
<blockquote><p>-x, /Qx<br />
按照该选项指定的处理器类型生成相应的优化代码。 比如-xSSE3, 该选项指定编译器生成Intel® SSE3指令的代码。 又比如-xSSE3_ATOM, 该选项针对Intel® Atom™  处理器进行优化。<br />
-ax, /Qax<br />
如果指定该选项， 在生成的单一目标文件中， 不但会生成专门针对指定的处理器类型进行优化的代码， 同时也生成通用的IA-32架构的代码。 该选项主要是为了生成代码的兼容性考虑。</p>
<p>-vec, /Qvec<br />
打开或者关闭编译器的向量化优化。 默认情况下自动向量化是打开的。</p>
<p>-vec-report, /Qvec-report<br />
该选项用户控制在编译过程中产生的向量化消息报告。</p></blockquote>
<p>编译器提供的自动向量化优化默认情况下是打开的。 在编译过程中我们可以使用-vec-report选项来打开向量化诊断消息报告。 这样编译器可以告诉我们有哪些循环被向量化了， 有哪些循环没有被向量化已经无法向量化的原因。</p>
<p>在编译程序的过程中， 有时候我们会发现编译器报告说某个循环无法被向量化。 很多时候无法向量化的原因都是因为循环中存在的变量依赖关系。 有时候我们可以修改程序来消除这种依赖关系，有的时候我们可以使用编译器提供的一些编译指示来显示的告诉编译器如何处理这种依赖关系。 即使在某个循环已经可以被自动向量化的时候， 使用编译器提供的对向量化的语言支持和编译指示还可以提高编译器向量化的效率， 提高程序执行的性能。</p>
<p>下面我们来详细解释一下编译器提供的编译指示以及这些指示对编译器编译的影响。</p>
<p>在Intel编译器中， 我们提供下面这样一些对自动向量化的语言支持和编译指示。</p>
<blockquote>
<p>__declspec(align(n))<br />
指导编译器将变量按照n字节对齐<br />
__declspec(align(n,off))<br />
指导编译器将变量按照n字节再加上off字节的编译量进行对齐<br />
restrict<br />
消除别名分析中的二义性<br />
__assume_aligned(a,n)<br />
当编译器无法获取对齐信息时，假定数组a已经按照n字节对齐</p>
<p>#pragma ivdep<br />
提示编译器忽略可能存在的向量依赖关系<br />
#pragma vector {aligned|unaligned|always}<br />
指定向量化的方式<br />
#pragma novector<br />
指定不做向量化</p></blockquote>
<p>下面我们就这些编译指示做一些详细的了解。</p>
<ul>
<li> <strong>__declspec(align(n))</strong></li>
</ul>
<p>首先我们来看看如何使用__declspec(align(n))来进行自动向量化。该指示主要是用来告诉编译器一个变量的对齐方式。 当一个变量的对齐方式为16字节对齐时， 生成的向量化指令是最高效的。 当编译器不知道一个变量的对齐方式的时候， 他可能没有办法对该变量的使用进行向量化， 或者编译器会不得不生成条件语句来进行有条件的向量化。 我们来看一下下面这个例子。</p>
<blockquote><p>File: vec1.c<br />
char a[];<br />
void vec1(void)<br />
{<br />
int i;<br />
for(i=0;i&lt;1024;i++)<br />
a[i] = 1;<br />
}</p></blockquote>
<p>使用下面命令编译该程序:<br />
icl vec1.c -O2 -c /Qvec-report:3<br />
这时编译器输出：</p>
<blockquote><p>vec1.c<br />
vec1.c(10) (col. 2): remark: LOOP WAS VECTORIZED.</p></blockquote>
<p>我们可以看到编译器对上面这个程序进行了自动向量化。 但是实际上， 由于编译器不知道a的对齐字节数， 所以他对变量a数据进行了一些条件处理。 我们可以在编译的时候加上-S选项来查看编译器生成的汇编代码。 实际上， 编译器对该程序做了如下处理：</p>
<blockquote><p>temp = a&amp;0x0f;<br />
if(temp != 0)<br />
{<br />
temp = 16-temp;<br />
for(i=0;i&lt;temp;i++) a[i] = 1;<br />
}<br />
/*下面是对齐的访问*/<br />
for(i=temp;i&lt;1024;i++) a[i] = 1;</p></blockquote>
<p>如果我们指定了a的对齐方式， 比如我们使用__declspec(align(16))来定义变量a, 如下所示：</p>
<blockquote><p>__declspec(align(16)) char a[];<br />
void vec1(void)<br />
{<br />
int i;<br />
for(i=0;i&lt;1024;i++)<br />
a[i] = 1;<br />
}</p></blockquote>
<p>对于上面这段程序， 编译器做了自动向量化。 如果我们检查生成的汇编代码可以发现，对于a的对齐方式的条件处理代码已经不见了。<br />
正确使用__declspec(align(n))以及其他align相关编译指示可以帮助编译器进行自动向量化以及提高编译器自动向量化的效率。</p>
<ul>
<li> <strong>restrict</strong></li>
</ul>
<p>使用restrict关键字可以显式的告诉编译器取消指针之间的二义性。 我们还是用下面这个例子来说明restrict的使用。</p>
<blockquote><p>File: vec2.c</p>
<p>void vec2(char* a, char* b, int n)<br />
{<br />
int i;<br />
for(i=0;i&lt;n;i++)<br />
a[i] = b[i];<br />
}</p></blockquote>
<p>使用以下命令进行编译：<br />
icl vec2.c -O2 -c /Qvec-report:3<br />
编译器输出：</p>
<blockquote><p>vec2.c<br />
restrict.c(5) (col. 2): remark: LOOP WAS VECTORIZED.<br />
restrict.c(5) (col. 2): remark: loop skipped: multiversioned.</p></blockquote>
<p>此时编译器输出multiversioned向量化代码， 对同一个循环产生了多个版本的实现。实际上编译器对代码进行了条件处理， 如下所示：</p>
<blockquote><p>void vec2(char* a, char* b, int n)<br />
{<br />
int i;<br />
if(a+n&lt;b || b+n&lt;a)<br />
for(i=0;i&lt;n;i++) a[i] = b[i]; /*向量化循环*/<br />
else<br />
for(i=0;i&lt;n;i++) a[i] = b[i]; /*串行循环*/<br />
}</p></blockquote>
<p>可以看出，由于编译器不知道指针a 和b之间是否存在重叠， 所以他对循环进行了条件处理。 如果我们从语义上能够保证a和b是不会发生重叠的， 那么我们就可以使用restrict关键字来显式的告诉编译器这一点。</p>
<blockquote><p>void vec2(char* restrict a, char* restrict b, int n)<br />
{<br />
int i;<br />
for(i=0;i&lt;n;i++)<br />
a[i] = b[i];<br />
}</p></blockquote>
<p>此时编译器输出没有multiversioned。</p>
<blockquote><p>restrict.c<br />
restrict.c(5) (col. 2): remark: LOOP WAS VECTORIZED.</p></blockquote>
<p>注意C90里面不支持restrict关键字， 在windows平台编译的时候我们需要加上选项/Qrestrict来让编译器认识restrict关键字。</p>
<ul>
<li> <strong>#pragma vector</strong></li>
</ul>
<p>使用#pragma vector编译指示来显式告诉编译器使用某种方式来进行自动向量化。 比如在下面这个例子中， 我们可以保证变量a的地址是16字节对齐的，那么我们就可以使用#pragma vector aligned来显式的告诉编译器不需要考虑非对齐的情况。这样产生的向量化代码是最高效的。</p>
<blockquote><p>File: vec3.c<br />
#include &lt;malloc.h&gt;<br />
void vec3(void)<br />
{<br />
int i;<br />
char* a=_aligned_malloc(1024, 16);<br />
#pragma vector aligned<br />
for(i=0;i&lt;1024;i++)<br />
a[i] = 1;<br />
}</p></blockquote>
<p>在上面这个例子中， 如果我们不加上#pragma vector aligned, 编译器会对循环进行条件处理后的向量化。 大家可以对比一下两种情况下生成的汇编代码的区别。请注意我们在使用#pragma vector aligned的时候需要保证被处理变量的对齐方式是16字节对齐的， 否则在使用了该编译指示后可能会产生错误的结果。在上面这个例子中， 我们稍作如下修改：</p>
<blockquote><p>#include &lt;malloc.h&gt;<br />
void vec3(void)<br />
{<br />
int i;<br />
char* a=_aligned_malloc(1024, 16);<br />
char* b = a+1;<br />
#pragma vector aligned<br />
for(i=0;i&lt;1023;i++)<br />
b[i] = 1;<br />
}</p></blockquote>
<p>循环中的b的地址不是16字节对齐的， 但是如果我们还是按照aligned的方式来做向量化， 产生的结果是编译出来的可执行程序运行时异常。 在上面的例子中， 我们需要使用#pragma vector unaligned 编译指示来正确的引导编译器。</p>
<ul>
<li> <strong>#pragma ivdep</strong></li>
</ul>
<p>使用#pragma ivdep显式的告诉编译器忽略向量之间可能存在的依赖关系。参考下面这个例子。</p>
<blockquote><p>File: vec4.c<br />
void vec4(int* a, unsigned int n, unsigned int m)<br />
{<br />
int i;<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i+m];<br />
}</p></blockquote>
<p>使用编译器编译该程序：<br />
icl vec4.c –O2 -c /Qvec-report:3<br />
编译器输出：</p>
<blockquote><p>vec4.c<br />
vec4.c(6) (col. 2): remark: loop was not vectorized: existence of<br />
vector dependence.<br />
vec4.c(7) (col. 3): remark: vector dependence: assumed ANTI dependence between a line 7 and a line 7.<br />
vec4.c(7) (col. 3): remark: vector dependence: assumed FLOW dependence between a line 7 and a line 7.<br />
vec4.c(7) (col. 3): remark: vector dependence: assumed FLOW dependence between a line 7 and a line 7.<br />
vec4.c(7) (col. 3): remark: vector dependence: assumed ANTI dependence between a line 7 and a line 7.</p></blockquote>
<p>如果我们可以保证a[0]到a[n-1]和a[m]到a[m+n-1]之间不存在重叠， 那么我们就可以使用#pragma ivdep来显式的告诉编译器可以忽略a[i]和a[i+m]之间的依赖关系， 修改程序如下:</p>
<blockquote><p>void vec4(int* a, unsigned int n, unsigned int m)<br />
{<br />
int i;<br />
#pragma ivdep<br />
for(i=0;i&lt;n;i++)<br />
a[i] = a[i+m];<br />
}</p></blockquote>
<p>这样程序中的循环就可以被自动向量化了。</p>
<p>英特尔编译器提供了强大的自动向量化支持，并且对自动向量化的优化也一直在进行之中。 在新版本的编译器中， 我们可以看到更多的自动向量化有关的支持。 更多的内容请参考后续博客更新。</p>
<table align="center" width="100%" cellpadding="6" cellspacing="0" rules="all" border="1">
<tbody>
<tr>
<th valign="middle"><strong>Optimization Notice</strong> </th>
</tr>
<tr bgcolor="#e7e7e7">
<td style="padding-left: 6;padding-right: 6;padding-top: 3;padding-bottom: 3">
<p>Intel® compilers, associated libraries and associated development tools may include or utilize options that optimize for instruction sets that are available in both Intel® and non-Intel microprocessors (for example SIMD instruction sets), but do not optimize equally for non-Intel microprocessors. In addition, certain compiler options for Intel compilers, including some that are not specific to Intel micro-architecture, are reserved for Intel microprocessors. For a detailed description of Intel compiler options, including the instruction sets and specific microprocessors they implicate, please refer to the "Intel® Compiler User and Reference Guides" under "Compiler Options." Many library routines that are part of Intel® compiler products are more highly optimized for Intel microprocessors than for other microprocessors. While the compilers and libraries in Intel® compiler products offer optimizations for both Intel and Intel-compatible microprocessors, depending on the options you select, your code and other factors, you likely will get extra performance on Intel microprocessors.</p>
<p>Intel® compilers, associated libraries and associated development tools may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include Intel® Streaming SIMD Extensions 2 (Intel® SSE2), Intel® Streaming SIMD Extensions 3 (Intel® SSE3), and Supplemental Streaming SIMD Extensions 3 (Intel® SSSE3) instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors.</p>
<p>While Intel believes our compilers and libraries are excellent choices to assist in obtaining the best performance on Intel® and non-Intel microprocessors, Intel recommends that you evaluate other compilers and libraries to determine which best meet your requirements. We hope to win your business by striving to offer the best performance of any compiler or library; please let us know if you find we do not.</p>
<p align="right">Notice revision #20101101</p>
</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/09/06/400005000/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SIMD编译指示中的向量化长度的指定</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/09/06/simd/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/09/06/simd/#comments</comments>
		<pubDate>Mon, 06 Sep 2010 05:24:31 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[Blog Challenge]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/09/06/simd/</guid>
		<description><![CDATA[SIMD编译指示中的向量化长度的指定]]></description>
			<content:encoded><![CDATA[<p><strong>SIMD编译指示中的向量化长度的指定</strong></p>
<p>SIMD 向量化是英特尔编译器12.0版支持的一个新功能。 该向量化使用 #pragma simd (c/c++) 或者 !DIR$ SIMD(fortran) 编译指示来有效地实现循环向量化。该向量化语法如下所示：</p>
<p>#pragma simd [clause[ [,] clause]...]</p>
<p>在#pragma simd之后可以带一些字句来让编译器得到更多的信息以便做更好的优化。 这些字句可以是：</p>
<blockquote><p>vectorlength (vl_list)<br />
private (expr_list, expr)<br />
linear (var_step_list)<br />
reduction (oper_var_list)<br />
[no]assert</p></blockquote>
<p>在本文中， 我们针对vectorlength子句来进行一些讨论。<br />
<strong><br />
vectorlength(num1, num2, …, numN)<br />
</strong><br />
vectorlength (简称VL) 用来指导向量优化单元从指定的若干向量长度num1, num2, … , numN中选择某个长度来进行向量化。对于选定的VL，向量循环的每一次执行的计算工作相当于原来标量循环VL次执行的计算工作。多个向量长度子句会合并成一个集合， 编译器从这些指定的长度中选择某个针对目标机器的最优长度进行向量化。<br />
看下面这个例子。</p>
<blockquote><p>void foo(int* a, int* b)<br />
{<br />
#pragma simd vectorlength(4)<br />
#pragma nounroll<br />
for(int i=0;i&lt;1024;i++)<br />
{<br />
a[i]=b[i];<br />
}<br />
}</p></blockquote>
<p>在支持128bit向量长度的机器上， 编译器生成相应的SSEx指令来向量化上面程序中的循环。 用户指定的VL是4， 理论上说， 一次向量循环相当于4次标量循环。 在上面这个例子中， 每次向量操作的长度正好是32*4=128bit。理论上的向量循环次数为1024/4=256次。如果我们指定VL为8， 理论上说编译器在一次向量循环中会做两次128位的向量操作， 相当于做了256位(32*4+32*4)的向量操作， 对应的循环次数为1024/8=128次。 当然，如果我们不加上编译指示#pragma nounroll来阻止编译器的loop unroll优化，编译器会进行循环展开优化， 这样实际的循环次数可能更少。</p>
<p>在上面的例子中， 如果我们指定多个VL， 比如#pragma simd vectorlength(4,8)。编译器会根据目标机器的向量长度和其内部的cost-modeling计算选择最优的VL。</p>
<p>Vectorlength 不是必须指定的。 如果没有指定vectorlength, 一般情况下编译器会根据目标机器的向量长度和标量循环的变量类型来选择合适的VL。 那我们在什么情况下需要指定vectorlength呢？ 一般情况下， 这需要根据程序的语义和对性能的要求来决定。 比如下面这个例子。</p>
<blockquote><p>void foo(double a*, double * b, int m, int n)<br />
{<br />
for(int i=n; i&lt;m;i++)<br />
{<br />
a[i] = b[i];<br />
}<br />
}</p></blockquote>
<p>我们要对该例子中的循环进行向量化。 但是如果a 和 b存在别名关系, 比如a = b+n, 那么我们就无法通过restrict关键字来向量化上面这个循环。 如果我们的程序语义可以保证n一定满足: n=2 或者n=3, 那么我们就可以通过simd来向量化这个循环。 比如加上#pragma vectorlength(2). 这样在支持SSEx的目标机器上， 可以做到128bit的循环向量化。 在支持AVX的目标机器上， 默认情况下的向量化长度是256bit的， 所以如果没有VL为2的指定， 那么编译器可能会生成256bit的向量化循环， 对应的VL为4， 在这种情况下这样的向量化是不符合程序的语义的， 也就会产生运行时错误。 所以我们需要显式指定vectorlength(2)来满足语义的需要。</p>
<p>Vectorlength的值一定是2的幂次方。 不同类型的数据针对不同的目标机器有不同的VL的范围。 比如对于支持128bit SSEx的机器来说， char类型操作的VL为16， short类型可以为8或16， int类型则可以为4，8，16。 如果指定了不合适的VL， 编译器会报告一个warning， 同时放弃对应的向量化操作。</p>
<p>
<b>Optimization Notice</b><br />
Intel® Compiler includes compiler options that optimize for instruction sets that are available in both Intel® and non-Intel microprocessors (for example SIMD instruction sets), but do not optimize equally for non-Intel microprocessors. In addition, certain compiler options for Intel® Compiler are reserved for Intel microprocessors. For a detailed description of these compiler options, including the instruction sets they implicate, please refer to "Intel® Compiler User and Reference Guides &gt; Compiler Options". Many library routines that are part of Intel® Compiler are more highly optimized for Intel microprocessors than for other microprocessors. While the compilers and libraries in Intel® Compiler offer optimizations for both Intel and Intel-compatible microprocessors, depending on the options you select, your code and other factors, you likely will get extra performance on Intel microprocessors.</p>
<p>While the paragraph above describes the basic optimization approach for Intel® Compiler, with respect to Intel's compilers and associated libraries as a whole, Intel® Compiler may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include Intel® Streaming SIMD Extensions 2 (Intel® SSE2), Intel® Streaming SIMD Extensions 3 (Intel® SSE3), and Supplemental Streaming SIMD Extensions 3 (Intel® SSSE3) instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors.</p>
<p>Intel recommends that you evaluate other compilers to determine which best meet your requirements.<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/09/06/simd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>支持分布式内存系统的并行开发模式Concurrent Collections (CnC)</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/07/07/concurrent-collections-cnc/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/07/07/concurrent-collections-cnc/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 09:01:25 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/07/07/concurrent-collections-cnc/</guid>
		<description><![CDATA[英特尔发布了Concurrent Collections 0.5版本。在这个新版本中提供了一个新的比较吸引人的功能：对分布式内存系统的支持(distCnC)。 现有的大部分并行开发模式都是基于共享内存系统的， 比如openmp， cilk等。 在CnC中实现了对分布式内存系统的支持， 这就允许用户开发一个大型的CnC并行程序并且运行在分布式内存系统中比如用于计算机集群系统。
]]></description>
			<content:encoded><![CDATA[<p>英特尔发布了Concurrent Collections 0.5版本。在这个新版本中提供了一个新的比较吸引人的功能：对分布式内存系统的支持(distCnC)。 现有的大部分并行开发模式都是基于共享内存系统的， 比如openmp， cilk等。 在CnC中实现了对分布式内存系统的支持， 这就允许用户开发一个大型的CnC并行程序并且运行在分布式内存系统中比如用于计算机集群系统。<br />
原则上说， 一个正确运行的共享内存CnC程序同样可以在分布内存CnC中正确的运行。 对于数据的分布几乎完全的被distCnC运行系统内部搞定， 程序员无需知道底层的细节问题。 当然， 为了让一个共享内存的CnC程序正确的在分布式内存系统中， 我们需要做一些小的修改。 一旦做了这些修改， 这样的程序不但可以运行在分布式内存系统， 同样也可以运行在共享内存系统。<br />
理论上说， distCnC可以支持任何类型的网络。但是当前版本的CnC仅仅支持基于socket的通讯模式。 将来可能会支持基于MPI的通讯模式。在最新的CnC0.5版本中已经包含了支持分布式系统所需要的通讯库。这些函数库是在运行时根据需要加载的。 用户不需要链接额外的函数库。<br />
修改现有CnC程序来支持分布式系统也很简单， 只要包含相应头文件以及进行相应初始化即可。<br />
更多的信息请参考CnC文档以及：</p>
<p>http://software.intel.com/en-us/blogs/2010/06/15/introducingconcurrent-collections-for-distributed-memory-systems-distcnc/</p>
<p>下载试用CnC请访问：</p>
<p>http://software.intel.com/en-us/articles/intel-concurrent-collections-for-cc/</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/07/07/concurrent-collections-cnc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intel® Concurrent Collections (CnC) – 一个新的平行开发模式</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/07/05/intel-concurrent-collections-cnc/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/07/05/intel-concurrent-collections-cnc/#comments</comments>
		<pubDate>Mon, 05 Jul 2010 09:52:35 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/07/05/intel-concurrent-collections-cnc/</guid>
		<description><![CDATA[Intel® Concurrent Collections (简称CnC) 是一个全新C++的并行编程模式。在这种编程模式下， 用户可以不用考虑太多的并行系统问题。 如同创建线性程序一样， 用户可以把更多的精力放在程序的整体架构上， 专注于解决专业领域内的问题， 而把Tuning expert要做的事情交给CnC来完成。]]></description>
			<content:encoded><![CDATA[<p>开发多核应用程序的用户一般比较头疼的问题是跟线程相关的问题， 比如程序运行的硬件架构， 线程的同步， 调度与分配，负载平衡等。 某个系统领域内的专家(Domain expert)一般都会专注于程序语义的正确性以及程序本身的一些限制， 所以这些并行相关的问题对于Domain expert来说比较困难。而对于并行系统内的专家（Tuning expert）来说, 由于缺乏对某个领域内专业知识的了解，即使他对并行系统非常了解， 往往也很难开发出非常高效的某个专业领域的应用。<br />
Intel® Concurrent Collections (简称CnC) 是一个全新C++的并行编程模式。在这种编程模式下， 用户可以不用考虑太多的并行系统问题。 如同创建线性程序一样， 用户可以把更多的精力放在程序的整体架构上， 专注于解决专业领域内的问题， 而把Tuning expert要做的事情交给CnC来完成。 这样， Domain expert就可以从并行系统里解放出来， 开发出高效的适用于某个专业领域的并行程序。在CnC这个编程模式下， 如同写线性程序一样， 用户可以专注于各个功能模块， 处理好各个功能模块的输入和输出， 以及这些功能模块的执行先后次序。 这些问题其实就是应用程序本身的流程问题。<br />
并行的本质是一个处理数据依赖关系（Data Dependence） 和控制依赖关系(Control Dependence)的一个过程。 Data Dependence就是我们经常说的生产者和消费者关系。 一个功能模块生成一些数据提供给其他功能模块。 数据被某个生产者模块产生， 然后被某个消费者模块使用。 Control Dependence 是一个控制与被控制关系。 这个关系涉及到两个因素， 如果(if)和何时(when)。 在线性程序里面， if 和 when 是紧密结合在一起的。 在CnC里面， 我们引入了Tag这个概念。 如果某个控制模块执行完成了， 那么他产生一个Tag， 这样被控制的模块就可以被调度起来。 但是要注意， 这里和线性程序不一样的是， 线性程序里面被控制的模块是马上就开始执行了, 但是在CnC里面，被控制模块是被调度到一个线程池里面， 被控制模块并不见得就是马上开始执行。<br />
所以在Data Dependence 和Control Dependence 中， 我们需要3个元素来满足这两个关系。<br />
Step: Step就是计算， 就是我们的程序功能模块， 对应程序中的某个function。.<br />
Item: Item是数据， 就是执行某个程序需要的数据以及该程序生成的数据。<br />
Tag: Tag 用来维护function之间的控制与被控制的关系。</p>
<p>这3个元素其实也是我们在开发一般程序的时候需要考虑的问题。 根据这3个元素， 我们就可以构造一个程序的流程图(Graph). 这个Graph的实质就是在描述数据依赖关系和控制依赖关系。举个例子来说， 在我们的程序里面我们可以有这样一些元素：<br />
Item Data: [I1], [I2]<br />
Step function: (S1), (S2)<br />
Tag: ,<br />
那么我们可以这样描述我们的程序：<br />
::(S1) 只有当Tag 准备好的时候， S1才可以被执行<br />
::(S2) 只有当Tag 准备好的时候， S2才可以被执行<br />
[I1]-&gt; (S1) -&gt; [I2], -&gt;(S2)<br />
数据[I1]输入给function (S1), (S1)在执行完后生成数据[I2], 并且生成Tag 。<br />
实际上， 在这个例子中， 我们就是在用文本的方式来描述我们的程序流程图：<br />
[I1]--&gt;(S1)--&gt;[I2]--&gt;(S2)<br />
只是在模块S1和模块S2之间， 我们用T2来控制S1 和S2之间的Control Dependence. 那么S2什么时候开始执行呢？ 根据这个关系我们知道， 当S1执行完成生成Tag 后， S2就被调度到线程池。 当数据I2准备好之后， S2就可以开始真正执行了。<br />
当我们把上述关系用文本的方式记录在一个文件中后， 我们就可以开始CnC编程了。<br />
下面这个图描述了CnC这种并行编程模式。</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/07/CnCprogrammingmodel1.jpg"><img class="aligncenter size-full wp-image-400004385" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/07/CnCprogrammingmodel1.jpg" alt="" width="560" height="375" /></a></p>
<p>用户在定义好文本方式的关系图后， CnC中的Translator会把它转换成一个C++头文件以及一个C++程序提示文件。 在C++程序提示文件里面定义好了系统的框架， 用户需要做的大部分工作就是往这些具体的功能模块里面填写具体的程序代码即可。在程序开发完成后， 编译器会自动链接一个CnC的Runtime库， 生成最终的应用程序。 当然， 这个应用程序是真成的多线程并行应用程序。<br />
CnC支持各种形式的并行开发，比如Data, Task, 和Pipeline Parallel. 目前CnC同时提供Windows 版和Linux版。 在Windows 版本下， CnC可以嵌入Visual Studio 中， 用户可以在Visual Studio的框架下开发基于CnC的并行程序。<br />
下载和使用CnC或者想要了解更多的关于CnC的信息， 请访问网站: http://software.intel.com/en-us/articles/intel-concurrent-collections-for-cc/</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/07/05/intel-concurrent-collections-cnc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intel® Cilk™ Plus 中的工作密取调度</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-2/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-2/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 02:57:39 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-2/</guid>
		<description><![CDATA[Intel® Cilk Plus中的工作密取调度介绍]]></description>
			<content:encoded><![CDATA[<p>在Intel® Cilk™ Plus中， 我们可以使用cilk_spawn 来创建一个新的可以并行执行的任务。 从语义上来说， 该新任务是可以与原有任务并行的执行的。 但在实际的运行过程中， 能否并行取决于Intel® Cilk™ Plus的任务调度(scheduler)。Intel® Cilk™ Plus中的调度是动态的。 它使用一种叫工作密取(work stealing)算法来动态的进行任务的分配。<br />
下面我们来解释一下什么是工作密取。 假设我们有下面这样一些任务。<br />
mywork (1);<br />
A: cilk_spawn mywork(3)<br />
mywork(2)<br />
B: cilk_sync;<br />
mywork(4)</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image001.gif"><img class="aligncenter size-full wp-image-400004301" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image001.gif" alt="" width="295" height="82" /></a></p>
<p>对于该段程序来说， 他可以串行的执行， 也可以有多个线程并行的执行。 如上图所示， 在A点， 我们衍生出一个新的任务(3)。 这里稍微解释一下， 我们把这种情况下的任务(3)叫子任务(Child), 把任务(2)叫后续任务(Continuation)。 在大多数的文档里面， 我们都保持这个命名规则。<br />
在上述程序中，如果是串行的执行，各个任务的执行顺序如下图所示：</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image002.gif"><img class="aligncenter size-full wp-image-400004302" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image002.gif" alt="" width="371" height="86" /></a></p>
<p>该执行次序完全保证了串行的语义。 假设有2个工作线程(I)和(II)， 那么执行的次序可以用下图来描述。</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image003.gif"><img class="aligncenter size-full wp-image-400004303" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image003.gif" alt="" width="375" height="86" /></a></p>
<p>当前线程(I)在执行到A点时衍生出新的任务（3）。 该线程(I)会保存当前执行状态， 然后继续执行子任务（3）。 Intel® Cilk™ Plus线程调度发现此时线程(II)空闲, 就会激活线程(II)去密取(steal)线程(I)的后继任务（2）来执行。 两个工作线程在B点进行同步(cilk_sync)。 同步后线程(I)继续执行任务(4)。 这种工作调度模式我们就称之为工作密取。<br />
在Intel® Cilk™ Plus中我们使用工作密取方式进行多任务调度。 除了工作密取方式， 在多线程调度中还经常采用工作共享(work sharing)方式调度。 在工作共享方式中， 当线程产生新的工作子任务时， 调度程序会转移一些子任务到别的工作线程以期望使用当前空闲处理器来处理这些任务。 而在工作密取方式中， 空闲的处理器采取主动出击的办法， 通过”秘密偷取”的方式来得到可以执行的任务。 从概念上来说， 工作密取方式要比工作共享方式高效。 比如当程序有足够的并行度的时候， 也就说当所有处理器都有工作在执行的时候， 工作密取方式下不会发生任务的转移（从一个处理器到另一个处理器的任务转移）， 而工作共享方式总是会产生这种转移。因而相比工作共享方式， 工作密取方式会有较少的通讯和同步的开销。关于这两种调度模式更进一步的对比， 请参考相关的技术文档。 这里不再讨论。总之， 在Intel® Cilk™ Plus中采用的是一种高效的工作密取调度。<br />
工作密取的调度方式自动保证了各个处理器之间的负载平衡。当一个处理器空闲的时候， 它会主动获取新的工作任务。 当程序的并行度足够高的时候， 每个处理器都不会空闲下来。<br />
工作密取是有一定的开销的， 因为它涉及到一个工作任务的转移， 这必然带来通讯和同步的开销。 但是在Intel® Cilk™ Plus中， 大多数的衍生都不会导致工作密取的发生。 在我们的程序设计中， 我们应该尽量保证处理任务的在各个处理器上的平衡。 这种负载的分配越是平衡， 就会产生越少的工作密取， 因而带来的密取开销也越少。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intel® Cilk™ Plus 中的 Reducer 视图</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-reducer/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-reducer/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 02:57:06 +0000</pubDate>
		<dc:creator>Yang Wang (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-reducer/</guid>
		<description><![CDATA[Cilk中的Reducer视图介绍]]></description>
			<content:encoded><![CDATA[<p>Reducer视图 (The Reducer View)<br />
这里我们来讨论一下Intel® Cilk™ Plus 中的Reducer视图。在Intel® Cilk™ Plus 中， Reducer是我们支持的一种超级对象(Hyperobject)。什么是超级对象？ 他是一种被Intel® Cilk™ Plus 运行环境支持的构件，使多个strand能互不影响地访问共享变量和数据结构，它是通过同时提供给每个strand一个超级对象的不同视图来实现。Reducer是我们目前唯一支持的超级对象。 根据超级对象的概念我们可以知道， 视图(View)其实是超级对象的一个状态。 视图作为输入(input)提供给strand， 不同的strand具有不同的Reducer视图， 他们根据该视图可以互不影响的访问共享变量和数据。<br />
理解了Reducer视图的概念，那么Intel® Cilk™ Plus 运行系统如何产生一个Reducer 视图呢？ 我们同样用一个例子来说明视图的生成。<br />
假设我们有下面这样一些任务。<br />
mywork (1);<br />
A: cilk_spawn mywork(3)<br />
mywork(2)<br />
B: cilk_sync;<br />
mywork(4)</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image001.gif"><img class="aligncenter size-full wp-image-400004301" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image001.gif" alt="" width="295" height="82" /></a></p>
<p>我们知道， cilk_spawn衍生出一个新的可以并行执行的任务。 这时可以分为密取发生和不发生两种情况。 当密取不发生的时候， 如下图所示， 此时的程序执行是串行的， 没有新的线程来并行执行， 也就没有新的Reducer 视图被创建。</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image002.gif"><img class="aligncenter size-full wp-image-400004302" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image002.gif" alt="" width="371" height="86" /></a></p>
<p>当密取行为发生的时候，如下图所示， 此时在A点， 我们的主线程(I)有一个Reducer的当前执行视图(V1)， 线程(I)执行strand (3), strand(3)中使用的视图就是V1. 另一线程(II)密取工作strand (2), 这时strand(2)会得到一个新的Reducer视图(V2)。新生成的V2拥有Reducer的恒等值(identity value)， strand(2)基于该V2进行操作。 在B点进行Reducer同步的时候， 新生成的V2与原来的视图V1进行合并。 合并后， V2被注销。 strand(4) 继续基于V1进行操作。</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image003.gif"><img class="aligncenter size-full wp-image-400004303" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2010/06/image003.gif" alt="" width="375" height="86" /></a></p>
<p>理论上说， 我们可以理解为每个strand都有一个reducer的私有视图。 然而基于性能的考虑， 视图的产生是延迟的(Lazy semantics)。并不是每一次的衍生调用都会有新的视图的生成。新视图的创建了必须符合下面两个条件:<br />
1. 首先，新的视图的创建必须在密取行为发生之后。 如果密取行为没有发生， 程序的执行其实是线性的。 这时就没有必要产生新的视图。<br />
2. 其次， 只有在新的strand里面首次存取reducer的时候， 新的视图才会被创建。 也就是说， 当密取行为发生后， 视图也不是马上被创建出来的。 如果在新的strand里面没有基于reducer的存取操作， 那么我们是没有必要产生新的reducer视图的。 如果新的strand里面有对reducer的存取操作， 那么在首次存取该reducer的时候， 系统才会在该存取点创建新的视图实例。<br />
如果新的视图被创建， 他会在cilk_sync点与先前的视图进行合并。 如果没有新的视图生成， 合并是不必要的。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/06/25/intel-cilk-plus-reducer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

