C++循环展开性能

4

我正在阅读《C++模板完全指南》这本书,其中涉及到元编程的部分。在第17.7节中有一个循环展开的例子。我已经为点积计算实现了该程序:

#include <iostream>
#include <sys/time.h>

using namespace std;

template<int DIM, typename T>
struct Functor
{
    static T dot_product(T *a, T *b)
    {
        return *a * *b + Functor<DIM - 1, T>::dot_product(a + 1, b + 1);
    }
};

template<typename T>
struct Functor<1, T>
{
    static T dot_product(T *a, T *b)
    {
        return *a * *b;
    }
};


template<int DIM, typename T>
T dot_product(T *a, T *b)
{
    return Functor<DIM, T>::dot_product(a, b);
}

double dot_product(int DIM, double *a, double *b)
{
    double res = 0;
    for (int i = 0; i < DIM; ++i)
    {
        res += a[i] * b[i];
    }
    return res;
}


int main(int argc, const char * argv[])
{
    static const int DIM = 100;

    double a[DIM];
    double b[DIM];

    for (int i = 0; i < DIM; ++i)
    {
        a[i] = i;
        b[i] = i;
    }


    {
        timeval startTime;
        gettimeofday(&startTime, 0);

        for (int i = 0; i < 100000; ++i)
        {
            double res = dot_product<DIM>(a, b); 
            //double res = dot_product(DIM, a, b);
        }

        timeval endTime;
        gettimeofday(&endTime, 0);

        double tS = startTime.tv_sec * 1000000 + startTime.tv_usec;
        double tE = endTime.tv_sec   * 1000000 + endTime.tv_usec;

        cout << "template time: " << tE - tS << endl;
    }

    {
        timeval startTime;
        gettimeofday(&startTime, 0);

        for (int i = 0; i < 100000; ++i)
        {
            double res = dot_product(DIM, a, b);
        }

        timeval endTime;
        gettimeofday(&endTime, 0);

        double tS = startTime.tv_sec * 1000000 + startTime.tv_usec;
        double tE = endTime.tv_sec   * 1000000 + endTime.tv_usec;

        cout << "loop time: " << tE - tS << endl;
    }

    return 0;
}

我正在使用Xcode,并关闭了所有代码优化。根据这本书,我预计模板版本应该比简单循环更快。但结果是(t-模板,l=循环):
DIM 5:t = ~5000,l = ~3500
DIM 50:t = ~55000,l = 16000
DIM 100:t = 130000,l = 36000
我还尝试将模板函数设置为内联,但没有性能差异。
为什么简单循环会快得多呢?

5
"performance ... I turned all code optimisations off"(Jamie的声音)这就是问题所在! 翻译:您的代码性能有问题,我把所有的代码优化都关闭了。(杰米的声音)这就是您的问题所在! - avakar
3
你已经回答了自己的问题:"我关闭了所有代码优化"。如果dot_product的实例没有被内联,那么调用它们将比运行循环慢得多。 - Mike Seymour
3
性能测试的第一条规则是使用优化构建。第二条规则是不要在调试器中运行。还有许多其他规则。 - Skizz
还有一点需要注意:循环展开可以提高性能,但是过多的展开级别可能会破坏指令缓存。这是您正在深入探索的微调问题... - Matthieu M.
1个回答

5
根据编译器的不同,如果您不打开性能优化,循环展开可能不会发生。
很容易理解原因:递归模板实例化基本上创建了一系列函数。编译器无法将所有内容转换为内联的、展开的循环,并保持可用的合理调试信息。假设在其中一个函数内部发生段错误或抛出异常?您是否希望能够获取显示每个帧的堆栈跟踪?除非您打开优化并授权编译器对代码进行操作,否则编译器认为您可能需要这样做。

谢谢,我已经开启了优化,现在模板速度快多了。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接