如何将我的结构变量放入CPU缓存中以消除主存储器页面访问时间?选项

时间:2011-03-31 13:48:28

标签: performance caching memory cpu

很明显,没有明确的方式或某些系统调用 帮助程序员将变量放入CPU缓存中。

但我认为某种编程风格或精心设计 算法可以增加可能性 变量可以缓存到CPU缓存中。

以下是我的例子:

我想在数组的末尾添加一个8字节结构 在全局主存中声明的相同类型结构 区域。

此过程不断重复进行400万次操作。此过程需要6秒,每次操作需要1.5 us。我认为这个结果表明两个内存区域尚未缓存。

我从cache-oblivious algorithm得到了一些线索,所以我尝了几个 提高这一点的方法。到现在为止,还没有增强。

我认为一些聪明的代码可以减少经过的时间,最多可达10到100 倍。请告诉我。

-------------------------------------------------------------------------

附加(2011-04-01)

达蒙〜谢谢你的评论!

阅读完评论后,我再次分析了我的代码,发现了几件事 我错过了我附上的以下代码是我原始代码的缩写版本。

为了准确测量每个操作的执行时间(在原始代码中,有几种不同类型的操作),我使用clock_gettime()函数插入了时间测量代码。我想如果我测量每个操作的执行时间并累积它们,就可以避免主循环的额外成本。

在原始代码中,时间测量代码被宏功能隐藏,所以我完全忘了它。

此代码的运行时间差不多是6秒。但是,如果我摆脱主循环中的时间测量功能,它将变为0.1秒。

由于clock_gettime()函数支持非常高的精度(高达1纳秒),在独立线程的基础上执行,并且它还需要非常大的结构, 我认为该函数导致了执行连续插入的主存储区的缓存输出。

再次感谢您的评论。为了进一步增强,任何建议都将对我优化我的代码非常有帮助。

我认为分层定义的结构变量可能会导致不必要的时间成本, 但在我将其更改为更多C风格的代码之前,我首先要知道它会有多少。


typedef struct t_ptr {
    uint32 isleaf :1, isNextLeaf :1, ptr :30;
    t_ptr(void) {
        isleaf = false;
        isNextLeaf = false;
        ptr = NIL;
    }
} PTR;

typedef struct t_key {
    uint32 op :1, key :31;
    t_key(void) {
        op = OP_INS;
        key = 0;
    }
} KEY;

typedef struct t_key_pair {
    KEY key;
    PTR ptr;
    t_key_pair() {
    }

    t_key_pair(KEY k, PTR p) {
        key = k;
        ptr = p;
    }
} KeyPair;

typedef struct t_op {
    KeyPair keyPair;
    uint seq;
    t_op() {
        seq = 0;
    }
} OP;

#define MAX_OP_LEN 4000000
typedef struct t_opq {
    OP ops[MAX_OP_LEN];
    int freeOffset;
    int globalSeq;
    bool queueOp(register KeyPair keyPair);
} OpQueue;

bool OpQueue::queueOp(register KeyPair keyPair) {
    bool isFull = false;
    if (freeOffset == (int) (MAX_OP_LEN - 1)) {
        isFull = true;
    }
    ops[freeOffset].keyPair = keyPair;
    ops[freeOffset].seq = globalSeq++;
    freeOffset++;
}

OpQueue opQueue;
#include <sys/time.h>
int main() {
    struct timespec startTime, endTime, totalTime;
    for(int i = 0; i < 4000000; i++) {
        clock_gettime(CLOCK_REALTIME, &startTime);
        opQueue.queueOp(KeyPair());
        clock_gettime(CLOCK_REALTIME, &endTime);
        totalTime.tv_sec += (endTime.tv_sec - startTime.tv_sec);
        totalTime.tv_nsec += (endTime.tv_nsec - startTime.tv_nsec);
    }
    printf("\n elapsed time: %ld", totalTime.tv_sec * 1000000LL + totalTime.tv_nsec / 1000L);
}

2 个答案:

答案 0 :(得分:3)

您不会将结构放入任何缓存中。 CPU会自动为您执行此操作。 CPU比那更聪明;如果您访问顺序内存,它将开始将内存中的内容放入缓存,然后再读取它们

实际上,对于像这样的简单代码,你应该花费在测量上的时间是执行代码的时间的十倍(在你的情况下显然是60倍)。

因为你对clock_gettime()充满信心:我建议你连续五次调用它并存储结果,然后打印差异。有分辨率,有精确度,而且返回当前时间需要多长时间,这是非常长的。

答案 1 :(得分:2)

我无法强制缓存,但您可以强制内存不可缓存。如果您有其他大型数据结构,则可以排除这些数据结构,这样它们就不会污染您的缓存。这可以通过为Windows VirutalAllocXXX函数指定PAGE_NOCACHE来完成。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx