How to find runtime efficiency of a C++ code
我正在努力寻找一个程序的效率,我最近在StackOverflow上发布了这个程序。
如何有效地从给定另一个向量的向量中删除元素
为了将代码的效率与其他答案进行比较,我使用了
它是检查运行时效率的正确方法吗?
如果没有,那么请用一个例子来建议一种方法。
科利鲁代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <iostream> #include <vector> #include #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; } |
产量
1 2 3 4 | Time difference = 1472 7 8 9 |
Is it a correct way to check the runtime efficiency?
看起来不是最好的方法。我发现你的方法有以下缺陷:
- 排序数据与未排序数据
v3 适合CPU缓存,而v3 的大小超过了CPU缓存。还可以考虑当(v1.length() + v3.length()) * sizeof(int) 与缓存是否匹配,(v1.length() + v2.length() + v3.length()) * sizeof(int) 与缓存是否匹配等所有组合的情况。
你的方法最大的问题是:
1)您要测试的代码太短,而且是可预测的。您需要运行它至少几千次,以便在测量之间至少有几百毫秒。您需要使数据集更大,更不容易预测。一般来说,CPU缓存确实基于合成输入数据PITA进行精确测量。
2)编译器可以自由地重新排序代码。一般来说,很难确保您正在计时的代码在调用之间执行以检查时间(而没有其他事情,因为这一点)。一方面,您可以向下拨优化,但另一方面,您希望测量优化的代码。
一种解决方案是关闭整个程序优化,并将计时调用放入另一个编译单元。
另一种可能的解决方案是在测试周围使用内存隔离,例如
1 | std::atomic_thread_fence(std::memory_order_seq_cst); |
(需要EDCOX1×4)和一个C++ 11能力编译器。
此外,您可能希望用事件探查器数据补充您的度量,以了解使用1/2/3缓存的效率、内存瓶颈、指令失效率等。不幸的是,英特尔x86的最佳工具是商业(vtune),但在AMD x86上,类似的工具是免费的(codexl)。
您可以考虑使用一个基准库(如celero)来为您进行度量,并处理性能度量中的棘手部分,而您仍然关注您试图优化的代码。在我在前面问题的答案中链接的代码中有更复杂的示例(如何有效地从给定另一个向量的向量中删除元素),但是一个简单的用例如下所示:
1 2 3 4 5 6 7 8 9 10 11 | 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()); } |