代码之家  ›  专栏  ›  技术社区  ›  horseyguy

图像处理的快速内存?

  •  31
  • horseyguy  · 技术社区  · 16 年前

    我正在用C语言进行图像处理,这需要在内存周围复制大量数据——源和目标永远不会重叠。

    在使用 GCC (何处) SSE ,SSE2而不是SSE3是否可用?

    我希望解决方案是在组装中还是使用gcc内部函数?

    我找到了以下链接,但不知道这是否是最好的方法(作者还说它有一些错误): http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm.x86/2006-02/msg00123.html

    编辑:请注意,复制是必需的,我不能到处复制数据(我可以解释为什么,但我会给你一个解释:)

    6 回复  |  直到 10 年前
        1
  •  40
  •   einpoklum    10 年前

    礼节 William Chan 和谷歌。比Microsoft Visual Studio 2005中的memcpy快30-70%。

    void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size)
    {
    
      __asm
      {
        mov esi, src;    //src pointer
        mov edi, dest;   //dest pointer
    
        mov ebx, size;   //ebx is our counter 
        shr ebx, 7;      //divide by 128 (8 * 128bit registers)
    
    
        loop_copy:
          prefetchnta 128[ESI]; //SSE2 prefetch
          prefetchnta 160[ESI];
          prefetchnta 192[ESI];
          prefetchnta 224[ESI];
    
          movdqa xmm0, 0[ESI]; //move data from src to registers
          movdqa xmm1, 16[ESI];
          movdqa xmm2, 32[ESI];
          movdqa xmm3, 48[ESI];
          movdqa xmm4, 64[ESI];
          movdqa xmm5, 80[ESI];
          movdqa xmm6, 96[ESI];
          movdqa xmm7, 112[ESI];
    
          movntdq 0[EDI], xmm0; //move data from registers to dest
          movntdq 16[EDI], xmm1;
          movntdq 32[EDI], xmm2;
          movntdq 48[EDI], xmm3;
          movntdq 64[EDI], xmm4;
          movntdq 80[EDI], xmm5;
          movntdq 96[EDI], xmm6;
          movntdq 112[EDI], xmm7;
    
          add esi, 128;
          add edi, 128;
          dec ebx;
    
          jnz loop_copy; //loop please
        loop_copy_end:
      }
    }
    

    您可以根据您的具体情况和任何假设进一步优化它。

    您可能还需要检查memcpy源(memcpy.asm)并去掉它的特殊情况处理。可能会进一步优化!

        2
  •  6
  •   caf    16 年前

    在任何优化水平 -O1 或更高版本,gcc将为以下函数使用内置定义 memcpy -有权利的 -march 参数( -march=pentium4 对于您提到的一组特性),它应该生成非常优化的特定于体系结构的内联代码。

    我会把它作为基准,看看会有什么结果。

        3
  •  6
  •   Nils Pipenbrinck    16 年前

    Hapalibashi发布的SSE代码就是一条路。

    如果你需要更高的性能,不要回避编写设备驱动程序的漫长而曲折的道路:现在所有重要的平台都有一个DMA控制器,它能够更快地完成复制工作,并且与CPU代码并行。

    但这需要写一个驱动程序。由于存在安全风险,我所知道的任何大型操作系统都不会向用户端公开此功能。

    然而,它可能是值得的(如果你需要性能),因为地球上没有任何代码可以比一个硬件设计来做这样的工作。

        4
  •  6
  •   Andrew Bainbridge    10 年前

    这个问题已经四岁了,我有点惊讶还没有人提到内存带宽。CPU-Z报告我的机器有PC3-10700 RAM。RAM的峰值带宽(即传输速率、吞吐量等)为10700兆字节/秒。我机器的CPU是一个I5-2430M的CPU,峰值涡轮频率为3GHz。

    理论上,有了一个无限快的CPU和我的RAM,memcpy可以 5300兆字节/秒 ,即10700的一半,因为memcpy必须读取并写入RAM。(编辑:正如V.Oddou指出的,这是一个简单的近似值)。

    另一方面,假设我们有无限快的RAM和一个现实的CPU,我们能实现什么?让我们以我的3GHz CPU为例。如果它能在每个周期中进行32位读和32位写,那么它就可以传输3E9*4= 12000兆字节/秒 . 对于现代CPU来说,这似乎很容易实现。我们已经看到,在CPU上运行的代码并不是真正的瓶颈。这是现代机器拥有数据缓存的原因之一。

    当我们知道数据被缓存时,我们可以通过基准测试memcpy来测量CPU真正能做什么。准确地做这件事很费劲。我做了一个简单的应用程序,将随机数写入一个数组,memcpy将它们放入另一个数组,然后对复制的数据进行校验和。我在调试程序中仔细检查了代码,以确保聪明的编译器没有删除副本。改变数组的大小会改变缓存性能——小数组适合缓存,大数组则不适合缓存。我得到了以下结果:

    • 40千字节阵列:16000兆字节/秒
    • 400千字节阵列:11000兆字节/秒
    • 4000千字节阵列:3100兆字节/秒

    显然,我的CPU每周期可以读写32位以上,因为16000比我上面理论计算的12000多。这意味着CPU的瓶颈比我想象的还要小。我使用的是Visual Studio 2005,进入标准的memcpy实现,我可以看到它在我的机器上使用了movqda指令。我想这可以读写每周期64位。

    Hapalibashi发布的漂亮代码在我的机器上达到了4200兆字节/秒,比2005年的实现速度快了40%。我想它更快,因为它使用预取指令来提高缓存性能。

    总之,在CPU上运行的代码并不是瓶颈,调优这些代码只会做一些小的改进。

        5
  •  3
  •   Clifford    13 年前

    如果针对英特尔处理器,您可能会从 IPP . 如果你知道它将与Nvidia GPU一起运行,也许你可以使用 CUDA -在这两种情况下,看起来更宽可能比优化memcpy()更好——它们提供了在更高级别改进算法的机会。然而,它们都依赖于特定的硬件。

        6
  •  2
  •   Peter Mortensen Pieter Jan Bonestroo    16 年前

    如果您在Windows上,请使用 DirectX API,具有特定的 GPU -图形处理的优化程序(速度有多快?您的CPU未加载。在GPU咀嚼的时候做些别的事情)。

    如果你想成为一个不可知论者,试试看 OpenGL .

    不要摆弄汇编程序,因为你很可能会惨遭失败,超过10年以上熟练的库制作软件工程师。

    推荐文章