OpenMP的用法由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“openmp的用法”。
在双重循环中怎样写OpenMP? 那要分析你的外循环跟内循环有没有彼此依赖的关系
unsigned int nCore = GetComputeCore();
unsigned int nStep = IMAGETILEYSIZE / nCore;
#pragma omp parallel for private(Level0_x, Level0_y, ChangeLevel0_x, ChangeLevel0_y, InterX1, InterX2, InterY1, InterY2)
for(int k = 0;k
{
int begin = k * nStep;
int end =(k + 1)* nStep;
for(int YOff = begin;YOff
{
for(int XOff = 0;XOff
{
Level0_x = pPixelXBuf[YOff][XOff];
Level0_y = pPixelYBuf[YOff][XOff];
ChangeLevel0_x = Level0_xYMin;
//寻找坐标在Level1Buf中对应的4个像素值
InterX1 =(int)(ChangeLevel0_x);
InterX2 =(int)(ChangeLevel0_x + 1);
InterY1 =(int)(ChangeLevel0_y);
InterY2 =(int)(ChangeLevel0_y + 1);
//双线性插值对Level0_Buf赋值
ZoomInterpolation(Level0Buf, Level1Buf, ChangeLevel0_x, ChangeLevel0_y, SamplesPerPixel, nXSize,nYSize, InterX1, InterX2, InterY1, InterY2, XOff, YOff);
}
}
}
我也想应该这样,可是如果nCore=1的时候,外循环只循环一次,线程是怎么分配的呢。
其实最外层的循环如果很多,就在外循环分配线程是不是就可以不考虑里面的循环了?
nCore = 1,就是单核单cpu,多核循环就跟普通的循环没有差别,openmp默认有几个内核就开几个线程同时运行。所以单核openmp也没有什么意义,此时你也可以开两个线程“同时”运行,但在单核机器上,两个线程是不可能同时运行的可以不考虑里面的循环。你只要保证外循环跟外循环之间,内寻环跟内循环之间没有数据依赖关系就行。
假设
for(int i = 0;i
在双核的机器上,第一个线程从0到100000000,第二个从100000000到200000000,两个循环同时运行,但是10000000是依赖9999999,或者第一个的其他数值,那就不能用openmp来并行,或者要改变并行的方式
我给你的例子中,是一个对2G的图像进行L0_L1转换的一段重采样代码,首先取图像的一块,如512*512,判断有几个内核,然后将512分给内核,那么每个内核处理的内存大小就是512*512/ncore,这几个内核同时对这个512*512大小的内存进行重采样,因为图像数据间彼此没有依赖关系,每个像素对应一个RGB值。所以可以用openmp.请问:openmp这三种实现方法的本质差别
我想要在两个功能相似的for循环中使用并行,使用了如下三种方法:
1,并行度:4.53%;使用并行的函数运行时间:78031;
#pragma omp parallel for nowait firstprivate(cipher0,plain,cipher1,Key)private(j)
for(i=0;i
{
plain[i]=1;
for(j=(i+1);j
{
plain[j]=1;
degree_0(cipher0);
desfunc(cipher1,plain,Key);
if(cipher1[j])
{
#pragma omp atomic
num_of_degree[j]++;//InterlockIncrement(&num_of_degree[m]);
}
plain[i]=0;
}
}
#pragma omp parallel for firstprivate(cipher0,plain,cipher1,Key)private(j)
for(i=0;i
{
Key[i]=1;
for(j=(i+1);j
{
Key[j]=1;
degree_0(cipher0);
desfunc(cipher1,plain,Key);
if(cipher1[j])
{
#pragma omp atomic
num_of_degree[j]++;
}
Key[i]=0;
}
}
2,并行度:4.35%;使用并行的函数运行时间:78571;
#pragma omp parallel
{
#pragma omp for nowait firstprivate(cipher0,plain,cipher1,Key)private(j,k,m)
for(i=0;i
{…}
#pragma omp for firstprivate(cipher0,plain,cipher1,Key)private(j,k,m)
for(i=0;i
{…}
}
3, 并行度:5.49%;使用并行的函数运行时间:51453;
#pragma omp parallel firstprivate(cipher0,plain,cipher1,Key)private(i,j,k,m)
{
#pragma omp sections
{
#pragma omp section
{
for(i=0;i
{…}
}
#pragma omp section
{
for(i=0;i
{…}
}
}
}
其中,并行度是由Intel thread profiler分析得到的,而运行时间是根据finish_clock()-start_clock()得到;
问题一:这三种实现方法 在这两个时间参数上 为什么会有这么大的差别??原因何在?问题二:
#pragma omp atomic
num_of_degree[j]++;
怎么才能运用InterlockIncrement(&num_of_degree[m])实现?像这样的num_of_degree[]全局数组递增 怎样实现能更好一些呢?
第一种和第二种方法没有本质区别,第一种是简写形式
第三种采用section,此时是一个section对应一个线程,这种方式减少了并发时atomic互斥访问等待时间,所以比前两种都要快
谢谢!可是 用Intel profiler分析第一、二种,发现 第一种方式的并行过程并不全是两个线程同时执行的,中间有单线程执行过程;而第二种就不会出现单线程的情况;
还有,是不是每个#pragma omp parallel前后都有一次fork/join? 直观告诉我第二种应该比第一种方式好才对,可是Intel profiler分析结果并不是这样...所以 应该是哪里没理解...第一个问题:
是的,每次parallel region都会有一次fork/join,但对于一个好的OpenMP实现来说,第一种实现的效率应该不会比第二种更差。实际上反而应该是第二种更差,因为第二种方法多了一次implicit barrier,在worksharing loop之后也是有implicit barrier的。但我猜由于程序绝大部分的开销还是来自atomic,所以没体现出来。
至于为啥sections更快,我倒没看出明显的原因。因为你没说OMP_NUM_THREADS你设成了多少。要是>2的话,可能就是1楼说的原因了,因为sections的版本只有两个线程。而前两个版本就是OMP_NUM_THREADS个线程了
第二个问题:
粗略的看,或许你想办法把那个双重循环做一下interchange,把j循环放到外层做并行,然后用个临时变量代替num_of_degree[j]做 reduction可能会有用,否则atomic或许是最好的方法了。一个好的编译器和OpenMP实现会帮你把++变成尽可能快的实现的谢谢你的建议!
事实上 第一种方式的两个时间参数都比第二种方式的好,如果说每次parallel region都会有一次fork/join,那么第一种方式是不是应该进行了两次fork/join? 而第二种我使用了 nowait 是不是没有了implicit barrier??不明白为什么第二种会比第一种效果更差...确实,每次parallel region都会有implicit barrier
第一种方案barrier之后才会进入下一个region
第二种方案用得是nowait,线程在前一个region结束后立即进入下一个region,下一个region里面用到了同一个互斥变量
这时会和前一个region的线程形成争用,由于线程运行顺序是无法预计的,这种方案的争用存在比第一种方案多的风险
根据实际测试的结果也可以看出这一点,如果你把互斥变量去掉,看看两次运行时间会如何
因为不光是#pragma omp parallel,如果你仔细看OpenMP的规范就知道#pragma omp for后面也是有implicit barrier的。所以
#pragma omp parallel
#pragma omp for
这种结构实际上有两个barrier,你在for里用了一个nowait,但外层的parallel的barrier还在,而
#pragma omp parallel for就只有一个implicit barrier了,你用了nowait,就相当于一个也没有了
楼上说的也是可能的造成第二种性能更差的原因
谢谢两位!后来发现 测试结果我弄错了~ 不小心加了一语句!非常感谢!
在OPENMP中,一个循环可以用#pragma omp parallel for解
如果是
for()
{
for()
{
}
for()
{
}
}
这样该如何并行,是不是还只用一句
#pragma omp parallel for?
最好对外层循环进行并行化,如果对内层进行并行化,将会形成过多的迭代空间,使得程序在串并环境间转换的时间远远大于多核优化的性能提升,使程序整体性能下降!
sharing)问题
作者: sy8111(1 篇文章)日期: 二月 26, 2010 在 11:39 下午
1.背景介绍
首先简单说一下计算机中处理器-内存体系结构。由于CPU速度远大于内存访问速度,现代CPU设计中都引入了缓存(cache)作为CPU和内存两 者之间交流的缓冲中介。缓存的速度也介于两者之间。缓存中存放了最经常被访问的内存数据,CPU在很大程度上只需要访问高速缓存,大大提高了系统性能。系 统对缓存进行读写的单位被称作缓存行(cache line)。大家知道系统对内存的操作单位一般是word,如果对缓存操作也用word作单位,就显得太小,缺乏效率,因此一般cache line大概是8个word,这是缓存与内存沟通的最小单位。
在可以预见的几年内,计算机系统会逐渐向多核心CPU或者多CPU结构过渡,出现多个处理核心共享内存的局面。一个很自然的问题马上出现,那就是多 个处理核心对单一内存资源的访问冲突。这个冲突本来不难解决,只要给内存访问加锁就可以了。但是,当把缓存纳入考虑范围时,情况就复杂了。缓存是集成在每 个CPU内部的小内存,除了这个CPU,其他CPU不能访问。而按照单CPU系统的简单缓存设计,缓存并不能察觉除本CPU以外的外部因素对内存内容的修 改。因此,假设出现下面的情况:处理器A将内存中某块内容C读入自己的缓存,并在缓存中修改了该内容,然后处理器B也将内存中这块内容C读入自己的缓存,那么,B看到的只是原始版本的内容,而看不到存在于A缓存中的更新的内容,这就产生了内容不一致的问题。多处理器系统一般是设计控制协议来协调各个CPU 缓存读写,保证内容一致,以解决这种冲突。
2.伪共享
顾名思义,“伪共享”就是“其实不是共享”。那什么是“共享”?多CPU同时访问同一块内存区域就是“共享”,就会产生冲突,需要控制协议来协调访 问。会引起“共享”的最小内存区域大小就是一个cache line。因此,当两个以上CPU都要访问同一个cache line大小的内存区域时,就会引起冲突,这种情况就叫“共享”。但是,这种情况里面又包含了“其实不是共享”的“伪共享”情况。比如,两个处理器各要访 问一个word,这两个word却存在于同一个cache line大小的区域里,这时,从应用逻辑层面说,这两个处理器并没有共享内存,因为他们访问的是不同的内容(不同的word)。但是因为cache line的存在和限制,这两个CPU要访问这两个不同的word时,却一定要访问同一个cache line块,产生了事实上的“共享”。显然,由于cache line大小限制带来的这种“伪共享”是我们不想要的,会浪费系统资源。
举例来说,当多进程程序操作同一个int型数组int a[100]时,如果进程0只访问a[0],进程1只访问a[1],进程2只访问a[2],...那么,实际上每个进程不应该发生数据共享。但是,一般cache line可以包含几个int,因此访问同一个cache line内int数组元素的几个进程就需要系统花费额外资源和时间运用控制协议来协调,这是不必要的。在这种情况下,把每个数组元素单独放在一个 cache line大小的内存区域里在时间上是最有效率的,然而空间上就变成最没效率的了。
计算机设计就是处理矛盾的艺术