优化' std::vector operator [] ' (vector访问),当它成为瓶颈时
optimizing `std::vector operator []` (vector access) when it becomes a bottleneck
gprof说我的高计算应用程序在std::vector <...> operator [] (unsigned long)
中花费了53%的时间,其中32%的时间用于一个经常使用的向量。更糟糕的是,我怀疑我的并行代码无法扩展到3-6核以上是由于相关的内存瓶颈。虽然我的应用确实花了很多时间访问和写入内存,但似乎我应该能够(或至少尝试)做得比52%更好。我应该尝试使用动态数组代替(大小保持不变,在大多数情况下)?这可能有助于解决可能出现的瓶颈吗?
实际上,为了方便起见,我更喜欢的解决方案是解决瓶颈并保持向量不变。基于以上,是否有任何可能的罪魁祸首或解决方案(tcmalloc出局)?
你检查你的内存访问模式本身了吗?
在访问数组时是否尝试使用原始指针?
// regular place
for (int i = 0; i < arr.size(); ++i)
wcout << arr[i];
// In bottleneck
int *pArr = &arr.front();
for (int i = 0; i < arr.size(); ++i)
wcout << pArr[i];
我怀疑gprof会阻止函数内联。尝试使用另一种分析方法。std::vector operator []
不能成为瓶颈,因为它与原始数组访问没有太大区别。SGI的实现如下所示:
reference operator[](size_type __n) { return *(begin() + __n); }
iterator begin() { return _M_start; }
您不能信任gprof
进行高速代码分析,您应该使用oprofile
这样的被动分析方法来获得真实的情况。
作为另一种选择,你可以通过手动修改代码来进行分析(例如,将一个计算调用10次而不是一次,并检查执行时间增加了多少)。请注意,这将受到缓存问题的影响,所以YMMV.
vector类很受欢迎,并以牺牲性能为代价提供了一定的便利,当您不是特别需要性能时,这是很好的。
如果您确实需要性能,那么绕过vector类并直接使用简单的老式手工数组(无论是静态分配还是动态分配)不会对您造成太大伤害。然后1)你现在花在索引上的时间就会消失,从而加快你的应用程序的速度,2)你可以转移到任何"下一件大事"上,那就是在你的应用程序中花费时间。
编辑:大多数程序的加速空间比您想象的要大得多。我制作了一个演练项目来说明这一点。如果我可以快速总结一下,它是这样的:
-
初始时间为2.7 msec每个"作业"("作业"的数量可以改变,以获得足够的运行时间来分析它)。
-
第一次切割显示大约60%的时间花在矢量操作上,包括索引、追加和删除。我从MFC替换了一个类似的矢量类,时间减少到1.8毫秒/工作。(这是1.5倍或50%的加速)
-
即使使用这个数组类,大约40%的时间花在[]索引操作符上。我想让它直接索引,所以我强制它直接索引,而不是通过运算符函数。
将时间降低到1.5毫秒/作业,速度提高了1.2倍。 现在大约60%的时间是在数组中添加/删除项。另外一部分花费在"新建"answers"删除"上。我决定放弃数组,做两件事。一种是使用自己动手的链表,并汇集使用过的对象。第一个将时间减少到1.3毫秒(1.15倍)。第二次减少到0.44毫秒(2.95倍)。
在那段时间里,我发现大约60%的时间是在我编写的代码中对列表进行索引(就好像它是一个数组)。我决定用一个直接指向列表的指针来代替。结果:0.14 msec (3.14x)
现在我发现几乎所有的时间都花在了打印到控制台的诊断I/O行上。我决定去掉:0.0037 msec (38x)。
我本可以继续走下去,但我停了下来。每次作业的总时间减少了约700倍的复合系数。
我想让你明白的是,如果你需要的性能差到足以偏离可能被认为是公认的做事方式,你不必在遇到一个"瓶颈"后就停下来。仅仅因为你有一个大的加速并不意味着没有更多。事实上,就加速因素而言,下一个"瓶颈"可能比第一个更大。所以提高你的期望,你可以得到加速,并尝试打破。
- std::vector::assign/std::vector::operator=(const&) 是否保证在"this"中重用缓冲区?
- 为什么 std::vector::operator= 过度分配内存
- 我可以在 c++ 中正确设置 std::vector by operator[] 的第 n 个值吗?
- 如何重载 std::vector::operator=()
- 为什么 vector::operator[] 的实现方式与 map::operator[] 不同?
- Vector::at vs. vector::operator[] -- 不同的行为
- std::vector::back 和 vector::operator[ vector::size() - 1] 之间
- vector::push_back vs vector::operator[]
- 正在获取 C++11 中 std::vector::operator[](size) 未定义行为的地址
- 对矢量(vector::operator[]和vector:(size))的只读访问是异步安全的
- 如何在使用vector::operator[]迭代结构的向量时访问结构成员
- vector::at vs. vector::operator[]
- 从std::vector::operator[]获取返回地址做什么
- std::vector:<T>:resize(n) vs reserve(n) with operator[]
- 优化' std::vector operator [] ' (vector访问),当它成为瓶颈时
- 为什么vector迭代器没有显示operator= ?
- 使用std::vector::at或std::vector::operator[]访问vector:中存储的对象
- std::vector::operator[]返回的引用可以使用多长时间?
- C++: std::vector [] operator
- EASTL 与 STL,std::vector:<uint64_t>:operator[] 怎么会有这样的性能差异