Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 内存性能/缓存难题_C_Performance_Cpu_Cpu Cache - Fatal编程技术网

C 内存性能/缓存难题

C 内存性能/缓存难题,c,performance,cpu,cpu-cache,C,Performance,Cpu,Cpu Cache,我有一个记忆性能难题。我正在尝试基准测试从主内存获取一个字节所需的时间,以及各种BIOS设置和内存硬件参数对它的影响。我为Windows编写了以下代码,在循环中,通过读取另一个缓冲区来刷新缓存,然后以不同的步幅每次读取一个字节的目标缓冲区。我想,一旦跨距是缓存线的大小,这就是我试图测量的数量,因为每次读取都会进入主内存。下面是基准代码(请注意,缓冲区的大小是跨步x1MB,我将线程固定到核心1): 以下是我的问题: 为什么在跨距大于缓存线大小(Sandy Bridge为64字节)后,性能会继续下

我有一个记忆性能难题。我正在尝试基准测试从主内存获取一个字节所需的时间,以及各种BIOS设置和内存硬件参数对它的影响。我为Windows编写了以下代码,在循环中,通过读取另一个缓冲区来刷新缓存,然后以不同的步幅每次读取一个字节的目标缓冲区。我想,一旦跨距是缓存线的大小,这就是我试图测量的数量,因为每次读取都会进入主内存。下面是基准代码(请注意,缓冲区的大小是跨步x1MB,我将线程固定到核心1):

以下是我的问题:

  • 为什么在跨距大于缓存线大小(Sandy Bridge为64字节)后,性能会继续下降?我假设,当跨步足够大,每次读取都需要缓存线传输时,性能会最差,但即使在这之后,时间也会增加两倍。。。我错过了什么
  • 为什么最大时间(发生在循环的第一次迭代时)比最小时间长2-4倍?我每次迭代都刷新缓存
  • 由于预取,在缓存线大小达到一定值后,性能会继续下降——只要您以稳定的速度跨过缓存线(甚至跨过缓存线),您就会享受到硬件预取器在接下来的几行中带来的好处。L2拖缆特别有用,因为它会比您的访问流运行得更快。
    但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
    为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃

  • 我相信,由于TLB较冷,您的第一次迭代时间较长。您可以通过尝试刷新(硬…)或运行预热迭代并仅从第二次测量来测试这一点

  • 由于预取,在缓存线大小达到一定值后,性能会继续下降——只要您以稳定的速度跨过缓存线(甚至跨过缓存线),您就会享受到硬件预取器在接下来的几行中带来的好处。L2拖缆特别有用,因为它会比您的访问流运行得更快。
    但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
    为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃

  • 我相信,由于TLB较冷,您的第一次迭代时间较长。您可以通过尝试刷新(硬…)或运行预热迭代并仅从第二次测量来测试这一点

  • 由于预取,在缓存线大小达到一定值后,性能会继续下降——只要您以稳定的速度跨过缓存线(甚至跨过缓存线),您就会享受到硬件预取器在接下来的几行中带来的好处。L2拖缆特别有用,因为它会比您的访问流运行得更快。
    但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
    为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃

  • 我相信,由于TLB较冷,您的第一次迭代时间较长。您可以通过尝试刷新(硬…)或运行预热迭代并仅从第二次测量来测试这一点

  • 由于预取,在缓存线大小达到一定值后,性能会继续下降——只要您以稳定的速度跨过缓存线(甚至跨过缓存线),您就会享受到硬件预取器在接下来的几行中带来的好处。L2拖缆特别有用,因为它会比您的访问流运行得更快。
    但是,一旦跨距超过128字节,您就应该在流预取器之前开始运行,并且每次访问都会产生完全延迟。
    为确保确实如此,请禁用预取(希望您的系统在BIOS中允许此操作) 编辑:Stephen还就访问与TLB查找的比率提出了一个非常好的观点——这将解释巨大的进步。如果你画出每一步的时间,我敢打赌,由于TLB未命中率,你会看到一个强劲的趋势,最重要的是64到128字节的步幅之间的跳跃

  • 我相信,由于TLB较冷,您的第一次迭代时间较长。您可以通过尝试刷新(硬…)或运行预热迭代并仅从第二次测量来测试这一点


  • 缓存线不是跟踪内存的唯一粒度。从虚拟地址到物理地址的转换发生在页面粒度上。您的系统几乎肯定使用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