简易 Timer
我打算积累一些算法。不过刚一动手就遇到了大麻烦,在 Windows 上配置一个简单的 Benchmark 似乎有点困难。Google Benchmark 我观察了半天也没研究明白怎么安,于是想了想,不如自己写一个简易 Timer,作为一切的起点!
Timer 的功能
- 首先,Timer 有开始计时和终止计时的功能。一个 Timer 可以多次计时,并支持取平均数。以后我可能加上点极值啊回归啊什么的(
无限期鸽鸽了)。 - 其次,Timer 应该可以打包计时,就是一次计时中做多次运算。这是因为有的运算需要的时间非常少,所以需要测多次再平均才能准一点。
 - 最后,还要能生成一个 string report,方便输出。
 
Timer 的声明
有了上面的想法,可以简单设计出一个 Timer 类:
// seideun/include/auxiliary/Timer.hpp
//
// Created by Deuchie on 2020/8/14.
#ifndef SEIDEUN_TIMER_HPP
#define SEIDEUN_TIMER_HPP
#include <string>
#include <chrono>
namespace seideun::auxiliary {
/** A simple timer
 *
 * # Functionalities
 *
 * - count time with high resolution, generate report in nanoseconds
 * - count the same task multiple times to get average time cost
 * - bulk-count low cost tasks to get higher accuracy and more simplicity
 * - convenient well-formatted report
 */
class Timer {
public:
  Timer();
  explicit Timer(std::string task_name);
  void start();
  void stop(uint32_t repetitions_taken = 1);
  auto get_latest_duration() -> std::chrono::nanoseconds;
  auto get_average_duration() -> std::chrono::nanoseconds;
  auto report() -> std::string;
  void clear(); // clear all saved records
private:
  std::string const task_name_ = "Anonymous Task";
  std::chrono::nanoseconds average_duration_{};
  std::chrono::nanoseconds latest_duration_{};
  std::chrono::time_point<std::chrono::high_resolution_clock> start_time_{};
  uint32_t total_repetitions_ = 0;
};
}
#endif //SEIDEUN_TIMER_HPP
Timer 的实现
// seideun/src/auxiliary/Timer.cpp
//
// Created by Deuchie on 2020/8/14.
#include "auxiliary/Timer.hpp"
#include "fmt/format.h"
void seideun::auxiliary::Timer::start() {
  start_time_ = std::chrono::high_resolution_clock::now();
}
seideun::auxiliary::Timer::Timer(std::string task_name)
  : task_name_(std::move(task_name)) {}
void seideun::auxiliary::Timer::stop(uint32_t repetitions_taken) {
  auto this_duration = std::chrono::high_resolution_clock::now() - start_time_;
  auto new_total_repetitions = total_repetitions_ + repetitions_taken;
  latest_duration_ = this_duration / repetitions_taken;
  average_duration_ = (total_repetitions_ * average_duration_ + this_duration) / new_total_repetitions;
  total_repetitions_ = new_total_repetitions;
}
auto seideun::auxiliary::Timer::get_latest_duration() -> std::chrono::nanoseconds {
  return latest_duration_;
}
auto seideun::auxiliary::Timer::get_average_duration() -> std::chrono::nanoseconds {
  return average_duration_;
}
auto seideun::auxiliary::Timer::report() -> std::string {
  char static constexpr format_string[] = R"({}:
    total repetition times: {}
    average duration: {} ns)";
  return fmt::format(format_string, task_name_, total_repetitions_, average_duration_.count());
}
void seideun::auxiliary::Timer::clear() {
  total_repetitions_ = 0;
}
seideun::auxiliary::Timer::Timer() = default;
测试 Timer
这里我没有用 Google Test,就简单写了一个 Demo 看看输出正不正常即可
#include "auxiliary/Timer.hpp"
#include "auxiliary/primitive_aliases.hpp"
#include "fmt/format.h"
#include <fstream>
int main() {
  std::ofstream out("temp.txt"); // I used this to prevent compiler optimization
  seideun::auxiliary::Timer timer;
  timer.start();
  for (u32 i = 0; i != 10000; ++i) {
    out << i * 32 - 7 << ' ';
  }
  timer.stop(10000);
  fmt::print("# Latest duration: {} ns\n# Report:\n{}\n", timer.get_latest_duration().count(), timer.report());
  // Let's try another cycle
  timer.start();
  for (u32 i = 0; i != 5000; ++i) {
    out << i * i * i + 41976283 << ' ';
  }
  timer.stop(5000);
  puts("\nAnother Test:");
  fmt::print("# Latest duration: {} ns\n# Report:\n{}\n", timer.get_latest_duration().count(), timer.report());
}
输出是这样的:
>>> ./seideun.exe
# Latest duration: 313 ns
# Report:
Anonymous Task:
    total repetition times: 10000
    average duration: 313 ns
Another Test:
# Latest duration: 367 ns
# Report:
Anonymous Task:
    total repetition times: 15000
    average duration: 331 ns
Process finished with exit code 0
PS: primitive_alias 里的声明如下:
using u8 = uint8_t; using u16 = uint16_t; using u32 = uint32_t; using u64 = uint64_t; using i8 = int8_t; using i16 = int16_t; using i32 = int32_t; using i64 = int64_t;我个人觉得这个写起来方便,而且定长好处多多啊朋友们!

                
            
        
浙公网安备 33010602011771号