首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >STL向量上的重复操作是否允许“内在并行性”/Improved内存访问?

STL向量上的重复操作是否允许“内在并行性”/Improved内存访问?
EN

Stack Overflow用户
提问于 2013-09-23 22:27:15
回答 2查看 113关注 0票数 1

我有一个两相过程,在我的模拟程序中构成一个循环。我或多或少地有以下几点:

代码语言:javascript
复制
struct Coordinates
{
   double * x, * y, * z;
   uint * kind, count;
   double GetDist(const uint p1, const uint p2);
};

struct Polynomial
{
   double * A, * B;
   uint n1, n2;
   uint Flatten(const uint i, const uint j);
   double CalcResult(double distSq, uint kind1, uint kind2)
   {
      uint ij = Flatten(kind1, kind2);
      double base = B * distSq;
      return A[ij]*(pow(base,n2)-pow(base,n1));
   }
};

我的问题是如果我写我的代码

代码语言:javascript
复制
struct Model
{
   Coordinates c;
   Polynomial f;
   double DoTest()
   {
      double result = 0;
      uint count = 0;
      std::vector<double> distSq;
      for (uint i=0; i<c.count; i++)
      {
         for (uint j=i; j<c.count; j++)
         {
            result = c.GetDist(i,j);
            distSq.push_back(result);
         }
      }
      result = 0;
      for (uint i=0; i<c.count; i++)
      {
         for (uint j=i; j<c.count; j++)
         {
            result += f.CalcResult(distSq[count], i, j);
            count++;
         }
      }
      return result;
   }
   double DoTest2()
   {
      double result = 0;
      for (uint i=0; i<c.count; i++)
         for (uint j=i; j<c.count; j++)
            result += f.CalcResult(c.GetDist(i,j), i, j);
      return result;
   }
}

考虑到Test在单个数据集上的重复操作,它会自动启用x86芯片上的并行性(例如矢量化数学或改进内存访问)吗?

否则,Test是一种垃圾方法--它使用额外的存储( std::vector<double> distSq;),并且在代码读取方面要长得多。从逻辑上讲,它或多或少是相同的,但是如果我们将GetDist f_A (函数A)和CalcResult f_B (函数B)称为CalcResultf_B(函数B),测试是:

代码语言:javascript
复制
f_A f_A f_A ... f_A    f_B f_B .... f_B

其中,作为较短/较小的内存密集型函数是

代码语言:javascript
复制
f_A f_B f_A f_B .... f_A f_B

我听说过-O#编译的C代码中有所谓的“固有并行性”,因为生成了矢量化的数学操作,等等。Test是否能够启用这种编译器派生的并行(例如向量化的数学或优化的内存访问)?在x86芯片上,考虑到它在单个数据集上的重复操作?

(否则,Test2是唯一合理的方法,因为它使用较少的内存。)

另外,用x替代c样式的yz数组是否有可能以任何方式加速计算或内存访问?

请不要回答“基准你自己”。我之所以要求更好地理解是否值得从理论角度(基于编译器和“固有并行性”)通过基准测试方法来测试Test

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-23 23:50:36

无论并行性如何,内存访问都会杀死您。在调用.reserve(c.count*c.count())以防止.push_back中的重新分配方面,有一个小的改进,但这还不够。如果c.count足够大,这将浪费L1缓存和可能的L2。

下一个问题是您的f_A函数依赖于内存访问。现代处理器可以同时发出读取和处理以前的f_B的命令。不存在数据依赖关系。这使得Test2更加高效。

CalcResult(i,j)和CalcResult(j,i)非常相似吗?合并计算可能会使您受益。

我会制作AB double const*。毕竟,你没有把它们写下来。

最有用的是一个#pragma omp for reduction(+, result)

票数 1
EN

Stack Overflow用户

发布于 2013-09-24 00:24:44

经典SIMD编译器优化

已知编译器易于使用SIMD指令进行优化的代码的一个简单示例如下:

代码语言:javascript
复制
for (int i = 0; i < N; ++i) 
     C[i] = A[i] + B[i];

基于VC++的SIMD优化实例

,在您的例子中,

使用c.GetDist的第一个循环看起来似乎所有的迭代都是相互独立的,但是根据GetDist的实际操作,再加上将结果推回向量,我认为编译器生成SIMD指令可能比简单地在内置数组中添加2个向量更困难。不过,我不是编译专家,所以我可能错了。它也可能因编译器而异。

确定的最佳方法是编译代码,查看反汇编,看看编译器生成了什么样的指令。例如,如果您使用的是IA-32或64位Intel,请查找对MMX或XMM寄存器起作用的指令。您也可以尝试用内置数组替换向量,以查看它是否有任何不同。

Intel汇编语言参考

有趣的谈话

最近,我在2013年土著大会上观看了吉姆·拉迪根( Jim )的一次有趣的演讲。他在微软C++编译器后端团队工作,擅长于代码优化。他谈到了几个有趣的主题,其中包括在生成的机器代码中实现并行性。下面是演讲的链接:

Jim谈到编译器优化

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18969943

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档