x86 和 x86_64 中 float 和 double 的性能差异
Performance difference between float and double in x86 and x86_64
前段时间听说一些编译器使用SSE2扩展来进行x86_64架构的浮点运算,所以我用这个简单的代码来确定它们之间的性能差异。
我通过 BIOS 禁用了 Intel SpeedStep 技术,系统负载在我的测试中大致相等。我在 OpenSuSE 64 位上使用 GCC 4.8。
我正在编写一个包含大量 FPU 操作的程序,我想知道这个测试是否有效?
关于每种体系结构下 float
和 double
之间的性能差异的任何信息,我们将不胜感激。
代码:
#include <iostream>
#include <sys/time.h>
#include <vector>
#include <cstdlib>
using namespace std;
int main()
{
timeval t1, t2;
double elapsedTime;
double TotalTime = 0;
for(int j=0 ; j < 100 ; j++)
{
// start timer
gettimeofday(&t1, NULL);
vector<float> RealVec;
float temp;
for (int i = 0; i < 1000000; i++)
{
temp = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX));
RealVec.push_back(temp);
}
for (int i = 0; i < 1000000; i++)
{
RealVec[i] = (RealVec[i]*2-435.345345)/15.75;
}
// stop timer
gettimeofday(&t2, NULL);
elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms
elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms
TotalTime = TotalTime + elapsedTime;
}
cout << TotalTime/100 << " ms.\n";
return 0;
}
结果:
32 位双精度
157.781 毫秒。
151.994 毫秒。
152.244 毫秒
32 位浮点数
149.896 毫秒。
148.489 毫秒。
161.086 毫秒
64 位双精度
110.125 毫秒。
111.612 毫秒。
113.818 毫秒
64 位浮点数
110.393 毫秒。
106.778 毫秒。
107.833 毫秒
不是真的有效。您基本上是在测试随机数生成器的性能。
此外,您并没有尝试强制执行 SSE2 SIMD 操作,因此您不能真正声称这比较了与 SSE 相关的任何内容。
在什么意义上有效?
使用您的实际代码衡量实际使用情况。
一些人工测试套件可能无法帮助您评估性能特征。
您可以使用 typedef
,然后轻按开关更改实际的基础类型。
你真的没测多少;也许只是编译器的程度
优化。为了使测量有效,你真的
必须对结果做些什么,否则编译器可以优化掉
全部或测试的主要部分。我要做的是 1) 初始化
向量,2) 获取开始时间(可能使用 clock
,因为那
只考虑 CPU 时间), 3) 执行第二个循环 a 100 (或
更多......足以持续几秒钟,至少)次,4)得到
结束时间,最后,5)输出向量中元素的和。
关于您可能会发现的差异:独立于
浮点处理器,64位机器有更多的通用寄存器
供编译器使用。这可能会产生巨大的影响。
除非你看生成的汇编器,否则你根本不知道。
前段时间听说一些编译器使用SSE2扩展来进行x86_64架构的浮点运算,所以我用这个简单的代码来确定它们之间的性能差异。
我通过 BIOS 禁用了 Intel SpeedStep 技术,系统负载在我的测试中大致相等。我在 OpenSuSE 64 位上使用 GCC 4.8。
我正在编写一个包含大量 FPU 操作的程序,我想知道这个测试是否有效?
关于每种体系结构下 float
和 double
之间的性能差异的任何信息,我们将不胜感激。
代码:
#include <iostream>
#include <sys/time.h>
#include <vector>
#include <cstdlib>
using namespace std;
int main()
{
timeval t1, t2;
double elapsedTime;
double TotalTime = 0;
for(int j=0 ; j < 100 ; j++)
{
// start timer
gettimeofday(&t1, NULL);
vector<float> RealVec;
float temp;
for (int i = 0; i < 1000000; i++)
{
temp = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX));
RealVec.push_back(temp);
}
for (int i = 0; i < 1000000; i++)
{
RealVec[i] = (RealVec[i]*2-435.345345)/15.75;
}
// stop timer
gettimeofday(&t2, NULL);
elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms
elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms
TotalTime = TotalTime + elapsedTime;
}
cout << TotalTime/100 << " ms.\n";
return 0;
}
结果:
32 位双精度
157.781 毫秒。 151.994 毫秒。 152.244 毫秒
32 位浮点数
149.896 毫秒。 148.489 毫秒。 161.086 毫秒
64 位双精度
110.125 毫秒。 111.612 毫秒。 113.818 毫秒
64 位浮点数
110.393 毫秒。 106.778 毫秒。 107.833 毫秒
不是真的有效。您基本上是在测试随机数生成器的性能。
此外,您并没有尝试强制执行 SSE2 SIMD 操作,因此您不能真正声称这比较了与 SSE 相关的任何内容。
在什么意义上有效?
使用您的实际代码衡量实际使用情况。
一些人工测试套件可能无法帮助您评估性能特征。
您可以使用 typedef
,然后轻按开关更改实际的基础类型。
你真的没测多少;也许只是编译器的程度
优化。为了使测量有效,你真的
必须对结果做些什么,否则编译器可以优化掉
全部或测试的主要部分。我要做的是 1) 初始化
向量,2) 获取开始时间(可能使用 clock
,因为那
只考虑 CPU 时间), 3) 执行第二个循环 a 100 (或
更多......足以持续几秒钟,至少)次,4)得到
结束时间,最后,5)输出向量中元素的和。
关于您可能会发现的差异:独立于 浮点处理器,64位机器有更多的通用寄存器 供编译器使用。这可能会产生巨大的影响。 除非你看生成的汇编器,否则你根本不知道。