C 内存性能/缓存难题
我有一个记忆性能难题。我正在尝试基准测试从主内存获取一个字节所需的时间,以及各种BIOS设置和内存硬件参数对它的影响。我为Windows编写了以下代码,在循环中,通过读取另一个缓冲区来刷新缓存,然后以不同的步幅每次读取一个字节的目标缓冲区。我想,一旦跨距是缓存线的大小,这就是我试图测量的数量,因为每次读取都会进入主内存。下面是基准代码(请注意,缓冲区的大小是跨步x1MB,我将线程固定到核心1): 以下是我的问题:C 内存性能/缓存难题,c,performance,cpu,cpu-cache,C,Performance,Cpu,Cpu Cache,我有一个记忆性能难题。我正在尝试基准测试从主内存获取一个字节所需的时间,以及各种BIOS设置和内存硬件参数对它的影响。我为Windows编写了以下代码,在循环中,通过读取另一个缓冲区来刷新缓存,然后以不同的步幅每次读取一个字节的目标缓冲区。我想,一旦跨距是缓存线的大小,这就是我试图测量的数量,因为每次读取都会进入主内存。下面是基准代码(请注意,缓冲区的大小是跨步x1MB,我将线程固定到核心1): 以下是我的问题: 为什么在跨距大于缓存线大小(Sandy Bridge为64字节)后,性能会继续下
- 为什么在跨距大于缓存线大小(Sandy Bridge为64字节)后,性能会继续下降?我假设,当跨步足够大,每次读取都需要缓存线传输时,性能会最差,但即使在这之后,时间也会增加两倍。。。我错过了什么
- 为什么最大时间(发生在循环的第一次迭代时)比最小时间长2-4倍?我每次迭代都刷新缓存
但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃
但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃
但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃
但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃
缓存线不是跟踪内存的唯一粒度。从虚拟地址到物理地址的转换发生在页面粒度上。您的系统几乎肯定使用4k页面 步幅为64时,每页有64个条目,因此有16384页。L2 TLB只能跟踪其中512个页面,因此在每个新页面上都会出现L2 TLB未命中(e
#include <stdio.h>
#include <memory.h>
#define NREAD (1024*1024)
#define CACHE_SIZE (50*1024*1024)
char readTest(int stride) {
LARGE_INTEGER frequency;
LARGE_INTEGER start;
LARGE_INTEGER end;
int rep, i,ofs;
double time, min_time=1e100, max_time=0.0, mean_time=0.0;
char *buf = (char *)malloc(NREAD*stride);
char *flusher = (char *)malloc(CACHE_SIZE);
char jnk=0;
for(rep=0; rep<255; rep++) {
// read the flusher to flush the cache
for(ofs = 0; ofs<CACHE_SIZE; ofs+=64) jnk+=flusher[ofs];
if (QueryPerformanceFrequency(&frequency) == FALSE) exit(-1);
if (QueryPerformanceCounter(&start) == FALSE) exit(-2);
// here's the timed loop
for(ofs=0; ofs<NREAD*stride; ofs+=stride) jnk += buf[ofs];
if (QueryPerformanceCounter(&end) == FALSE) exit(-3);
time = (double)(end.QuadPart - start.QuadPart) / (double)frequency.QuadPart*1e6;
max_time = time > max_time ? time : max_time;
min_time = time < min_time ? time : min_time;
mean_time += time;
}
mean_time /= 255;
printf("Stride = %4i, Max: %6.0f us, Min: %6.0f us, Mean: %6.0f us, B/W: %4.0f MB/s\n", stride, max_time, min_time, mean_time, NREAD/min_time);
free(buf);
free(flusher);
return jnk;
}
int main(int argc, char* argv[]) {
SetThreadAffinityMask(GetCurrentThread(), 1); // pin to core 1 to avoid weirdness
// run the tests
readTest(1); readTest(2); readTest(4); readTest(6); readTest(8);
readTest(12); readTest(16); readTest(24); readTest(32); readTest(48);
readTest(64); readTest(96); readTest(128); readTest(192); readTest(256);
readTest(384); readTest(512); readTest(768); readTest(1024); readTest(1536);
return 0;
}
// here's the timed loop
for(ofs=0; ofs<NREAD*stride; ofs+=stride) jnk += buf[ofs];
00F410AF xor eax,eax
00F410B1 test edi,edi
00F410B3 jle readTest+0C2h (0F410C2h)
00F410B5 mov edx,dword ptr [buf]
00F410B8 add bl,byte ptr [eax+edx]
00F410BB add eax,dword ptr [stride]
00F410BE cmp eax,edi
00F410C0 jl readTest+0B5h (0F410B5h)
Stride = 1, Max: 2362 us, Min: 937 us, Mean: 950 us, B/W: 1119 MB/s
Stride = 2, Max: 1389 us, Min: 968 us, Mean: 978 us, B/W: 1083 MB/s
Stride = 4, Max: 1694 us, Min: 1026 us, Mean: 1037 us, B/W: 1022 MB/s
Stride = 6, Max: 2418 us, Min: 1098 us, Mean: 1124 us, B/W: 955 MB/s
Stride = 8, Max: 2835 us, Min: 1234 us, Mean: 1252 us, B/W: 850 MB/s
Stride = 12, Max: 4203 us, Min: 1527 us, Mean: 1559 us, B/W: 687 MB/s
Stride = 16, Max: 5130 us, Min: 1816 us, Mean: 1849 us, B/W: 577 MB/s
Stride = 24, Max: 7370 us, Min: 2408 us, Mean: 2449 us, B/W: 435 MB/s
Stride = 32, Max: 10039 us, Min: 2901 us, Mean: 3014 us, B/W: 361 MB/s
Stride = 48, Max: 14248 us, Min: 4652 us, Mean: 4731 us, B/W: 225 MB/s
Stride = 64, Max: 19149 us, Min: 6340 us, Mean: 6447 us, B/W: 165 MB/s
Stride = 96, Max: 28848 us, Min: 8475 us, Mean: 8615 us, B/W: 124 MB/s
Stride = 128, Max: 37449 us, Min: 9900 us, Mean: 10160 us, B/W: 106 MB/s
Stride = 192, Max: 51718 us, Min: 11282 us, Mean: 11563 us, B/W: 93 MB/s
Stride = 256, Max: 62193 us, Min: 11558 us, Mean: 11924 us, B/W: 91 MB/s
Stride = 384, Max: 86943 us, Min: 11829 us, Mean: 12260 us, B/W: 89 MB/s
Stride = 512, Max: 108661 us, Min: 11847 us, Mean: 12401 us, B/W: 89 MB/s
Stride = 768, Max: 167951 us, Min: 11797 us, Mean: 12946 us, B/W: 89 MB/s
Stride = 1024, Max: 211700 us, Min: 12893 us, Mean: 13979 us, B/W: 81 MB/s
Stride = 1536, Max: 332214 us, Min: 12967 us, Mean: 15077 us, B/W: 81 MB/s