HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
time_stamp_count.hpp
1// Copyright Take Vos 2019-2020.
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 {
50 hi_not_implemented();
51 }
52 }
53
57 {
58 if constexpr (processor::current == processor::x64) {
59 _count = __rdtscp(&_aux);
60 } else {
61 hi_not_implemented();
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 {
75 hi_not_implemented();
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 auto 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 hilet
Invariant should be the default for variables.
Definition required.hpp:23
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...
STL namespace.
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