gpt4 book ai didi

c++ - 如何优化一个简单的循环?

转载 作者:搜寻专家 更新时间:2023-10-31 02:18:33 24 4
gpt4 key购买 nike

循环很简单

void loop(int n, double* a, double const* b)
{
#pragma ivdep
for (int i = 0; i < n; ++i, ++a, ++b)
*a *= *b;
}

我正在使用英特尔C++编译器,并使用 #pragma ivdep当前进行优化。有什么方法可以使其更好地工作,例如一起使用多核和向量化,还是其他技术?

最佳答案

  • 此循环可由编译器绝对矢量化。但是,请确保该循环实际上是矢量化的(使用Compiler'-qopt-report5,程序集输出,Intel (vectorization) Advisor以及其他任何技术)。执行此操作的另一种过大方法是使用-no-vec选项(将禁用ivdep驱动和自动矢量化)创建性能基准,然后将执行时间与其进行比较。这不是检查矢量化存在性的好方法,但对于后续项目符号的常规性能分析很有用。

  • 如果尚未实际对循环进行矢量化,请确保按编译器对其进行自动矢量化。为了 push 编译器,请参阅下一个项目符号。请注意,即使成功将循环自动向量化,下一个项目符号也可能有用。
  • 要使编译器矢量化,请使用:(a)关键字限制为“消除” a和b指针的歧义(有人已经向您建议了它)。 (b) #pragma omp simd (它比ivdep具有更多的可移植性和灵活性,但还具有一个缺点,即intel编译器版本14之前的旧编译器不支持该缺点,对于其他循环,则更“危险” )。再次强调:给定的项目符号似乎与ivdep具有相同的功能,但是根据各种情况,它可能是更好,更强大的选择。
  • 给定的循环具有细粒度的迭代(每次迭代的计算量太小),并且总体上并不是纯粹的计算范围(因此,如果不更大,CPU从/从缓存/内存加载/存储数据所花费的工作量/周期是相当的)进行乘法所花费的精力/周期)。展开通常是稍微减轻这些缺点的好方法。但是我建议使用 #pragma unroll 明确要求编译器将其展开。实际上,对于某些编译器版本,将自动进行展开。同样,您可以使用-qopt-report5,循环汇编或Intel(Vectorization)Advisor来检查编译器何时执行此操作:
    enter image description here
  • 在给定的循环中,您处理“流式”访问模式。即您正在连续地从内存中加载/存储数据(对于大的“n”值,高速缓存子系统将无济于事)。因此,取决于目标硬件,多线程的使用(在SIMD之上)等,您的循环最终可能会成为绑定(bind)的内存带宽。一旦成为受内存限制的带宽,您就可以使用诸如循环阻止,非临时存储,积极的预取之类的技术。所有这些技术都值得在单独的文章中找到,尽管对于预取/ NT存储,您可以在英特尔编译器中使用一些实用工具。
  • 如果n很大,并且您已经准备好解决内存带宽问题,则可以将 #pragma omp parallel用作simd ,这将同时对线程进行并行化和向量化循环。但是,仅在非常新的编译器版本AFAIK中才使此功能的质量令人满意,因此,您可能希望半手动拆分n。即 n = n1xn2xn3 ,其中n1-是要在线程之间分配的迭代次数,n2-用于高速缓存阻塞,n3-用于矢量化。重写给定的循环以使其最嵌套3个嵌套循环,其中外循环进行n1次迭代(并应用#pragma omp并行),下一级循环进行n2次迭代,n3-最内层(应用#pragma omp simd)。

  • 一些最新的链接,包括语法示例和更多信息:
  • 展开:https://software.intel.com/en-us/articles/avoid-manual-loop-unrolling
  • OpenMP SIMD编译指示(不是那么新鲜和详细,但仍然相关):https://software.intel.com/en-us/articles/enabling-simd-in-program-using-openmp40
  • restrict vs. ivdep
  • NT存储和预取:https://software.intel.com/sites/default/files/managed/22/a3/mtaap2013-prefetch-streaming-stores.pdf

  • 注意1:很抱歉,我在这里没有提供各种代码段。这里没有提供它们的理由至少有两个:1.我的5个项目符号非常适用于很多内核,而不仅仅是您的内核。 2.另一方面,实用程序/手动重写技术和相应的性能结果的特定组合将根据目标平台,ISA和编译器版本而有所不同。

    注意2:关于您的GPU问题的最后评论。考虑一下您的循环与诸如LINPACK或STREAM之类的简单行业基准。实际上,最后您的循环可能与其中的某些循环非常相似。现在考虑x86 CPU,尤其是LINPACK / STREAM的Intel Xeon Phi平台特性。它们确实非常好,并且在高带宽内存平台(例如Xeon Phi 2nd gen)上将变得更好。因此,从理论上讲,没有任何单一的理由认为您的给定循环没有很好地映射到x86硬件的至少某些变体(请注意,我没有对Universe中的任意内核说过类似的话)。

    关于c++ - 如何优化一个简单的循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34415583/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com