在Fortran中将值写入大型数组

时间:2017-02-16 01:44:52

标签: c multithreading performance optimization fortran

我正在尝试使用OpenMP优化我的C / Fortran代码来计算有限差分梯度。代码为串行和多线程情况输出正确的值。但是,当我尝试将计算值存储在一个数组中时,代码会减慢很多,而不仅仅是执行计算。

我写了一个简单的例子来提出这个问题:

我在C:

中分配我的数组
 #pragma omp parallel default(none) shared(phi, rhs)
{
 /* Divide up slices in the z-direction over the available threads */
    cur_thread = omp_get_thread_num();
    num_threads = omp_get_num_threads();
    nslices = khi_fb - klo_fb + 1;

    /* Current lo and hi indices in the z-direction */
    cur_klo_fb = klo_fb + nslices * cur_thread/num_threads;
    cur_khi_fb = klo_fb + nslices * (cur_thread + 1)/num_threads - 1;

    if (cur_khi_fb > khi_fb)
        cur_khi_fb = khi_fb;

 /* Start timing the program */
    time0 = omp_get_wtime();
/* Run 100 times for better timing */
    for (i = 0; i < 100; i++)
    {
        /* Calling Fortran routine for calculating derivatives */
        CALC_DERIV(phi, rhs, 
            &(ilo_gb), &(ihi_gb), &(jlo_gb), &(jhi_gb), &(klo_gb), &(khi_gb),
            &(ilo_fb), &(ihi_fb), &(jlo_fb), &(jhi_fb), 
            &(cur_klo_fb), &(cur_khi_fb),
            &dx);
    }
   time1 = omp_get_wtime();

我的数组大小为256 ^ 3,每端有3个单元格为“padding”,这使得“SIZE”为262 ^ 3。

然后我在并行OMP区域内调用我的Fortran函数,在k方向上将工作划分为不同的线程:

  do k=klo_fb,khi_fb
    do j=jlo_fb,jhi_fb
      do i=ilo_fb,ihi_fb

        phi_x = (phi(i+1,j,k) - phi(i-1,j,k))*dx_factor
        phi_y = (phi(i,j+1,k) - phi(i,j-1,k))*dy_factor
        phi_z = (phi(i,j,k+1) - phi(i,j,k-1))*dz_factor

        temp = rhs(i,j,k) + phi_x + phi_y + phi_z
        rhs(i,j,k) = temp
      enddo
    enddo
  enddo

在我的Fortran例程中,我遍历数组,计算每个点的每个方向的中心差异:

rhs(i,j,k) = temp

这里,后缀“_fb”指的是填充框。所以迭代在i和j方向上从3:258开始,在k方向上超过'cur_klo_fb'和'cur_khi_fb'。

这是我的问题:当我运行如图所示的代码时,1个线程(串行行为)的时序是~2.17s。当我注释掉integer count count = 1 c { begin loop over grid do k=klo_fb,khi_fb do j=jlo_fb,jhi_fb do i=ilo_fb,ihi_fb phi_x = (phi(i+1,j,k) - phi(i-1,j,k))*dx_factor phi_y = (phi(i,j+1,k) - phi(i,j-1,k))*dy_factor phi_z = (phi(i,j,k+1) - phi(i,j,k-1))*dz_factor temp = rhs(i,j,k) + phi_x + phi_y + phi_z temp2 = temp2 + temp c rhs(i,j,k) = temp enddo enddo enddo c } end loop over grid 行时,我的时间是3e-4s。为什么会有这么大的差异?我正在进行相同数量的计算。唯一的区别是我将临时变量'temp'存储在rhs中的给定数组位置。此外,我正在阅读阵列'phi'很多次,但它似乎并没有影响速度。似乎在数组'rhs'中写'temp'可以减慢速度。

当我使用OpenMP运行时,我获得了加速,但它不是最佳的。我想我错过了什么。

我希望我能清楚地解释我的问题。我很乐意提供我正在测试的完整代码。

编辑2:

基于这些评论,我试验了看编译器是否实际上只是完全忽略了循环。

我进一步修改了帖子,包括@jabirali和@VladimirF的建议。我也添加了时间。

所以我修改了Fortran循环:

Case 1: With temp2, no rhs(i,j,k), 1 thread: 3.24s
Case 2: With temp2, no rhs(i,j,k), 2 threads: 1.65s
Case 3: Without temp2, with rhs(i,j,k), 1 thread: 1.23s
Case 4: Without temp2, with rhs(i,j,k), 2 threads: 0.74s
Case 5: Without temp2, without rhs, 1 thread: 1e-6s

以下是各种情况的时间安排(针对1和2个线程):

fieldDecl( hasType( tyoedefType().bind("typedef") ) ).bind("field")

仍然困惑:(。

0 个答案:

没有答案