Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 投机性执行是否会导致昂贵的操作?_C++_X86_Branch Prediction_Speculative Execution - Fatal编程技术网

C++ 投机性执行是否会导致昂贵的操作?

C++ 投机性执行是否会导致昂贵的操作?,c++,x86,branch-prediction,speculative-execution,C++,X86,Branch Prediction,Speculative Execution,如果我正确理解了分支(x86),处理器有时会推测性地采用代码路径,执行指令并“取消”错误路径的结果。如果错误代码路径中的操作非常昂贵,比如导致缓存丢失的内存读取或一些昂贵的数学操作,该怎么办?处理器是否会尝试提前执行一些昂贵的操作?处理器通常如何处理这个问题 if (likely) { // do something lightweight (addition, subtraction, etc.) } else { // do something expensive (cach

如果我正确理解了分支(x86),处理器有时会推测性地采用代码路径,执行指令并“取消”错误路径的结果。如果错误代码路径中的操作非常昂贵,比如导致缓存丢失的内存读取或一些昂贵的数学操作,该怎么办?处理器是否会尝试提前执行一些昂贵的操作?处理器通常如何处理这个问题

if (likely) {
    // do something lightweight (addition, subtraction, etc.)
} else {
    // do something expensive (cache-miss, division, sin/cos/tan etc.)
}

tl:dr:影响并不像你想象的那么严重,因为CPU不再需要等待缓慢的事情,即使它没有取消它们。几乎所有的事情都是通过大量管道进行的,因此许多操作可以同时进行。错误推测的操作并不能阻止新操作的启动


当前的x86设计不会同时在分支的两侧进行推测。他们只是沿着预测的路径进行推测

我不知道有任何特定的微体系结构在任何情况下都会沿着分支的两个方向进行推测,但这并不意味着没有。我基本上只读过微体系结构(参见TagWiki获取Agner Fog的微体系结构gude的链接)。我相信这已经在学术论文中提出,甚至可能在某个地方的真实设计中实现


我不确定在当前Intel和AMD设计中,当检测到分支预测失误,而缓存未命中加载或存储已在执行挂起,或者一个divide正在占用divide单元时,会发生什么。当然,无序执行不必等待结果,因为未来的UOP都不会依赖它

在P4以外的UARCHE上,当检测到预测失误时,ROB/调度程序中的伪造UOP将被丢弃。来自Agner Fog的Microach doc,谈论P4与其他UARCHE:

由于两个原因,预测失误的惩罚异常高。。。[长输管道和] ... 预测失误分支中的伪μ操作不是 在他们退休前就被抛弃了。预测失误通常涉及45个方面 μops。如果这些操作是分区或其他耗时的操作 那么,预测失误的代价可能非常高昂。其他微处理器 一旦检测到预测失误,就可以丢弃μops,以便 不要不必要地使用执行资源

目前占用执行单位的UOP是另一种情况:

除除法器外,几乎所有的执行单元都是完全流水线的,因此可以在不取消飞行中FP FMA的情况下启动另一个乘法、洗牌或任何操作。(Haswell:5个周期延迟,两个执行单元,每个执行单元的每时钟吞吐量为一个,总持续吞吐量为每0.5c一个。这意味着最大吞吐量需要同时保持10个FMA,通常使用10个向量累加器)。不过,分裂很有趣。整数除法是许多UOP,因此分支预测失误至少会停止发出它们。FP div只是一条uop指令,但没有完全流水线,尤其是在较旧的CPU中。取消绑定divide单元的FP div会很有用,但如果可能的话,请取消IDK。如果添加取消功能会降低正常情况下的速度,或者耗电更多,那么它可能会被忽略。这是一个罕见的特殊情况,可能不值得花费在晶体管上

x87
fsin
或其他东西是非常昂贵的指令的一个很好的例子。直到我回去重读这个问题,我才注意到这一点。它是微代码的,所以即使它有47-106个周期的延迟(Intel Haswell),它也有71-100个uops。分支预测失误会阻止前端发出剩余的UOP,并取消所有排队的UOP,就像我说的整数除法。请注意,real
libm
实现通常不使用
fsin
等,因为它们比软件(即使没有SSE)IIRC实现的速度更慢、精度更低


对于缓存未命中,它可能会被取消,这可能会节省三级缓存(可能还有主内存)中的带宽。即使没有,指令也不再需要退出,所以在等待指令完成之前,ROB不会填满。这就是为什么缓存未命中会对OOO执行造成如此大的伤害,但在这里,最糟糕的情况是只需要绑定一个加载或存储缓冲区。现代CPU在运行中可能会同时出现许多突出的缓存未命中。通常,代码无法实现这一点,因为未来的操作取决于缓存中丢失的加载的结果(例如,链表或树中的指针跟踪),因此多个内存操作无法流水线进行。即使分支预测失误不会取消大部分飞行内存操作,它也可以避免大多数最坏的影响



我听说在代码块的末尾放一个
ud2
(非法指令),以防止指令预取在代码块位于页面末尾时触发TLB未命中。我不确定什么时候需要这种技术。也许如果有一个条件分支总是被执行?这没有意义,你只需要使用一个无条件的分支。至少就我所知,它以同样的方式执行指令流,不管它是否在推测性地执行指令流。事实上,我不认为代码被推测性执行的事实会被传输到执行单元。它是在之后(退役单元)决定退役什么和扔掉什么。@JerryCoffin我不明白这对一条指令执行而不是翻译成执行单元意味着什么,你能重新措辞吗?您的意思是推测指令不占用任何CPU周期吗?请注意,分支预测和推测执行是两种独立的技术。标题提到了分支预测,问题主体则谈到了推测性执行。推测执行的指令当然会消耗CPU执行单元的资源。@void\u ptr噢,对不起,w