C++ 如何为类的每个方法添加计时器?

C++ 如何为类的每个方法添加计时器?,c++,boost,timer,C++,Boost,Timer,如何“隐式”为类的每个方法(不包括构造函数和析构函数)添加某种计时器 我现在为每种课堂方法做的是: void MyClass::SomeFunc() { cout << __PRETTY_FUNCTION__ <<endl; boost::timer::cpu_timer timer; //Some code boost::timer::cpu_times elapsed = timer.elapsed(); cout <

如何“隐式”为类的每个方法(不包括构造函数和析构函数)添加某种计时器

我现在为每种课堂方法做的是:

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;
}

假设这两部分代码的行为应该是等效的。

使用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;
};
当然,如果您喜欢宏:

#define FL FunctionLogger _(__PRETTY_FUNCTION__)

void MyClass::SomeFunc()
{
    FL;
    //Some code
}

如果你正在为这类事情寻找工业级的解决方案,艺术的术语是。但是C++没有直接支持。

几乎可以使用RAII:< /P>实现这一点。
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;
};
当然,如果您喜欢宏:

#define FL FunctionLogger _(__PRETTY_FUNCTION__)

void MyClass::SomeFunc()
{
    FL;
    //Some code
}

如果你正在为这类事情寻找工业级的解决方案,艺术的术语是。但是它不是C++直接支持的。

你所要做的就是大家所知的剖析(获取每个函数调用的持续时间)和仪器(将代码注入到函数中以获得更详细,但可能不太准确的时序信息)。
到目前为止最好的方法是不要自己动手,而是在剖析器(一个现成的应用程序,它可以自动进行计时和插装,并且可以选择自动进行,而不会污染源代码)下运行代码。

您试图做的就是所谓的剖析(获取每个函数调用的持续时间)和插装(向函数中注入代码以获得更详细但可能不太准确的计时信息)


到目前为止最好的方法不是自己动手,而是在探查器下运行代码(一个现成的应用程序,可以自动执行计时和插装,并且可以选择自动执行,所有这些都不会污染源代码。)

如果您希望避免修改代码,并且愿意牺牲
\uu PRETTY\u函数\uuuu
输出。您可以通过计时句柄访问类来实现这一点

首先,您定义一个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_; }
};

如果您希望避免修改代码,并且愿意牺牲
\uu PRETTY\u函数\uuuu
输出。您可以通过计时句柄访问类来实现这一点

首先,您定义一个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 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)...);
    };
}

注意:您还可以让lambda为不同的通话积累数据,并报告总计/平均值。

稍微反转一下计划,您也可以使用:

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)...);
    };
}

注意,你也可以让LAMBDA为不同的调用积累数据,并报告总数/平均值。

比我把代码作为lambda运行到函数的想法要好得多。你可以考虑使用“\n”而不是Endl,顶部避免刷新缓冲器。@乔纳斯:也许,但是你应该建议OP,而不是我。他到底想要还是NEE。我不知道。我只是复制了相同的行为。比我把代码作为lambda运行到函数的想法要好得多。你可以考虑使用‘\n’而不是Endl,最好避免刷新缓冲区。@乔纳斯:也许,但是你应该建议OP,而不是我。不管他想要还是需要刷新,我都不知道。我只是复制。添加了一个生成类似于497455µs中完成的
(main.cpp:25 std::getline(std::cin,line)的输出的程序。
添加了一个生成类似于
(main.cpp:25 std::getline(std::cin,line)的输出的程序。
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)...);
    };
}
timed_rand = time("Generate a random number", &::rand);

for (int i = 0; i<10; ++i)
     std::cout << timed_rand() << " ";
#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)