C++中原始类型比用户自定义类型慢吗?

3
我很好奇并做了一个小基准测试来确定原始类型(如 intfloat)和用户自定义类型之间的性能差异。
我创建了一个模板类 Var,创建了一些内联算术运算符。测试包括对原始类型和 Var 向量执行此循环:
for (unsigned i = 0; i < 1000; ++i) {
    in1[i] = i;
    in2[i] = -i;
    out[i] = (i % 2) ? in1[i] + in2[i] : in2[i] - in1[i];
}

我对结果感到非常惊讶,发现我的 Var 类在大多数情况下比 int 更快,平均循环时间减少了约 5700 纳秒。在 3000 次运行中,int 比 Var 快 11 次,而 Var 比 int 快 2989 次。在使用 float 时也有类似的结果,Var 比 float 快 15100 纳秒,在 2991 次运行中更快。

难道原始类型不应该更快吗?

编辑:编译器是 rather ancient mingw 4.4.0,构建选项是 QtCreator 的默认选项,没有进行优化。

qmake call: qmake.exe C:\...\untitled15.pro -r -spec win32-g++ "CONFIG+=release"

好的,发布完整源代码,平台为64位Win7,4 GB DDR2-800,Core2Duo @ 3Ghz。

#include <QTextStream>
#include <QVector>
#include <QElapsedTimer>

template<typename T>
class Var{
public:
    Var() {}
    Var(T val) : var(val) {}

    inline T operator+(Var& other)
    {
        return var + other.value();
    }

    inline T operator-(Var& other)
    {
        return var - other.value();
    }

    inline T operator+(T& other)
    {
        return var + other;
    }

    inline T operator-(T& other)
    {
        return var - other;
    }

    inline void operator=(T& other)
    {
        var = other;
    }

    inline T& value()
    {
        return var;
    }

private:
    T var;
};

int main()
{
    QTextStream cout(stdout);
    QElapsedTimer timer;

    unsigned count = 1000000;

    QVector<double> pin1(count), pin2(count), pout(count);
    QVector<Var<double> > vin1(count), vin2(count), vout(count);

    unsigned t1, t2, pAcc = 0, vAcc = 0, repeat = 10, pcount = 0, vcount = 0, ecount = 0;
    for (int cc = 0; cc < 5; ++cc)
    {
        for (unsigned c = 0; c < repeat; ++c)
        {
            timer.restart();
            for (unsigned i = 0; i < count; ++i)
            {
                pin1[i] = i;
                pin2[i] = -i;
                pout[i] = (i % 2) ? pin1[i] + pin2[i] : pin2[i] - pin1[i];
            }
            t1 = timer.nsecsElapsed();
            cout << t1 << endl;

            timer.restart();
            for (unsigned i = 0; i < count; ++i)
            {
                vin1[i] = i;
                vin2[i] = -i;
                vout[i] = (i % 2) ? vin1[i] + vin2[i] : vin2[i] - vin1[i];
            }
            t2 = timer.nsecsElapsed();
            cout << t2 << endl;;
            pAcc += t1;
            vAcc += t2;
        }

        pAcc /= repeat;
        vAcc /= repeat;
        if (pAcc < vAcc) {
            cout << "primitive was faster" << endl;
            pcount++;
        }
        else if (pAcc > vAcc) {
            cout << "var was faster" << endl;
            vcount++;
        }
        else {
            cout << "amazingly, both are equally fast" << endl;
            ecount++;
        }

        cout << "Average for primitive type is " << pAcc << ", average for Var is " << vAcc << endl;

    }
    cout << "int was faster " << pcount << " times, var was faster " << vcount << " times, equal " << ecount << " times, " << pcount + vcount + ecount << " times ran total" << endl;
}

相对而言,使用类Var比使用floats快6-7%,使用int约为3%。
我还将测试向量长度从原始的1000增加到1000万,并且结果仍然一致并且更有利于使用类。

4
请添加编译器和构建选项。还有Var的实现方式。 - Forgottn
3
并比较汇编代码。 - RolandXu
6
根据度量的方式不同,这个循环可能运行时间太短,无法产生精确或可重复的性能数据。 - Peter G.
4
你是否在计算数组的声明时间?你的类版本会在构造函数中将每个值都清零,但 POD 类型不会这样做。这会将内存加载到高速缓存中,因此后续循环的执行速度会更快。尝试在计时循环之外将 POD 数组设置为 0,以获得一个等效的测试案例。 - Peter
3
为什么会有人在没有优化的情况下尝试进行性能分析? - Chad
显示剩余16条评论
2个回答

2
使用std::vector替换QVector后,在-O2优化级别下,由GCC生成的两种类型的代码完全相同,每个指令都一样。
如果不进行替换,则生成的代码不同,但这并不奇怪,考虑到对于基本类型和非基本类型,QtVector的实现方式是不同的(请查看qvector.h中的QTypeInfo<T> ::isComplex)。 更新: 看起来isComplex不影响内部oop,即被测量部分。尽管两种类型的循环代码略有不同,但似乎差异是由GCC引起的。

我已经使用std::vector和原始的C风格数组进行了测试,使用标准向量性能略微偏向于原始类型,而使用原始数组则情况相反。 - dtech

0

我对 QVector 和 float* 的运行时间和内存分配进行了基准测试,两者之间的差异非常小


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