如何解决测量函数的执行时间
我想测量函数执行的时间。
我可以这样使用:
template <typename Function,typename... Args>
auto measure_time(Function func,Args&&... args)
{
using namespace std::chrono;
auto start = steady_clock::now();
func(std::forward<Args>(args)...); // handle lvalues and rvalues
return duration<double>(steady_clock::now() - start).count();
}
但是对我来说,我似乎非DRY。所以我创建了一个小函数来做到这一点:
measure_time(func,arg1,arg2,arg3); // for common functions
measure_time([](){func(arg1,arg3);); // for member or template functions
我这样称呼它:
func
这对我来说很好,但确实有一些缺点:
- 我不清楚如何方便地 更改它以同时获取
void
(当然也可以是important_function(arg1,arg2); // reads well measure_time(important_function,arg2); // measure_time steals the spotlight
)的返回值? - 这显然与功能单一的规则相矛盾
- 代码的可读性被大大破坏:
using namespace std::chrono; template <typename Container> class Timer{ public: Timer(Container& _c) : c(_c) {} ~Timer() { c.push_back(duration<float>(steady_clock::now() - start).count()); } private: time_point<steady_clock> start{steady_clock::now()}; Container& c; };
是否有应对这些问题的准则?
更新:
我忘了提到函数执行后,我需要将经过的时间存储到容器中。
更新2:
在@puio回答之后,我最终得到了这一点:
auto mc = MyContainer{};
...
{
auto t = Timer<MyContainer>(mc);
// things to measure
}
// mc.back() is the elapsed time
用法:
v-pre
干燥并清洁:)
解决方法
在函数中实例化此类,它将显示对象超出范围的时间。
class Timer {
private:
std::chrono::steady_clock::time_point begin;
std::string_view func_name;
public:
Timer(std::string_view func)
{
func_name = func;
begin = std::chrono::steady_clock::now();
}
~Timer()
{
const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << func_name << " Time: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()
<< " microseconds " << std::endl;
}
};
用法:
void slow_func(){
Timer timer{__func__};
// ...
// Destruct automatically.
}
chrono
函数是从这里获取的,因为我一直忘了它。
但是我需要将经过的时间存储在一个容器中
我想象它是std::vector
,通过非常量引用(作为返回值)将其传递给构造函数,将该引用存储在private
访问中,并且push_back
析构函数中的向量。
这样做的公共成员函数,或者用所说的std::vector
显式调用析构函数,只会很麻烦。此外,呼叫者可能会错过使用该功能的机会。
如果记录时间不属于程序的主要目标。您可以使用GCC -finstrument-functions
选项并提供功能的定义:
struct Record {
std::chrono::time_point<std::chrono::steady_clock> start,stop;
};
std::map<void *,Record> container;
void __cyg_profile_func_enter (void *this_fn,void *call_site) {
auto &record = container[this_fn];
auto start = std::chrono::steady_clock::now();
// do something with start
record.start = start;
}
void __cyg_profile_func_exit (void *this_fn,void *call_site) {
auto stop = std::chrono::steady_clock::now();
// do something with stop
container[this_fn].stop = stop;
}
,
...我尚不清楚如何方便地更改它以同时检索
的返回值。func
另一种可能的解决方案是返回持续时间的tuple
,如果不是void
,则返回函数的返回值。
类似这样的东西(C ++ 17):
using Clock = std::chrono::high_resolution_clock;
template <typename Function,typename... Args>
auto measure_time(const Function& function,Args&&... args) {
auto start = Clock::now();
if constexpr (std::is_same_v<std::invoke_result_t<Function,Args...>,void>) {
std::invoke(function,std::forward<Args>(args)...);
return std::make_tuple<Clock::duration>(Clock::now() - start);
}
else {
std::tuple<Clock::duration,std::invoke_result_t<Function,Args...>> res{0,std::invoke(function,std::forward<Args>(args)...) };
std::get<0>(res) = Clock::now() - start;
return res;
}
}
用作:
using namespace std::chrono_literals;
int main() {
auto [dur,res] = measure_time(&some_func,some_args);
std::cout << "some_func: " << res << ",time: " << dur / 1us << "us\n";
}
注意:
-
通过创建元组和调用结果,我们将从RVO中受益(结果将存储在调用站点中,而不会被复制/移动)。
-
std::invoke
允许调用指针成员函数。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。