C++ C++;使用std::chrono可以很好地度量成员函数的执行情况
我想优化我的应用程序,特别是某些函数的执行速度 假设有一个包含一些成员函数的类C++ C++;使用std::chrono可以很好地度量成员函数的执行情况,c++,time,std,chrono,C++,Time,Std,Chrono,我想优化我的应用程序,特别是某些函数的执行速度 假设有一个包含一些成员函数的类 class Test { public: Test(); virtual ~Test(); int init(int arg1, double arg2); private: [...] 在我的构造函数中,我调用其中一个方法 Test::Test() { [...] int value = init(1, 1.2); } 如何在不中断程序的情况下,以一种简洁明了的
class Test
{
public:
Test();
virtual ~Test();
int init(int arg1, double arg2);
private:
[...]
在我的构造函数中,我调用其中一个方法
Test::Test()
{
[...]
int value = init(1, 1.2);
}
如何在不中断程序的情况下,以一种简洁明了的方式测量方法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";
}
我不知道是否可以将返回值从function()
传递到countTime()
,以避免中断代码的工作流程
编辑:
这是我的计时课
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)...);
}
}
int init(const std::string&filepath)const
在这里将字符串带到文件中。所以在我的情况下,这只是一个论点
不幸的是,我得到了一个非静态成员函数“int init(const string&)const”的无效用法错误
我想知道构造函数是否不是成员函数。那么为什么我会得到这个错误呢
编辑2:
根据OznOg的回答,我只是忘了交一个指向我函数的指针
因此,这将是正确的函数调用
tools::measure(this, &Test::init, filepath);
您可以创建一个类,如:
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;
};
依我看,这比你提议的要少一些
如果确实需要函数,可以尝试以下包装器:
template <class T, class F, class... Args>
auto MeasureTimeFn(T *t, F &&fn, Args&&... args) {
MeasureTime timer;
return (t->*fn)(std::forward<Args>(args)...);
}
但不确定它是否真的好得多
您可以尝试使用宏隐藏对象:
#define MEASURE(f, ...) \
MeasureTimeFn(this, &std::remove_reference_t<decltype(*this)>::f, __VA_ARGS__)
这与您所要求的非常相似,但只在成员函数内部工作,成员函数(非静态)
无论如何,这可能是一个好的开始
*编辑*
如果可以修改类的继承,可以尝试
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);
}
模板
结构测量醇{
模板
自动测量(F&&fn,参数&&…参数){
工具:TimeMeasure TimeMeasure;
返回(静态_cast(this)->*fn)(标准::向前(args)…);
}
};
类别测试:公共测量工具
{
公众:
Test();
虚拟~Test(){}
int init(const std::string&filepath){u path=filepath;返回0;}
const auto&getPath()const{return\u path;}
私人:
std::string\u路径;
};
Test::Test()
{
std::string文件路径(“/some/where”);
int value=measure(&Test::init,filepath);
度量(&Test::getPath);
}
而且,这一次,似乎符合您的第一个要求(但非常麻烦…)
现在,一切都在您的手中:)您可以使用这样的实现:
template<typename Fn, typename... Args>
typename std::enable_if<!std::is_void<typename std::result_of<Fn&&(Args...)>::type>::value,
std::tuple<std::chrono::duration<double>, typename std::result_of<Fn&&(Args...)>::type>
>::type
countTime(Fn&& fn, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
auto fnret = std::forward<Fn>(fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start, fnret);
}
template<typename Fn, typename... Args>
typename std::enable_if<std::is_void<typename std::result_of<Fn&&(Args...)>::type>::value,
std::tuple<std::chrono::duration<double>>
>::type
countTime(Fn&& fn, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
std::forward<Fn>(fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start);
}
template<typename R, class C, typename... Args>
typename std::enable_if<!std::is_same<R, void>::value,
std::tuple<std::chrono::duration<double>, R>
>::type
countTime(R (C::*fn)(Args...), C& obj, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
auto fnret = (obj.*fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start, fnret);
}
template<class C, typename... Args>
std::tuple<std::chrono::duration<double>>
countTime(void (C::*fn)(Args...), C& obj, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
(obj.*fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start);
}
实时版本可在处获得。我始终使用
#包括
...
boost::timer::cpu\u定时器;
对于(int i=0;i<1000;++i)
funct();
std::无法将停止-启动
分配到std::chrono::duration
,并删除*1000
。让
为您进行这些转换。如果你养成这样做的习惯,当事情变得非常复杂时,你会有更少的编码错误。@HowardHinnant谢谢你的建议!我不知道this@LightnessRacesinOrbit我已经发现了这个工具。不幸的是,这对我的需要来说太多了。我只想测量某些函数。此外,gprof
似乎会产生相对较大的开销。它不是“太多”,它正是分析函数执行的合适工具,而不是通过应用程序散布时间度量值,因为应用程序容易出现各种错误。当然,它会减慢你的程序速度,所以你不会得到绝对速度,但绝对速度无论如何都是无用的(你的程序将在多台电脑上运行,对吗?)-你需要知道哪个函数当前比所有其他函数都慢,这一点是正确的。目前我也用类似的方式来做。但是如果我让析构函数为我做这项工作,并将int value=init(…)
放入作用域,我将丢失value
。我返回某些内容并将其保存在变量中是有原因的。我想稍后在我的Test()
构造函数中对它做些什么。我认为在我高效的codewith语句表达式中尽可能少地更改会很好,您可以删除模板函数,但不确定这是否更好(可移植性较差),我喜欢更新的方式。我认为,如果您只想测量函数的时间,而不经常更改代码,那么就不那么容易混淆了。不幸的是,我在编译时遇到了一个无效使用非静态成员函数“[…]”
的错误。我认为指向我的成员函数的指针应该足够调用它了?你应该在某处显示代码,我认为你不是从成员函数调用宏;宏还可以,但没有直接使用,缺少了&;您应该尝试使用int value=MeasureTimeFn(this,&Test::init,1,1.2)代码>
int value = MeasureTimeFn(this, &Test::init, 1, 1.2);
#define MEASURE(f, ...) \
MeasureTimeFn(this, &std::remove_reference_t<decltype(*this)>::f, __VA_ARGS__)
int value = MEASURE(init, 1, 1.2);
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);
}
template<typename Fn, typename... Args>
typename std::enable_if<!std::is_void<typename std::result_of<Fn&&(Args...)>::type>::value,
std::tuple<std::chrono::duration<double>, typename std::result_of<Fn&&(Args...)>::type>
>::type
countTime(Fn&& fn, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
auto fnret = std::forward<Fn>(fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start, fnret);
}
template<typename Fn, typename... Args>
typename std::enable_if<std::is_void<typename std::result_of<Fn&&(Args...)>::type>::value,
std::tuple<std::chrono::duration<double>>
>::type
countTime(Fn&& fn, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
std::forward<Fn>(fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start);
}
template<typename R, class C, typename... Args>
typename std::enable_if<!std::is_same<R, void>::value,
std::tuple<std::chrono::duration<double>, R>
>::type
countTime(R (C::*fn)(Args...), C& obj, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
auto fnret = (obj.*fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start, fnret);
}
template<class C, typename... Args>
std::tuple<std::chrono::duration<double>>
countTime(void (C::*fn)(Args...), C& obj, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
(obj.*fn)(std::forward<Args>(args)...);
auto stop = std::chrono::high_resolution_clock::now();
return std::make_tuple(stop - start);
}
auto ret = countTime([](int a) -> int {
std::this_thread::sleep_for(std::chrono::milliseconds(a));
return a * 2;
}, 10);
std::cout << "function executed in: " <<
std::chrono::duration_cast<std::chrono::milliseconds>(std::get<0>(ret)).count() <<
" milliseconds." << std::endl;
std::cout << "function returned: " << std::get<1>(ret) << std::endl;
auto ret = countTime(&Test::init, *this, 1, 1.2);
int value = std::get<1>(ret);
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::get<0>(ret)).count() << "ms" << std::endl;
auto ret = countTime(init, 1, 1.2);
int value = std::get<1>(ret);
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::get<0>(ret)).count() << "ms" << std::endl;
#include <boost/timer/timer.hpp>
...
boost::timer::cpu_timer timer;
for(int i = 0; i < 1000; ++i)
funct();
std::cout << timer.format();