前锋与后退阵列步行

时间:2014-08-21 23:44:58

标签: c++ caching memory

首先让我先说明这一点,我知道这种微观优化很少具有成本效益。我很好奇这些东西是如何起作用的。对于所有的高速缓存行数等,我在考虑x86-64 i5 Intel CPU。对于不同的CPU,数字显然会有所不同。

我经常觉得走向阵列向前走的速度比走向后走得快。我相信这是因为大量数据是以前向方式完成的 - 也就是说,如果我读取字节0x128,那么高速缓存行(假设长度为64字节)将以字节0x128读取 - 0x191包含。因此,如果我想要访问的下一个字节是0x129,那么它就已经在缓存中了。

然而,在读了一下之后,我现在的印象是它实际上没关系?因为高速缓存行对齐将在最接近的64可分边界处选择起始点,然后如果我选择字节0x127开始,我将加载0x64-0x127(包括端点),因此将在缓存中具有数据以供我向后移动。当从0x128转换到0x127时,我会遇到缓存,但这是我为这个例子选择地址的结果,而不是任何现实世界的考虑。

我知道缓存行是以8字节块的形式读入的,因此如果我们向后走,第一次操作可能会开始之前必须加载完整的缓存行,但我怀疑它会非常重要差。

如果我就在这里,有人可以清理,老我错了吗?我已经搜索了一整天,仍未能得到最终答案。

tl; dr:我们走阵的方向真的那么重要吗?它真的有所作为吗?它在过去有所作为吗? (到15年前左右)

我已使用以下基本代码进行测试,并向前和向后看到相同的结果:

#include <windows.h>
#include <iostream>
// Size of dataset
#define SIZE_OF_ARRAY 1024*1024*256
// Are we walking forwards or backwards?
#define FORWARDS 1

int main()
{
    // Timer setup
   LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
   LARGE_INTEGER Frequency;

   int* intArray = new int[SIZE_OF_ARRAY];
    // Memset - shouldn't affect the test because my cache isn't 256MB!
   memset(intArray, 0, SIZE_OF_ARRAY);

    // Arbitrary numbers for break points
   intArray[SIZE_OF_ARRAY - 1] = 55;
   intArray[0] = 15;

   int* backwardsPtr = &intArray[SIZE_OF_ARRAY - 1];

   QueryPerformanceFrequency(&Frequency); 
   QueryPerformanceCounter(&StartingTime);

    // Actual code
   if (FORWARDS)
   {
    while (true)
    {
        if (*(intArray++) == 55)
            break;
    }
   }
   else
   {
    while (true)
    {
        if (*(backwardsPtr--) == 15)
            break;
    }
   }

    // Cleanup
   QueryPerformanceCounter(&EndingTime);
   ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
   ElapsedMicroseconds.QuadPart *= 1000000;
   ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

   std::cout << ElapsedMicroseconds.QuadPart << std::endl;

    // So I can read the output
   char a;
   std::cin >> a;
   return 0;
}

我为A)Windows代码和B)Hacky实现道歉。它被抛在一起来检验一个假设,但不能证明这个推理。

任何有关行走方向如何产生影响的信息,不仅仅是缓存,还有其他方面,我们将不胜感激!

1 个答案:

答案 0 :(得分:3)

正如您的实验所示,没有区别。与处理器和L1高速缓存之间的接口不同,存储器系统在完整的高速缓存行而不是字节上进行交易。正如@ user657267指出的那样,存在处理器特定的预取器。这些可能偏好向前与向后,但我非常怀疑它。所有现代预取器都会检测方向而不是假设它们。此外,他们也检测到步幅。它们涉及极其复杂的逻辑,而且方向并不容易成为他们的垮台。

简短的回答:走向你想要的任何一个方向,并为两者享受相同的表现!