-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
258 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#include "quill/Backend.h" | ||
#include "quill/Frontend.h" | ||
#include "quill/LogMacros.h" | ||
#include "quill/Logger.h" | ||
#include "quill/sinks/ConsoleSink.h" | ||
#include "quill/StopWatch.h" | ||
|
||
#include <thread> | ||
|
||
/** | ||
* Stopwatch logging example | ||
*/ | ||
|
||
int main() | ||
{ | ||
quill::BackendOptions backend_options; | ||
quill::Backend::start(backend_options); | ||
|
||
// Frontend | ||
auto console_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>( | ||
"sink_id_1", quill::ConsoleSink::ColourMode::Automatic); | ||
|
||
quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink)); | ||
|
||
{ | ||
quill::StopWatchTsc swt; | ||
LOG_INFO(logger, "Begin Tsc StopWatch"); | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
LOG_INFO(logger, "After 1s, elapsed: {:.6}s", swt); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
LOG_INFO(logger, "After 500ms, elapsed: {}s", swt); | ||
LOG_INFO(logger, "elapsed: {}", swt.elapsed_as<std::chrono::nanoseconds>()); | ||
LOG_INFO(logger, "elapsed: {}", swt.elapsed_as<std::chrono::seconds>()); | ||
LOG_INFO(logger, "Reset"); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
LOG_INFO(logger, "After 500ms, elapsed: {}", swt); | ||
} | ||
|
||
{ | ||
quill::StopWatchChrono swt; | ||
LOG_INFO(logger, "Begin Chrono StopWatch"); | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
LOG_INFO(logger, "After 1s, elapsed: {:.6}s", swt); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
LOG_INFO(logger, "After 500ms, elapsed: {}s", swt); | ||
LOG_INFO(logger, "elapsed: {}", swt.elapsed_as<std::chrono::nanoseconds>()); | ||
LOG_INFO(logger, "elapsed: {}", swt.elapsed_as<std::chrono::seconds>()); | ||
LOG_INFO(logger, "Reset"); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
LOG_INFO(logger, "After 500ms, elapsed: {}", swt); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/** | ||
* @page copyright | ||
* Copyright(c) 2020-present, Odysseas Georgoudis & quill contributors. | ||
* Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
#include "quill/TriviallyCopyableCodec.h" | ||
#include "quill/core/Attributes.h" | ||
#include "quill/core/Common.h" | ||
#include "quill/core/Rdtsc.h" | ||
#include "quill/backend/RdtscClock.h" | ||
|
||
#include "quill/bundled/fmt/format.h" | ||
#include "quill/std/Chrono.h" | ||
|
||
QUILL_BEGIN_NAMESPACE | ||
|
||
namespace detail | ||
{ | ||
/** | ||
* Displays elapsed seconds since construction as double. | ||
* | ||
* @code | ||
* quill::StopWatchTsc swt; | ||
* LOG_INFO(logger, "Begin"); | ||
* std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
* LOG_INFO(logger, "After 1s, elapsed: {:.6}", swt); | ||
* std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
* LOG_INFO(logger, "After 500ms, elapsed: {}", swt); | ||
* @endcode | ||
*/ | ||
template <ClockSourceType ClockType> | ||
class StopWatch | ||
{ | ||
public: | ||
static_assert((ClockType == ClockSourceType::Tsc) || (ClockType == ClockSourceType::System), | ||
"Invalid ClockType"); | ||
|
||
StopWatch() | ||
{ | ||
if constexpr (ClockType == ClockSourceType::Tsc) | ||
{ | ||
_ns_per_tick = RdtscClock::RdtscTicks::instance().ns_per_tick(); | ||
_start_tp = rdtsc(); | ||
} | ||
else | ||
{ | ||
_start_tp = std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
std::chrono::steady_clock::now().time_since_epoch()) | ||
.count(); | ||
} | ||
} | ||
|
||
[[nodiscard]] std::chrono::duration<double> elapsed() const | ||
{ | ||
if constexpr (ClockType == ClockSourceType::Tsc) | ||
{ | ||
return std::chrono::duration<double>( | ||
std::chrono::nanoseconds{static_cast<uint64_t>((rdtsc() - _start_tp) * _ns_per_tick)}); | ||
} | ||
else | ||
{ | ||
return std::chrono::duration<double>(std::chrono::nanoseconds{ | ||
std::chrono::steady_clock::now().time_since_epoch().count() - _start_tp}); | ||
} | ||
} | ||
|
||
/** | ||
* Get the desired duration type | ||
*/ | ||
template <typename T> | ||
[[nodiscard]] T elapsed_as() const | ||
{ | ||
if constexpr (ClockType == ClockSourceType::Tsc) | ||
{ | ||
return std::chrono::duration_cast<T>( | ||
std::chrono::nanoseconds{static_cast<uint64_t>((rdtsc() - _start_tp) * _ns_per_tick)}); | ||
} | ||
else | ||
{ | ||
return std::chrono::duration_cast<T>(std::chrono::nanoseconds{ | ||
std::chrono::steady_clock::now().time_since_epoch().count() - _start_tp}); | ||
} | ||
} | ||
|
||
void reset() | ||
{ | ||
if constexpr (ClockType == ClockSourceType::Tsc) | ||
{ | ||
_start_tp = rdtsc(); | ||
} | ||
else | ||
{ | ||
_start_tp = std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
std::chrono::steady_clock::now().time_since_epoch()) | ||
.count(); | ||
} | ||
} | ||
|
||
private: | ||
double _ns_per_tick{0}; | ||
uint64_t _start_tp{0}; | ||
}; | ||
} // namespace detail | ||
|
||
using StopWatchTsc = detail::StopWatch<ClockSourceType::Tsc>; | ||
using StopWatchChrono = detail::StopWatch<ClockSourceType::System>; | ||
|
||
QUILL_END_NAMESPACE | ||
|
||
template <quill::ClockSourceType ClockType> | ||
struct quill::Codec<quill::detail::StopWatch<ClockType>> | ||
: quill::TriviallyCopyableTypeCodec<quill::detail::StopWatch<ClockType>> | ||
{ | ||
}; | ||
|
||
template <quill::ClockSourceType ClockType> | ||
struct fmtquill::formatter<quill::detail::StopWatch<ClockType>> : fmtquill::formatter<double> | ||
{ | ||
template <typename FormatContext> | ||
auto format(quill::detail::StopWatch<ClockType> const& sw, FormatContext& ctx) const | ||
-> decltype(ctx.out()) | ||
{ | ||
return fmtquill::formatter<double>::format(sw.elapsed().count(), ctx); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include "doctest/doctest.h" | ||
|
||
#include "quill/StopWatch.h" | ||
#include <thread> | ||
|
||
TEST_SUITE_BEGIN("StopWatch"); | ||
|
||
TEST_CASE("StopWatchTsc") | ||
{ | ||
quill::StopWatchTsc swt; | ||
std::this_thread::sleep_for(std::chrono::seconds{1}); | ||
|
||
// greater than 1 second | ||
REQUIRE_GE(swt.elapsed().count(), 1.0); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::nanoseconds>().count(), 1'000'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::microseconds>().count(), 1'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::milliseconds>().count(), 1'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::seconds>().count(), 1); | ||
|
||
swt.reset(); | ||
REQUIRE_LT(swt.elapsed().count(), 1.0); | ||
|
||
std::this_thread::sleep_for(std::chrono::seconds{2}); | ||
|
||
// greater than 2 seconds | ||
REQUIRE_GE(swt.elapsed().count(), 2.0); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::nanoseconds>().count(), 2'000'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::microseconds>().count(), 2'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::milliseconds>().count(), 2'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::seconds>().count(), 2); | ||
} | ||
|
||
TEST_CASE("StopWatchChrono") | ||
{ | ||
quill::StopWatchChrono swt; | ||
std::this_thread::sleep_for(std::chrono::seconds{1}); | ||
|
||
// greater than 1 second | ||
REQUIRE_GE(swt.elapsed().count(), 1.0); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::nanoseconds>().count(), 1'000'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::microseconds>().count(), 1'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::milliseconds>().count(), 1'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::seconds>().count(), 1); | ||
|
||
swt.reset(); | ||
REQUIRE_LT(swt.elapsed().count(), 1.0); | ||
|
||
std::this_thread::sleep_for(std::chrono::seconds{2}); | ||
|
||
// greater than 2 seconds | ||
REQUIRE_GE(swt.elapsed().count(), 2.0); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::nanoseconds>().count(), 2'000'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::microseconds>().count(), 2'000'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::milliseconds>().count(), 2'000); | ||
REQUIRE_GE(swt.elapsed_as<std::chrono::seconds>().count(), 2); | ||
} | ||
|
||
TEST_SUITE_END(); |