C++ 高性能计算中的数组C[]=A[]*B[]

C++ 高性能计算中的数组C[]=A[]*B[],c++,arrays,performance,C++,Arrays,Performance,我相信在C语言中有这样的代码是很常见的++ for(size_t i=0;i<ARRAY_SIZE;++i) A[i]=B[i]*C[i]; for(size\u t i=0;iMy g++4.5.2为两个循环生成完全相同的代码(修复了double*pA=A、*pB=B、*pC=C;中的错误) .L3: movapd B(%rax), %xmm0 mulpd C(%rax), %xmm0 movapd %xmm0, A(%rax) addq

我相信在C语言中有这样的代码是很常见的++

for(size_t i=0;i<ARRAY_SIZE;++i)
    A[i]=B[i]*C[i];

for(size\u t i=0;iMy g++4.5.2为两个循环生成完全相同的代码(修复了
double*pA=A、*pB=B、*pC=C;
中的错误)

.L3:
    movapd  B(%rax), %xmm0
    mulpd   C(%rax), %xmm0
    movapd  %xmm0, A(%rax)
    addq    $16, %rax
    cmpq    $80000, %rax
    jne .L3
(其中我的数组大小为10000)


编译器作者已经知道了这些技巧。OpenMP和其他并发解决方案值得研究。

我的g++4.5.2为两个循环生成完全相同的代码(修复了
double*pA=A、*pB=B、*pC=C;中的错误,并且是

.L3:
    movapd  B(%rax), %xmm0
    mulpd   C(%rax), %xmm0
    movapd  %xmm0, A(%rax)
    addq    $16, %rax
    cmpq    $80000, %rax
    jne .L3
(其中我的数组大小为10000)


编译器作者已经知道这些技巧。OpenMP和其他并发解决方案值得研究。

第一种形式正是编译器将识别和优化的结构类型,几乎肯定会自动发出SSE指令

对于这种琐碎的内部循环,缓存效果是不相关的,因为您正在对所有内容进行迭代。如果您有嵌套的循环或一系列操作(如g(f(a,B),C)),那么您可以尝试安排重复访问小内存块,以使缓存更友好

不要手动展开循环。如果这是一个好主意(可能不是在现代CPU上),编译器也会这样做

如果循环非常大,并且其中的操作非常复杂,以至于您还没有内存限制,OpenMP可能会有所帮助


一般来说,以自然、直接的方式编写代码,因为这是优化编译器最容易理解的。第一种形式正是编译器将识别和优化的结构类型,几乎可以肯定会自动发出SSE指令

对于这种琐碎的内部循环,缓存效果是不相关的,因为您正在对所有内容进行迭代。如果您有嵌套的循环或一系列操作(如g(f(a,B),C)),那么您可以尝试安排重复访问小内存块,以使缓存更友好

不要手动展开循环。如果这是一个好主意(可能不是在现代CPU上),编译器也会这样做

如果循环非常大,并且其中的操作非常复杂,以至于您还没有内存限制,OpenMP可能会有所帮助


一般来说,请以自然、直观的方式编写代码,因为这是优化编译器最容易理解的内容。

您可以使用一些简单的并行化方法。Cuda依赖于硬件,但SSE几乎是每个CPU的标准配置。此外,您还可以使用多线程。在多线程中,您仍然可以使用pointer技巧,这不是很重要。这些简单的优化也可以由编译器完成。如果您使用Visual Studio 2010,则可以使用并行调用来并行执行函数,而无需处理windows线程。在Linux中,pThread库非常容易使用。

您可以使用一些简单的并行化方法。Cuda将很难使用依赖,但SSE几乎在每个CPU中都是标准的。您也可以使用多个线程。在多线程中,您仍然可以使用指针技巧,这一点并不重要。这些简单的优化也可以由编译器完成。如果您使用Visual Studio 2010,则可以使用parallel_invoke并行执行函数,而无需处理windows线程。在Linux中,pThread库非常易于使用。

性能规则如下

  • 还没有

  • 找到目标

  • 了解有多少改进是可能的,并验证是否值得花时间来实现

  • 现代处理器更是如此。关于您的问题:

  • 简单的索引到指针映射通常是由编译器完成的,当他们不这样做时,他们可能有很好的理由

  • 处理器通常已经针对对缓存的顺序访问进行了优化:简单的代码生成通常会提供最佳性能

  • SSE或许可以改善这一点。但如果您已经受到带宽限制,则不能。因此,我们回到测量和确定边界阶段

  • 并行化:与SSE相同。如果带宽有限,则使用单个处理器的多个内核将没有帮助。根据内存体系结构,使用不同的处理器可能会有所帮助

  • 手动循环展开(在现已删除的答案中建议)通常是一个坏主意。编译器知道如何在值得明智的情况下进行此操作(例如,如果它可以进行软件管道),而对于现代OOO处理器,情况往往不是这样(它增加了指令和跟踪缓存的压力,而OOO执行、跳转推测和寄存器重命名将自动带来展开和软件流水线的大部分好处)


  • 执行规则如下:

  • 还没有

  • 找到目标

  • 了解有多少改进是可能的,并验证是否值得花时间来实现

  • 现代处理器更是如此。关于您的问题:

  • 简单的索引到指针映射通常是由编译器完成的,当他们不这样做时,他们可能有很好的理由

  • 处理器通常已经针对对缓存的顺序访问进行了优化:简单的代码生成通常会提供最佳性能

  • SSE或许可以改善这一点。但如果您已经受到带宽限制,则不能。因此,我们回到测量和确定边界阶段

  • 并行化:与SSE相同。如果带宽有限,则使用单个处理器的多个内核将没有帮助。根据内存体系结构,使用不同的处理器可能会有所帮助

  • 手动循环展开(在现已删除的答案中建议)通常不是一个好主意。编译器知道如何在值得明智的情况下进行此操作(