我正在阅读英特尔架构文档,第3卷,第8.1.3节;
自修改代码将以比非自修改或普通代码更低的性能级别执行。性能恶化的程度取决于修改的频率和代码的特定特征。
所以,如果我遵守规则:
(*选项1 *) 将修改后的代码(作为数据)存储到代码段中;跳转到新代码或中间位置;执行新代码;
(*选项2 ) 将修改后的代码(作为数据)存储到代码段中; 执行序列化指令; (例如,CPUID指令*)执行新代码;
并且每周修改一次代码,我只应在下次修改此代码并即将执行时支付罚金。但在那之后,性能应该与非修改代码相同(+跳转到该代码的成本)。
我的理解是否正确?
答案 0 :(得分:3)
“下一次”可能不是这样;缓存算法考虑到第一个以外的访问(不这样做会相当幼稚)。然而,在前几次访问后不久,惩罚应该消失。 (“很少”可能是两个或几千个,但对于一台计算机,即使一百万也没什么。)
即使是当前正在执行的代码也会在某些时候写入内存(可能是最近由于分页),所以它最初会受到类似的惩罚,但很快就会消失,所以你不必担心。
答案 1 :(得分:3)
尚未缓存的代码之间存在差异,修改已经在投机中进行的指令的代码(获取,可能已解码,甚至可能位于调度程序中并重新排序)无序核心中的缓冲区)。写入已经被CPU查看的内存会导致它回退到非常慢的操作。这就是自修改代码通常意味着什么。即使JIT编译不太困难,也要避免这种减速。只是不要跳到你的缓冲区,直到它全部写好。
每周修改一次意味着如果你做错了,你每周可能会被罚1微秒。确实,经常使用的数据不太可能从缓存中逐出(这就是为什么多次读取内容更有可能使其成为"坚持"),但自我-modifying-code pipeline-flush应该只在第一次应用,如果您遇到它。之后,正在执行的缓存行是概率。在L1 I-cache(和uop缓存)中仍然很热,如果第二次运行没有太多干预代码。它在L1 D-cache中仍未处于修改状态。
我忘了如果http://agner.org/optimize/谈论自修改代码和JIT。即使没有,如果你在ASM中写任何东西,你应该阅读Agner的指南。主要的一些东西"优化asm"但是,它已经过时了,而且与Sandybridge和后来的英特尔CPU不太相关。由于uop缓存,对齐/解码问题不再是一个问题,对于SnB系列微博,对齐问题可能会有所不同。