HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
time_stamp_count.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "utility/module.hpp"
8#include "concurrency/module.hpp"
9#include "int_carry.hpp"
10#include <atomic>
11#include <array>
12#include <cstdint>
13
14#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
15#include <intrin.h>
16#elif HI_OPERATING_SYSTEM == HI_OS_LINUX
17#include <x86intrin.h>
18#endif
19
20namespace hi::inline v1 {
21
29public:
30 struct inplace {
31 };
33 };
35 };
36
37 constexpr time_stamp_count() noexcept : _count(0), _aux(0), _thread_id(0) {}
38
39 constexpr time_stamp_count(uint64_t count, uint32_t aux) noexcept : _count(count), _aux(aux), _thread_id(0) {}
40
43 explicit time_stamp_count(time_stamp_count::inplace) noexcept : _aux(0), _thread_id(0)
44 {
45 if constexpr (processor::current == processor::x64) {
46 uint32_t tmp;
47 _count = __rdtscp(&tmp);
48 } else {
50 }
51 }
52
56 {
57 if constexpr (processor::current == processor::x64) {
58 _count = __rdtscp(&_aux);
59 } else {
61 }
62 }
63
67 {
68 if constexpr (processor::current == processor::x64) {
69 constexpr uint64_t NT_TIB_CurrentThreadID = 0x48;
70
71 _count = __rdtscp(&_aux);
72 _thread_id = __readgsdword(NT_TIB_CurrentThreadID);
73 } else {
75 }
76 }
77
81 [[nodiscard]] static time_stamp_count now() noexcept
82 {
84 }
85
92 [[nodiscard]] ssize_t cpu_id() const noexcept
93 {
94 if (_aux_is_cpu_id.load(std::memory_order::relaxed)) {
95 // On Linux the upper bits are used for a node-id.
96 return _aux & 0xfff;
97 } else {
98 return cpu_id_fallback();
99 }
100 }
101
105 [[nodiscard]] constexpr uint32_t thread_id() const noexcept
106 {
107 return _thread_id;
108 }
109
114 [[nodiscard]] constexpr uint64_t count() const noexcept
115 {
116 return _count;
117 }
118
124 [[nodiscard]] static std::chrono::nanoseconds duration_from_count(uint64_t count) noexcept
125 {
126 using namespace std::chrono_literals;
127
128 hilet[lo, hi] = mul_carry(count, _period.load(std::memory_order::relaxed));
129 return 1ns * static_cast<int64_t>((hi << 32) | (lo >> 32));
130 }
131
136 [[nodiscard]] std::chrono::nanoseconds time_since_epoch() const noexcept
137 {
138 return duration_from_count(_count);
139 }
140
141 constexpr time_stamp_count &operator+=(uint64_t rhs) noexcept
142 {
143 _count += rhs;
144 return *this;
145 }
146
147 [[nodiscard]] constexpr time_stamp_count operator+(uint64_t rhs) const noexcept
148 {
149 auto tmp = *this;
150 tmp += rhs;
151 return tmp;
152 }
153
157 [[nodiscard]] static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept;
158
159 static void set_frequency(uint64_t frequency) noexcept
160 {
161 hilet period = (uint64_t{1'000'000'000} << 32) / frequency;
162 _period.store(period, std::memory_order_relaxed);
163 }
164
167 static void start_subsystem() noexcept;
168
169private:
170 uint64_t _count;
171
179 uint32_t _aux;
180
183 uint32_t _thread_id;
184
187 inline static std::atomic<uint64_t> _period = 0;
188
189 inline static std::atomic<bool> _aux_is_cpu_id = false;
190
193 inline static std::atomic<std::size_t> _num_aux_values = 0;
194
197 inline static std::array<uint32_t, maximum_num_cpus> _aux_values;
198
201 inline static std::array<std::size_t, maximum_num_cpus> _cpu_ids;
202
210 [[nodiscard]] ssize_t cpu_id_fallback() const noexcept;
211
212 static void populate_aux_values() noexcept;
213 static void configure_frequency() noexcept;
214};
215
216} // namespace hi::inline v1
#define hi_not_implemented(...)
This part of the code has not been implemented yet.
Definition assert.hpp:335
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
Since Window's 10 QueryPerformanceCounter() counts at only 10MHz which is too low to measure performa...
Definition time_stamp_count.hpp:28
static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept
Measure the frequency of the time_stamp_count.
constexpr uint32_t thread_id() const noexcept
Get the thread id.
Definition time_stamp_count.hpp:105
time_stamp_count(time_stamp_count::inplace_with_cpu_id) noexcept
Use a constructor to in-place create the timestamp.
Definition time_stamp_count.hpp:55
static time_stamp_count now() noexcept
Get the current count from the CPU's time stamp count.
Definition time_stamp_count.hpp:81
static void start_subsystem() noexcept
Start the time_stamp_count subsystem.
time_stamp_count(time_stamp_count::inplace) noexcept
Use a constructor to in-place create the timestamp.
Definition time_stamp_count.hpp:43
ssize_t cpu_id() const noexcept
Get the logical CPU index.
Definition time_stamp_count.hpp:92
time_stamp_count(time_stamp_count::inplace_with_thread_id) noexcept
Use a constructor to in-place create the timestamp.
Definition time_stamp_count.hpp:66
static std::chrono::nanoseconds duration_from_count(uint64_t count) noexcept
Convert a time-stamp count to a duration.
Definition time_stamp_count.hpp:124
std::chrono::nanoseconds time_since_epoch() const noexcept
Convert to nanoseconds since epoch.
Definition time_stamp_count.hpp:136
constexpr uint64_t count() const noexcept
Get the count since epoch.
Definition time_stamp_count.hpp:114
Definition time_stamp_count.hpp:30
Definition time_stamp_count.hpp:32
Definition time_stamp_count.hpp:34