我遇到了奇怪的内存访问性能问题,有什么想法吗?
int* pixel_ptr = somewhereFromHeap;
int local_ptr[307200]; //local
//this is very slow
for(int i=0;i<307200;i++){
pixel_ptr[i] = someCalculatedVal ;
}
//this is very slow
for(int i=0;i<307200;i++){
pixel_ptr[i] = 1 ; //constant
}
//this is fast
for(int i=0;i<307200;i++){
int val = pixel_ptr[i];
local_ptr[i] = val;
}
//this is fast
for(int i=0;i<307200;i++){
local_ptr[i] = someCalculatedVal ;
}
尝试将值合并到本地扫描线
int scanline[640]; // local
//this is very slow
for(int i=xMin;i<xMax;i++){
int screen_pos = sy*screen_width+i;
int val = scanline[i];
pixel_ptr[screen_pos] = val ;
}
//this is fast
for(int i=xMin;i<xMax;i++){
int screen_pos = sy*screen_width+i;
int val = scanline[i];
pixel_ptr[screen_pos] = 1 ; //constant
}
//this is fast
for(int i=xMin;i<xMax;i++){
int screen_pos = sy*screen_width+i;
int val = i; //or a constant
pixel_ptr[screen_pos] = val ;
}
//this is slow
for(int i=xMin;i<xMax;i++){
int screen_pos = sy*screen_width+i;
int val = scanline[0];
pixel_ptr[screen_pos] = val ;
}
有什么想法吗?我使用mingw和cflags -01 -std = c ++ 11 -fpermissive。
UPDATE4: 我不得不说这些是我程序中的代码片段,并且前后都有大量的代码/函数在运行。扫描线块在退出前确实在功能结束时运行。
现在有适当的测试程序。请问@Iwillnotexist。
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#define SIZE 307200
#define SAMPLES 1000
double local_test(){
int local_array[SIZE];
timeval start, end;
long cpu_time_used_sec,cpu_time_used_usec;
double cpu_time_used;
gettimeofday(&start, NULL);
for(int i=0;i<SIZE;i++){
local_array[i] = i;
}
gettimeofday(&end, NULL);
cpu_time_used_sec = end.tv_sec- start.tv_sec;
cpu_time_used_usec = end.tv_usec- start.tv_usec;
cpu_time_used = cpu_time_used_sec*1000 + cpu_time_used_usec/1000.0;
return cpu_time_used;
}
double heap_test(){
int* heap_array=new int[SIZE];
timeval start, end;
long cpu_time_used_sec,cpu_time_used_usec;
double cpu_time_used;
gettimeofday(&start, NULL);
for(int i=0;i<SIZE;i++){
heap_array[i] = i;
}
gettimeofday(&end, NULL);
cpu_time_used_sec = end.tv_sec- start.tv_sec;
cpu_time_used_usec = end.tv_usec- start.tv_usec;
cpu_time_used = cpu_time_used_sec*1000 + cpu_time_used_usec/1000.0;
delete[] heap_array;
return cpu_time_used;
}
double heap_test2(){
static int* heap_array = NULL;
if(heap_array==NULL){
heap_array = new int[SIZE];
}
timeval start, end;
long cpu_time_used_sec,cpu_time_used_usec;
double cpu_time_used;
gettimeofday(&start, NULL);
for(int i=0;i<SIZE;i++){
heap_array[i] = i;
}
gettimeofday(&end, NULL);
cpu_time_used_sec = end.tv_sec- start.tv_sec;
cpu_time_used_usec = end.tv_usec- start.tv_usec;
cpu_time_used = cpu_time_used_sec*1000 + cpu_time_used_usec/1000.0;
return cpu_time_used;
}
int main (int argc, char** argv){
double cpu_time_used = 0;
for(int i=0;i<SAMPLES;i++)
cpu_time_used+=local_test();
printf("local: %f ms\n",cpu_time_used);
cpu_time_used = 0;
for(int i=0;i<SAMPLES;i++)
cpu_time_used+=heap_test();
printf("heap_: %f ms\n",cpu_time_used);
cpu_time_used = 0;
for(int i=0;i<SAMPLES;i++)
cpu_time_used+=heap_test2();
printf("heap2: %f ms\n",cpu_time_used);
}
没有优化。
local:577.201000 ms
heap_:826.802000 ms
heap2:686.401000 ms
使用new和delete进行的第一次堆测试速度慢了2倍。 (按建议分页?)
具有重用堆数组的第二个堆仍然慢1.2倍。 但我想第二次测试并不实用,因为至少在我的情况下,往往会运行其他代码。对于我的情况,我的pixel_ptr当然只分配了一次 prograim初始化。
但如果有人有解决方案/想法加快速度,请回复!
我仍然感到困惑,为什么堆写入比堆栈段慢得多。 当然必须有一些技巧来使堆更多cpu / cache可以调味。
最终更新?:
我再次访问,这次再次拆卸,突然间,我知道为什么我的一些断点 不要激活。程序看起来很短,因此我怀疑编译器可能 已经删除了我放入的冗余虚拟代码,这解释了为什么本地数组神奇地快了很多倍。
答案 0 :(得分:3)
我有点好奇所以我做了测试,实际上我可以衡量堆栈和堆访问之间的区别。
第一个猜测是生成的程序集是不同的,但看了之后,堆和堆栈实际上是相同的(这是有道理的,内存不应该被区分)。
如果程序集相同,那么差异必须来自paging mechanism。猜测是在堆栈上,页面已经被分配,但是在堆上,第一次访问会导致页面错误和页面分配(不可见,这一切都发生在内核级别)。为了验证这一点,我做了相同的测试,但首先我会在测量之前访问堆。测试给出了堆栈和堆的相同时间。可以肯定的是,我还做了一个测试,我首先访问了堆,但只有每4096个字节(每1024个int),然后是8192,因为一个页面通常是4096个字节长。结果是,每次只访问4096个字节也会为堆和堆栈提供相同的时间,但访问每个8192会产生差异,但不会像以前没有访问那么多。这是因为事先只有一半的页面被访问和分配。
所以答案是在堆栈上已经分配了内存页面,但是在堆上,页面是即时分配的。这取决于操作系统分页策略,但所有主要的PC操作系统可能都有类似的操作系统。
对于我使用Windows的所有测试,使用MS编译器定位x64。
编辑:对于测试,我测量了一个更大的循环,因此每个内存位置只有一个访问权限。 delete
数组并多次测量相同的循环应该给堆栈和堆提供相似的时间,因为delete
内存可能不会取消分配页面,并且它们已经分配给下一个循环(如果在同一空间分配下一个new
)。
答案 1 :(得分:0)
以下两个代码示例在运行时应该与良好的编译器设置不同。可能你的编译器会生成相同的代码:
//this is fast
for(int i=0;i<307200;i++){
int val = pixel_ptr[i];
local_ptr[i] = val;
}
//this is fast
for(int i=0;i<307200;i++){
local_ptr[i] = pixel_ptr[i];
}
请尝试增加优化设置。