下面的代码片段仅用一条RET指令创建一个函数(有趣)。 循环重复调用该函数,并在返回后覆盖RET指令的内容。
#include <sys/mman.h>
#include<stdlib.h>
#include<unistd.h>
#include <string.h>
typedef void (*foo)();
#define RET (0xC3)
int main(){
// Allocate an executable page
char * ins = (char *) mmap(0, 4096, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE| MAP_ANONYMOUS, 0, 0);
// Just write a RET instruction
*ins = RET;
// make fun point to the function with just RET instruction
foo fun = (foo)(ins);
// Repeat 0xfffffff times
for(long i = 0; i < 0xfffffff; i++){
fun();
*ins = RET;
}
return 0;
}
X86 Broadwell计算机上的Linux性能具有以下icache和iTLB统计信息:
性能统计-e L1-icache-load-misses -e iTLB-load-misses ./a.out
“ ./ a.out”的性能计数器统计信息:
805,516,067 L1-icache-load-misses
4,857 iTLB-load-misses
32.052301220 seconds time elapsed
现在,在不覆盖RET指令的情况下查看相同的代码。
#include <sys/mman.h>
#include<stdlib.h>
#include<unistd.h>
#include <string.h>
typedef void (*foo)();
#define RET (0xC3)
int main(){
// Allocate an executable page
char * ins = (char *) mmap(0, 4096, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE| MAP_ANONYMOUS, 0, 0);
// Just write a RET instruction
*ins = RET;
// make fun point to the function with just RET instruction
foo fun = (foo)(ins);
// Repeat 0xfffffff times
for(long i = 0; i < 0xfffffff; i++){
fun();
// Commented *ins = RET;
}
return 0;
}
这是同一台机器上的性能统计。
性能统计-e L1-icache-load-misses -e iTLB-load-misses ./a.out
“ ./ a.out”的性能计数器统计信息:
11,738 L1-icache-load-misses
425 iTLB-load-misses
0.773433500 seconds time elapsed
请注意,覆盖指令会导致L1-icach-load-misses从11,738增加到805,516,067,这是一个多方面的增长。 还要注意,iTLB负载丢失从425个增长到4,857个,与L1 icache负载丢失相比增长了不少,但幅度较小。 运行时间从0.773433500秒增加到32.052301220秒,增长了41倍!
目前尚不清楚,如果指令占用空间太小,CPU为什么会导致i-cache丢失。这两个示例的唯一区别是修改了指令。授予L1 iCache和dCache是分开的,难道没有办法将代码安装到iCache中,从而可以避免缓存i-cache遗漏吗?
此外,为什么iTLB未命中率增长了10倍?
答案 0 :(得分:2)
授予L1 iCache和dCache分开的权限,难道没有办法将代码安装到iCache中,从而可以避免缓存i-cache遗漏吗?
否。
如果您要修改代码-唯一可以通过的路径如下:
请注意,您还会错过μOP缓存。
this diagram 1 对此进行了说明,我认为它足够准确。
我怀疑iTLB丢失可能是由于定期的TLB冲洗所致。如果不做任何修改,您就不会受到iTLB丢失的影响,因为您的指令实际上来自μOP缓存。
如果没有,我不确定。我认为L1指令缓存实际上已得到解决,因此如果出现问题,则无需访问TLB。
1:很遗憾,该图片的版权限制非常严格,因此我避免突出显示路径/内嵌图片。