我试图找到我最近在stackoverflow上发布的程序的效率。
How to efficiently delete elements from a vector given an another vector
将我的代码效率与使用chrono
对象的其他答案进行比较。
检查运行时效率是否正确?
如果没有,请通过示例建议一种方法。
#include <iostream>
#include <vector>
#include <algorithm>
#include <chrono>
#include <ctime>
using namespace std;
void remove_elements(vector<int>& vDestination, const vector<int>& vSource)
{
if(!vDestination.empty() && !vSource.empty())
{
for(auto i: vSource) {
vDestination.erase(std::remove(vDestination.begin(), vDestination.end(), i), vDestination.end());
}
}
}
int main() {
vector<int> v1={1,2,3};
vector<int> v2={4,5,6};
vector<int> v3={1,2,3,4,5,6,7,8,9};
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
remove_elements(v3,v1);
remove_elements(v3,v2);
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() <<std::endl;
for(auto i:v3)
cout << i << endl;
return 0;
}
输出
Time difference = 1472
7
8
9
答案 0 :(得分:26)
检查运行时效率是否正确?
看起来不是最好的方法。我在你的方法中看到了以下缺陷:
v3
适合CPU缓存与v3
大小超过CPU缓存。还要考虑(v1.length() + v3.length()) * sizeof(int)
是否符合缓存的情况,(v1.length() + v2.length() + v3.length()) * sizeof(int)
是否符合缓存等等所有组合。答案 1 :(得分:5)
您的方法存在的最大问题是:
1)您正在测试的代码太短且无法预测。您需要运行至少几千次,以便测量之间至少有几百毫秒。而且您需要使数据集更大且更难以预测。通常,CPU缓存实际上是基于PITA的合成输入数据进行精确测量。
2)编译器可以重新排序代码。一般来说,很难确保你在计时之间执行的代码会在检查时间之间执行(而不是其他任何事情)。一方面,您可以拨打优化,但另一方面,您需要测量优化代码。
一种解决方案是关闭整个程序优化并将计时调用放在另一个编译单元中。
另一种可能的解决方案是在测试周围使用内存栅栏,例如
std::atomic_thread_fence(std::memory_order_seq_cst);
(需要#include <atomic>
和支持C ++ 11的编译器)。
此外,您可能希望使用分析器数据来补充测量结果,以了解L1 / 2/3缓存的使用效率,内存瓶颈,指令退出率等。不幸的是,英特尔x86的最佳工具是商用( vtune),但在AMD x86上,类似的工具是免费的(codeXL)。
答案 2 :(得分:2)
您可以考虑使用像Celero这样的基准测试库来为您进行测量并处理性能测量的棘手部分,同时您仍然专注于您尝试优化的代码。我在上一个问题(How to efficiently delete elements from a vector given an another vector)的答案中链接的代码中提供了更复杂的示例,但是一个简单的用例如下所示:
BENCHMARK(VectorRemoval, OriginalQuestion, 100, 1000)
{
std::vector destination(10000);
std::generate(destination.begin(), destination.end(), std::rand);
std::sample(destination.begin(), destination.end(), std::back_inserter(source),
100, std::mt19937{std::random_device{}()})
for (auto i: source)
destination.erase(std::remove(destination.begin(), destination.end(), i),
destination.end());
}