C++ 使用 std::chrono 以一种很好的方式测量成员函数的执行

lin*_*ver 4 c++ time std c++-chrono

我想优化我的应用程序,尤其是某些功能的执行速度。

想象一下有一个带有一些成员函数的类

class Test
{
public:
    Test();
    virtual ~Test();
    int init(int arg1, double arg2);

private:
    [...]
Run Code Online (Sandbox Code Playgroud)

在我的构造函数中,我调用了这些方法之一

Test::Test()
{
    [...]
    int value = init(1, 1.2);
}
Run Code Online (Sandbox Code Playgroud)

如何init(...)在不破坏程序的情况下以一种漂亮而干净的方式测量我的方法的执行时间?

目前我使用以下代码

Test::Test()
{
    [...]
    auto start = std::chrono::high_resolution_clock::now();

    int value = init(1, 1.2);

    auto stop = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> duration = stop - start;
    std::cout << duration.count() * 1000 << "ms\n";
}
Run Code Online (Sandbox Code Playgroud)

它按预期工作,但我认为它非常混乱,我想要一个“更干净”的解决方案。

有没有办法让某种函数接受一个成员函数和其他参数,像这样

int value = countTime(function, arg1, arg2);
Run Code Online (Sandbox Code Playgroud)

我不知道是否有可能从通过返回值function()countTime()为了不打断我的代码的工作流程。

编辑: 这是我的 TimeMeasure 类

namespace tools 
{
    class TimeMeasure 
    {
    public:
        TimeMeasure() 
        {
            m_start = std::chrono::high_resolution_clock::now();
        }

        virtual ~TimeMeasure()
        {
            m_stop = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double, std::milli> duration = m_stop - m_start;
            std::cout << duration.count() << "ms\n";
        }

    public:
        typedef std::chrono::time_point<std::chrono::high_resolution_clock> HighResClock;

    private:
        HighResClock m_start;
        HighResClock m_stop;
    };

    template <typename T, typename F, typename... Args>
    auto measure(T *t, F &&fn, Args... args)
    {
        tools::TimeMeasure timeMeasure;
        return (t->*fn)(std::forward<Args>(args)...);
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的构造函数中,Test()我以measure这种方式使用该函数

Test()
{
    [...]
    tools::measure(this, Test::init, filepath);
}
Run Code Online (Sandbox Code Playgroud)

int init(const std::string& filepath) const此处将字符串转换为文件。所以就我而言,这只是一个论点

不幸的是我收到一个invalid use of non-static member function 'int init(const string&) const'错误

我想知道构造函数是否不是成员函数。那么为什么我会收到这个错误呢?

编辑2:

根据 OznOg 的回答,我只是忘记提交指向我的函数的指针。

所以这将是正确的函数调用

tools::measure(this, &Test::init, filepath);
Run Code Online (Sandbox Code Playgroud)

Ozn*_*nOg 5

您可以创建一个类,如:

struct MeasureTime {
    MeasureTime() : _start(std::chrono::high_resolution_clock::now()) {}

    ~MeasureTime() {
        auto stop = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double> duration = stop - _start;
        std::cout << duration.count() * 1000 << "ms\n";
    }
private:
    std::chrono::time_point<std::chrono::high_resolution_clock>  _start;
};
Run Code Online (Sandbox Code Playgroud)

只需在您的代码中使用它:

Test::Test()
{
    MeasureTime mt;
    [...]
    { //or even this for just the init call
    MeasureTime mt2;
    int value = init(1, 1.2);
    }
}
Run Code Online (Sandbox Code Playgroud)

恕我直言,它不像你提出的那样具有侵入性。

如果你真的想要一个函数,你可以尝试一个包装器,如:

template <class T, class F, class... Args>
auto MeasureTimeFn(T *t, F &&fn, Args&&... args) {
    MeasureTime timer;
     return (t->*fn)(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

并称之为:

int value = MeasureTimeFn(this, &Test::init, 1, 1.2);
Run Code Online (Sandbox Code Playgroud)

但不确定它真的好多了。

您可以尝试使用宏隐藏内容:

#define MEASURE(f, ...) \
  MeasureTimeFn(this, &std::remove_reference_t<decltype(*this)>::f, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

这样你就可以写

int value = MEASURE(init, 1, 1.2);
Run Code Online (Sandbox Code Playgroud)

什么与您要求的非常相似,但仅适用于成员函数和成员函数(非静态)。

无论如何可能是一个开始的好地方。

* EDIT* 如果你可以修改你的类的继承,你可以试试

template<class T>
struct MeasureTool {
    template <class F, class... Args>
    auto measure(F &&fn, Args&&... args) {
        tools::TimeMeasure timeMeasure;
        return (static_cast<T*>(this)->*fn)(std::forward<Args>(args)...);
    }
};

class Test : public MeasureTool<Test>
{
public:
    Test();
    virtual ~Test() {}
    int init(const std::string &filepath) { _path = filepath; return 0; }
    const auto &getPath() const { return _path; }
private:
    std::string _path;

};

Test::Test()
{
    std::string filepath("/some/where");
    int value = measure(&Test::init, filepath);
    measure(&Test::getPath);
}
Run Code Online (Sandbox Code Playgroud)

而且,这一次,似乎符合您的第一个要求(但非常具有侵入性......)

现在,一切都在你手中:)