本来想自己写的,一看github上面都有就不再重复造轮子了。github上的项目如下:
- StopWatch 纯标准库实现:使用std::chrono::high_resolution_clock,其实就是std::chrono::steady_clock的别名。
- StopWatch 类似C#的实现:和C#的StopWatch比较像,在Windows下使用的是QueryPerformanceCounter系统API,其它系统下使用std::chrono::steady_clock。
纯标准库实现
第一种纯标准库实现的Stopwatch.hpp内容如下:
// Copyright Ingo Proff 2017. // https://github.com/CrikeeIP/Stopwatch // Distributed under the MIT Software License (X11 license). // (See accompanying file LICENSE) #pragma once #include <vector> #include <string> #include <chrono> namespace stopwatch{ class Stopwatch{ public: enum TimeFormat{ NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS }; Stopwatch(): start_time(), laps({}) { start(); } void start(){ start_time = std::chrono::high_resolution_clock::now(); laps = {start_time}; } template<TimeFormat fmt = TimeFormat::MILLISECONDS> std::uint64_t lap(){ const auto t = std::chrono::high_resolution_clock::now(); const auto last_r = laps.back(); laps.push_back( t ); return ticks<fmt>(last_r, t); } template<TimeFormat fmt = TimeFormat::MILLISECONDS> std::uint64_t elapsed(){ const auto end_time = std::chrono::high_resolution_clock::now(); return ticks<fmt>(start_time, end_time); } template<TimeFormat fmt_total = TimeFormat::MILLISECONDS, TimeFormat fmt_lap = fmt_total> std::pair<std::uint64_t, std::vector<std::uint64_t>> elapsed_laps(){ std::vector<std::uint64_t> lap_times; lap_times.reserve(laps.size()-1); for( std::size_t idx = 0; idx <= laps.size()-2; idx++){ const auto lap_end = laps[idx+1]; const auto lap_start = laps[idx]; lap_times.push_back( ticks<fmt_lap>(lap_start, lap_end) ); } return { ticks<fmt_total>(start_time, laps.back()), lap_times }; } private: typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_pt; time_pt start_time; std::vector<time_pt> laps; template<TimeFormat fmt = TimeFormat::MILLISECONDS> static std::uint64_t ticks( const time_pt& start_time, const time_pt& end_time){ const auto duration = end_time - start_time; const std::uint64_t ns_count = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count(); switch(fmt){ case TimeFormat::NANOSECONDS: { return ns_count; } case TimeFormat::MICROSECONDS: { std::uint64_t up = ((ns_count/100)%10 >= 5) ? 1 : 0; const auto mus_count = (ns_count /1000) + up; return mus_count; } case TimeFormat::MILLISECONDS: { std::uint64_t up = ((ns_count/100000)%10 >= 5) ? 1 : 0; const auto ms_count = (ns_count /1000000) + up; return ms_count; } case TimeFormat::SECONDS: { std::uint64_t up = ((ns_count/100000000)%10 >= 5) ? 1 : 0; const auto s_count = (ns_count /1000000000) + up; return s_count; } } } }; constexpr Stopwatch::TimeFormat ns = Stopwatch::TimeFormat::NANOSECONDS; constexpr Stopwatch::TimeFormat mus = Stopwatch::TimeFormat::MICROSECONDS; constexpr Stopwatch::TimeFormat ms = Stopwatch::TimeFormat::MILLISECONDS; constexpr Stopwatch::TimeFormat s = Stopwatch::TimeFormat::SECONDS; constexpr Stopwatch::TimeFormat nanoseconds = Stopwatch::TimeFormat::NANOSECONDS; constexpr Stopwatch::TimeFormat microseconds = Stopwatch::TimeFormat::MICROSECONDS; constexpr Stopwatch::TimeFormat milliseconds = Stopwatch::TimeFormat::MILLISECONDS; constexpr Stopwatch::TimeFormat seconds = Stopwatch::TimeFormat::SECONDS; std::string show_times( const std::vector<std::uint64_t>& times ){ std::string result("{"); for( const auto& t : times ){ result += std::to_string(t) + ","; } result.back() = static_cast<char>('}'); return result; } }
使用示例如下:
//创建一个stopwatch sw::Stopwatch my_watch; my_watch.start(); //Do something time-consuming here... //纳秒 std::uint64_t elapsed_ns = my_watch.elapsed<sw::ns>(); //微秒 std::uint64_t elapsed_mus = my_watch.elapsed<sw::mus>(); //毫秒 std::uint64_t elapsed_ms = my_watch.elapsed(); //秒 std::uint64_t elapsed_s = my_watch.elapsed<sw::s>();
类似C#的实现
第二种类似C#的实现,StopWatch.h代码如下:
#ifndef __STOPWATCH_H__ #define __STOPWATCH_H__ #if defined(_MSC_VER) || defined(__MINGW32__) || defined(WIN32) #include <Windows.h> #else #include <chrono> #endif class StopWatch { public: StopWatch(); ~StopWatch(); //开启计时 void Start(); //暂停计时 void Stop(); //重新计时 void ReStart(); //微秒 double Elapsed(); //毫秒 double ElapsedMS(); //秒 double ElapsedSecond(); private: long long elapsed_; #if defined(_MSC_VER) || defined(__MINGW32__) || defined(WIN32) LARGE_INTEGER start_; LARGE_INTEGER stop_; LARGE_INTEGER frequency_; #else typedef std::chrono::high_resolution_clock Clock; typedef std::chrono::microseconds MicroSeconds; std::chrono::steady_clock::time_point start_; std::chrono::steady_clock::time_point stop_; #endif }; #endif // __STOPWATCH_H__
StopWatch.cpp代码如下:
#include "StopWatch.h" #if defined(_MSC_VER) || defined(__MINGW32__) || defined(WIN32) StopWatch::StopWatch():elapsed_(0) { elapsed_ = 0; start_.QuadPart = 0; stop_.QuadPart = 0; QueryPerformanceFrequency(&frequency_); } #else StopWatch::StopWatch():elapsed_(0),start_(MicroSeconds::zero()),stop_(MicroSeconds::zero()) { } #endif StopWatch::~StopWatch() { } void StopWatch::Start() { #if defined(_MSC_VER) || defined(__MINGW32__) || defined(WIN32) QueryPerformanceCounter(&start_); #else start_ = Clock::now(); #endif } void StopWatch::Stop() { #if defined(_MSC_VER) || defined(__MINGW32__) || defined(WIN32) QueryPerformanceCounter(&stop_); elapsed_ += (stop_.QuadPart - start_.QuadPart) * 1000000 / frequency_.QuadPart; #else stop_ = Clock::now(); elapsed_ = std::chrono::duration_cast<MicroSeconds>(stop_ - start_).count(); #endif } void StopWatch::ReStart() { elapsed_ = 0; Start(); } double StopWatch::Elapsed() { return static_cast<double>(elapsed_); } double StopWatch::ElapsedMS() { return elapsed_ / 1000.0; } double StopWatch::ElapsedSecond() { return elapsed_ / 1000000.0; }
使用示例如下(和C#比较像):
StopWatch sw; sw.Start(); //Do something time-consuming here... sw.Stop(); std::cout << "运行时间:" << sw.ElapsedMS() << "毫秒" << std::endl;
总结
- 如果有代码洁癖的话就使用第一种,纯标准库实现、功能全面、使用方法偏向传统C++。
- 如果不介意使用系统API的话就使用第二种,功能简单、使用方法偏向传统C#。