【发布时间】:2016-06-14 06:51:19
【问题描述】:
我正在尝试对不同缓存级别的内存访问进行准确测量,并想出了以下代码进行探测:
__asm__ __volatile__(
"xor %%eax, %%eax \n"
"xor %%edi, %%edi \n"
"xor %%edx, %%edx \n"
/* time measurement */
"lfence \n"
"rdtsc \n"
"shl $32, %%rdx \n"
"or %%rdx, %%rax \n"
"movq %%rax, %%rdi \n"
/* memory access */
"movq (%%rsi), %%rbx\n"
/* time measurement */
"rdtscp \n"
"shl $32, %%rdx \n"
"or %%rdx, %%rax \n"
"movq %%rax, %%rsi \n"
"cpuid \n"
: /* output operands */
"=S"(t2), "=D"(t1)
: /* input operands */
"S" (mem)
: /* clobber description */
"ebx", "ecx", "edx", "cc", "memory"
);
但是 L1 和 L2 缓存访问仅相差 8 个周期,结果波动很大,因此我决定检查周围代码(除了实际内存访问)对时序的影响有多大:
__asm__ __volatile__(
"xor %%eax, %%eax \n"
"xor %%edi, %%edi \n"
"xor %%edx, %%edx \n"
/* time measurement */
"lfence \n"
"rdtsc \n"
"shl $32, %%rdx \n"
"or %%rdx, %%rax \n"
"movq %%rax, %%rdi \n"
/* memory access */
//"movq (%%rsi), %%rbx\n"
/* time measurement */
"rdtscp \n"
"shl $32, %%rdx \n"
"or %%rdx, %%rax \n"
"movq %%rax, %%rsi \n"
"cpuid \n"
: /* output operands */
"=S"(t2), "=D"(t1)
: /* input operands */
"S" (mem)
: /* clobber description */
"ebx", "ecx", "edx", "cc", "memory"
);
结果如下所示:
./cache_testing
From Memory: 42
From L3: 46
From L2: 40
From L1: 38
./cache_testing
From Memory: 40
From L3: 38
From L2: 36
From L1: 40
我知道我目前并没有按目的达到不同的缓存级别,但我想知道为什么在丢失内存访问的情况下时间波动如此之大。 代码以最高优先级的 SCHED_FIFO 运行,固定在一个 CPU 上,不应在运行时分派。 谁能告诉我是否可以改进我的代码,从而以任何方式改进结果?
【问题讨论】:
-
根据Agner Fog's microarch pdf,英特尔 Haswell 上缓存加载->使用延迟的正确数字是 L1 为 4c,L2 为 12c。衡量这一点的一个好方法(特别是对于 L1)是指针追踪。对于 L1,只需设置一个指向自身的指针,然后在循环中运行
mov (%rax), %rax。对于 L2,您需要一个不适合 L1 的大链表。 -
相关clflush to invalidate cache line via C function有一个关于lfence+rdtsc+lfence的详细答案。
标签: caching memory assembly x86-64 timing