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 TT_OPERATING_SYSTEM == TT_OS_WINDOWS
16#include <intrin.h>
17#elif TT_OPERATING_SYSTEM == TT_OS_LINUX
18#include <x86intrin.h>
19#endif
20
21namespace tt {
22
30public:
31 struct inplace {};
34
35 constexpr time_stamp_count() noexcept : _count(0), _aux(0), _thread_id(0) {}
36
37 constexpr time_stamp_count(uint64_t count, uint32_t aux) noexcept : _count(count), _aux(aux), _thread_id(0) {}
38
41 explicit time_stamp_count(time_stamp_count::inplace) noexcept : _aux(0), _thread_id(0)
42 {
43 if constexpr (processor::current == processor::x64) {
44 uint32_t tmp;
45 _count = __rdtscp(&tmp);
46 } else {
47 tt_not_implemented();
48 }
49 }
50
54 {
55 if constexpr (processor::current == processor::x64) {
56 _count = __rdtscp(&_aux);
57 } else {
58 tt_not_implemented();
59 }
60 }
61
65 {
66 if constexpr (processor::current == processor::x64) {
67 constexpr uint64_t NT_TIB_CurrentThreadID = 0x48;
68
69 _count = __rdtscp(&_aux);
70 _thread_id = __readgsdword(NT_TIB_CurrentThreadID);
71 } else {
72 tt_not_implemented();
73 }
74 }
75
79 [[nodiscard]] static time_stamp_count now() noexcept
80 {
82 }
83
90 [[nodiscard]] ssize_t cpu_id() const noexcept
91 {
92 if (_aux_is_cpu_id.load(std::memory_order::relaxed)) {
93 // On Linux the upper bits are used for a node-id.
94 return _aux & 0xfff;
95 } else {
96 return cpu_id_fallback();
97 }
98 }
99
103 [[nodiscard]] constexpr uint32_t thread_id() const noexcept
104 {
105 return _thread_id;
106 }
107
112 [[nodiscard]] constexpr uint64_t count() const noexcept
113 {
114 return _count;
115 }
116
122 [[nodiscard]] static std::chrono::nanoseconds duration_from_count(uint64_t count) noexcept
123 {
124 using namespace std::literals::chrono_literals;
125
126 ttlet [lo, hi] = mul_carry(count, _period.load(std::memory_order::relaxed));
127 return 1ns * static_cast<int64_t>((hi << 32) | (lo >> 32));
128 }
129
134 [[nodiscard]] std::chrono::nanoseconds time_since_epoch() const noexcept
135 {
136 return duration_from_count(_count);
137 }
138
139 constexpr time_stamp_count &operator+=(uint64_t rhs) noexcept
140 {
141 _count += rhs;
142 return *this;
143 }
144
145 [[nodiscard]] constexpr time_stamp_count operator+(uint64_t rhs) const noexcept
146 {
147 auto tmp = *this;
148 tmp += rhs;
149 return tmp;
150 }
151
155 [[nodiscard]] static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept;
156
157 static void set_frequency(uint64_t frequency) noexcept
158 {
159 auto period = (uint64_t{1'000'000'000} << 32) / frequency;
160 _period.store(period, std::memory_order_relaxed);
161 }
162
165 static void start_subsystem() noexcept;
166
167private:
168 uint64_t _count;
169
177 uint32_t _aux;
178
181 uint32_t _thread_id;
182
185 inline static std::atomic<uint64_t> _period = 0;
186
187 inline static std::atomic<bool> _aux_is_cpu_id = false;
188
191 inline static std::atomic<size_t> _num_aux_values = 0;
192
195 inline static std::array<uint32_t, maximum_num_cpus> _aux_values;
196
199 inline static std::array<size_t, maximum_num_cpus> _cpu_ids;
200
208 [[nodiscard]] ssize_t cpu_id_fallback() const noexcept;
209
210 static void populate_aux_values() noexcept;
211 static void configure_frequency() noexcept;
212};
213
214} // namespace tt
STL namespace.
Since Window's 10 QueryPerformanceCounter() counts at only 10MHz which is too low to measure performa...
Definition time_stamp_count.hpp:29
constexpr uint32_t thread_id() const noexcept
Get the thread id.
Definition time_stamp_count.hpp:103
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:53
constexpr uint64_t count() const noexcept
Get the count since epoch.
Definition time_stamp_count.hpp:112
ssize_t cpu_id() const noexcept
Get the logical CPU index.
Definition time_stamp_count.hpp:90
static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept
Measure the frequency of the time_stamp_count.
static std::chrono::nanoseconds duration_from_count(uint64_t count) noexcept
Convert a time-stamp count to a duration.
Definition time_stamp_count.hpp:122
std::chrono::nanoseconds time_since_epoch() const noexcept
Convert to nanoseconds since epoch.
Definition time_stamp_count.hpp:134
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:64
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:41
static time_stamp_count now() noexcept
Get the current count from the CPU's time stamp count.
Definition time_stamp_count.hpp:79
Definition time_stamp_count.hpp:31
Definition time_stamp_count.hpp:32
Definition time_stamp_count.hpp:33
T load(T... args)
T store(T... args)