【发布时间】:2015-05-12 16:38:02
【问题描述】:
我的目标是使用简单的代码来衡量(不同的)缓存的效果。我正在关注这篇文章,特别是第 20 页和第 21 页: https://people.freebsd.org/~lstewart/articles/cpumemory.pdf
我正在开发 64 位 Linux。 L1d缓存为32K,L2为256K,L3为25M。
这是我的代码(我用 g++ 编译这段代码,没有标志):
#include <iostream>
// ***********************************
// This is for measuring CPU clocks
#if defined(__i386__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
#elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
#endif
// ***********************************
static const int ARRAY_SIZE = 100;
struct MyStruct {
struct MyStruct *n;
};
int main() {
MyStruct myS[ARRAY_SIZE];
unsigned long long cpu_checkpoint_start, cpu_checkpoint_finish;
// Initializing the array of structs, each element pointing to the next
for (int i=0; i < ARRAY_SIZE - 1; i++){
myS[i].n = &myS[i + 1];
for (int j = 0; j < NPAD; j++)
myS[i].pad[j] = (long int) i;
}
myS[ARRAY_SIZE - 1].n = NULL; // the last one
for (int j = 0; j < NPAD; j++)
myS[ARRAY_SIZE - 1].pad[j] = (long int) (ARRAY_SIZE - 1);
// Filling the cache
MyStruct *current = &myS[0];
while ((current = current->n) != NULL)
;
// Sequential access
current = &myS[0];
// For CPU usage in terms of clocks (ticks)
cpu_start = rdtsc();
while ((current = current->n) != NULL)
;
cpu_finish = rdtsc();
unsigned long long avg_cpu_clocks = (cpu_finish - cpu_start) / ARRAY_SIZE;
std::cout << "Avg CPU Clocks: " << avg_cpu_clocks << std::endl;
return 0;
}
我有两个问题:
1- 我将 ARRAY_SIZE 从 1 更改为 1,000,000(因此我的数组大小在 2B 到 2MB 之间),但平均 CPU 时钟始终为 10。
根据该 PDF(第 21 页的图 3-10),当阵列完全适合 L1 时,我预计会获得 3-5 个时钟,而当它超过 L1 的大小时,我会获得更高的数字(9 个周期)。
2- 如果我将 ARRAY_SIZE 增加到 1,000,000 以上,我会得到分段错误(核心转储),这是由于堆栈溢出。我的问题是使用动态分配 (MyStruct *myS = new MyStruct[ARRAY_SIZE]) 是否不会导致任何性能损失。
【问题讨论】:
-
您需要让您的编译器针对基准测试进行优化。所以用
g++ -O2 -Wall -mtune=native编译;不要使用rdtsc,而是阅读time(7) -
@BasileStarynkevitch 我使用了这些标志,现在平均 cpu 时钟为 4,仍然与数组的长度无关。这表明要么一切都适合 L1d(事实并非如此),要么预取做得很好(我怀疑)。
-
@BasileStarynkevitch 另外,你能告诉我为什么 rdtsc 不适合这个目的吗?
-
@narengi:rdtsc 不可靠,因为每个内核都不同。如果它检查一个核心,做数学运算,然后检查另一个核心,它可以报告它在 -100 滴答声中完成。
-
对于 4 个时钟,您的 while 循环实际上什么都不做,因此编译器为您删除了它。基准测试很难。