哪些因素会影响这些操作的性能?可能是编译器和编译器版本;但是操作系统或 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 是否有任何现有的基准测试结果?
可能,但我不知道。即使有,它也只会对您有点意义,因为操作的组合对操作速度非常关键。
如果性能是您的应用程序的重要组成部分,那么对您的代码(或其中的一些代表性部分)进行基准测试。如果您的代码在相同情况下速度慢或快一些完全不同的量,Benchmark 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()
{
// spin up CPU to full speed...
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 位上它更快吗?我听到你们中的一些人问:使用相同的编译器选项,只需 -m64 而不是 -m32 - yupp,更快:
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 位中编译 no-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 --std=c++11 -O2
$ ./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 --std=c++11 -O2
$ ./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 --std=c++11 -O2
$ ./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 --std=c++11 -O2
$ ./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