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

我还尝试使模板函数内联而没有性能差异。

为什么简单循环这么快?

4

1 回答 1

5

根据编译器的不同,如果您不打开性能优化,可能不会发生循环展开。

原因很容易理解:您的递归模板实例化基本上是在创建一系列函数。编译器无法将所有这些都变成内联的展开循环,并且仍然保持可用的合理调试信息。假设在您的某个函数中某处发生了段错误,或者抛出了异常?您不想获得显示每一帧的堆栈跟踪吗?编译器认为您可能想要这样,除非您打开优化,这使您的编译器可以访问您的代码。

于 2012-04-13T14:22:20.240 回答