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 {};
33
34 constexpr time_stamp_count() noexcept : _count(0), _aux(0) {}
35
36 constexpr time_stamp_count(uint64_t count, uint32_t aux) noexcept : _count(count), _aux(aux) {}
37
41 {
42 if constexpr (processor::current == processor::x64) {
43 _count = __rdtscp(&_aux);
44 } else {
45 tt_not_implemented();
46 }
47 }
48
52 {
53 if constexpr (processor::current == processor::x64) {
54 constexpr uint64_t NT_TIB_CurrentThreadID = 0x48;
55
56 _count = __rdtscp(&_aux);
57 _thread_id = __readgsdword(NT_TIB_CurrentThreadID);
58 } else {
59 tt_not_implemented();
60 }
61 }
62
66 [[nodiscard]] static time_stamp_count now() noexcept
67 {
69 }
70
77 [[nodiscard]] ssize_t cpu_id() const noexcept
78 {
79 if (_aux_is_cpu_id.load(std::memory_order::relaxed)) {
80 // On Linux the upper bits are used for a node-id.
81 return _aux & 0xfff;
82 } else {
83 return cpu_id_fallback();
84 }
85 }
86
90 [[nodiscard]] constexpr uint32_t thread_id() const noexcept
91 {
92 return _thread_id;
93 }
94
99 [[nodiscard]] constexpr uint64_t count() const noexcept
100 {
101 return _count;
102 }
103
108 [[nodiscard]] std::chrono::nanoseconds time_since_epoch() const noexcept
109 {
110 auto [lo, hi] = wide_mul(_count, _period.load(std::memory_order::relaxed));
111 return 1ns * static_cast<int64_t>((hi << 32) | (lo >> 32));
112 }
113
114 constexpr time_stamp_count &operator+=(uint64_t rhs) noexcept
115 {
116 _count += rhs;
117 return *this;
118 }
119
120 [[nodiscard]] constexpr time_stamp_count operator+(uint64_t rhs) const noexcept
121 {
122 auto tmp = *this;
123 tmp += rhs;
124 return tmp;
125 }
126
130 [[nodiscard]] static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept;
131
132 static void set_frequency(uint64_t frequency) noexcept
133 {
134 auto period = (uint64_t{1'000'000'000} << 32) / frequency;
135 _period.store(period, std::memory_order_relaxed);
136 }
137
140 static void start_subsystem() noexcept;
141
142private:
143 uint64_t _count;
144
152 uint32_t _aux;
153
156 uint32_t _thread_id;
157
160 inline static std::atomic<uint64_t> _period = 0;
161
162 inline static std::atomic<bool> _aux_is_cpu_id = false;
163
166 inline static std::atomic<size_t> _num_aux_values = 0;
167
170 inline static std::array<uint32_t, maximum_num_cpus> _aux_values;
171
174 inline static std::array<size_t, maximum_num_cpus> _cpu_ids;
175
183 [[nodiscard]] ssize_t cpu_id_fallback() const noexcept;
184
185 static void populate_aux_values() noexcept;
186 static void configure_frequency() noexcept;
187};
188
189} // 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:90
constexpr uint64_t count() const noexcept
Get the count since epoch.
Definition time_stamp_count.hpp:99
ssize_t cpu_id() const noexcept
Get the logical cpu index.
Definition time_stamp_count.hpp:77
static uint64_t measure_frequency(std::chrono::milliseconds duration) noexcept
Measure the frequency of the time_stamp_count.
std::chrono::nanoseconds time_since_epoch() const noexcept
Convert to nanoseconds since epoch.
Definition time_stamp_count.hpp:108
time_stamp_count(time_stamp_count::inplace_with_thread_id) noexcept
Use a constructor to inplace create the timestamp.
Definition time_stamp_count.hpp:51
static void start_subsystem() noexcept
Start the time_stamp_count subsystem.
time_stamp_count(time_stamp_count::inplace) noexcept
Use a constructor to inplace create the timestamp.
Definition time_stamp_count.hpp:40
static time_stamp_count now() noexcept
Get the current count from the CPU's time stamp count.
Definition time_stamp_count.hpp:66
Definition time_stamp_count.hpp:31
Definition time_stamp_count.hpp:32
T load(T... args)
T store(T... args)