2#ifndef LIBSBX_CORE_PROFILER_HPP_
3#define LIBSBX_CORE_PROFILER_HPP_
7#include <unordered_map>
11#include <libsbx/units/time.hpp>
13#include <libsbx/utility/assert.hpp>
15#include <libsbx/utility/hashed_string.hpp>
16#include <libsbx/utility/iterator.hpp>
17#include <libsbx/utility/exception.hpp>
21template<
typename Type>
26 using value_type = Type;
27 using size_type = std::size_t;
29 sampler(
const std::size_t capacity)
30 : _data{utility::make_reserved_vector<value_type>(capacity)},
38 _data.reserve(other._data.capacity());
39 _data.insert(_data.end(), other._data.begin(), other._data.end());
42 auto record(
const value_type value) ->
void {
43 if (_data.size() < _data.capacity()) {
44 _data.push_back(value);
47 _sum = _sum - _data[_index] + value;
48 _data[_index] = value;
51 _index = (_index + 1u) % _data.capacity();
54 template<
typename Other>
55 [[nodiscard]]
auto average_as()
const -> Other {
56 return _data.size() == 0u ?
static_cast<Other
>(0) :
static_cast<Other
>(_sum) /
static_cast<Other
>(_data.size());
59 [[nodiscard]]
auto size()
const -> size_type {
63 [[nodiscard]]
auto data()
const ->
const value_type* {
70 _sum =
static_cast<value_type
>(0);
73 auto write_in_order(std::span<value_type> target)
const ->
void {
74 utility::assert_that(target.size() >= _data.capacity(),
"Insufficient buffer size");
76 if (_data.size() < _data.capacity()) {
77 for (
auto i = 0u; i < _data.size(); ++i) {
81 for (
auto i = _data.size(); i < _data.capacity(); ++i) {
82 target[i] =
static_cast<value_type
>(0);
87 for (
auto i = _index; i < _data.capacity(); ++i) {
88 target[position++] = _data[i];
91 for (
auto i = 0u; i < _index; ++i) {
92 target[position++] = _data[i];
99 std::vector<value_type> _data;
107 using node_id = std::uint64_t;
109 inline static constexpr auto null_node =
static_cast<node_id
>(-1);
110 inline static constexpr auto max_nodes = std::uint64_t{516u};
112 inline static constexpr auto null_time = std::chrono::microseconds{
static_cast<std::uint64_t
>(-1)};
114 std::string_view label;
115 std::string_view file;
116 std::string_view function;
120 std::chrono::microseconds time;
133 std::array<scope_info, scope_info::max_nodes> nodes;
135 scope_info::node_id next_node_id = 0u;
136 scope_info::node_id current_node_id = scope_info::null_node;
138 std::uint32_t current_depth = 0u;
140 [[nodiscard]]
auto create_node(
const std::string_view label,
const std::string_view file,
const std::string_view function,
const std::uint32_t line) ->
scope_info& {
141 if (next_node_id >= scope_info::max_nodes) [[unlikely]] {
145 const auto id = next_node_id++;
150 .function = function,
152 .time = scope_info::null_time,
154 .parent_id = scope_info::null_node,
155 .depth = current_depth,
161 inline static auto instance() ->
database& {
162 static thread_local auto instance =
database{};
170 using clock = std::chrono::steady_clock;
173 clock::time_point start_time;
174 scope_info::node_id previous_node_id;
179 start_time{clock::now()},
180 previous_node_id{database::instance().current_node_id} {
181 info.parent_id = database::instance().current_node_id;
182 database::instance().current_node_id = info.id;
183 database::instance().current_depth = info.depth + 1u;
189 info.time = std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start_time);
190 database::instance().current_node_id = previous_node_id;
191 database::instance().current_depth = info.depth;
196#define SBX_CONCAT_TOKENS_IMPL(a, b) a##b
198#define SBX_CONCAT_TOKENS(a, b) SBX_CONCAT_TOKENS_IMPL(a, b)
200#define SBX_UNIQUE_NAME(name) SBX_CONCAT_TOKENS(name, __LINE__)
202#if defined(__clang__) || defined(__GNUC__)
203 #define FUNC_NAME __PRETTY_FUNCTION__
204#elif defined(_MSC_VER)
205 #define FUNC_NAME __FUNCSIG__
207 #define FUNC_NAME __func__
212#define SBX_PROFILE_SCOPE(label) \
213 static thread_local auto& SBX_UNIQUE_NAME(profiler_scope_info) = ::sbx::core::detail::database::instance().create_node((label), __FILE__, FUNC_NAME, __LINE__); \
214 const auto SBX_UNIQUE_NAME(profiler_scope_guard) = ::sbx::core::detail::scope_guard{SBX_UNIQUE_NAME(profiler_scope_info)}
216#define SBX_PROFILE_BLOCK(label) \
217 static thread_local auto& SBX_UNIQUE_NAME(profiler_scope_info) = ::sbx::core::detail::database::instance().create_node((label), __FILE__, FUNC_NAME, __LINE__); \
218 if (const auto SBX_UNIQUE_NAME(profiler_scope_guard) = ::sbx::core::detail::scope_guard{SBX_UNIQUE_NAME(profiler_scope_info)}; true)
220inline auto scope_infos() -> std::span<const scope_info> {
221 return std::span<const scope_info>{detail::database::instance().nodes.data(), detail::database::instance().next_node_id};
Definition: profiler.hpp:22
Definition: profiler.hpp:131
Definition: profiler.hpp:168
Definition: profiler.hpp:105
Definition: exception.hpp:18