【问题标题】:Faster method to copy arrays after typecasting in C?在 C 中进行类型转换后复制数组的更快方法?
【发布时间】:2013-06-17 06:18:48
【问题描述】:

我有一个二维整数数组InArray[2][60] 携带short 2 个 LS 字节的数据和 2 个 MS 字节的位字段数据。请建议一种更快的方法来提取short 数据并将其复制到short OutArray[60],在memcpy() 的行上。我认为遍历每个项目并不是这样做的最佳方法。 TIA

编辑:添加代码 sn-p

int InArray[2][60];
short OutArray[60];
for (int i=0; i < 60;i++)
{
    OutArray[i] = (short)(InArray[0][i] & 0xffff);
}

有没有更好,可能更快的方法来做到这一点

【问题讨论】:

  • 您使用的某些术语我不清楚。
  • 您是否对数组进行迭代测试并发现它的性能不够好?
  • short InArray[2][60]int InArray[2][60]。如果是后者,还有一些您没有告诉我们的事情,因为您拥有的数据是所需数据的两倍。
  • @Antonio 位域是您可以在 C/C++ 中执行的操作。我建议谷歌搜索。 LS 和 MS 通常表示最不重要和最重要。
  • @Bleamer 是什么让您认为memcpy() 本身不使用循环?它的实现者不能假设他们被要求复制的任何数据块都适合寄存器。

标签: c arrays optimization


【解决方案1】:

如果你真的要复制一个 60 元素的数组,那也没关系。

如果阵列更大并且/或者您经常这样做,那么您需要查看SIMD 指令集:英特尔平台上的 SSEx,PPC 上的 Altivec...

例如,使用 SSE4,您可以使用 _mm_packus_epi32() 将 2*4 32 位操作数打包(并饱和)成 8 个 16 位操作数。

您的编译器可能具有使用这些的内在函数:http://msdn.microsoft.com/en-us/library/hh977022.aspxhttp://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/PowerPC-AltiVec-Built_002din-Functions.html...

【讨论】:

【解决方案2】:

这只有在您多次执行此类操作时才会有所帮助。我使用 Agner Fog 的矢量类来执行此操作 (http://www.agner.org/optimize/vectorclass.zip)。这是一个使用 SSE/AVX 的类。但是,如果您将标签 SSE 和 AVX 添加到您的问题中,您会找到最佳答案。

如果您可以确保数组是 16 字节或 32 字节对齐的,您也会获得更好的结果。在下面的代码中,它还有助于使数组的宽度等于 64(即使您只打算使用 60 个元素)或使数组的长度成为 64 的倍数。

#include <stdio.h>
#include "vectorclass.h"

void foo(int InArray[2][60],  short OutArray[60]) {
    for (int i=0; i < 60; i++) {
        OutArray[i] = (short)(InArray[0][i] & 0xffff);
    }
}

void foo_vec8s(int InArray[2][60],  short OutArray[60]) {
    int i=0;
    for (; i <(60-8); i+=8) {
        Vec8s v1 = Vec8s().load(&InArray[0][i]);
        Vec8s v2 = Vec8s().load(&InArray[0][i+4]);
        Vec8s out = blend8s<0,2,4,6,8,10,12,14>(v1,v2);
        out.store(&OutArray[i]);
    }
    //clean up since arrays are not a multiple of 64
    for (;i < 60; i++) {
        OutArray[i] = (short)(InArray[0][i] & 0xffff);
    }
}

int main() {
    int InArray[2][60];
    for(int i=0; i<60; i++) { 
        InArray[0][i] = i | 0xffff0000;
    }

    short OutArray1[60] = {0};
    foo(InArray, OutArray1);
    for(int i=0; i<60; i++) {
        printf("%d ", OutArray1[i]);
    } printf("\n");

    short OutArray2[60] = {0};
    foo_vec8s(InArray, OutArray2);
    for(int i=0; i<60; i++) {
        printf("%d ", OutArray2[i]);
    } printf("\n");  
}

【讨论】:

  • 感谢您的回复,虽然我的查询应该更具描述性,但我正在寻找 ARM 目标的解决方案(矢量类似乎针对 x86 进行了优化),您有任何资源吗?
  • 不,我从来没有为 ARM 编程过。
  • ARM 上的 SIMD 称为 NEON(和 NEONv2)。它像 SSE 一样是 4 宽。它也有 FMA(或至少有一些)。这是我知道的全部。您可能可以对 ARM 使用类似的逻辑。我的意思是制作你自己的向量类,称为 Vec8s,它同时在八个短裤(四个整数)上运行。我不知道 NEON 是否可以(有效地)做到这一点。
猜你喜欢
  • 2010-10-07
  • 1970-01-01
  • 2017-11-30
  • 2011-06-21
  • 2011-07-03
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多