Sha*_*ank 5 performance x86 caching alignment execution
我有一个简单的程序,首先将一些本机x86指令写入声明的缓冲区,然后设置一个指向此缓冲区的函数指针并进行调用.但是,当在堆栈上分配缓冲区时(而不是在堆上,甚至在全局数据区中),我注意到严重的性能损失.我验证了数据缓冲区中指令序列的开始是在一个16字节的边界上(我假设这是cpu需要(或想要)的内容).我不知道为什么它会在我执行指令的过程中产生影响,但在下面的程序中,"GOOD"在我的双核工作站上执行4秒钟,而"BAD"需要6分钟左右.是否存在某种对齐/ i-cache /预测问题?我对VTune的评估许可刚刚结束,所以我甚至无法对此进行分析:(.谢谢.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int (*funcPtrType)(int, int);
int foo(int a, int b) { return a + b; }
void main()
{
// Instructions in buf are identical to what the compiler generated for "foo".
char buf[201] = {0x55,
0x8b, 0xec,
0x8b, 0x45, 0x08,
0x03, 0x45, 0x0c,
0x5D,
0xc3
};
int i;
funcPtrType ptr;
#ifdef GOOD
char* heapBuf = (char*)malloc(200);
printf("Addr of heap buf: %x\n", &heapBuf[0]);
memcpy(heapBuf, buf, 200);
ptr = (funcPtrType)(&heapBuf[0]);
#else // BAD
printf("Addr of local buf: %x\n", &buf[0]);
ptr = (funcPtrType)(&buf[0]);
#endif
for (i=0; i < 1000000000; i++)
ptr(1,2);
}
Run Code Online (Sandbox Code Playgroud)
运行此结果的结果是:
$ cl -DGOOD ne3.cpp
Microsoft(R)32位C/C++优化编译器版本11.00.7022适用于80x86
版权所有(C)Microsoft Corp 1984-1997.版权所有.
ne3.cpp
Microsoft(R)32位增量链接器版本5.10.7303
版权所有(C)Microsoft Corp 1992-1997.版权所有.
/out:ne3.exe
ne3.obj
$ time ./ne3
堆buf的地址:410eb0
real 0m 4.33s
user 0m 4.31s
sys 0m 0.01s
$
$
$ cl ne3.cpp
Microsoft(R)32位C/C++优化编译器版本11.00.7022 for 80x86
版权所有(C)Microsoft Corp 1984-1997.版权所有.
ne3.cpp
Microsoft(R)32位增量链接器版本5.10.7303
版权所有(C)Microsoft Corp 1992-1997.版权所有.
/out:ne3.exe
ne3.obj
$ time ./ne3
本地buf地址:12feb0
真正的6m41.19s
用户6m40.46s
系统0m 0.03s
$
谢谢.
i我的猜测是,由于堆栈上也有变量,因此当您在循环i中进行更改for时,您会丢弃代码所在的同一缓存行。将代码放在缓冲区中间的某个位置(并且可能会放大buffer) 以便将其与其他堆栈变量分开。
另请注意,在堆栈上执行指令通常是被利用的安全漏洞(例如缓冲区溢出)的标志。
因此,操作系统通常配置为禁止这种行为。病毒扫描程序也可能对其采取行动。也许您的程序每次尝试访问该堆栈页面时都会通过安全检查(尽管我希望sys在这种情况下时间字段会更大)。
如果您想“正式”使内存页可执行,您可能应该查看VirtualProtect().