diff --git a/power_overwhelming/include/power_overwhelming/timestamp_resolution.h b/power_overwhelming/include/power_overwhelming/timestamp_resolution.h index 69645e70..520b49f8 100644 --- a/power_overwhelming/include/power_overwhelming/timestamp_resolution.h +++ b/power_overwhelming/include/power_overwhelming/timestamp_resolution.h @@ -29,6 +29,12 @@ namespace power_overwhelming { /// microseconds, + /// + /// Timestamp is specified in units of hundred nanoseconds (the native + /// quantity of many Windows APIs). + /// + hundred_nanoseconds, + /// /// Timestamp is specified in nanoseconds (Billionth of a second). /// diff --git a/power_overwhelming/src/timestamp.cpp b/power_overwhelming/src/timestamp.cpp index f0a3806b..7e7df618 100644 --- a/power_overwhelming/src/timestamp.cpp +++ b/power_overwhelming/src/timestamp.cpp @@ -11,10 +11,10 @@ */ visus::power_overwhelming::timestamp_type visus::power_overwhelming::detail::convert( - const timestamp_type fileTime, + const timestamp_type file_time, const timestamp_resolution resolution) { using namespace std::chrono; - duration ft(fileTime); + duration ft(file_time); switch (resolution) { case timestamp_resolution::microseconds: @@ -26,11 +26,14 @@ visus::power_overwhelming::detail::convert( case timestamp_resolution::nanoseconds: return duration_cast(ft).count(); + case timestamp_resolution::hundred_nanoseconds: + return file_time; + case timestamp_resolution::seconds: return duration_cast(ft).count(); default: - return fileTime; + return file_time; } } diff --git a/power_overwhelming/src/timestamp.h b/power_overwhelming/src/timestamp.h index 75ac365a..9411784f 100644 --- a/power_overwhelming/src/timestamp.h +++ b/power_overwhelming/src/timestamp.h @@ -41,11 +41,12 @@ namespace detail { /// This API is only exposed for unit tests and should not be accessed by /// any other clients. /// - /// The file time value in 100ns units. + /// The file time value in 100ns units. /// The desired resolution of the timestamp. /// /// The timestamp in the requested resolution. - timestamp_type POWER_OVERWHELMING_API convert(const timestamp_type fileTime, + timestamp_type POWER_OVERWHELMING_API convert( + const timestamp_type file_time, const timestamp_resolution resolution); #if defined(_WIN32) @@ -53,14 +54,14 @@ namespace detail { /// Convert the given raw to a timestamp of the /// specified resolution. /// - /// The file time value in 100ns units. + /// The file time value in 100ns units. /// The desired resolution of the timestamp. /// /// The timestamp in the requested resolution. inline POWER_OVERWHELMING_API decltype(LARGE_INTEGER::QuadPart) convert( - const LARGE_INTEGER& fileTime, + const LARGE_INTEGER& file_time, const timestamp_resolution resolution) { - return convert(fileTime.QuadPart, resolution); + return convert(file_time.QuadPart, resolution); } #endif /* defined(_WIN32) */ diff --git a/power_overwhelming/src/timestamp.inl b/power_overwhelming/src/timestamp.inl index 9f255dae..680c6657 100644 --- a/power_overwhelming/src/timestamp.inl +++ b/power_overwhelming/src/timestamp.inl @@ -58,10 +58,11 @@ visus::power_overwhelming::detail::convert( TDuration>& timestamp, _In_ const timestamp_resolution resolution) { using namespace std::chrono; + typedef duration filetime_dur; // The offset of the FILETIME epoch to the UNIX epoch. const auto dz = duration(11644473600000LL); + detail::filetime_period>(116444736000000000LL); // Find out what the difference between the time point and the UNIX // epoch is. Because we cannot rely on the epoch of the STL clock being the @@ -72,6 +73,9 @@ visus::power_overwhelming::detail::convert( // Transform the origin of the timestamp clock to the origin of FILETIME. switch (resolution) { + case timestamp_resolution::hundred_nanoseconds: + return duration_cast(dt + dz).count(); + case timestamp_resolution::microseconds: return duration_cast(dt + dz).count(); diff --git a/test/timestamp_test.cpp b/test/timestamp_test.cpp index 057a3091..59fd8f9b 100644 --- a/test/timestamp_test.cpp +++ b/test/timestamp_test.cpp @@ -38,36 +38,69 @@ namespace test { this->_system_zero = std::chrono::system_clock::from_time_t(0); } + TEST_METHOD(test_convert) { + auto a = detail::convert(std::chrono::system_clock::from_time_t(0), timestamp_resolution::hundred_nanoseconds); + Assert::AreEqual(this->_filetime_zero, a, L"Unix epoch as FILETIME", LINE_INFO()); + } + TEST_METHOD(test_microseconds) { + typedef std::chrono::microseconds unit; + static const auto resolution = timestamp_resolution::microseconds; + const auto max_dt = std::chrono::duration_cast(std::chrono::milliseconds(100)).count(); + auto n = std::chrono::system_clock::now(); - auto t = detail::create_timestamp(timestamp_resolution::microseconds); - auto s = std::chrono::duration_cast(n - this->_system_zero).count(); - auto z = detail::convert(this->_filetime_zero, timestamp_resolution::microseconds); - Assert::IsTrue(s - z - t < 1000000, L"timestamp microsecond", LINE_INFO()); + auto t = detail::create_timestamp(resolution); + auto s = std::chrono::duration_cast(n - this->_system_zero).count(); + auto z = detail::convert(this->_filetime_zero, resolution); + Assert::IsTrue(s - z - t < max_dt, L"timestamp microsecond", LINE_INFO()); } TEST_METHOD(test_milliseconds) { + typedef std::chrono::milliseconds unit; + static const auto resolution = timestamp_resolution::milliseconds; + const auto max_dt = std::chrono::duration_cast(std::chrono::milliseconds(100)).count(); + auto n = std::chrono::system_clock::now(); auto t = detail::create_timestamp(timestamp_resolution::milliseconds); auto s = std::chrono::duration_cast(n - this->_system_zero).count(); auto z = detail::convert(this->_filetime_zero, timestamp_resolution::milliseconds); - Assert::IsTrue(t - z - s < 1000, L"timestamp millisecond", LINE_INFO()); + Assert::IsTrue(t - z - s < max_dt, L"timestamp millisecond", LINE_INFO()); + } + + TEST_METHOD(test_hundred_nanoseconds) { + typedef std::chrono::duration unit; + static const auto resolution = timestamp_resolution::milliseconds; + const auto max_dt = std::chrono::duration_cast(std::chrono::milliseconds(100)).count(); + + auto n = std::chrono::system_clock::now(); + auto t = detail::create_timestamp(resolution); + auto s = std::chrono::duration_cast(n - this->_system_zero).count(); + auto z = detail::convert(this->_filetime_zero, resolution); + Assert::IsTrue(t - z - s < max_dt, L"timestamp 100 nanoseconds", LINE_INFO()); } TEST_METHOD(test_nanoseconds) { + typedef std::chrono::milliseconds unit; + static const auto resolution = timestamp_resolution::milliseconds; + const auto max_dt = std::chrono::duration_cast(std::chrono::milliseconds(100)).count(); + auto n = std::chrono::system_clock::now(); - auto t = detail::create_timestamp(timestamp_resolution::nanoseconds); - auto s = std::chrono::duration_cast(n - this->_system_zero).count(); - auto z = detail::convert(this->_filetime_zero, timestamp_resolution::nanoseconds); - Assert::IsTrue(t - z - s < 1000000000, L"timestamp nanosecond", LINE_INFO()); + auto t = detail::create_timestamp(resolution); + auto s = std::chrono::duration_cast(n - this->_system_zero).count(); + auto z = detail::convert(this->_filetime_zero, resolution); + Assert::IsTrue(t - z - s < max_dt, L"timestamp nanosecond", LINE_INFO()); } TEST_METHOD(test_seconds) { + typedef std::chrono::seconds unit; + static const auto resolution = timestamp_resolution::seconds; + const auto max_dt = std::chrono::duration_cast(std::chrono::milliseconds(100)).count(); + auto n = std::chrono::system_clock::now(); - auto t = detail::create_timestamp(timestamp_resolution::seconds); - auto s = std::chrono::duration_cast(n - this->_system_zero).count(); - auto z = detail::convert(this->_filetime_zero, timestamp_resolution::seconds); - Assert::IsTrue(s - z - t < 1, L"timestamp second", LINE_INFO()); + auto t = detail::create_timestamp(resolution); + auto s = std::chrono::duration_cast(n - this->_system_zero).count(); + auto z = detail::convert(this->_filetime_zero, resolution); + Assert::IsTrue(s - z - t < max_dt, L"timestamp second", LINE_INFO()); } private: