我正在研究一种不支持未对齐内存访问的嵌入式设备。
对于视频解码器,我必须处理8x8像素块中的像素(每像素一个字节)。该器件具有一些SIMD处理功能,允许我并行处理4个字节。
问题是,8x8像素块不能保证在对齐的地址上启动,并且这些函数需要读/写多达这些8x8块中的三个。
如果你想要非常好的表现,你会如何处理?经过一番思考后,我提出了以下三个想法:
将所有内存访问都作为字节。这是最简单的方法,但速度慢,而且它与SIMD功能不兼容(这是我目前在我的参考C代码中所做的)。
写入四个复制函数(每个对齐情况一个),通过两次32位读取加载像素数据,将位移到正确的位置,并将数据写入一些对齐的临时存储器块。然后,视频处理功能可以使用32位访问和SIMD。缺点:CPU无法隐藏处理后的内存延迟。
与上面相同的想法,但不是将像素写入临时存储器,而是进行视频处理。这可能是最快的方法,但我必须为这种方法编写的函数数量很多(我估计大约60)。
顺便说一句:我必须在汇编程序中编写所有函数,因为编译器在SIMD扩展时会生成可怕的代码。
你会选择哪条路,或者你还有另外的想法如何处理这个问题?
答案 0 :(得分:4)
您可以使用memcpy
(如果可以的话,可以优化以执行单词复制),以复制到对齐的数据结构(例如,在堆栈上分配的内容或来自malloc
)。然后对该对齐的数据结构执行处理。
但最有可能的是,您需要处理处理器寄存器中的内容而不是内存中的内容。你如何处理你的任务取决于硬件的能力(例如,一个32位寄存器可以分成四个8位寄存器吗?SIMD操作操作的寄存器是什么?)如果你要走简单路线,你可以调用一个小的加载器函数来执行你的未对齐读取。
答案 1 :(得分:3)
首先对齐数据,然后采用对齐的SIMD方法。
这比选项3的工作少,幸运的是,您的代码将在25%的时间内处于最高速度(即已经对齐的情况)。在知道输入正确对齐的情况下,您可以在将来愉快地重复使用代码。
如果您认为这不能令您满意,那么您应该考虑将所有四种对齐方式硬编码到您的功能中。
答案 2 :(得分:3)
您应该首先将代码分解为提取/处理部分。
获取代码应该复制到工作缓冲区中,并且具有对齐的内存(使用SIMD寄存器应该能够复制的内存)和需要逐字节复制的非对齐内存(如果平台无法进行未对齐访问,并且您的source / dest具有不同的对齐方式,那么这是您可以做到的最佳选择。)
您的处理代码可以是SIMD,保证处理对齐的数据。对于任何实际程度的处理,复制+处理肯定比未对齐数据上的非SIMD操作更快。
假设你的来源& dest是相同的,如果源是未对齐的,则进一步优化将仅使用工作缓冲区,并且如果存储器对齐则进行就地处理。这样做的好处取决于数据的特征。
根据您的体系结构,您可以通过在处理之前预取数据来获得进一步的好处。您可以在此处发出指令,以便在需要之前将内存区域提取到缓存中,因此您可以在处理当前内容之前为下一个块发出提取。
答案 3 :(得分:2)
我会选择选项1),直到你知道它太慢(慢速就好,太慢就是坏)
答案 4 :(得分:2)
一般建议:为什么不选择听起来合理的东西(比如#2),然后测量性能呢?如果这是不可接受的,你可以回到绘图板。
在测量之前,在汇编程序中手工制作60个函数肯定会像“过早优化”一样。 :)