在STL算法中跨函数边界循环重新排序

时间:2010-12-17 01:41:01

标签: c++ stl compiler-optimization

为简单起见,我们假设每个N行都有M个矩阵向量。我正在使用STL std::accumulate来计算所有矩阵的总和。我传递一个二元仿函数,它接受两个矩阵(通过引用)并返回它们的总和(通过引用)。完全披露:我正在使用libstdc ++并行模式。在仿函数内部,我分别循环遍历行以计算总和。

虽然每个矩阵都太大而无法放入缓存中,但是一行非常合适。因此,重新排序循环以使外循环在M行和N矩阵上的内部索引上进行索引将是有利的。除了定义函数内联之外,还有什么我可以做的来鼓励这样的跨函数边界循环重新排序。我当然可以重构代码,但我希望保持使用STL算法所提供的简单结构。如果有一些特定于gcc的东西,我也不会介意。

我实际上并没有处理矩阵,这只是一个例子,但同样的问题结构也适用。主要问题是绩效问题。解释实际场景太麻烦了,但核心问题是:STL的累积需要在嵌套循环之间进行排序,这对于非常缓存非常友好,因为它试图在移动到下一个对象之前完成两个对象的添加。单个对象太大而无法保存在缓存中,但部分对象可以。因此,如果一次计算“添加”一个“部分”(在所有对象上),则可以加快执行速度。重新排序循环的手导致FLOPS的实质性改进。但我理想情况下会喜欢编译器进行重新排序,以便我可以在STL级别进行编码(尽可能)。所以我正在寻找这样做的技巧。

3 个答案:

答案 0 :(得分:1)

我无法想象编译器会解决这个问题,除非所有内容都被内联并且M和N是不变的。即便如此,这也是一段时间。

为了保持STL算法风格,在累加上使用foreach M并使functor只需加一行。

答案 1 :(得分:1)

编写新算法,或将内容包装在for循环或std::for_each()调用中。这比找到适应std::accumulate()的方法要容易得多。我认为这里唯一的另一种选择是向库引入一个新的抽象级别,这超出了迭代器。只需编写新算法或引入额外的循环就更容易了。

答案 2 :(得分:1)

class Matrix;
class Row;
struct SumNRow {
  int _rowidx;
//  Row _tempRow; //For return by reference left out for simplicity
  SumNRow(int iRowIdx): _rowIdx(iRowIdx) {}
  Row operator(const Matrix & iMarix1, const Matrix iMatrix2) {
    return iMarix1[_rowIdx] + iMatrix2[_rowIdx];
  }
};

template<class MatrixIterator>
void sum(const MatrixIterator & iMarixStart, const MatrixIterator & iMatrixEnd, Matrix & oMarix) {
  for (int i = 0; i < iMarixStart->rowCount(); ++i) {
    oMarix[i]=std::accumulate(iMarixStart, iMatrixEnd, SumNRow(i));
  }
}