159 lines
4.3 KiB
C++
159 lines
4.3 KiB
C++
/*
|
|
* Copyright (c) 2018 MariaDB Corporation Ab
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
*
|
|
* Change Date: 2022-01-01
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2 or later of the General
|
|
* Public License.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <maxbase/ccdefs.hh>
|
|
#include <chrono>
|
|
#include <iosfwd>
|
|
#include <string>
|
|
|
|
namespace maxbase
|
|
{
|
|
|
|
/**
|
|
* @class Clock
|
|
*
|
|
* MaxScale "standard" std::chrono clock
|
|
*/
|
|
using Clock = std::chrono::steady_clock;
|
|
|
|
/**
|
|
* @class Duration
|
|
*
|
|
* Duration behaves exactly like Clock::duration, but adds ADL and, a
|
|
* conveniece constructor and function secs() for seconds as a double.
|
|
*/
|
|
struct Duration : public Clock::duration
|
|
{
|
|
using Clock::duration::duration;
|
|
Duration() = default;
|
|
Duration(Clock::duration d)
|
|
: Clock::duration(d)
|
|
{
|
|
}
|
|
|
|
/** From seconds */
|
|
explicit Duration(double secs)
|
|
: Duration{rep(secs * period::den / period::num)}
|
|
{
|
|
}
|
|
|
|
/** To seconds */
|
|
double secs() const
|
|
{
|
|
return std::chrono::duration<double>(*this).count();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @class TimePoint
|
|
*
|
|
* A std::chrono::time_point to go with Clock and Duration.
|
|
*/
|
|
using TimePoint = std::chrono::time_point<Clock, Duration>;
|
|
|
|
/**
|
|
* @class StopWatch
|
|
*
|
|
* Simple stopwatch for measuring time.
|
|
*
|
|
* Example usage:
|
|
* auto limit = maxbase::Duration(std::chrono::milliseconds(100));
|
|
*
|
|
* maxbase::StopWatch sw;
|
|
* foo();
|
|
* auto duration = sw.split();
|
|
*
|
|
* std::cout << "foo duration " << duration << std::endl;
|
|
* if (duration > limit)
|
|
* {
|
|
* maxbase::Duration diff = duration - limit; // no auto, would become Clock::duration.
|
|
* std::cerr << "foo exceeded the limit " << limit << " by " << diff << std::endl;
|
|
* }
|
|
* Possible output:
|
|
* foo duration 100.734ms
|
|
* foo exceeded the limit 100ms by 733.636us
|
|
*/
|
|
class StopWatch
|
|
{
|
|
public:
|
|
/** Create and start the stopwatch. */
|
|
StopWatch();
|
|
|
|
/** Split time. Overall duration since creation or last restart(). */
|
|
Duration split() const;
|
|
|
|
/** Lap time. Time since last lap() call, or if lap() was not called, creation or last restart(). */
|
|
Duration lap();
|
|
|
|
/** Return split time and restart stopwatch. */
|
|
Duration restart();
|
|
private:
|
|
TimePoint m_start;
|
|
TimePoint m_lap;
|
|
};
|
|
|
|
/** IntervalTimer for accumulating intervals (i.e. durations). Do not expect many very short
|
|
* durations to accumulate properly (unless you have a superfast processor, RTLinux, etc.)
|
|
*
|
|
* Usage pattern:
|
|
* IntervalTimer timer; // created ahead of time.
|
|
* ...
|
|
* In some sort of a loop (explicit or implicit):
|
|
* timer.start_interval();
|
|
* foo();
|
|
* timer.end_interval();
|
|
* ...
|
|
* And finally:
|
|
* std::cout << timer.total() << std::endl;
|
|
*
|
|
*/
|
|
class IntervalTimer
|
|
{
|
|
public:
|
|
/** Create but do not start the intervaltimer, i.e. starting in paused mode. */
|
|
IntervalTimer();
|
|
|
|
/** Resume measuring time. Ok to call multiple times without an end_interval(). */
|
|
void start_interval();
|
|
|
|
/** Pause measuring time. Ok to call without a start_interval. */
|
|
void end_interval();
|
|
|
|
/** Total duration of intervals (thus far). */
|
|
Duration total() const;
|
|
private:
|
|
TimePoint m_last_start;
|
|
Duration m_total;
|
|
};
|
|
|
|
/** Returns the duration as a double and string adjusted to a suffix like ms for milliseconds.
|
|
* The double and suffix (unit) combination is selected to be easy to read.
|
|
* This is for output conveniece. You can always convert a duration to a specific unit:
|
|
* long ms {std::chrono::duration_cast<std::chrono::milliseconds>(dur).count()};
|
|
*/
|
|
std::pair<double, std::string> dur_to_human_readable(Duration dur);
|
|
|
|
/** Create a string using dur_to_human_readable, std::ostringstream << d.first << sep << d.second. */
|
|
std::string to_string(Duration dur, const std::string& sep = "");
|
|
|
|
/** Stream to os << d.first << d.second. Not using to_string(), which would use a default stream. */
|
|
std::ostream& operator<<(std::ostream& os, Duration dur);
|
|
|
|
/** TimePoint to string, formatted using strftime formats. */
|
|
std::string to_string(TimePoint tp, const std::string& fmt = "%F %T");
|
|
|
|
/** Stream to std::ostream using to_string(tp) */
|
|
std::ostream& operator<<(std::ostream&, TimePoint tp);
|
|
}
|