【发布时间】:2015-01-08 06:21:26
【问题描述】:
我遇到了奇怪的内存访问性能问题,有什么想法吗?
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 ;
}
有什么想法吗?我正在使用带有 cflags -01 -std=c++11 -fpermissive 的 mingw。
更新4: 我不得不说这些是我程序中的 sn-ps,并且在之前和之后运行了大量的代码/函数。扫描线块确实在退出之前在函数末尾运行。
现在有了适当的测试程序。感谢@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);
}
符合但没有优化。
本地:577.201000 毫秒
堆_:826.802000 毫秒
heap2:686.401000 毫秒
使用 new 和 delete 的第一个堆测试慢 2 倍。 (按建议分页?)
具有重用堆数组的第二个堆仍然慢 1.2 倍。 但我想第二个测试并不那么实用,因为至少在我的情况下,之前和之后都会运行其他代码。就我而言,我的 pixel_ptr 当然只在 程序初始化。
但如果有人有加快速度的解决方案/想法,请回复!
我仍然很困惑为什么堆写入比堆栈段慢得多。 肯定有一些技巧可以让堆更有 cpu/cache 的味道。
最终更新?:
我重新访问,再次拆卸,这一次,我突然知道为什么我的一些断点 不要激活。该程序看起来很短,因此我怀疑编译器可能 已经删除了我放入的冗余虚拟代码,这解释了为什么本地数组神奇地快了很多倍。
【问题讨论】:
-
请解释一下奇怪的内存访问性能问题..
-
为什么只有
-O1?试试-O2或-O3? -
“慢”有多慢?
-
您应该将测试代码放在外部循环中并忽略第一次迭代,因为您可能只是看到与缓存相关的性能问题。
标签: c++ arrays performance