Add name buffer to tracy client library

To be used by Python and Go bindings to store const char * accessible via a lookup
This commit is contained in:
Arnim Balzer 2024-04-20 09:04:07 +01:00
parent 6199b2f883
commit 9e4af3aca0
No known key found for this signature in database
GPG Key ID: 785EF903F0917AB7
11 changed files with 159 additions and 108 deletions

View File

@ -82,6 +82,7 @@ set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF)
set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF) set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF)
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF) set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF)
set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF) set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF)
set_option(TRACY_NAME_BUFFER "Enable name buffer for other languages" OFF)
if(NOT TRACY_STATIC) if(NOT TRACY_STATIC)
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS) target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
@ -141,6 +142,16 @@ set(common_includes
${TRACY_PUBLIC_DIR}/common/TracyUwp.hpp ${TRACY_PUBLIC_DIR}/common/TracyUwp.hpp
${TRACY_PUBLIC_DIR}/common/TracyYield.hpp) ${TRACY_PUBLIC_DIR}/common/TracyYield.hpp)
if(TRACY_NAME_BUFFER)
set(TRACY_BUFFER_SIZE 128 CACHE STRING "The size of the name buffer")
set(TRACY_NAME_LENGTH 128 CACHE STRING "The length of a name in the buffer")
list(APPEND common_includes ${TRACY_PUBLIC_DIR}/common/TracyNameBuffer.hpp)
target_compile_definitions(TracyClient PRIVATE TRACY_BUFFER_SIZE=${TRACY_BUFFER_SIZE})
target_compile_definitions(TracyClient PRIVATE TRACY_NAME_LENGTH=${TRACY_NAME_LENGTH})
endif()
install(TARGETS TracyClient install(TARGETS TracyClient
EXPORT TracyConfig EXPORT TracyConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
@ -169,6 +180,9 @@ if(TRACY_CLIENT_PYTHON)
if(TRACY_STATIC) if(TRACY_STATIC)
message(FATAL_ERROR "Python-bindings require a shared client library") message(FATAL_ERROR "Python-bindings require a shared client library")
endif() endif()
if(NOT TRACY_NAME_BUFFER)
message(FATAL_ERROR "Python-bindings require name buffer being enabled")
endif()
add_subdirectory(python) add_subdirectory(python)
endif() endif()

View File

@ -2316,15 +2316,15 @@ Please not the use of ids as way to cope with the need for unique pointers for c
\subsubsection{Building the Python package} \subsubsection{Building the Python package}
To build the Python package, you will need to use the CMake build system to compile the Tracy-Client. To build the Python package, you will need to use the CMake build system to compile the Tracy-Client.
The CMake option \texttt{-D TRACY\_CLIENT\_PYTHON=ON} is used to enable the generation of the Python bindings in conjunction with a mandatory creation of a shared Tracy-Client library via one of the CMake options \texttt{-D BUILD\_SHARED\_LIBS=ON} or \texttt{-D DEFAULT\_STATIC=OFF}. The CMake option \texttt{-D TRACY\_CLIENT\_PYTHON=ON} is used to enable the generation of the Python bindings in conjunction with a mandatory creation of a shared Tracy-Client library via one of the CMake options \texttt{-D BUILD\_SHARED\_LIBS=ON} or \texttt{-D DEFAULT\_STATIC=OFF}. Moreover, the tracy name buffer needs to be built into the client via \texttt{-D TRACY\_NAME\_BUFFER=ON}.
The following other variables are available in addition: The following other variables are available in addition:
\begin{itemize} \begin{itemize}
\item \texttt{EXTERNAL\_PYBIND11} --- Can be used to disable the download of pybind11 when Tracy is embedded in another CMake project that already uses pybind11. \item \texttt{EXTERNAL\_PYBIND11} --- Can be used to disable the download of pybind11 when Tracy is embedded in another CMake project that already uses pybind11.
\item \texttt{TRACY\_CLIENT\_PYTHON\_TARGET} --- Optional directory to copy Tracy Python bindings to when Tracy is embedded in another CMake project. \item \texttt{TRACY\_CLIENT\_PYTHON\_TARGET} --- Optional directory to copy Tracy Python bindings to when Tracy is embedded in another CMake project.
\item \texttt{BUFFER\_SIZE} --- The size of the global pointer buffer (defaults to 128) for naming Tracy profiling entities like frame marks, plots, and memory locations. \item \texttt{TRACY\_BUFFER\_SIZE} --- The size of the global pointer buffer (defaults to 128) for naming Tracy profiling entities like frame marks, plots, and memory locations.
\item \texttt{NAME\_LENGTH} --- The maximum length (defaults to 128) of a name stored in the global pointer buffer. \item \texttt{TRACY\_NAME\_LENGTH} --- The maximum length (defaults to 128) of a name stored in the global pointer buffer.
\end{itemize} \end{itemize}
Be aware that the memory allocated by this buffer is global and is not freed, see section~\ref{uniquepointers}. Be aware that the memory allocated by this buffer is global and is not freed, see section~\ref{uniquepointers}.
@ -2334,7 +2334,7 @@ See below for example steps to build the Python bindings using CMake:
\begin{lstlisting} \begin{lstlisting}
mkdir build mkdir build
cd build cd build
cmake -DTRACY_STATIC=OFF -DTRACY_CLIENT_PYTHON=ON ../ cmake -DTRACY_STATIC=OFF -DTRACY_NAME_BUFFER=ON -DTRACY_CLIENT_PYTHON=ON ../
\end{lstlisting} \end{lstlisting}
Once this has finished building the Python package can be built as follows: Once this has finished building the Python package can be built as follows:

View File

@ -49,6 +49,10 @@
# endif # endif
#endif #endif
#ifdef TRACY_NAME_BUFFER
#include "common/TracyNameBuffer.cpp"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "dbghelp.lib") # pragma comment(lib, "dbghelp.lib")

View File

@ -0,0 +1,44 @@
#include "TracyNameBuffer.hpp"
using namespace tracy;
#include "TracyApi.h"
#ifndef TRACY_BUFFER_SIZE
#define TRACY_BUFFER_SIZE = 128
#endif
#ifndef TRACY_NAME_LENGTH
#define TRACY_NAME_LENGTH = 128
#endif
NameBuffer::NameBuffer() : m_buffer(TRACY_BUFFER_SIZE, nullptr), m_index(0ul) {
for (std::size_t index = 0ul, end = m_buffer.size(); index < end; ++index)
m_buffer[index] = new char[TRACY_NAME_LENGTH];
}
BufferEntry NameBuffer::add( const std::string& name ) {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_index >= TRACY_BUFFER_SIZE || name.size() > TRACY_NAME_LENGTH)
return std::make_pair(std::nullopt, nullptr);
auto index = m_index++;
name.copy(m_buffer[index], name.size());
return std::make_pair(index, m_buffer[index]);
}
const char* NameBuffer::get( uint16_t index ) {
std::lock_guard<std::mutex> lock(m_mutex);
if (index >= TRACY_BUFFER_SIZE) return nullptr;
return m_buffer[index];
}
#ifdef TRACY_NAME_BUFFER
TRACY_API const char* ___tracy_name_buffer_add( const char* name, uint16_t* id ) {
auto entry = NameBuffer::Add(name);
if (!entry.first) return nullptr;
if (id != nullptr) *id = *entry.first;
return entry.second;
}
TRACY_API const char* ___tracy_name_buffer_get( uint16_t id ) { return NameBuffer::Get(id); }
#endif

View File

@ -0,0 +1,37 @@
#pragma once
#include <mutex>
#include <optional>
#include <string>
#include <vector>
namespace tracy {
using OptionalNumber = std::optional<uint16_t>;
using BufferEntry = std::pair<OptionalNumber, const char*>;
class NameBuffer {
public:
static inline BufferEntry Add( const std::string& name ) {
return getBuffer().add(name);
}
static inline const char* Get( uint16_t index ) {
return getBuffer().get(index);
}
private:
NameBuffer();
std::mutex m_mutex;
std::vector<char*> m_buffer;
std::size_t m_index;
static inline NameBuffer& getBuffer() {
static NameBuffer buffer;
return buffer;
}
BufferEntry add( const std::string& name );
const char* get( uint16_t index );
};
} // namespace tracy

View File

@ -291,6 +291,10 @@
# define TracyFiberLeave tracy::Profiler::LeaveFiber() # define TracyFiberLeave tracy::Profiler::LeaveFiber()
#endif #endif
#ifdef TRACY_NAME_BUFFER
# include "../common/TracyNameBuffer.hpp"
#endif
#endif #endif
#endif #endif

View File

@ -37,6 +37,8 @@ TRACY_API void ___tracy_set_thread_name( const char* name );
#ifndef TRACY_ENABLE #ifndef TRACY_ENABLE
#define TracyCEnabled() 0
typedef const void* TracyCZoneCtx; typedef const void* TracyCZoneCtx;
typedef const void* TracyCLockCtx; typedef const void* TracyCLockCtx;
@ -116,8 +118,15 @@ typedef const void* TracyCLockCtx;
# define TracyCFiberLeave # define TracyCFiberLeave
#endif #endif
#ifdef TRACY_NAME_BUFFER
# define TracyCNameBufferAdd(name, id) 0
# define TracyCNameBufferGet(id) 0
#endif
#else #else
#define TracyCEnabled() 1
#ifndef TracyConcat #ifndef TracyConcat
# define TracyConcat(x,y) TracyConcatIndirect(x,y) # define TracyConcat(x,y) TracyConcatIndirect(x,y)
#endif #endif
@ -408,6 +417,14 @@ TRACY_API void ___tracy_fiber_leave( void );
# define TracyCFiberLeave ___tracy_fiber_leave(); # define TracyCFiberLeave ___tracy_fiber_leave();
#endif #endif
#ifdef TRACY_NAME_BUFFER
TRACY_API const char* ___tracy_name_buffer_add( const char* name, uint16_t* id );
TRACY_API const char* ___tracy_name_buffer_get( uint16_t id );
# define TracyCNameBufferAdd(name, id) ___tracy_name_buffer_add( name, id );
# define TracyCNameBufferGet(id) ___tracy_name_buffer_get( id );
#endif
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -9,14 +9,8 @@ if(EXTERNAL_PYBIND11)
FetchContent_MakeAvailable(pybind11) FetchContent_MakeAvailable(pybind11)
endif() endif()
set(BUFFER_SIZE 128 CACHE STRING "The size of the pointer buffer")
set(NAME_LENGTH 128 CACHE STRING "The length of a name in the buffer")
pybind11_add_module(TracyClientBindings SHARED bindings/Module.cpp) pybind11_add_module(TracyClientBindings SHARED bindings/Module.cpp)
target_link_libraries(TracyClientBindings PUBLIC TracyClient) target_link_libraries(TracyClientBindings PUBLIC TracyClient)
target_compile_definitions(TracyClientBindings PUBLIC BUFFER_SIZE=${BUFFER_SIZE})
target_compile_definitions(TracyClientBindings PUBLIC NAME_LENGTH=${NAME_LENGTH})
set(TRACY_PYTHON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tracy_client) set(TRACY_PYTHON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tracy_client)
set(TRACY_LIB_SYMLINK $<TARGET_FILE_PREFIX:TracyClient>$<TARGET_FILE_BASE_NAME:TracyClient>$<TARGET_FILE_SUFFIX:TracyClient>) set(TRACY_LIB_SYMLINK $<TARGET_FILE_PREFIX:TracyClient>$<TARGET_FILE_BASE_NAME:TracyClient>$<TARGET_FILE_SUFFIX:TracyClient>)

View File

@ -3,8 +3,8 @@
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
namespace py = pybind11; namespace py = pybind11;
#include "NameBuffer.hpp"
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
using namespace tracy;
using OptionalString = std::optional<std::string>; using OptionalString = std::optional<std::string>;
using OptionalInt = std::optional<int>; using OptionalInt = std::optional<int>;
@ -61,6 +61,7 @@ bool MemoryFree(const Type &type, const OptionalNumber &id = std::nullopt,
return true; return true;
} }
#else #else
using OptionalNumber = std::optional<uint16_t>;
template <typename Type = uint64_t> template <typename Type = uint64_t>
OptionalNumber MemoryAllocate(const Type &, std::size_t, const OptionalString &, OptionalNumber MemoryAllocate(const Type &, std::size_t, const OptionalString &,

View File

@ -1,25 +1,18 @@
#include "Memory.hpp" #include "Memory.hpp"
#include "ScopedZone.hpp" #include "ScopedZone.hpp"
#include "tracy/TracyC.h" #include "tracy/TracyC.h"
using namespace tracy;
namespace tracy { namespace tracy {
#ifndef TRACY_ENABLE #ifndef TRACY_ENABLE
enum class PlotFormatType : uint8_t { Number, Memory, Percentage }; enum class PlotFormatType : uint8_t { Number, Memory, Percentage };
#endif #endif
constexpr static inline bool IsEnabled() {
#ifdef TRACY_ENABLE
return true;
#else
return false;
#endif
}
} // namespace tracy } // namespace tracy
PYBIND11_MODULE(TracyClientBindings, m) { PYBIND11_MODULE(TracyClientBindings, m) {
m.doc() = "Tracy Client Bindings"; m.doc() = "Tracy Client Bindings";
m.def("is_enabled", &tracy::IsEnabled); m.def("is_enabled", []() -> bool { return TracyCEnabled(); });
py::enum_<tracy::Color::ColorType>(m, "ColorType") py::enum_<tracy::Color::ColorType>(m, "ColorType")
.value("Snow", tracy::Color::Snow) .value("Snow", tracy::Color::Snow)
@ -703,10 +696,10 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"program_name", "program_name",
[](const std::string &name) { [](const std::string &name) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
auto entry = NameBuffer::Add(name); auto ptr = TracyCNameBufferAdd(name.c_str(), nullptr);
if (!entry.first) return false; if (!ptr) return false;
TracySetProgramName(entry.second); TracySetProgramName(ptr);
return true; return true;
}, },
"name"_a.none(false)); "name"_a.none(false));
@ -714,7 +707,7 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"thread_name", "thread_name",
[](const std::string &name) { [](const std::string &name) {
if (!tracy::IsEnabled()) return; if (!TracyCEnabled()) return;
tracy::SetThreadName(name.c_str()); tracy::SetThreadName(name.c_str());
}, },
"name"_a.none(false)); "name"_a.none(false));
@ -722,7 +715,7 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"app_info", "app_info",
[](const std::string &text) { [](const std::string &text) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
if (text.size() >= std::numeric_limits<uint16_t>::max()) return false; if (text.size() >= std::numeric_limits<uint16_t>::max()) return false;
TracyAppInfo(text.c_str(), text.size()); TracyAppInfo(text.c_str(), text.size());
return true; return true;
@ -732,7 +725,7 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"message", "message",
[](const std::string &message) { [](const std::string &message) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
if (message.size() >= std::numeric_limits<uint16_t>::max()) if (message.size() >= std::numeric_limits<uint16_t>::max())
return false; return false;
TracyMessage(message.c_str(), message.size()); TracyMessage(message.c_str(), message.size());
@ -743,7 +736,7 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"message", "message",
[](const std::string &message, uint32_t pColor) { [](const std::string &message, uint32_t pColor) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
if (message.size() >= std::numeric_limits<uint16_t>::max()) if (message.size() >= std::numeric_limits<uint16_t>::max())
return false; return false;
TracyMessageC(message.c_str(), message.size(), pColor); TracyMessageC(message.c_str(), message.size(), pColor);
@ -755,20 +748,21 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"frame_mark_start", "frame_mark_start",
[](const std::string &name) { [](const std::string &name) -> OptionalNumber {
if (!tracy::IsEnabled()) return static_cast<OptionalNumber>(0ul); if (!TracyCEnabled()) return 0ul;
auto entry = NameBuffer::Add(name); uint16_t id = 0ul;
if (!entry.first) return static_cast<OptionalNumber>(std::nullopt); auto ptr = TracyCNameBufferAdd(name.c_str(), &id);
FrameMarkStart(entry.second); if (!ptr) return static_cast<OptionalNumber>(std::nullopt);
return entry.first; FrameMarkStart(ptr);
return id;
}, },
"name"_a.none(false)); "name"_a.none(false));
m.def( m.def(
"frame_mark_end", "frame_mark_end",
[](std::size_t id) { [](std::size_t id) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
auto ptr = NameBuffer::Get(id); auto ptr = TracyCNameBufferGet(id);
if (!ptr) return false; if (!ptr) return false;
FrameMarkEnd(ptr); FrameMarkEnd(ptr);
return true; return true;
@ -779,7 +773,7 @@ PYBIND11_MODULE(TracyClientBindings, m) {
"frame_image", "frame_image",
[](const py::bytes &image, uint16_t width, uint16_t height, [](const py::bytes &image, uint16_t width, uint16_t height,
uint8_t offset = 0, bool flip = false) { uint8_t offset = 0, bool flip = false) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
if (width % 4 != 0 || height % 4 != 0) return false; if (width % 4 != 0 || height % 4 != 0) return false;
TracyCFrameImage(std::string(image).data(), width, height, offset, TracyCFrameImage(std::string(image).data(), width, height, offset,
flip); flip);
@ -821,12 +815,13 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"_plot_config", "_plot_config",
[](const std::string &name, int type, bool step, bool fill, [](const std::string &name, int type, bool step, bool fill,
uint32_t color = 0) { uint32_t color = 0) -> OptionalNumber {
if (!tracy::IsEnabled()) return static_cast<OptionalNumber>(0ul); if (!TracyCEnabled()) return 0ul;
auto entry = NameBuffer::Add(name); uint16_t id = 0ul;
if (!entry.first) return static_cast<OptionalNumber>(std::nullopt); auto ptr = TracyCNameBufferAdd(name.c_str(), &id);
TracyCPlotConfig(entry.second, type, step, fill, color); if (!ptr) return static_cast<OptionalNumber>(std::nullopt);
return entry.first; TracyCPlotConfig(ptr, type, step, fill, color);
return id;
}, },
"name"_a.none(false), "type"_a.none(false), "step"_a.none(false), "name"_a.none(false), "type"_a.none(false), "step"_a.none(false),
"fill"_a.none(false), "color"_a.none(false)); "fill"_a.none(false), "color"_a.none(false));
@ -840,8 +835,8 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"plot", "plot",
[](std::size_t id, double value) { [](std::size_t id, double value) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
auto ptr = NameBuffer::Get(id); auto ptr = TracyCNameBufferGet(id);
if (!ptr) return false; if (!ptr) return false;
TracyCPlot(ptr, value); TracyCPlot(ptr, value);
return true; return true;
@ -850,8 +845,8 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"plot", "plot",
[](std::size_t id, float value) { [](std::size_t id, float value) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
auto ptr = NameBuffer::Get(id); auto ptr = TracyCNameBufferGet(id);
if (!ptr) return false; if (!ptr) return false;
TracyCPlotF(ptr, value); TracyCPlotF(ptr, value);
return true; return true;
@ -860,8 +855,8 @@ PYBIND11_MODULE(TracyClientBindings, m) {
m.def( m.def(
"plot", "plot",
[](std::size_t id, int64_t value) { [](std::size_t id, int64_t value) {
if (!tracy::IsEnabled()) return true; if (!TracyCEnabled()) return true;
auto ptr = NameBuffer::Get(id); auto ptr = TracyCNameBufferGet(id);
if (!ptr) return false; if (!ptr) return false;
TracyCPlotI(ptr, value); TracyCPlotI(ptr, value);
return true; return true;

View File

@ -1,59 +0,0 @@
#pragma once
#include <mutex>
#include <optional>
#include <string>
#include <vector>
#ifndef BUFFER_SIZE
#define BUFFER_SIZE = 128
#endif
#ifndef NAME_LENGTH
#define NAME_LENGTH = 128
#endif
using OptionalNumber = std::optional<std::size_t>;
using BufferEntry = std::pair<OptionalNumber, const char*>;
class NameBuffer {
public:
static inline BufferEntry Add(const std::string& name) {
return getBuffer().add(name);
}
static inline const char* Get(std::size_t index) {
return getBuffer().get(index);
}
private:
NameBuffer() : m_buffer(BUFFER_SIZE, nullptr), m_index(0ul) {
for (std::size_t index = 0ul, end = m_buffer.size(); index < end; ++index)
m_buffer[index] = new char[NAME_LENGTH];
}
std::mutex m_mutex;
std::vector<char*> m_buffer;
std::size_t m_index;
static inline NameBuffer& getBuffer() {
static NameBuffer buffer;
return buffer;
}
BufferEntry add(const std::string& name) {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_index >= BUFFER_SIZE || name.size() > NAME_LENGTH)
return std::make_pair(std::nullopt, nullptr);
auto index = m_index++;
name.copy(m_buffer[index], name.size());
return std::make_pair(index, m_buffer[index]);
}
const char* get(std::size_t index) {
std::lock_guard<std::mutex> lock(m_mutex);
if (index >= BUFFER_SIZE) return nullptr;
return m_buffer[index];
}
};