C++ STL에는 OS에 상관없이 일관된 방식으로 시간을 다룰 수 있는 <chrono>라이브러리가 있습니다. 시각 측정을 위한 clock은 용도에 따라 steady_clock, system_clock, high_resolution_clock 세 가지가 존재하며 high_resolution_clock은 컴파일러에 따라 앞의 두 clock 중 하나와 동일할 수 있습니다.
MSVC의 구현에선 high_resolution_clock = steady_clock 입니다. 또한 steady_clock은 내부적으로 QueryPerformanceCounter를 사용하고 system_clock은 사용 가능 여부에 따라 순서대로GetSystemTimePreciseAsFileTime 또는 GetSystemTimeAsFileTime을 사용합니다. API 문서에 따르면 시간 간격을 구하는 데는 QueryPerformanceCounter가 더 적절하므로 스톱워치에는 steady_clock이나 high_resolution_clock을 사용하면 됩니다.
기본적으로 시간은 종료 시각에서 시작 시각을 빼는 방식으로 측정할 수 있습니다. 시간 간격 양 끝의 두 시각만 구하면 되므로 스톱워치의 시간이 경과하는 도중에 오버헤드 발생하지 않습니다.
main.cpp
#include <iostream>
#include <chrono>
using namespace std;
using namespace chrono;
int main() {
auto begin = high_resolution_clock::now();
// ...somework
auto end = high_resolution_clock::now();
cout << "took " << duration_cast<milliseconds>(end - begin).count() << "ms\n";
return 0;
}
C++이를 클래스를 통해 좀 더 사용하기 쉽도록 만들면 다음과 같습니다.
stopwatch.h
#pragma once
#include <chrono>
#include <cmath>
class StopWatch {
using clock = std::chrono::high_resolution_clock;
using time_point = clock::time_point;
public:
inline StopWatch()
: ticking(true), begin(clock::now()) {}
inline void start() {
begin = clock::now();
ticking = true;
}
inline void stop() {
end = clock::now();
ticking = false;
}
inline bool isTicking() { return ticking; }
private:
static constexpr double pow10(uint32_t exp) {
constexpr double table[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11 };
return exp > 11 ? 1e12 : table[exp];
}
public:
inline int64_t in_tick() {
if (ticking)
return (clock::now() - begin).count();
else
return (end - begin).count();
}
inline double in_hour(uint32_t precision = 3) {
int64_t tick = in_tick();
auto pow = pow10(precision);
return std::round((tick / 36e11) * pow) / pow;
}
inline double in_min(uint32_t precision = 3) {
int64_t tick = in_tick();
auto pow = pow10(precision);
return std::round((tick / 6e10) * pow) / pow;
}
inline double in_s(uint32_t precision = 3) {
int64_t tick = in_tick();
auto pow = pow10(precision);
return std::round((tick / 1e9) * pow) / pow;
}
inline double in_ms(uint32_t precision = 3) {
int64_t tick = in_tick();
auto pow = pow10(precision);
return std::round((tick / 1e6) * pow) / pow;
}
inline double in_us(uint32_t precision = 3) {
int64_t tick = in_tick();
auto pow = pow10(precision);
return std::round((tick / 1e3) * pow) / pow;
}
inline double in_ns(uint32_t precision = 3) {
int64_t tick = in_tick();
auto pow = pow10(precision);
return std::round(tick * pow) / pow;
}
private:
bool ticking;
time_point begin;
time_point end;
};
C++사용법은 다음과 같습니다.
사용법
{
StopWatch sw; // 타이머가 생성되자마자 시작
// ...somework
sw.stop();
cout << "took " << sw.in_ms() << "ms...\n"; // stop 시점까지의 경과시간 출력
}
{
StopWatch sw;
// ...somework
cout << "took " << sw.in_ms() << "ms...\n"; // 현재 경과시간 출력
}
{
StopWatch sw;
sw.start(); // reset 동작과 동일
// ...somework
cout << "took " << sw.in_s(5) << "s...\n"; // 초 단위에서 소수점 5자리 반올림
}
C++
최신 댓글