Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.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++ 硬件是否将多个代码操作合并为一个物理CPU操作?_C++_C_Optimization_Cpu Architecture_Cpu Cache - Fatal编程技术网

C++ 硬件是否将多个代码操作合并为一个物理CPU操作?

C++ 硬件是否将多个代码操作合并为一个物理CPU操作?,c++,c,optimization,cpu-architecture,cpu-cache,C++,C,Optimization,Cpu Architecture,Cpu Cache,我读过一篇2006年的文章,内容是关于CPU如何对整个一级缓存线执行操作,即使在您只需要对一级缓存线所包含内容的一小部分执行操作的情况下(例如,加载一整条一级缓存线以写入布尔变量显然是过分的)。本文通过以一级缓存友好的方式管理内存来鼓励优化 假设我有两个int变量,它们恰好在内存中是连续的,在我的代码中,我连续地写入这两个变量 硬件是否将我的两个代码操作合并为单个一级缓存线上的一个物理操作(假定CPU有足够大的一级缓存线来容纳这两个变量),还是没有 有没有办法在C++或C?< /P>中向CPU提

我读过一篇2006年的文章,内容是关于CPU如何对整个一级缓存线执行操作,即使在您只需要对一级缓存线所包含内容的一小部分执行操作的情况下(例如,加载一整条一级缓存线以写入布尔变量显然是过分的)。本文通过以一级缓存友好的方式管理内存来鼓励优化

假设我有两个
int
变量,它们恰好在内存中是连续的,在我的代码中,我连续地写入这两个变量

硬件是否将我的两个代码操作合并为单个一级缓存线上的一个物理操作(假定CPU有足够大的一级缓存线来容纳这两个变量),还是没有

有没有办法在C++或C?< /P>中向CPU提出这样的建议?
如果硬件没有以任何方式进行整合,那么您认为如果在代码中实现这样的功能,它会产生更好的性能吗?分配一个与l1行大小相同的内存块,并用尽可能多的热数据变量填充它?

这是一个相当广泛的问题,但我将尝试涵盖要点

是的,只看一个
bool
就将数据读入缓存是有点浪费的-但是,处理器通常不知道在那之后您打算做什么,例如,如果您是否需要下一个连续值。您可以依赖于位于同一类或结构中的数据彼此相邻,因此使用该类或结构来存储您经常一起操作的数据将使您受益匪浅

对于“一次处理多个数据”的操作,大多数现代处理器都有各种形式的扩展,可以对多个数据项(SIMD-同一指令,多个数据)执行相同的操作。这始于20世纪90年代末的MMX,现已扩展到包括3DNow!,用于x86的SSE和AVX。在ARM中有“Neon”扩展,它也提供类似的功能。PowerPC也有类似的东西,我现在不知道它的名字

< C或C++程序无法立即控制指令的选择或缓存使用。但是,现代编译器如果有正确的选项,将生成代码,例如,使用SIMD指令在一个更大的数组中对所有
int
进行求和,每次添加4项,然后在完成整批操作后,水平添加4个值。或者,如果您有一组X、Y、Z坐标,则可以使用SIMD将两组此类数据添加到一起。这是编译器的选择,但它可以节省相当多的时间,因此编译器中的优化程序正在修改,以找到有帮助的情况,并使用这些类型的指令


最后,大多数大型现代处理器(自ca 1995年以来的x86处理器、ARM A15处理器、PowerPC处理器)也执行超标量执行——一次执行多条指令,并且“无序执行”(处理器理解指令的依赖性,执行“就绪”的指令)执行,而不是完全按照它们给处理器的顺序)。编译器将知道这一点,并尝试“帮助”安排代码,使处理器能够轻松完成任务。

缓存线的大小主要与并发性相关。它是可以在多个处理器之间同步的最小数据块

正如您所建议的,需要加载整个缓存线,以便仅对其中的几个字节执行操作。如果在同一个处理器上执行多个操作,尽管不需要不断地重新加载。顾名思义,它实际上是缓存的。这包括缓存对数据的写入。只要只有一个处理器在访问数据,您通常可以放心,它正在高效地访问数据

在多个处理器访问数据的情况下,对齐数据可能会有所帮助。使用C++ <代码>对齐方式< /COD>属性或编译器扩展,可以帮助您获得按您想要的方式排列的数据结构。
您可能会对我的文章感兴趣,这篇文章提供了一些关于低级别(至少在逻辑上)发生的情况的见解。

缓存的整个要点是允许许多高度本地化的内存操作快速发生

当然,最快的操作涉及寄存器。使用它们所涉及的唯一延迟是指令获取、解码和执行。在一些寄存器丰富的体系结构(以及向量处理器)中,它们实际上像专用缓存一样使用。除速度最慢的处理器外,所有处理器都有一个或多个级别的缓存,除了速度更快之外,与普通指令的内存类似

为了简化相对于实际处理器的考虑,假设一个假设处理器运行在2 GHz(每时钟0.5纳秒),存储器需要5 ns来加载任意64位(8字节)字的存储器,但只有1纳秒来加载来自存储器的每个连续64位字。(也假设写操作是类似的。)在这样的机器上,在内存中翻转一个位的速度非常慢:1 ns加载指令(仅当指令尚未在管道中时——但在远程分支后5 ns),5 ns加载包含该位的字,0.5 ns执行指令,5 ns将更改后的字写回内存。内存拷贝更好:加载指令的时间大约为零(因为管道可能对指令循环做了正确的事情),加载前8个字节的时间为5ns,执行指令的时间为0.5ns,存储前8个字节的时间为5ns,每增加8个字节的时间为1+0.5+1ns。地方性使事情更容易。但有些操作可能是病态的:增加数组的每个字节会加载最初的5ns、0.5ns指令、最初的5ns存储,然后是每个字节(而不是每个字)1+0.5+1。(不在同一单词边界上的内存副本也是坏消息。)

让这个职业