【问题标题】:How to bulk-allocate for boost::ptr_vector and call the stored class' constructor?如何批量分配 boost::ptr_vector 并调用存储类的构造函数?
【发布时间】:2016-03-08 00:21:45
【问题描述】:

对于进化算法,我需要一个容器来存储个体群体 - 即对象向量。我需要在每次迭代时对该向量进行排序,这应该是有效的。此外,我想避免缓存未命中,所以我想预先批量分配整个人口(它的大小是已知的并且是固定的)。但是,我并不满足于类的默认构造函数,而是想在每个对象上调用一个特定的构造函数。

我在当前代码上运行了cachegrind,发现缓存未命中次数最多的是Individual::operator <(const Individual &other),这是我对总体进行排序的谓词。由于我的人口在每次迭代中都进行了排序,我认为此时进行优化会给我带来最大的好处。我已经将operator <() 中的缓存未命中解释为源于Individual 对象在我的系统内存上的分布——如果不是这样,我会在访问器函数中看到缓存未命中,例如存储的std::vector<double>个人的参数吧?

根据我的要求,我选择了boost::ptr_vector。主要是因为它允许我 (a) 将我的对象保存在一块内存中,同时提供不创建和销毁临时对象的 sort() 实现。

现在,为了避免缓存未命中,我想将整个人口分配为一块。我想做的是类似于......

boost::ptr_vector<Individual> population;
auto *rawPopulaton = new Individual[populationSize](templateObject);
population.transfer(population.begin(), rawPopulation, populationSize);
return population;

然而,我不确定如何实现这一点,以便违反空间局部性的概念(即,我想避免缓存未命中)。我可以愉快地循环:

for (size_t i = 0; i < populationSize; ++i) {
    auto *individual = new Individual(templateObject);
    population.push_back(individual);
}

...但我担心这会导致我的人口分布在不同的内存块上。

所以这里其实有两个问题:

  1. 我的设计选择是否符合优化目标?
  2. 如何批量分配我的人口调用特定的构造函数?

【问题讨论】:

  • 实际上是否存在缓存未命中导致的性能瓶颈? (任何测量完成?) 使用memory pool 分配对象怎么样? (或者自己写,使用placement new
  • 关于 更具体——由于分配导致的未命中,而不是说似乎很可能发生的对该内存的非顺序访问。
  • @DanMašek:关于(1),是的,我进行了测量。我会更新我的问题以反映这些。

标签: c++ optimization boost


【解决方案1】:

我选择了 boost::ptr_vector。主要是因为它允许我 (a) 将我的对象保存在一块内存中

它不这样做。您的 transfer 方法很接近,但是

  • “索引”和后备存储之间存在非本地性。
  • 排序打破了完美的顺序

同时提供不创建和销毁临时对象的 sort() 实现。

您可能正在寻找stable_vector 或侵入性容器。


我的设计选择是否符合优化目标?

我不确定,但我对此表示怀疑。 (您是否分析过您的瓶颈?您似乎建议重新排序应该在物理上重新排序以进行顺序访问。在这种情况下,只需使用vector&lt;X&gt; 而不是ptr_vector&lt;X&gt;?)

如何批量分配我的人口并调用特定的构造函数?

你考虑过std::fill[_n]std::generate[_n]吗?

【讨论】:

  • std::generate 直到现在我才知道 - 感谢您的提示!但是对于局部性 高效排序,我不确定是否有一种数据结构可以同时满足我的要求。 stable_vector 使用不连续的内存块,其中std::sort 创建临时对象。或者也许我只是误解了一些东西。此外,我用来自 cachegrind 的信息更新了我原来的问题;请你看看我的假设好吗?
  • 您的缓存未命中似乎是由于随机访问。当跳跃是“随机的”时,连续性并不重要。也许您应该使用堆/陷阱?保持分类更便宜的东西。 IIRC std::priority_queue 在内部使用类似的东西。另请参阅std::make_heapstd::push_heapstd::pop_heapstd::sort_heap
  • 谢谢,这些是非常有用的指针。我将相应地调查和调整我的代码。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 2020-03-04
  • 2016-02-23
  • 1970-01-01
  • 2013-03-06
相关资源
最近更新 更多