哪个未对齐的存储和未对齐的负载更昂贵?

时间:2013-06-10 22:13:26

标签: performance assembly alignment

假设我在两个相隔1024000 + 1个字节的数组之间复制数据。由于偏移量不是字大小的倍数,我需要做一些未对齐的访问 - 加载或存储(暂时,让我们忘记可以完全避免错位访问与一些ORing和位移)。哪些未对齐的负载或未对齐的商店会更贵?

这是一个假设的情况,所以我不能只是对它进行基准测试:-)我更感兴趣的是哪些因素会导致性能差异,如果有的话。指向某些进一步阅读的指针会很棒。

谢谢!

3 个答案:

答案 0 :(得分:2)

实际上,这在很大程度上取决于您使用的CPU。在较新的Intel CPU上,加载和存储未对齐的单词没有任何代价(至少没有你能注意到的)。仅当您加载并存储16字节或32字节未对齐的块时,您才会发现性能下降很小。

答案 1 :(得分:1)

未对齐写入需要读取两个目标字,合并新数据,并写入两个字。这将与对齐的读取相结合。所以,3R + 2W。

未对齐的读取将需要读取两个源字,并合并数据(shift和bitor)。这将与对齐的写入组合。所以,2R + 1W。

因此,未对齐的阅读是一个明显的赢家。

当然,正如您所说,有更有效的方法可以避免任何错误对齐的操作,除非在数组的末尾。

答案 2 :(得分:0)

多少数据?我们在谈论在大块数据(在噪声中)或未对齐(100%数据)的一个项目(字等)末端未对齐的两件事情吗?

您使用memcpy()移动此数据等吗?

  

我对哪些因素会导致表现更感兴趣   差异,如果有的话。

存储器,模块,芯片,模块等通常以固定的访问大小进行组织,至少在某个地方有固定的访问大小。让我们说64位宽,这些天不是不常见的大小。因此,无论在哪个层,您只能以对齐的64位单位进行写入或读取。

如果您考虑写入与读取,通过读取发送地址并且必须转到内存并且数据返回,则必须进行完整的往返。通过写入执行写入所需要知道的一切都在出站路径上进行,因此在内存控制器获取地址和数据并告诉处理器写入已完成的情况下,发生火灾并忘记类型处理并不罕见信息没有网到达记忆。它确实需要时间,但不会像读取那样长(因为读取需要两个路径,因此不会在这里讨论flash / proms)。因此,对于对齐的全宽度内容,写入CAN可以更快,某些系统可能会等待数据一直到达内存,然后返回完成,这可能与读取的时间大致相同。这取决于你的系统,内存技术可以使内存中的一个或另一个更快或更慢。现在,在没有发生任何事情之后的第一次写入可以做到这一点并且忘记了事情,但是连续的第二个或第三个或第四个或第16个最终在路径的某处填充缓冲区并且处理器必须等待最旧的一个在最近的一个在队列中占有一席之前,它一直到内存。因此,对于突发性内容,写入可能比读取更快,但对于大量数据移动,它们彼此接近。

现在对齐。整个存储器宽度将在读取时读取,在这种情况下可以说是64位,如果您只对这些位中的8位感兴趣,那么在存储器和处理器之间的某处,其他24位被丢弃,这取决于系统。写入不是整数,对齐,内存大小意味着你必须读取内存的宽度,比如64位,修改新位,比如说8位,然后再写回整个64位。读 - 修改 - 写。只读需要读取写入需要读取 - 修改 - 写入,距离需要读取修改写入的内存越远,所需的时间就越慢,无论读取 - 修改 - 写入是否比任何更快都要快单独读取所以读取速度会更快,读取位的修整通常不会占用任何时间,因此读取一个字节相比,从同一位置读取16位或32位或64位,只要总线和目标是宽度一直以来,从同一个地方,一般来说,或者应该在同一时间。

未对齐只会使问题倍增。如果你想读取16位,使得8位在一个64位位置而另一位在下一个64位位置,则需要读取128位以满足16位读取。如何确切地发生这种情况以及惩罚的多少取决于您的系统。一些总线设置了传输X个时钟,但是之后数据是每个总线宽度一个时钟,因此128位读取可能只需要一个时钟(比几十到几百个)时钟读取64个,或者最坏的情况为了获得这个16位读取所需的128位,可能需要两倍的时间。写,是一个读 - 修改 - 写,所以拿读取时间,然后修改两个64位项,然后再写回来,同样的交易可能是每个方向X + 1个时钟,或者可能是2X个时钟数的坏在每个方向。

缓存帮助和伤害。使用缓存的一个好处是你可以平滑传输到慢速内存,你可以让缓存担心确保所有内存访问都是对齐的,所有写操作都是64位写入,等等。缓存将执行相同或更大的读取。因此,读取8位可能会导致慢速内存的一次或多次64位读取,对于第一个字节,如果您在下一个字节位置之后立即执行第二次读取,并且如果该位置位于同一缓存行中,那么它不会出去慢速内存,它从缓存中读取,速度更快。等等,直到你跨越到另一个缓存边界或其他读取导致该缓存行被驱逐。如果正在写入的位置在高速缓存中,那么读取 - 修改 - 写入发生在高速缓存中,如果不在高速缓存中那么它取决于系统,写入并不一定意味着读取修改写入导致高速缓存行填充,它可能发生在缓存的背面不存在。现在,如果您修改了高速缓存行中的一个字节,现在该行必须被写回,它就不能被丢弃,因此您有一到几个内存宽度可以作为结果写回。你的修改很快,但最终写入发生在缓慢的内存中,这会影响整体性能。

你可能会遇到(字节)读取的情况,如果高于外部存储器宽度的高速缓存行可以使读取速度慢于高速缓存不存在的情况,那么你会对某些项目进行字节写入缓存行,因为它在缓存中,所以速度很快。所以你可能有实验表明写入速度更快。

一个痛苦的案例是读取16位未对齐,这样它们不仅跨越64位内存宽度边界而且跨越高速缓存行边界,这样就必须读取两个高速缓存行,而不是读取128可能需要读取256或512或1024位的位才能获得16位。

例如,计算机上的记忆棒实际上是多个记忆,比如可能是8位宽,可以制作64位整体宽度,或者16位宽可以制作整体64位宽度等等。这并不意味着你可以隔离在一条通道上写道,但也许,我不太了解这些模块,但有些系统你可以/可以做到这一点,但那些系统我认为是8位或4位宽,只要最小可寻址大小不是64位就这个讨论而言。 ECC让事情变得更糟。首先,您需要额外的内存芯片或更多,基本上更宽的72位,例如支持64位。您必须使用ECC进行完整写入,因为整个72位可以说必须进行自我检查,因此您无法进行分数。如果存在可纠正的(单个位)错误,则读取不会受到实际损失,它会得到纠正的64位(在此检查发生的路径中的某处)。理想情况下,您希望系统写回更正的值,但这不是所有系统的工作方式,因此读取可以变成读取修改写入,对齐或不对齐。主要的惩罚是,如果你能够进行分数写入,你现在不能使用ECC必须是整个宽度写入。

现在我的问题,让我们说你使用memcpy来移动这些数据,许多C库被调整为进行对齐传输,至少在可能的情况下,如果源和目标以不同的方式对齐,可能是坏的,你可能想要自己管理部分副本。说它们以同样的方式不对齐,memcpy将首先尝试复制未对齐的字节,直到它到达对齐的边界,然后它转换为高速档,复制对齐的块直到它接近结束,它降档并复制最后一个几个字节(如果有的话),以未对齐的方式。因此,如果您正在谈论的这个内存副本是数千个字节,并且唯一未对齐的内容接近结束,那么是的,它将花费您额外的读取多达两个额外的高速缓存行填充,但这可能在噪声中。即使在较小的大小上,即使在32位边界上对齐,如果你没有移动整个高速缓存行或整个内存宽度,仍然可能涉及额外的高速缓存行,对齐或不对齐,你可能只会遇到额外的高速缓存行,值得阅读写...

纯粹传统的,非缓存的内存视图,所有其他事物保持不变,正如Doug所写。跨越这些边界之一的未对齐读取,如两个64位字上的16位,需要额外读取2R与1R。类似的写入花费你2R + 2W对1W,更贵。缓存和其他东西只会使问题复杂化,从而大大有助于解决问题"它取决于......你需要很好地了解你的系统以及其他正在发生的事情,如果有的话。缓存帮助和伤害,任何缓存都可以制作测试以显示缓存使事情变慢,并且使用相同的系统可以编写测试以显示缓存使事情变得更快。

进一步阅读将查看数据手册/表格技术参考手册或供应商称之为各种事项的文档。对于ARM,在其总线上获取AXI / AMBA文档,获取其缓存的缓存文档(例如PL310)。有关ddr内存的信息,你插入计算机的模块中使用的各个芯片都在那里,有很多时序图等等。(注意只是因为你认为你正在购买千兆赫兹内存,你不是,dram没有得到更快的速度就像10年或更长时间一样,它在133Mhz附近非常慢,只是总线速度更快并且可以排队更多的传输,ddr内存周期仍需要数百到数千个处理器周期,读取一个错过所有缓存的字节并且你的处理器等待永恒)。因此,处理器上的存储器接口和各种存储器上的文档等可以提供帮助,以及一般的缓存等教科书等。