如何将计时器添加到每种类方法中

How to add timer to every method of class?

本文关键字:种类 类方法 添加 计时器      更新时间:2023-10-16

如何为每种类的方法添加某种计时器,不包括构造函数和destructor?

我现在正在为每种类的方法做什么:

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
}

假设代码的两个部分的行为应等效。

您几乎可以使用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
}

如果您正在为这种事情寻找工业级解决方案,那么艺术的术语是面向方面的编程。但这不是C 直接支持的。

您试图做的是称为分析(获取每个函数呼叫的持续时间)和仪器(将代码注入函数中以获得更详细的信息,但可能不太准确,可能不太准确,定时信息)。

到目前为止最好的方法是不自己执行,而是在探险仪下运行代码(一个实时的应用程序,可以执行时间安排,并且可以选择地,自动,所有这些都不污染您的源代码。)

如果要避免修改代码,并且愿意牺牲__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 */);

对您也可以使用的一点点主动性:

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() << " ";

有了一点宏帮助,您可以使其更具变色为:

活在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累积不同呼叫的数据,并报告总计/平均值。