优化中迷失/困惑

时间:2013-05-06 16:07:25

标签: c optimization for-loop openmp raytracing

我刚刚完成了一个计算机图形学课程,我们必须编写一个光线跟踪器。尽管所有结果都是正确的,但我对OpenMP的使用感到困惑(BTW不是课程的一部分)。我有这个循环(C ++):

#pragma omp parallel for private(L, ray)
//  for (x = x_from; x < x_till; x++) {
//  printf("Col: %5d\n", x);
//  for (y = y_from; y < y_till; y++) {
  for (int xy = 0; xy < xy_range; xy++) {
    int x = x_from + (xy % x_width);
    int y = y_from + (xy / x_width);
        ray = cam->get_ray_at(x, y);
        L = trace_ray(ray, 0, cam->inter);
    #pragma omp critical
    cam->set_pixel(x, y, L);
  }
//  }
}

我尝试了很多配置。但最让我困惑的是,上面的版本,单独使用,单独使用,效率最低(对于单独的x和y,150秒对120秒。“关键”并没有显着改变时间。< / p>

更多:虽然我希望单个for循环并行化每个单独的迭代,但事实并非如此。使用此方法,25个循环作为8 - 8 - 8 - 1(8个核心)的组执行。实际上,单独的y循环(在列表中注释掉)似乎更有效地分配负载。删除'并行'中的'for'确实有所改进 稍微(148 vs 150s;)

此外,我尝试了本地和全局定义(使用必要的私有pragma)。我试图在循环中声明L和射线。一切都无济于事......

我很欣赏建议或指示...

以下是一些更精确的数据:

Single loop             Yes                     No                      No                      Yes    
'Critical"              No                      No                      Yes                     Yes
                ----------------------  ----------------------  ----------------------  ----------------------
                User    CPU     Mean    User    CPU     Mean    User    CPU     Mean    User    CPU     Mean
Scene 5         37.9    158.9   3.66    26.5    185.5   7.00    27.0    187.7   6.95    38.7    161.8   4.18
Scene 6         18.8    110     5.85    17.7    112     6.32    18.1    113.8   5.29    19.4    112.2   5.78
Scene 7         149     658.8   4.42    114     679.9   5.96    114     653.8   5.73    149     659.8   4.43
Plane           112.0   497.3   4.44    105     520.5   4.95    103.8   525     5.06    113.5   504.8   4.45     
5-balls         126     760.2   6.03    162.3   697.5   4.36    170.3   725.3   4.23    127.3   766.5   6.02

'Mean'是CPU /用户,这是平均核心职业。请注意,在某些情况下,平均值仅为4.xx。

解决方案和结果:

Single loop             Yes                     No
                ----------------------  ----------------------
                User    CPU     Mean    User    CPU     Mean
Scene 5         23.9    190.1   7.95    24.4    190.7   7.82
Scene 6         14.3    114.2   7.98    14.5    114.9   7.92
Scene 7         85.5    675.9   7.91    106.9   698.8   6.54
Plane           72.7    579.1   7.97    72.6    578.4   7.97
5-balls         104.8   823.3   7.86    103.9   825.1   7.94

这个优秀的结果是通过添加时间表(动态,1)来获得的 像这样的#pragma omp并行:

#pragma omp parallel for schedule(dynamic, 1)

它可以看到核心的运行时负载分布(相对于 编译时间)。

再多注意一下,',1'参数是限制的大小 块。它可以省略,在这种情况下openmp使用默认值 值。也许添加1使得负载分布过于细粒度, 但在这种情况下我无法找到任何性能差异。 我猜光线追踪任务太慢,隐藏任何管理 开销。

1 个答案:

答案 0 :(得分:3)

我写了一个Whitted sytle光线跟踪器,它在OpenCL中对全光线树(反射和折射)进行操作。我还没有使用OpenMP,但这是我的下一个目标。如果你想学习OpenMP,我会先从一些简单的任务开始。但是,请允许我发表一些意见。

你是如何做你的时间的?你写了“删除'为''并行'为'确实略有改善'。这是没有意义的。删除for将在每个线程上运行相同的代码,而不是将脚步分配到不同的迭代(执行一些hello world测试以显示此信息)。它应该更慢而不是更快。这让我想知道你如何做时机。我添加了一些代码来说明如何进行计时。

您不必使用critical。如果每次迭代写入不同的像素,那么它就不是必需的。根据您的场景的复杂程度critical可能会慢得多。

最后,为了获得最佳性能,您还需要使用SSE / AVX并同时操作多个像素。这可以通过所谓的基于数据包的光线跟踪来完成。有关此http://graphics.stanford.edu/~boulos/papers/cook_gi07.pdf

的详细讨论,请参阅以下链接

编辑:由于每个像素可能需要不同的时间,您希望使用调度(动态)而不是调度(静态),这通常(但不一定)是默认值。见代码。

Ingo Wald的博士论文: http://www.sci.utah.edu/~wald/PhD/

double dtime = omp_get_wtime();
#pragma omp parallel
{
    Ray ray;
    Color L;
    #pragma omp for schedule(dynamic)
    for (int xy = 0; xy < xy_range; xy++) {
        int x = x_from + (xy % x_width);
        int y = y_from + (xy / x_width);
        ray = cam->get_ray_at(x, y);
        L = trace_ray(ray, 0, cam->inter);
        cam->set_pixel(x, y, L);
     }
}
dtime = omp_get_wtime() - dtime;
printf("time %f\n", dtime);