8#include "time_stamp_count.hpp"
9#include "../utility/utility.hpp"
10#include "../concurrency/concurrency.hpp"
11#include "../macros.hpp"
23hi_export_module(hikogui.time.time_stamp_utc);
26hi_export
namespace hi::inline
v1 {
38 utc_nanoseconds shortest_tp;
42 for (
auto i = 0; i != 10; ++i) {
43 auto const tmp_tsc1 = time_stamp_count::now();
44 auto const tmp_tp = std::chrono::utc_clock::now();
45 auto const tmp_tsc2 = time_stamp_count::now();
47 if (tmp_tsc1.cpu_id() != tmp_tsc2.cpu_id()) {
48 throw os_error(
"CPU Switch detected during get_sample(), which should never happen");
51 if (tmp_tsc1.count() > tmp_tsc2.count()) {
58 auto const diff = tmp_tsc2.count() - tmp_tsc1.count();
60 if (diff < shortest_diff) {
63 shortest_tsc = tmp_tsc1 + (diff / 2);
68 throw os_error(
"Unable to get TSC sample.");
85 auto i = tsc.cpu_id();
87 auto const tsc_epoch = tsc_epochs[i].load(std::memory_order::relaxed);
88 if (tsc_epoch != utc_nanoseconds{}) {
89 return tsc_epoch + tsc.time_since_epoch();
94 auto const ref_tp = std::chrono::utc_clock::now();
95 auto const ref_tsc = time_stamp_count::now();
96 auto const diff_ns = ref_tsc.time_since_epoch() - tsc.time_since_epoch();
97 return ref_tp - diff_ns;
104 return hi::start_subsystem(global_state_type::time_stamp_utc_is_running, init_subsystem, deinit_subsystem);
123 inline static
std::jthread subsystem_thread;
124 inline static unfair_mutex mutex;
125 inline static
std::array<
std::atomic<utc_nanoseconds>, maximum_num_cpus> tsc_epochs = {};
127 static void subsystem_proc_frequency_calibration(std::stop_token stop_token)
129 using namespace std::chrono_literals;
137 for (
auto i = 0; i != frequencies.
size();) {
138 auto const f = time_stamp_count::measure_frequency(1s);
144 if (stop_token.stop_requested()) {
148 std::ranges::sort(frequencies);
149 auto const iqr_size = frequencies.
size() / 2;
151 auto const iqr_last =
std::next(iqr_first, iqr_size);
152 auto const frequency =
std::accumulate(iqr_first, iqr_last, uint64_t{0}) / iqr_size;
154 time_stamp_count::set_frequency(frequency);
156 static void subsystem_proc(std::stop_token stop_token)
158 using namespace std::chrono_literals;
161 subsystem_proc_frequency_calibration(stop_token);
166 while (not stop_token.stop_requested()) {
170 auto const lock = std::scoped_lock(time_stamp_utc::mutex);
172 time_stamp_count tsc;
173 auto const tp = time_stamp_utc::now(tsc);
174 hi_assert(tsc.cpu_id() == narrow_cast<ssize_t>(current_cpu));
176 tsc_epochs[current_cpu].store(tp - tsc.time_since_epoch(), std::memory_order::relaxed);
182 static bool init_subsystem() noexcept
184 time_stamp_utc::subsystem_thread = std::jthread{subsystem_proc};
190 static void deinit_subsystem() noexcept
193 if (time_stamp_utc::subsystem_thread.joinable()) {
194 time_stamp_utc::subsystem_thread.request_stop();
195 time_stamp_utc::subsystem_thread.join();
200 [[nodiscard]]
static std::size_t find_cpu_id(uint32_t cpu_id)
noexcept;
205 using namespace std::chrono_literals;
207 if (duration >= 1s) {
208 return std::format(
"{:.3g}s ", narrow_cast<double>(duration / 1ns) / 1'000'000'000);
209 }
else if (duration >= 1ms) {
210 return std::format(
"{:.3g}ms", narrow_cast<double>(duration / 1ns) / 1'000'000);
211 }
else if (duration >= 1us) {
212 return std::format(
"{:.3g}us", narrow_cast<double>(duration / 1ns) / 1'000);
214 return std::format(
"{:.3g}ns", narrow_cast<double>(duration / 1ns));
std::vector< bool > process_affinity_mask()
Get the current process CPU affinity mask.
void set_thread_name(std::string_view name) noexcept
Set the name of the current thread.
T::value_type start_subsystem(T &check_variable, typename T::value_type off_value, typename T::value_type(*init_function)(), void(*deinit_function)())
Start a sub-system.
Definition subsystem.hpp:117
bool global_state_disable(global_state_type subsystem, std::memory_order order=std::memory_order::seq_cst) noexcept
Disable a subsystem.
Definition global_state.hpp:249
std::size_t advance_thread_affinity(std::size_t &cpu) noexcept
Advance thread affinity to the next CPU.
Definition thread_intf.hpp:121
void stop_subsystem(void(*deinit_function)())
Stop a sub-system.
Definition subsystem.hpp:203
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Since Window's 10 QueryPerformanceCounter() counts at only 10MHz which is too low to measure performa...
Definition time_stamp_count.hpp:36
Timestamp.
Definition time_stamp_utc.hpp:30
static void stop_subsystem() noexcept
This will stop the calibration subsystem.
Definition time_stamp_utc.hpp:109
static bool start_subsystem() noexcept
This will start the calibration subsystem.
Definition time_stamp_utc.hpp:102
static utc_nanoseconds make(time_stamp_count const &tsc) noexcept
Make a time point from a time stamp count.
Definition time_stamp_utc.hpp:83
static utc_nanoseconds now(time_stamp_count &tsc)
Get the current time and TSC value.
Definition time_stamp_utc.hpp:34
static void adjust_for_drift() noexcept
A calibration step which will drift the per-cpu tsc-offset.