概述
- 在这里我们初步学习了timer库,现在我们来看它们的高精度版本cpu_timer
- cpu_timer使用了chrono库的高精度时钟high_resolution_clock,不仅能够度量进程使用的实际时间,还能够度量CPU时间,它支持最高到微秒精度的计时,而且使用起来同样方便,是旧版本timer的很好替代品
- cpu_timer库需要system库和chrone库的支持;将-lboost_timer添加到库;它位于名字空间boost::timer,需要包含头文件
<boost/timer/timer>
#include <boost/timer/timer.hpp>
using namespace boost::timer;
时间类型
typedef boost::int_least64_t nanosecond_type; //计时用的ns类型
struct cpu_times //cpu时间类型
{
nanosecond_type wall; //挂钟(日历时间)
nanosecond_type user; //用户CPU(进程)时间
nanosecond_type system; //系统CPU(进程)时间
void clear() { wall = user = system = 0LL; } //清零
};
- cpu_timer库以nanosecond_type作为计时单位,但是因为系统限制它不会达到ns级别的精确度。实际情况wall的精度大约是us(1000ns),CPU时间的精度大约是10-15ms(1000*1000ns)
- cpu_timers整合里三个计算机常用的时间度量
度量 | 说明 |
---|---|
wall | 挂钟(日历时间),进程运行的实际时间 |
user | 用户CPU(进程)时间,进程执行用户指令使用的CPU时间 |
system | 系统CPU(进程)时间,进程执行系统内核调用使用的CPU时间 |
- cpu_timers是一个POD类型,只有一个简单的clear()成员函数用于时间清理
cpu_timer
class BOOST_TIMER_DECL cpu_timer
{
public:
cpu_timer() { start(); } //构造函数,启用计时器
bool is_stopped() const ; // 计时器是否停止
cpu_times elapsed() const; // 计时器启动后流逝的时间
//格式化输出
std::string format(short places, const std::string& format) const;
std::string format(short places = default_places) const;
// actions
void start(); // 启动计时器
void stop(); // 暂停计时器
void resume(); // 恢复计时器计时
private:
cpu_times m_times; //计时成员变量
bool m_is_stopped; //是否停止计时器
};
- cpu_timer的实现原理与timer类似,只是内部改用chrono库的高精度时钟来获得时间计量,并且时间计量也不是一个简单的std::clock_t,而是改成了含有三个数值的类型cpu_times
- cpu_timer的构造函数调用start()记录当前时间作为计时起点,之后就可以用elapsed()来获得启动后流逝的挂钟/用户CPU/系统CPU时间。计时过程中我们可以用stop()暂停计时器,用resume()恢复计时器的运行,如果想重新启动计时器则需要调用start() 【timer需要使用的是restart()】
- cpu_timers没有流输出功能,但是提供了格式化函数format(),可以把elapsed()的结构转换为一个可读的字符串:
Xs wall, Ys user + Zs system = Cs CPU (P%)
,表示进程运行了X秒的挂钟时间,Y秒的用户CPU时间,Z秒的系统CPU时间,合计C秒的CPU时间,总CPU时间占挂钟时间的百分比是P(当然,字符串的格式是可以自定义的)
#include <iostream>
#include <boost/timer/timer.hpp>
#include <vector>
using namespace boost::timer;
using namespace std;
#include <boost/algorithm/string.hpp>
int main()
{
vector<string> v(10, "nanodo");
cpu_timer t; //构造函数,启动计时器
assert(!t.is_stopped()); //计时器是否停止
for(int i = 0; i < 10000; ++i){
boost::join(v, "-");
}
t.stop(); //停止计时器
assert(t.is_stopped());
cout << "pause for a while..." << endl; //不计入时间
cout << "we can do something..." << endl;
t.resume(); //恢复计时器运行
assert(!t.is_stopped());
for(string& x : v)
{ x +=x; }
cout << t.format(); //格式化输出
}
从上面我们可以知道,进程总共花费了0.012s时间,其中用户CPU时间约0.01s,系统CPU时间为0(即没有发生系统调用),CPU时间占总运行时间78.0%
auto_cpu_timer
auto_cpu_timer是一个类似progress_timer
的自动计时器,它继承自cpu_timer:
class BOOST_TIMER_DECL auto_cpu_timer : public cpu_timer
{
public:
explicit auto_cpu_timer(short places = default_places);
auto_cpu_timer(short places, const std::string& format);
explicit auto_cpu_timer(const std::string& format);
auto_cpu_timer(std::ostream& os, short places,const std::string& format)
explicit auto_cpu_timer(std::ostream& os, short places = default_places);
auto_cpu_timer(std::ostream& os, const std::string& format)
~auto_cpu_timer();
std::ostream& ostream() const { return *m_os; }
short places() const { return m_places; }
const std::string& format_string() const { return m_format; }
// actions
void report();
};
- auto_cpu_timer 具有cpu_timer的所有接口,同progress_timer一样,它会在析构的时候自动输出流逝的时间,非常的简单易用,我们也可以用report()函数直接向流输出计时结果
- auto_cpu_timer有6个构造函数,可以用来定制计时的输出格式
{
auto_cpu_timer t;
sleep(1);
}
定制输出格式
cpu_timer库的format函数使用两个参数来定制计时结果的时间类型cpu_timers的格式:
- 短整型places用于指定输出值的小数点后精确度,默认值是6us,最多可以是9ns(但是因为计时精度的限制通常是没有意义的)
- 字符串参数format用于指定输出的格式
const string fmt("%w 秒, %u 秒 + %s 秒 = %t 秒, 百分比是%p");
auto_cpu_timer t(3, fmt); // 指定精度和格式
- %w : 挂钟时间,即cpu_times.wall值
- %u:用户CPU时间,即cpu_times.user值
- %s:系统CPU时间,即cpu_times.system值
- %t:总计CPU时间,即cpu_times.user + cpu_timers.system
- %p:总计CPU时间占挂钟时间的百分比
cpu_timer库里面还有两个格式化函数,用来把cpu_times类型格式化为字符串,被cpu_timer和auto_cpu_timer调用:
BOOST_TIMER_DECL
std::string format(const cpu_times& times, short places, const std::string& format);
BOOST_TIMER_DECL
std::string format(const cpu_times& times, short places = default_places);
示例如下:
const nanosecond_type ms = 1000 * 1000;
cpu_times ct = {2000 * ms, 1000 * ms, 100 * ms};
cout << format(ct, 7);
如果CPU时间值太小,小于cpu_timer库的度量精度,那么百分比就会显式为n/a(not available)
cpu_times ct = {2000, 1000 , 100 };
cout << format(ct, 7); //使用默认格式输出