Openmp嵌套循环

只是玩弄openmp。 看看这段代码片段:

#pragma omp parallel { for( i =0;i<n;i++) { doing something } } 

 for( i =0;i<n;i++) { #pragma omp parallel { doing something } } 

为什么第一个比第二个慢得多(大约5倍)? 从理论上我认为第一个必须更快,因为并行区域只创建一次而不是像第二次那样n次? 谁可以给我解释一下这个?

我想要并行化的代码具有以下结构:

 for(i=0;i<n;i++) //wont be parallelizable { for(j=i+1;j<n;j++) //will be parallelized { doing sth. } for(j=i+1;j<n;j++) //will be parallelized for(k = i+1;k<n;k++) { doing sth. } } 

我做了一个简单的程序来测量时间并重现我的结果。

 #include  #include  void test( int n) { int i ; double t_a = 0.0, t_b = 0.0 ; t_a = omp_get_wtime() ; #pragma omp parallel { for(i=0;i<n;i++) { } } t_b = omp_get_wtime() ; for(i=0;i<n;i++) { #pragma omp parallel { } } printf( "directive outside for-loop: %lf\n", 1000*(omp_get_wtime()-t_a)) ; printf( "directive inside for-loop: %lf \n", 1000*(omp_get_wtime()-t_b)) ; } int main(void) { int i, n ; double t_1 = 0.0, t_2 = 0.0 ; printf( "n: " ) ; scanf( "%d", &n ) ; t_1 = omp_get_wtime() ; #pragma omp parallel { for(i=0;i<n;i++) { } } t_2 = omp_get_wtime() ; for(i=0;i<n;i++) { #pragma omp parallel { } } printf( "directive outside for-loop: %lf\n", 1000*(omp_get_wtime()-t_1)) ; printf( "directive inside for-loop: %lf \n", 1000*(omp_get_wtime()-t_2)) ; test(n) ; return 0 ; } 

如果我用不同的n开始,我总会得到不同的结果。

 n: 30000 directive outside for-loop: 0.881884 directive inside for-loop: 0.073054 directive outside for-loop: 0.049098 directive inside for-loop: 0.011663 n: 30000 directive outside for-loop: 0.402774 directive inside for-loop: 0.071588 directive outside for-loop: 0.049168 directive inside for-loop: 0.012013 n: 30000 directive outside for-loop: 2.198740 directive inside for-loop: 0.065301 directive outside for-loop: 0.047911 directive inside for-loop: 0.012152 n: 1000 directive outside for-loop: 0.355841 directive inside for-loop: 0.079480 directive outside for-loop: 0.013549 directive inside for-loop: 0.012362 n: 10000 directive outside for-loop: 0.926234 directive inside for-loop: 0.071098 directive outside for-loop: 0.023536 directive inside for-loop: 0.012222 n: 10000 directive outside for-loop: 0.354025 directive inside for-loop: 0.073542 directive outside for-loop: 0.023607 directive inside for-loop: 0.012292 

你怎么能解释我这个差异?!

您的版本结果:

 Input n: 1000 [2] directive outside for-loop: 0.331396 [2] directive inside for-loop: 0.002864 [2] directive outside for-loop: 0.011663 [2] directive inside for-loop: 0.001188 [1] directive outside for-loop: 0.021092 [1] directive inside for-loop: 0.001327 [1] directive outside for-loop: 0.005238 [1] directive inside for-loop: 0.001048 [0] directive outside for-loop: 0.020812 [0] directive inside for-loop: 0.001188 [0] directive outside for-loop: 0.005029 [0] directive inside for-loop: 0.001257 

因为并行区域只创建一次而不是像第二次那样的n次?

的种类。 那个工程

 #pragma omp parallel { } 

还意味着将工作项分配给'{‘上的线程并将线程返回到’}’上的线程池中。 它有很multithreading到线程的通信。 此外,默认情况下,等待线程将通过OS进入hibernate状态,并且唤醒线程需要一些时间。

关于你的中间样本:你可以试着用…来限制外部的并行性

 #pragma omp parallel private(i,k) { for(i=0;i 

通常,将嵌套的最高(上)可能性放置在嵌套上比将其放置在内环上更好。 如果需要顺序执行某些代码,请使用高级编译指示(如omp barrieromp masteromp single )或omp_locks作为此代码。 任何这种方式都会比多次omp parallel启动omp parallel更快

你的全面测试是非常错误的。 你确实计算了代码部分和第二部分的时间; 不是第一节的时间。 另外,printf的第二行确实测量了第一次printf的时间。

首次运行非常慢,因为这里有一个线程启动时间,内存初始化和缓存效果。 此外,omp的启发式可以在几个平行区域之后自动调整

我的测试版本:

 $ cat test.c #include  #include  void test( int n, int j) { int i ; double t_a = 0.0, t_b = 0.0, t_c = 0.0 ; t_a = omp_get_wtime() ; #pragma omp parallel { for(i=0;i 0 ) { t_1 = omp_get_wtime(); #pragma omp parallel { for(i=0;i 

我为程序内部的每个n做了3次运行。

结果:

 $ ./test Input n: 1000 [2] directive outside for-loop: 5.044824 [2] directive inside for-loop: 48.605116 [2] directive outside for-loop: 0.115031 [2] directive inside for-loop: 1.469195 [1] directive outside for-loop: 0.082415 [1] directive inside for-loop: 1.455855 [1] directive outside for-loop: 0.081297 [1] directive inside for-loop: 1.462352 [0] directive outside for-loop: 0.080528 [0] directive inside for-loop: 1.455786 [0] directive outside for-loop: 0.080807 [0] directive inside for-loop: 1.467101 

只有第一次运行test()会受到影响。 testmain()所有下一个结果都是相同的。

从这样的运行中获得更好更稳定的结果(我使用gcc-4.6.1和静态构建)

 $ OMP_WAIT_POLICY=active GOMP_CPU_AFFINITY=0-15 OMP_NUM_THREADS=2 ./test Input n: 5000 [2] directive outside for-loop: 0.079412 [2] directive inside for-loop: 4.266087 [2] directive outside for-loop: 0.031708 [2] directive inside for-loop: 4.319727 [1] directive outside for-loop: 0.047563 [1] directive inside for-loop: 4.290812 [1] directive outside for-loop: 0.033733 [1] directive inside for-loop: 4.324406 [0] directive outside for-loop: 0.047004 [0] directive inside for-loop: 4.273143 [0] directive outside for-loop: 0.092331 [0] directive inside for-loop: 4.279219 

我确实将两个omp性能环境变量和有限的线程数设置为2。

也。 你“并行”循环是错误的。 (我在我的^^^变体中重现了这个错误)i变量在这里共享:

  #pragma omp parallel { for(i=0;i 

你应该把它作为

  #pragma omp parallel { for(int local_i=0;local_i 

UPDATE7你的结果是n = 1000:

 [2] directive inside for-loop: 0.001188 [1] directive outside for-loop: 0.021092 [1] directive inside for-loop: 0.001327 [1] directive outside for-loop: 0.005238 [1] directive inside for-loop: 0.001048 [0] directive outside for-loop: 0.020812 [0] directive inside for-loop: 0.001188 [0] directive outside for-loop: 0.005029 [0] directive inside for-loop: 0.001257 

代码的0.001或0.02输出是......秒乘以1000,所以它是毫秒(ms)。 它是......大约1微秒或20微秒。 某些系统时钟( user timetime效用的system time输出字段)的粒度为1毫秒,3毫秒或10毫秒。 1微秒是2000-3000 CPU滴答(对于2-3GHz CPU)。 因此,如果没有特殊设置,您无法测量如此短的时间间隔。 你应该:

  1. 禁用CPU(Intel SpeedStep,AMD ???)的节能,可以通过降低时钟(频率)将CPU置于低功耗状态;
  2. 禁用CPU的动态超频(Intel turbostep);
  3. 在没有OS帮助的情况下测量时间,例如通过读取TSC( rdtsc asm指令)
  4. 通过添加cpuid指令(或将禁用重新排序的其他指令)禁用rdtsc之前和之后的rdtsc CPU上的指令重新排序(只有当前一代的primefaces不是OOO cpu)
  5. 在完全免费的系统上运行(在开始测试之前,两个cpu上的0%cpu负载)
  6. 以非交互方式重写测试(不要等待用户输入scanf ,通过argv[1]传递n argv[1]
  7. 不要使用Xserver和慢速终端输出结果
  8. 使中断号码更低(关闭网络,物理;不要在后台播放电影,不要触摸鼠标和键盘)
  9. 做了很多次运行(我的意思是不是程序重启,而是重新启动程序的测量部分;我的程序中j = 100)并在结果上添加统计计算。
  10. 不要经常运行printf(在措施之间); 它会污染缓存和TLB。 在内部存储结果并在完成所有测量后输出结果。

更新8:统计我的意思是:取几个值,7个或更多。 丢弃第一个值(如果测量的数值很大,则丢弃第一个值)。 排序他们。 丢弃...最大和最小结果的10-20%。 计算平均值。 按照字面

 double results[100], sum=0.0, mean = 0.0; int count = 0; // sort results[5]..results[100] here for(it=20; it< 85; it ++) { count++; sum+= results[it]; } mean = sum/count;