如何隐含地'为每个类的方法添加一些计时器,不包括构造函数和析构函数?
我现在为每个班级方法做的事情:
void MyClass::SomeFunc()
{
cout << __PRETTY_FUNCTION__ <<endl;
boost::timer::cpu_timer timer;
//Some code
boost::timer::cpu_times elapsed = timer.elapsed();
cout << __PRETTY_FUNCTION__ << " : WALLCLOCK TIME: " << elapsed.wall / 1e9 << " seconds" << endl;
}
我想要的是什么:
void MyClass::SomeFunc()
{
//Some code
}
假设这两部分代码的行为应该是等效的。
答案 0 :(得分:5)
使用RAII几乎可以达到这个目的:
struct FunctionLogger {
FunctionLogger(const char* func)
: m_func(func)
{
cout << func <<endl;
}
~FunctionLogger() {
boost::timer::cpu_times elapsed = timer.elapsed();
GSULOG << m_func << " : WALLCLOCK TIME: " << elapsed.wall / 1e9 << " seconds" << endl;
}
const char* m_func;
boost::timer::cpu_timer timer;
};
现在:
void MyClass::SomeFunc()
{
FunctionLogger _(__PRETTY_FUNCTION__);
//Some code
}
当然,如果你喜欢宏:
#define FL FunctionLogger _(__PRETTY_FUNCTION__)
void MyClass::SomeFunc()
{
FL;
//Some code
}
如果您正在为这类事物寻找工业级解决方案,那么艺术术语是Aspect Oriented Programming。但它不是C ++直接支持的。
答案 1 :(得分:4)
您要做的事情被称为分析(获取每个函数调用的持续时间)和检测(将代码注入函数以获取更详细但可能不太准确的时序信息)。
到目前为止这样做的最佳方式是不要自己动手,而是在分析器下运行代码(一种现成的应用程序,它可以执行时间安排,也可以选择进行检测所有这些都不会污染您的源代码。)
答案 2 :(得分:2)
如果您想避免修改代码,并愿意牺牲__PRETTY_FUNCTION__
输出。您可以通过计时句柄访问该类来实现此目的。
首先你定义一个RAII类用于计时,类似于 John Zwinck 的答案:
template<typename T>
struct TimingDecorator {
T *ptr_;
boost::timer::cpu_timer timer;
TimingDecorator (T* ptr) : ptr_(ptr) {}
~TimingDecorator () {
boost::timer::cpu_times elapsed = timer.elapsed();
GSULOG << " : WALLCLOCK TIME: " << elapsed.wall / 1e9 << " seconds" << endl;
}
T* operator->() { return ptr_; }
T const * operator->() const { return ptr_; }
};
然后定义一个句柄,强制通过装饰器对类进行所有访问:
template<typename T>
struct TimingHandle {
T &obj_;
boost::timer::cpu_timer timer;
TimingHandle (T const& obj) : obj_(obj) {}
TimingDecorator<T> operator->() { return &obj_; }
TimingDecorator<T const> operator->() const { return &obj_; }
};
然后,对于计时,您可以通过句柄进行所有访问:
MyClass obj;
TimingHandle<MyClass> obj_timing(obj);
GSULOG << "MyClass::SomeFunc" << endl;
obj_timing->SomeFunc();
我应该指出,最后两行可以包装在一个宏中(如果你不介意使用它),以避免重复自己。
#define MYCLASS_TIME_FUNC(handle, func) \
GSULOG << "MyClass::" #func << endl; \
(handle)->func
你最终可以用作
MYCLASS_TIME_FUNC(obj_timing, SomeFunc2)(/* params for SomeFunc2 */);
答案 3 :(得分:1)
您可以使用反转计划:
template <typename Caption, typename F>
auto timed(Caption const& task, F&& f) {
return [f=std::forward<F>(f), task](auto&&... args) {
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
Caption task;
~measure() { GSU_LOCK << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), task };
return f(std::forward<decltype(args)>(args)...);
};
}
您可以使用:Live On Coliru
timed_rand = time("Generate a random number", &::rand);
for (int i = 0; i<10; ++i)
std::cout << timed_rand() << " ";
通过一些MACRO帮助,你可以使它更具有使用性:
<强> Live On Coliru 强>
#include <iostream>
#include <chrono>
using namespace std::literals::string_literals;
#define GSU_LOG std::clog
template <typename Caption, typename F>
auto timed(Caption const& task, F&& f) {
return [f=std::forward<F>(f), task](auto&&... args) -> decltype(auto) {
using namespace std::chrono;
struct measure {
high_resolution_clock::time_point start;
Caption task;
~measure() { GSU_LOG << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; }
} timing { high_resolution_clock::now(), task };
return f(std::forward<decltype(args)>(args)...);
};
}
#define TIMED(expr) (timed(__FILE__ + (":" + std::to_string(__LINE__)) + " " #expr, [&]() -> decltype(auto) {return (expr);})())
int main() {
std::string line;
while (TIMED(std::getline(std::cin, line))) {
std::cout << "Simple arithmetic: " << TIMED(42 * TIMED(line.length())) << "\n";
}
}
打印
$ clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
$ for a in x xx xxx; do sleep 0.5; echo "$a"; done | ./a.out
-- (main.cpp:25 std::getline(std::cin, line) completed in 497455µs)
-- (main.cpp:26 line.length() completed in 36µs)
-- (main.cpp:26 42 * TIMED(line.length()) completed in 106µs)
Simple arithmetic: 42
-- (main.cpp:25 std::getline(std::cin, line) completed in 503516µs)
-- (main.cpp:26 line.length() completed in 14µs)
-- (main.cpp:26 42 * TIMED(line.length()) completed in 42µs)
Simple arithmetic: 84
-- (main.cpp:25 std::getline(std::cin, line) completed in 508554µs)
-- (main.cpp:26 line.length() completed in 14µs)
-- (main.cpp:26 42 * TIMED(line.length()) completed in 38µs)
Simple arithmetic: 126
-- (main.cpp:25 std::getline(std::cin, line) completed in 286µs)
请注意,您还可以使lambda累积不同呼叫的数据并报告总数/平均值。