Skip to content

Instantly share code, notes, and snippets.

@vittorioromeo
Created October 8, 2025 10:43
Show Gist options
  • Save vittorioromeo/71aba1be2c30a75ffc8147184650ea90 to your computer and use it in GitHub Desktop.
Save vittorioromeo/71aba1be2c30a75ffc8147184650ea90 to your computer and use it in GitHub Desktop.
#pragma once
// LICENSE AND COPYRIGHT (C) INFORMATION
// https://github.com/vittorioromeo/VRSFML/blob/master/license.md
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "SFML/System/Clock.hpp"
#include "SFML/System/Time.hpp"
#include "SFML/Base/Assert.hpp"
#include "SFML/Base/IntTypes.hpp"
#include "SFML/Base/SizeT.hpp"
#include "SFML/Base/Span.hpp"
#include "SFML/Base/StringView.hpp"
namespace sfex
{
////////////////////////////////////////////////////////////
struct [[nodiscard]] ScopeInfo
{
sf::base::StringView label;
sf::base::StringView file;
sf::base::StringView func;
int line;
sf::base::I64 timeUs;
sf::base::SizeT nodeId;
sf::base::SizeT parentNodeId;
sf::base::SizeT depth;
};
} // namespace sfex
namespace sfex::priv
{
////////////////////////////////////////////////////////////
inline constexpr sf::base::SizeT maxNodes = 128u;
inline constexpr auto nullNode = static_cast<sf::base::SizeT>(-1);
////////////////////////////////////////////////////////////
struct [[nodiscard]] Database
{
////////////////////////////////////////////////////////////
ScopeInfo nodes[priv::maxNodes]{};
sf::base::SizeT nextNodeId = 0u;
sf::base::SizeT currentNodeId = priv::nullNode;
sf::base::SizeT currentDepth = 0u;
////////////////////////////////////////////////////////////
[[nodiscard]] ScopeInfo& initNode(const sf::base::StringView label,
const sf::base::StringView file,
const sf::base::StringView func,
const int line)
{
const sf::base::SizeT id = nextNodeId++;
SFML_BASE_ASSERT(id < priv::maxNodes);
nodes[id] = ScopeInfo{
.label = label,
.file = file,
.func = func,
.line = line,
.timeUs = 0,
.nodeId = id,
.parentNodeId = nullNode,
.depth = currentDepth,
};
return nodes[id];
}
};
////////////////////////////////////////////////////////////
inline thread_local Database tlDatabase;
} // namespace sfex::priv
namespace sfex
{
////////////////////////////////////////////////////////////
struct [[nodiscard]] ScopeGuard
{
////////////////////////////////////////////////////////////
ScopeInfo& scopeInfo;
sf::Time startTime;
sf::base::SizeT previousNodeId;
////////////////////////////////////////////////////////////
[[gnu::always_inline]] explicit ScopeGuard(ScopeInfo& theScopeInfo) :
scopeInfo{theScopeInfo},
startTime{sf::Clock::now()},
previousNodeId{priv::tlDatabase.currentNodeId}
{
scopeInfo.parentNodeId = priv::tlDatabase.currentNodeId;
priv::tlDatabase.currentNodeId = scopeInfo.nodeId;
priv::tlDatabase.currentDepth = scopeInfo.depth + 1u;
}
////////////////////////////////////////////////////////////
[[gnu::always_inline]] ~ScopeGuard()
{
scopeInfo.timeUs = (sf::Clock::now() - startTime).asMicroseconds();
priv::tlDatabase.currentNodeId = previousNodeId;
priv::tlDatabase.currentDepth = scopeInfo.depth;
}
};
} // namespace sfex
namespace sfex
{
////////////////////////////////////////////////////////////
[[nodiscard, gnu::always_inline]] inline sf::base::Span<const ScopeInfo> getScopeInfos()
{
return sf::base::Span<const ScopeInfo>{priv::tlDatabase.nodes, priv::tlDatabase.nextNodeId};
}
} // namespace sfex
////////////////////////////////////////////////////////////
#define SFEX_PRIV_CONCAT_TOKENS_IMPL(a, b) a##b
////////////////////////////////////////////////////////////
#define SFEX_PRIV_CONCAT_TOKENS(a, b) SFEX_PRIV_CONCAT_TOKENS_IMPL(a, b)
////////////////////////////////////////////////////////////
#define SFEX_PRIV_UNIQUE_NAME(name) SFEX_PRIV_CONCAT_TOKENS(name, __LINE__)
////////////////////////////////////////////////////////////
#define SFEX_PROFILER_SCOPE(label) \
\
static thread_local auto& SFEX_PRIV_UNIQUE_NAME( \
sfProfilerScopeInfo) = ::sfex::priv::tlDatabase.initNode((label), __FILE__, __func__, __LINE__); \
\
const ::sfex::ScopeGuard SFEX_PRIV_UNIQUE_NAME(sfProfilerScopeGuard)(SFEX_PRIV_UNIQUE_NAME(sfProfilerScopeInfo))
////////////////////////////////////////////////////////////
/// \class sf::Profiler
/// \ingroup system
///
/// TODO P1: docs
///
/// \see TODO P1: docs
///
////////////////////////////////////////////////////////////
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment