哪些因素影响这些操作的性能? 可能是编译器和编译器版本; 但操作系统或CPU型号是否也会产生影响呢?
主要是处理器架构(和型号-在本节中提到处理器架构时请阅读型号)。编译器可能会有一些影响,但大多数编译器在此方面表现良好,因此处理器架构的影响将比编译器更大。
操作系统将完全没有影响(除了“如果您更改操作系统,则需要使用不同类型的编译器,这会改变编译器所做的事情”在某些情况下 - 但这可能是一个小效应)。
普通32位系统会使用现代CPU的64位寄存器吗?
这是不可能的。如果系统处于32位模式下,它将作为32位系统运行,寄存器的额外32位完全不可见,就像它实际上是“真正的32位系统”一样。
在32位模拟时,哪些操作将特别缓慢?或者哪些几乎不会减速?
加法和减法,由于这些必须按两个操作序列执行,并且第二个操作需要第一个操作已完成-如果编译器只是在独立数据上生成两个添加操作,则情况并非如此。
如果输入参数实际上是64位,则乘法将变得更糟 - 因此,2 ^ 35 * 83比2 ^ 31 * 2 ^ 31更糟。这是由于处理器可以将32 x 32位乘法产生为64位结果-大约需要5-10个时钟周期。但是,64 x 64位乘法需要相当多的额外代码,因此需要更长时间。
除法与乘法类似-但在这里,从一侧取一个64位输入,将其除以32位值并获得32位值是可以的。由于很难预测何时会起作用,所以64位除法几乎总是很慢的。
数据也将占用两倍的缓存空间,这可能会影响结果。同样的后果是,通常分配和传递数据将至少需要两倍的时间,因为有两倍的数据要操作。
编译器还需要使用更多寄存器。
是否有使用32位系统上的int64_t / uint64_t的现有基准结果?
可能有,但我不知道。即使有,它对您来说也仅略具意义,因为操作的混合方式极其关键。
如果性能是您的应用程序中重要的部分,那么请对您的代码(或其中一部分代表性代码)进行基准测试。如果在相同情况下,您的代码比基准测试X慢或快了完全不同的数量级,那么基准测试X给出的5%、25%或103%的结果都不重要。
有人有关于性能影响的个人经验吗?
我重新编译了一些使用64位整数的代码,用于64位架构,并发现某些代码段的性能提高了相当多——在某些代码段上提高了高达25%。
将操作系统更改为同一操作系统的64位版本会有所帮助吗?
编辑:
因为我喜欢找出这些事情的区别,所以我写了一些代码,并使用一些原始模板(我还在学习模板-模板并不是我的最热门话题,我必须说-给我一点位操作和指针算术,我通常会做得很好……)
以下是我编写的代码,试图复制几个常见函数:
#include <iostream>
#include <cstdint>
#include <ctime>
using namespace std;
static __inline__ uint64_t rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
}
template<typename T>
static T add_numbers(const T *v, const int size)
{
T sum = 0;
for(int i = 0; i < size; i++)
sum += v[i];
return sum;
}
template<typename T, const int size>
static T add_matrix(const T v[size][size])
{
T sum[size] = {};
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
sum[i] += v[i][j];
}
T tsum=0;
for(int i = 0; i < size; i++)
tsum += sum[i];
return tsum;
}
template<typename T>
static T add_mul_numbers(const T *v, const T mul, const int size)
{
T sum = 0;
for(int i = 0; i < size; i++)
sum += v[i] * mul;
return sum;
}
template<typename T>
static T add_div_numbers(const T *v, const T mul, const int size)
{
T sum = 0;
for(int i = 0; i < size; i++)
sum += v[i] / mul;
return sum;
}
template<typename T>
void fill_array(T *v, const int size)
{
for(int i = 0; i < size; i++)
v[i] = i;
}
template<typename T, const int size>
void fill_array(T v[size][size])
{
for(int i = 0; i < size; i++)
for(int j = 0; j < size; j++)
v[i][j] = i + size * j;
}
uint32_t bench_add_numbers(const uint32_t v[], const int size)
{
uint32_t res = add_numbers(v, size);
return res;
}
uint64_t bench_add_numbers(const uint64_t v[], const int size)
{
uint64_t res = add_numbers(v, size);
return res;
}
uint32_t bench_add_mul_numbers(const uint32_t v[], const int size)
{
const uint32_t c = 7;
uint32_t res = add_mul_numbers(v, c, size);
return res;
}
uint64_t bench_add_mul_numbers(const uint64_t v[], const int size)
{
const uint64_t c = 7;
uint64_t res = add_mul_numbers(v, c, size);
return res;
}
uint32_t bench_add_div_numbers(const uint32_t v[], const int size)
{
const uint32_t c = 7;
uint32_t res = add_div_numbers(v, c, size);
return res;
}
uint64_t bench_add_div_numbers(const uint64_t v[], const int size)
{
const uint64_t c = 7;
uint64_t res = add_div_numbers(v, c, size);
return res;
}
template<const int size>
uint32_t bench_matrix(const uint32_t v[size][size])
{
uint32_t res = add_matrix(v);
return res;
}
template<const int size>
uint64_t bench_matrix(const uint64_t v[size][size])
{
uint64_t res = add_matrix(v);
return res;
}
template<typename T>
void runbench(T (*func)(const T *v, const int size), const char *name, T *v, const int size)
{
fill_array(v, size);
uint64_t long t = rdtsc();
T res = func(v, size);
t = rdtsc() - t;
cout << "result = " << res << endl;
cout << name << " time in clocks " << dec << t << endl;
}
template<typename T, const int size>
void runbench2(T (*func)(const T v[size][size]), const char *name, T v[size][size])
{
fill_array(v);
uint64_t long t = rdtsc();
T res = func(v);
t = rdtsc() - t;
cout << "result = " << res << endl;
cout << name << " time in clocks " << dec << t << endl;
}
int main()
{
time_t t = time(NULL);
while(t == time(NULL)) ;
const int vsize=10000;
uint32_t v32[vsize];
uint64_t v64[vsize];
uint32_t m32[100][100];
uint64_t m64[100][100];
runbench(bench_add_numbers, "Add 32", v32, vsize);
runbench(bench_add_numbers, "Add 64", v64, vsize);
runbench(bench_add_mul_numbers, "Add Mul 32", v32, vsize);
runbench(bench_add_mul_numbers, "Add Mul 64", v64, vsize);
runbench(bench_add_div_numbers, "Add Div 32", v32, vsize);
runbench(bench_add_div_numbers, "Add Div 64", v64, vsize);
runbench2(bench_matrix, "Matrix 32", m32);
runbench2(bench_matrix, "Matrix 64", m64);
}
编译版本:
g++ -Wall -m32 -O3 -o 32vs64 32vs64.cpp -std=c++0x
结果如下:注意:请参见以下2016年的结果 - 由于64位模式下使用SSE指令的差异,这些结果略为乐观,但在32位模式下未使用SSE。
result = 49995000
Add 32 time in clocks 20784
result = 49995000
Add 64 time in clocks 30358
result = 349965000
Add Mul 32 time in clocks 30182
result = 349965000
Add Mul 64 time in clocks 79081
result = 7137858
Add Div 32 time in clocks 60167
result = 7137858
Add Div 64 time in clocks 457116
result = 49995000
Matrix 32 time in clocks 22831
result = 49995000
Matrix 64 time in clocks 23823
正如您所看到的,加法和乘法并没有那么糟糕。除法则变得非常糟糕。有趣的是,矩阵加法几乎没有什么区别。
还有一些人问,64位是否更快:
使用相同的编译器选项,只需将-m32替换为-m64 - 是的,快了很多:
result = 49995000
Add 32 time in clocks 8366
result = 49995000
Add 64 time in clocks 16188
result = 349965000
Add Mul 32 time in clocks 15943
result = 349965000
Add Mul 64 time in clocks 35828
result = 7137858
Add Div 32 time in clocks 50176
result = 7137858
Add Div 64 time in clocks 50472
result = 49995000
Matrix 32 time in clocks 12294
result = 49995000
Matrix 64 time in clocks 14733
编辑,更新至2016年:编译器有四个变体,分为32位和64位模式,有无SSE。
最近我通常使用clang++作为我的编译器。我尝试使用g++进行编译(但它仍然与上述版本不同,因为我已经更新了我的机器 - 我也有不同的CPU)。由于g++在64位中无法编译无SSE版本,所以我认为这没有意义。(g++给出的结果也相似)
简短的表格如下:
Test name | no-sse 32 | no-sse 64 | sse 32 | sse 64 |
----------------------------------------------------------
Add uint32_t | 20837 | 10221 | 3701 | 3017 |
----------------------------------------------------------
Add uint64_t | 18633 | 11270 | 9328 | 9180 |
----------------------------------------------------------
Add Mul 32 | 26785 | 18342 | 11510 | 11562 |
----------------------------------------------------------
Add Mul 64 | 44701 | 17693 | 29213 | 16159 |
----------------------------------------------------------
Add Div 32 | 44570 | 47695 | 17713 | 17523 |
----------------------------------------------------------
Add Div 64 | 405258 | 52875 | 405150 | 47043 |
----------------------------------------------------------
Matrix 32 | 41470 | 15811 | 21542 | 8622 |
----------------------------------------------------------
Matrix 64 | 22184 | 15168 | 13757 | 12448 |
带编译选项的完整结果。
$ clang++ -m32 -mno-sse 32vs64.cpp
$ ./a.out
result = 49995000
Add 32 time in clocks 20837
result = 49995000
Add 64 time in clocks 18633
result = 349965000
Add Mul 32 time in clocks 26785
result = 349965000
Add Mul 64 time in clocks 44701
result = 7137858
Add Div 32 time in clocks 44570
result = 7137858
Add Div 64 time in clocks 405258
result = 49995000
Matrix 32 time in clocks 41470
result = 49995000
Matrix 64 time in clocks 22184
$ clang++ -m32 -msse 32vs64.cpp
$ ./a.out
result = 49995000
Add 32 time in clocks 3701
result = 49995000
Add 64 time in clocks 9328
result = 349965000
Add Mul 32 time in clocks 11510
result = 349965000
Add Mul 64 time in clocks 29213
result = 7137858
Add Div 32 time in clocks 17713
result = 7137858
Add Div 64 time in clocks 405150
result = 49995000
Matrix 32 time in clocks 21542
result = 49995000
Matrix 64 time in clocks 13757
$ clang++ -m64 -msse 32vs64.cpp
$ ./a.out
result = 49995000
Add 32 time in clocks 3017
result = 49995000
Add 64 time in clocks 9180
result = 349965000
Add Mul 32 time in clocks 11562
result = 349965000
Add Mul 64 time in clocks 16159
result = 7137858
Add Div 32 time in clocks 17523
result = 7137858
Add Div 64 time in clocks 47043
result = 49995000
Matrix 32 time in clocks 8622
result = 49995000
Matrix 64 time in clocks 12448
$ clang++ -m64 -mno-sse 32vs64.cpp
$ ./a.out
result = 49995000
Add 32 time in clocks 10221
result = 49995000
Add 64 time in clocks 11270
result = 349965000
Add Mul 32 time in clocks 18342
result = 349965000
Add Mul 64 time in clocks 17693
result = 7137858
Add Div 32 time in clocks 47695
result = 7137858
Add Div 64 time in clocks 52875
result = 49995000
Matrix 32 time in clocks 15811
result = 49995000
Matrix 64 time in clocks 15168