这可以优化吗?

时间:2010-09-15 11:37:24

标签: c optimization fortran

我的程序运行速度比我想要的慢。

我做了一些分析,我发现这个部分占用了绝大部分的处理时间

        DO K = 0, K_MAX
            WRITE(EIGENVALUES_IO, *) K * 0.001 * PI, (W_UP(J), J=1, ATOM_COUNT)
            DCMPLXW_UP(:) = DCMPLX(W_UP(:))
            DO E = 1, ENERGY_STEPS
                ENERGY = MIN_ENERGY + ENERGY_STEP * REAL(E, DP)
                ZV = DCMPLX(ENERGY, DELTA)
                ON_SITE_SINGLE = DCMPLX(0.0_DP)
                DO Q = 1, ATOM_COUNT
                    DO J = 1, ATOM_COUNT
                        ON_SITE_SINGLE(J) = ON_SITE_SINGLE(J) + (MATRIX_UP(J, Q) * MATRIX_UP_CONJG(J, Q)) / (ZV - DCMPLXW_UP(Q))
                    END DO
                END DO
                DOS_DOWN(E) = DOS_DOWN(E) - WEIGHTS(K) * SUM(IMAG(ON_SITE_SINGLE))
            END DO
        END DO

该行

ON_SITE_SINGLE(J) = ON_SITE_SINGLE(J) + (MATRIX_UP(J, Q) * MATRIX_UP_CONJG(J, Q)) / (ZV - DCMPLXW_UP(Q))

是那个正在造成伤害的人。

我在这方面相当新手,有什么方法可以加快速度吗? AFAIK,同样的原则适用于C,所以你们的任何帮助也都会很好。

数组都是COMPLEX

K_MAX是1000

ENERGY_STEPS是1000

ATOM_COUNT很低(<50)

4 个答案:

答案 0 :(得分:5)

我的所有节目都比我想要的慢。在所有(好的,不是全部,但很多)我的科学程序中都有一个深度循环嵌套,其中最内层的语句占用了大部分的计算时间。通常我希望我的计算的90%以上被这些陈述所占用。你内心的声明正在执行2.5x10 ^ 9次,所以你应该期望它占用总时间的很大一部分。

记住这一点我建议你:

a)采用@Alexandre的建议来使用BLAS而不是自制的矩阵向量乘法。

b)忽略@Yuval关于将操作提升到循环之外的建议 - 如果你将优化调高,一个好的Fortran编译器会为你做这个(警告:这是一个自我实现的预言,就像编译器没有这不是一个好的。如今,我希望从好的Fortran中获得很多其他的优化,参见(d)。 (我不希望编译器优化内存访问,我希望从BLAS中获得。)

c)形成一个现实的期望,即你应该从你的程序中获得多少性能。如果您获得的持续FLOP率超过CPU额定性能的10%,那么您的表现非常好,应该花时间做其他事情而不是优化。

d)仔细阅读您的编译器文档。确保您了解优化标志实际执行的操作。确保为正在使用的CPU生成代码,而不是为某些旧版本生成代码。如果可用,请切换快速矢量操作。所有这一切。

e)开始并行化。 OpenMP是一个很好的起点,正如@Nicolas所说,学习曲线起初非常温和。

哦,您似乎遵循的建议0是衡量代码的性能并衡量您所做的任何更改的影响。

答案 1 :(得分:1)

你分开的因素,即

(ZV - DCMPLXW_UP(Q))

不依赖于J,仅依赖于Q. 因此,我会将此计算移至Q循环。 更好的是,计算:

1/(ZV - DCMPLXW_UP(Q))

在外部循环中,并乘以它而不是在循环内部分割 (AFAIR,乘法比分裂快)。 另外,检查矩阵数据结构是否与循环相对应(循环尽可能地遍历内存的连续部分)。 通常,如果您可以改进算法,这将是最大的运行时间改进。

Programming Pearls对类似的优化有很好的描述。

答案 2 :(得分:1)

如果常规代码优化让您陷入困境,您可以尝试OpenMP,这是为C和Fortran进行并行编程的API。在循环之前,您在代码中插入了一些指令,“预编译器”样式,并且它将在不同进程之间分割大量循环。

您可能需要尝试几条说明。例如:

#pragma omp parallel for
/* Loop here */

这是一个非常完整的API,您可以根据许多参数,共享变量和不同的并行拆分技术拆分所有内容。您还可以指定希望OpenMP创建的进程数,核心数等。

通过一些调整,您最终会找到一种提高计算速度的解决方案。

答案 3 :(得分:1)

请将BLAS用于'vactor plus matrix-vector multiplies'。你基本上是在

行中这样做的
ON_SITE_SINGLE(J) = ON_SITE_SINGLE(J) + (MATRIX_UP(J, Q) * MATRIX_UP_CONJG(J, Q)) / (ZV - DCMPLXW_UP(Q)) 

通过精心调整的BLAS库,您可以获得显着的改进。