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 "architecture.hpp"
8#include "cast.hpp"
9#include "int_carry.hpp"
10#include "thread.hpp"
11#include <atomic>
12#include <array>
13#include <cstdint>
14
15#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
16#include <intrin.h>
17#elif HI_OPERATING_SYSTEM == HI_OS_LINUX
18#include <x86intrin.h>
19#endif
20
21namespace hi::inline v1 {
22
30public:
31 struct inplace {
32 };
34 };
36 };
37
38 constexpr time_stamp_count() noexcept : _count(0), _aux(0), _thread_id(0) {}
39
40 constexpr time_stamp_count(uint64_t count, uint32_t aux) noexcept : _count(count), _aux(aux), _thread_id(0) {}
41
44 explicit time_stamp_count(time_stamp_count::inplace) noexcept : _aux(0), _thread_id(0)
45 {
46 if constexpr (processor::current == processor::x64) {
47 uint32_t tmp;
48 _count = __rdtscp(&tmp);
49 } else {
51 }
52 }
53
57 {
58 if constexpr (processor::current == processor::x64) {
59 _count = __rdtscp(&_aux);
60 } else {
62 }
63 }
64
68 {
69 if constexpr (processor::current == processor::x64) {
70 constexpr uint64_t NT_TIB_CurrentThreadID = 0x48;
71
72 _count = __rdtscp(&_aux);
73 _thread_id = __readgsdword(NT_TIB_CurrentThreadID);
74 } else {
76 }
77 }
78
82 [[nodiscard]] static time_stamp_count now() noexcept
83 {
85 }
86
93 [[nodiscard]] ssize_t cpu_id() const noexcept
94 {
95 if (_aux_is_cpu_id.load(std::memory_order::relaxed)) {
96 // On Linux the upper bits are used for a node-id.
97 return _aux & 0xfff;
98 } else {
99 return cpu_id_fallback();
100 }
101 }
102
106 [[nodiscard]] constexpr uint32_t thread_id() const noexcept
107 {
108 return _thread_id;
109 }
110
115 [[nodiscard]] constexpr uint64_t count() const noexcept
116 {
117 return _count;
118 }
119
125 [[nodiscard]] static std::chrono::nanoseconds duration_from_count(uint64_t count) noexcept
126 {
127 using namespace std::chrono_literals;
128
129 hilet[lo, hi] = mul_carry(count, _period.load(std::memory_order::relaxed));
130 return 1ns * static_cast<int64_t>((hi << 32) | (lo >> 32));
131 }
132
137 [[nodiscard]] std::chrono::nanoseconds time_since_epoch() const noexcept
138 {
139 return duration_from_count(_count);
140 }
141
142 constexpr time_stamp_count &operator+=(uint64_t rhs) noexcept
143 {
144 _count += rhs;
145 return *this;
146 }
147
148 [[nodiscard]] constexpr time_stamp_count operator+(uint64_t rhs) const noexcept
149 {
150 auto tmp = *this;
151 tmp += rhs;
152 return tmp;
153 }
154
158 [[nodiscard]] static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept;
159
160 static void set_frequency(uint64_t frequency) noexcept
161 {
162 hilet period = (uint64_t{1'000'000'000} << 32) / frequency;
163 _period.store(period, std::memory_order_relaxed);
164 }
165
168 static void start_subsystem() noexcept;
169
170private:
171 uint64_t _count;
172
180 uint32_t _aux;
181
184 uint32_t _thread_id;
185
188 inline static std::atomic<uint64_t> _period = 0;
189
190 inline static std::atomic<bool> _aux_is_cpu_id = false;
191
194 inline static std::atomic<std::size_t> _num_aux_values = 0;
195
198 inline static std::array<uint32_t, maximum_num_cpus> _aux_values;
199
202 inline static std::array<std::size_t, maximum_num_cpus> _cpu_ids;
203
211 [[nodiscard]] ssize_t cpu_id_fallback() const noexcept;
212
213 static void populate_aux_values() noexcept;
214 static void configure_frequency() noexcept;
215};
216
217} // namespace hi::inline v1
#define hi_not_implemented(...)
This part of the code has not been implemented yet.
Definition assert.hpp:193
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:15
geometry/margins.hpp
Definition assert.hpp:18
Since Window's 10 QueryPerformanceCounter() counts at only 10MHz which is too low to measure performa...
Definition time_stamp_count.hpp:29
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:106
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:56
static time_stamp_count now() noexcept
Get the current count from the CPU's time stamp count.
Definition time_stamp_count.hpp:82
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:44
ssize_t cpu_id() const noexcept
Get the logical CPU index.
Definition time_stamp_count.hpp:93
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:67
static std::chrono::nanoseconds duration_from_count(uint64_t count) noexcept
Convert a time-stamp count to a duration.
Definition time_stamp_count.hpp:125
std::chrono::nanoseconds time_since_epoch() const noexcept
Convert to nanoseconds since epoch.
Definition time_stamp_count.hpp:137
constexpr uint64_t count() const noexcept
Get the count since epoch.
Definition time_stamp_count.hpp:115
Definition time_stamp_count.hpp:31
Definition time_stamp_count.hpp:33
Definition time_stamp_count.hpp:35