加法操作是如何加速此内存访问的
How is an addition operation speeding up this memory access?
我正在查看以下代码,在对其性能进行计时时发现了一些奇怪的事情。
为了记录在案,我在Visual Studio 2010、Windows 7 x64、-O2优化和发布模式下执行此操作。我的处理器是英特尔i5。
代码中有一个部分可以写入内存。我以前是这样做的:
d_res_matrix[x][y] = a;
在这种情况下,执行整个程序大约需要2.3秒
d_res_matrix[x][y] = a + 0.00000001;
它在0.4s内执行!这是一个巨大的差异,但我不确定为什么会发生这种情况。
对我来说,如果速度慢一点是有道理的,因为额外的加法运算需要时间。我想我的另一个假设是,做加法会以某种方式迫使编译器SIMD这个操作(获取、添加和写入?)。也许写入会以其他方式暂停管道,但这可以防止这种情况发生?有什么想法吗
编辑(4月6日,6:19):我的家用电脑(Visual Studio 2012)上也出现了同样的问题。
编辑(4月6日,6:38):此问题也存在于Visual Studio 2008(-O2,Release)中。在调试中,它们都很慢,但速度相同。
编辑(4月8日,1:28):我安装了Intel Parallel Studio XE(我是一名学生),它向我展示了很多好东西——首先,我从未真正删除过我声明的数组(我现在没有修复它,但请注意)。然而,释放内存实际上并没有解决任何问题。正如Richard在回答中概述的那样,整个问题是由非正规浮点值引起的(请参阅此处的更多信息)。FP单元无法正确处理非正规值,而是启动微码序列,这非常缓慢。
#include <time.h>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#define DIM 1000
#define ITERATIONS 100
#define CPU_START clock_t t1; t1=clock();
#define CPU_END {long int final=clock()-t1; printf("CPU took %li ticks (%f seconds) n", final, ((float)final)/CLOCKS_PER_SEC);}
int main(void)
{
double ** d_matrix, ** d_res_matrix;
d_res_matrix = new double * [DIM];
d_matrix = new double * [DIM];
for (int i = 0; i < DIM; i++)
{
d_matrix[i] = new double [DIM];
d_res_matrix[i] = new double[DIM];
}
d_matrix[20][45] = 1; // start somewhere
double f0, f1, f2, f3, f4;
CPU_START;
for (int iter = 0; iter < ITERATIONS; iter++)
{
for (int x = 1; x < DIM-1; x++) // avoid boundary cases for this example
{
for (int y = 1; y < DIM-1; y++)
{
f0 = d_matrix[x][y];
f1 = d_matrix[x-1][y];
f2 = d_matrix[x+1][y];
f3 = d_matrix[x][y-1];
f4 = d_matrix[x][y+1];
double a = f0*0.6 + f1*0.1 + f2*0.1 + f3*0.1 + f4*0.1;
// THIS PART IS INTERESTING:
//d_res_matrix[x][y] = a;
d_res_matrix[x][y] = a + 0.000000001;
}
}
for (int x = 1; x < DIM-1; x++)
{
for (int y = 1; y < DIM-1; y++)
{
d_matrix[x][y] = d_res_matrix[x][y];
}
}
}
CPU_END;
return 0;
}
下面是输出的一些屏幕截图,以表明这不是一次发生:没有更多屏幕截图:D:D:D:D:D下面是一些文本!
无添加:
CPU took 3585 ticks <3.585000 seconds>
CPU took 3592 ticks <3.592000 seconds>
CPU took 3430 ticks <3.430000 seconds>
CPU took 2032 ticks <2.032000 seconds>
CPU took 3117 ticks <3.117000 seconds>
CPU took 2050 ticks <2.050000 seconds>
CPU took 3266 ticks <3.266000 seconds>
CPU took 3394 ticks <3.394000 seconds>
CPU took 3446 ticks <3.446000 seconds>
CPU took 3131 ticks <3.131000 seconds>
添加:
CPU took 430 ticks <0.430000 seconds>
CPU took 428 ticks <0.428000 seconds>
CPU took 470 ticks <0.470000 seconds>
CPU took 470 ticks <0.470000 seconds>
CPU took 470 ticks <0.470000 seconds>
CPU took 470 ticks <0.470000 seconds>
CPU took 460 ticks <0.460000 seconds>
CPU took 471 ticks <0.471000 seconds>
CPU took 471 ticks <0.471000 seconds>
CPU took 460 ticks <0.460000 seconds>
您可能在第一次运行时生成了非规范化,添加会避免这种情况。这些非标准化的后续操作可能会非常昂贵。在调试模式下,您的数据将被0初始化,但这在发布时不会发生,因此您正在操作的值可以是任何值。如果在分配d_matrix之后显式地将其memset为0,那么如果您仍然看到这种行为,我会感到惊讶。
- 将字符串存储在c++中的稳定内存中
- 加速C++练习2.4
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 使用加速进程间创建消息队列 - 内存访问冲突
- 加速进程间:管理共享内存错误
- 加速共享内存操作c++
- 加速 asio 中的内存泄漏
- 加法操作是如何加速此内存访问的
- C++:加速进程间内存映射文件错误
- 无法初始化加速共享内存
- (加速C++)章节管理内存