Added basic Python Support

Supported:
 - FrameMarks
 - ScopedZones
 - Memory allocations
 - Plots
 - ThreadNames
 - Messages
 - AppConfig

Not supported:
 - GPU
This commit is contained in:
Arnim Balzer 2024-03-17 10:51:38 +00:00
parent ac031e64d6
commit d65d96191a
No known key found for this signature in database
GPG Key ID: 785EF903F0917AB7
15 changed files with 5091 additions and 0 deletions

View File

@ -167,3 +167,13 @@ configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
option(TRACY_CLIENT_PYTHON "Whether to build Tracy python client library" OFF)
if(TRACY_CLIENT_PYTHON)
if(TRACY_STATIC)
message(FATAL_ERROR "Python-bindings require a shared client library")
endif()
add_subdirectory(python)
endif()

View File

@ -2181,6 +2181,129 @@ Since you are directly calling the profiler functions here, you will need to tak
disabling the code if the \texttt{TRACY\_ENABLE} macro is not defined.
\end{bclogo}
\subsection{Python API}
\label{pythonapi}
To profile Python code using Tracy, a Python package can be built. This is done using the excellent C++11 based Python bindings generator pybind11, see \url{https://pybind11.readthedocs.io}.
As a first step, a Tracy-Client shared library needs to be built (with the compile definitions you want to use) and then pybind11 is used to create the Python-bindings.
Afterwards, a Python c-extension package can be created (the package will be platform and Python version dependent).
An especially powerful feature is the ability to profile Python code and any other C/C++ code used in a single code base as long as the C/C++ code links to the same shared Tracy-Client library that is installed with the Python package.
\subsubsection{Bindings}
An example of how to use the Tracy-Client bindings is shown below:
\begin{lstlisting}
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from time import sleep
import numpy as np
import tracy_client as tracy
@tracy.ScopedFrameDecorator("framed")
@tracy.ScopedZoneDecorator(name="work", color=tracy.ColorType.Red4)
def work():
sleep(0.05)
def main():
assert tracy.program_name("MyApp")
assert tracy.app_info("this is a python app")
tracy.thread_name("python") # main thread so bit useless
plot_id = tracy.plot_config("plot", tracy.PlotFormatType.Number)
assert plot_id is not None
mem_id = None
index = 0
while True:
with tracy.ScopedZone(name="test", color=tracy.ColorType.Coral) as zone:
index += 1
tracy.frame_mark()
inner = tracy.ScopedZone(depth=5, color=tracy.ColorType.Coral)
inner.color(index % 5)
inner.name(str(index))
inner.enter()
if index % 2:
tracy.alloc(44, index)
else:
tracy.free(44)
if not index % 2:
if mem_id is None:
mem_id = tracy.alloc(1337000000, index, name="named", depth=4)
assert mem_id is not None
else:
tracy.alloc(1337000000, index, id=mem_id, depth=4)
else:
tracy.free(1337000000, mem_id, 4)
with tracy.ScopedFrame("custom"):
image = np.full([400, 400, 4], index, dtype=np.uint8)
assert tracy.frame_image(image.tobytes(), 400, 400)
inner.exit()
zone.text(index)
assert tracy.message(f"we are at index {index}")
assert tracy.message(f"we are at index {index}", tracy.ColorType.Coral)
assert tracy.plot(plot_id, index)
work()
sleep(0.1)
if __name__ == "__main__":
main()
\end{lstlisting}
Please not the use of ids as way to cope with the need for unique pointers for certain features of the Tracy profiler, see section~\ref{uniquepointers}.
\subsubsection{Building the Python package}
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 following two variables are available in addition:
\begin{itemize}
\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{NAME_LENGTH} --- The maximum length (defaults to 128) of a name stored in the global pointer buffer.
\end{itemize}
Be aware that the memory allocated by this buffer is global and is not freed, see section ~\ref{uniquepointers}.
See below for example steps to build the Python bindings using CMake:
\begin{lstlisting}
mkdir build
cd build
cmake -DTRACY_STATIC=OFF -DTRACY_CLIENT_PYTHON=ON ../
\end{lstlisting}
Once this has finished building the Python package can be built as follows:
\begin{lstlisting}
cd ../python
python3 setup.py bdist_wheel
\end{lstlisting}
The created package will be in the folder \texttt{python/dist}.
\subsection{Automated data collection}
\label{automated}

8
python/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
*.dylib
*.so.*
build
dist
tracy_client.egg-info
client
common
tracy

50
python/CMakeLists.txt Normal file
View File

@ -0,0 +1,50 @@
find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED)
include(FetchContent)
FetchContent_Declare(pybind11 GIT_REPOSITORY "https://github.com/pybind/pybind11.git" GIT_TAG "v2.11.1" GIT_SHALLOW ON TEST_BEFORE_INSTALL ON)
FetchContent_MakeAvailable(pybind11)
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)
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_LIB_SYMLINK $<TARGET_FILE_PREFIX:TracyClient>$<TARGET_FILE_BASE_NAME:TracyClient>$<TARGET_FILE_SUFFIX:TracyClient>)
add_custom_command(TARGET TracyClient TracyClientBindings POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${TRACY_PYTHON_DIR}/client
COMMAND ${CMAKE_COMMAND} -E copy ${client_includes} ${TRACY_PYTHON_DIR}/client
COMMAND ${CMAKE_COMMAND} -DFOLDER=${TRACY_PYTHON_DIR}/client -P ${CMAKE_CURRENT_SOURCE_DIR}/HeaderFixer.txt
COMMAND ${CMAKE_COMMAND} -E make_directory ${TRACY_PYTHON_DIR}/common
COMMAND ${CMAKE_COMMAND} -E copy ${common_includes} ${TRACY_PYTHON_DIR}/common
COMMAND ${CMAKE_COMMAND} -DFOLDER=${TRACY_PYTHON_DIR}/common -P ${CMAKE_CURRENT_SOURCE_DIR}/HeaderFixer.txt
COMMAND ${CMAKE_COMMAND} -E make_directory ${TRACY_PYTHON_DIR}/tracy
COMMAND ${CMAKE_COMMAND} -E copy ${tracy_includes} ${TRACY_PYTHON_DIR}/tracy
COMMAND ${CMAKE_COMMAND} -DFOLDER=${TRACY_PYTHON_DIR}/tracy -P ${CMAKE_CURRENT_SOURCE_DIR}/HeaderFixer.txt
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:TracyClientBindings> ${TRACY_PYTHON_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:TracyClient> ${TRACY_PYTHON_DIR}/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../${TRACY_LIB_SYMLINK} ${TRACY_PYTHON_DIR}/
BYPRODUCTS ${TRACY_PYTHON_DIR}/client ${TRACY_PYTHON_DIR}/common ${TRACY_PYTHON_DIR}/tracy
)
set(TRACY_CLIENT_PYTHON_TARGET "" CACHE STRING "Optional directory to copy python files to")
if(NOT TRACY_CLIENT_PYTHON_TARGET STREQUAL "")
file(GLOB_RECURSE TRACY_CLIENT_PYTHON_FILES ${TRACY_PYTHON_DIR}/*.py*)
add_custom_command(TARGET TracyClientBindings POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${TRACY_CLIENT_PYTHON_TARGET}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:TracyClientBindings> ${TRACY_CLIENT_PYTHON_TARGET}/
COMMAND ${CMAKE_COMMAND} -E copy ${TRACY_CLIENT_PYTHON_FILES} ${TRACY_CLIENT_PYTHON_TARGET}/
BYPRODUCTS ${TRACY_CLIENT_PYTHON_TARGET}
)
endif()

16
python/HeaderFixer.txt Normal file
View File

@ -0,0 +1,16 @@
function(fix_header FILE)
file(READ ${FILE} FILE_CONTENT)
string(REPLACE "../client" "client" FILE_CONTENT "${FILE_CONTENT}")
string(REPLACE "../common" "common" FILE_CONTENT "${FILE_CONTENT}")
string(REPLACE "../tracy" "tracy" FILE_CONTENT "${FILE_CONTENT}")
file(WRITE ${FILE} "${FILE_CONTENT}")
endfunction()
function(fix_headers FOLDER)
file(GLOB FILES "${FOLDER}/*.h*")
foreach(FILE ${FILES})
fix_header(${FILE})
endforeach()
endfunction()
fix_headers(${FOLDER})

View File

@ -0,0 +1,90 @@
#pragma once
#include <pybind11/pybind11.h>
namespace py = pybind11;
#include "NameBuffer.hpp"
#include "tracy/Tracy.hpp"
using OptionalString = std::optional<std::string>;
using OptionalInt = std::optional<int>;
template <typename Type = uint64_t>
OptionalNumber MemoryAllocate(const Type &type, std::size_t size,
const OptionalString &name = std::nullopt,
const OptionalNumber &id = std::nullopt,
OptionalInt depth = std::nullopt) {
#ifdef TRACY_ENABLE
if (!name && !id) {
if (!depth)
TracyAlloc(reinterpret_cast<void *>(type), size);
else
TracyAllocS(reinterpret_cast<void *>(type), size, *depth);
return std::nullopt;
}
BufferEntry entry;
if (id) {
entry.second = NameBuffer::Get(*id);
if (!entry.second) return std::nullopt;
} else {
entry = NameBuffer::Add(*name);
if (!entry.first) return std::nullopt;
}
if (!depth)
TracyAllocN(reinterpret_cast<void *>(type), size, entry.second);
else
TracyAllocNS(reinterpret_cast<void *>(type), size, *depth, entry.second);
return entry.first;
#else
static_cast<void>(type); // unused
static_cast<void>(size); // unused
static_cast<void>(name); // unused
static_cast<void>(id); // unused
static_cast<void>(depth); // unused
#endif
}
template <>
OptionalNumber MemoryAllocate(const py::object &object, std::size_t size,
const OptionalString &name,
const OptionalNumber &id, OptionalInt depth) {
return MemoryAllocate<uint64_t>(reinterpret_cast<uint64_t>(object.ptr()),
size, name, id, depth);
}
template <typename Type = uint64_t>
bool MemoryFree(const Type &type, const OptionalNumber &id = std::nullopt,
OptionalInt depth = std::nullopt) {
#ifdef TRACY_ENABLE
if (!id) {
if (!depth)
TracyFree(reinterpret_cast<void *>(type));
else
TracyFreeS(reinterpret_cast<void *>(type), *depth);
return true;
}
auto ptr = NameBuffer::Get(*id);
if (!ptr) return false;
if (!depth)
TracyFreeN(reinterpret_cast<void *>(type), ptr);
else
TracyFreeNS(reinterpret_cast<void *>(type), *depth, ptr);
return true;
#else
static_cast<void>(type); // unused
static_cast<void>(id); // unused
static_cast<void>(depth); // unused
#endif
}
template <>
bool MemoryFree(const py::object &object, const OptionalNumber &id,
OptionalInt depth) {
return MemoryFree<uint64_t>(reinterpret_cast<uint64_t>(object.ptr()), id,
depth);
}

872
python/bindings/Module.cpp Normal file
View File

@ -0,0 +1,872 @@
#include "Memory.hpp"
#include "ScopedZone.hpp"
#include "tracy/TracyC.h"
namespace tracy {
#ifndef TRACY_ENABLE
enum class PlotFormatType : uint8_t { Number, Memory, Percentage };
#endif
constexpr static inline bool IsEnabled() {
#ifdef TRACY_ENABLE
return true;
#else
return false;
#endif
}
} // namespace tracy
PYBIND11_MODULE(TracyClientBindings, m) {
m.doc() = "Tracy Client Bindings";
m.def("is_enabled", &tracy::IsEnabled);
py::enum_<tracy::Color::ColorType>(m, "ColorType")
.value("Snow", tracy::Color::Snow)
.value("GhostWhite", tracy::Color::GhostWhite)
.value("WhiteSmoke", tracy::Color::WhiteSmoke)
.value("Gainsboro", tracy::Color::Gainsboro)
.value("FloralWhite", tracy::Color::FloralWhite)
.value("OldLace", tracy::Color::OldLace)
.value("Linen", tracy::Color::Linen)
.value("AntiqueWhite", tracy::Color::AntiqueWhite)
.value("PapayaWhip", tracy::Color::PapayaWhip)
.value("BlanchedAlmond", tracy::Color::BlanchedAlmond)
.value("Bisque", tracy::Color::Bisque)
.value("PeachPuff", tracy::Color::PeachPuff)
.value("NavajoWhite", tracy::Color::NavajoWhite)
.value("Moccasin", tracy::Color::Moccasin)
.value("Cornsilk", tracy::Color::Cornsilk)
.value("Ivory", tracy::Color::Ivory)
.value("LemonChiffon", tracy::Color::LemonChiffon)
.value("Seashell", tracy::Color::Seashell)
.value("Honeydew", tracy::Color::Honeydew)
.value("MintCream", tracy::Color::MintCream)
.value("Azure", tracy::Color::Azure)
.value("AliceBlue", tracy::Color::AliceBlue)
.value("Lavender", tracy::Color::Lavender)
.value("LavenderBlush", tracy::Color::LavenderBlush)
.value("MistyRose", tracy::Color::MistyRose)
.value("White", tracy::Color::White)
.value("Black", tracy::Color::Black)
.value("DarkSlateGray", tracy::Color::DarkSlateGray)
.value("DarkSlateGrey", tracy::Color::DarkSlateGrey)
.value("DimGray", tracy::Color::DimGray)
.value("DimGrey", tracy::Color::DimGrey)
.value("SlateGray", tracy::Color::SlateGray)
.value("SlateGrey", tracy::Color::SlateGrey)
.value("LightSlateGray", tracy::Color::LightSlateGray)
.value("LightSlateGrey", tracy::Color::LightSlateGrey)
.value("Gray", tracy::Color::Gray)
.value("Grey", tracy::Color::Grey)
.value("X11Gray", tracy::Color::X11Gray)
.value("X11Grey", tracy::Color::X11Grey)
.value("WebGray", tracy::Color::WebGray)
.value("WebGrey", tracy::Color::WebGrey)
.value("LightGrey", tracy::Color::LightGrey)
.value("LightGray", tracy::Color::LightGray)
.value("MidnightBlue", tracy::Color::MidnightBlue)
.value("Navy", tracy::Color::Navy)
.value("NavyBlue", tracy::Color::NavyBlue)
.value("CornflowerBlue", tracy::Color::CornflowerBlue)
.value("DarkSlateBlue", tracy::Color::DarkSlateBlue)
.value("SlateBlue", tracy::Color::SlateBlue)
.value("MediumSlateBlue", tracy::Color::MediumSlateBlue)
.value("LightSlateBlue", tracy::Color::LightSlateBlue)
.value("MediumBlue", tracy::Color::MediumBlue)
.value("RoyalBlue", tracy::Color::RoyalBlue)
.value("Blue", tracy::Color::Blue)
.value("DodgerBlue", tracy::Color::DodgerBlue)
.value("DeepSkyBlue", tracy::Color::DeepSkyBlue)
.value("SkyBlue", tracy::Color::SkyBlue)
.value("LightSkyBlue", tracy::Color::LightSkyBlue)
.value("SteelBlue", tracy::Color::SteelBlue)
.value("LightSteelBlue", tracy::Color::LightSteelBlue)
.value("LightBlue", tracy::Color::LightBlue)
.value("PowderBlue", tracy::Color::PowderBlue)
.value("PaleTurquoise", tracy::Color::PaleTurquoise)
.value("DarkTurquoise", tracy::Color::DarkTurquoise)
.value("MediumTurquoise", tracy::Color::MediumTurquoise)
.value("Turquoise", tracy::Color::Turquoise)
.value("Cyan", tracy::Color::Cyan)
.value("Aqua", tracy::Color::Aqua)
.value("LightCyan", tracy::Color::LightCyan)
.value("CadetBlue", tracy::Color::CadetBlue)
.value("MediumAquamarine", tracy::Color::MediumAquamarine)
.value("Aquamarine", tracy::Color::Aquamarine)
.value("DarkGreen", tracy::Color::DarkGreen)
.value("DarkOliveGreen", tracy::Color::DarkOliveGreen)
.value("DarkSeaGreen", tracy::Color::DarkSeaGreen)
.value("SeaGreen", tracy::Color::SeaGreen)
.value("MediumSeaGreen", tracy::Color::MediumSeaGreen)
.value("LightSeaGreen", tracy::Color::LightSeaGreen)
.value("PaleGreen", tracy::Color::PaleGreen)
.value("SpringGreen", tracy::Color::SpringGreen)
.value("LawnGreen", tracy::Color::LawnGreen)
.value("Green", tracy::Color::Green)
.value("Lime", tracy::Color::Lime)
.value("X11Green", tracy::Color::X11Green)
.value("WebGreen", tracy::Color::WebGreen)
.value("Chartreuse", tracy::Color::Chartreuse)
.value("MediumSpringGreen", tracy::Color::MediumSpringGreen)
.value("GreenYellow", tracy::Color::GreenYellow)
.value("LimeGreen", tracy::Color::LimeGreen)
.value("YellowGreen", tracy::Color::YellowGreen)
.value("ForestGreen", tracy::Color::ForestGreen)
.value("OliveDrab", tracy::Color::OliveDrab)
.value("DarkKhaki", tracy::Color::DarkKhaki)
.value("Khaki", tracy::Color::Khaki)
.value("PaleGoldenrod", tracy::Color::PaleGoldenrod)
.value("LightGoldenrodYellow", tracy::Color::LightGoldenrodYellow)
.value("LightYellow", tracy::Color::LightYellow)
.value("Yellow", tracy::Color::Yellow)
.value("Gold", tracy::Color::Gold)
.value("LightGoldenrod", tracy::Color::LightGoldenrod)
.value("Goldenrod", tracy::Color::Goldenrod)
.value("DarkGoldenrod", tracy::Color::DarkGoldenrod)
.value("RosyBrown", tracy::Color::RosyBrown)
.value("IndianRed", tracy::Color::IndianRed)
.value("SaddleBrown", tracy::Color::SaddleBrown)
.value("Sienna", tracy::Color::Sienna)
.value("Peru", tracy::Color::Peru)
.value("Burlywood", tracy::Color::Burlywood)
.value("Beige", tracy::Color::Beige)
.value("Wheat", tracy::Color::Wheat)
.value("SandyBrown", tracy::Color::SandyBrown)
.value("Tan", tracy::Color::Tan)
.value("Chocolate", tracy::Color::Chocolate)
.value("Firebrick", tracy::Color::Firebrick)
.value("Brown", tracy::Color::Brown)
.value("DarkSalmon", tracy::Color::DarkSalmon)
.value("Salmon", tracy::Color::Salmon)
.value("LightSalmon", tracy::Color::LightSalmon)
.value("Orange", tracy::Color::Orange)
.value("DarkOrange", tracy::Color::DarkOrange)
.value("Coral", tracy::Color::Coral)
.value("LightCoral", tracy::Color::LightCoral)
.value("Tomato", tracy::Color::Tomato)
.value("OrangeRed", tracy::Color::OrangeRed)
.value("Red", tracy::Color::Red)
.value("HotPink", tracy::Color::HotPink)
.value("DeepPink", tracy::Color::DeepPink)
.value("Pink", tracy::Color::Pink)
.value("LightPink", tracy::Color::LightPink)
.value("PaleVioletRed", tracy::Color::PaleVioletRed)
.value("Maroon", tracy::Color::Maroon)
.value("X11Maroon", tracy::Color::X11Maroon)
.value("WebMaroon", tracy::Color::WebMaroon)
.value("MediumVioletRed", tracy::Color::MediumVioletRed)
.value("VioletRed", tracy::Color::VioletRed)
.value("Magenta", tracy::Color::Magenta)
.value("Fuchsia", tracy::Color::Fuchsia)
.value("Violet", tracy::Color::Violet)
.value("Plum", tracy::Color::Plum)
.value("Orchid", tracy::Color::Orchid)
.value("MediumOrchid", tracy::Color::MediumOrchid)
.value("DarkOrchid", tracy::Color::DarkOrchid)
.value("DarkViolet", tracy::Color::DarkViolet)
.value("BlueViolet", tracy::Color::BlueViolet)
.value("Purple", tracy::Color::Purple)
.value("X11Purple", tracy::Color::X11Purple)
.value("WebPurple", tracy::Color::WebPurple)
.value("MediumPurple", tracy::Color::MediumPurple)
.value("Thistle", tracy::Color::Thistle)
.value("Snow1", tracy::Color::Snow1)
.value("Snow2", tracy::Color::Snow2)
.value("Snow3", tracy::Color::Snow3)
.value("Snow4", tracy::Color::Snow4)
.value("Seashell1", tracy::Color::Seashell1)
.value("Seashell2", tracy::Color::Seashell2)
.value("Seashell3", tracy::Color::Seashell3)
.value("Seashell4", tracy::Color::Seashell4)
.value("AntiqueWhite1", tracy::Color::AntiqueWhite1)
.value("AntiqueWhite2", tracy::Color::AntiqueWhite2)
.value("AntiqueWhite3", tracy::Color::AntiqueWhite3)
.value("AntiqueWhite4", tracy::Color::AntiqueWhite4)
.value("Bisque1", tracy::Color::Bisque1)
.value("Bisque2", tracy::Color::Bisque2)
.value("Bisque3", tracy::Color::Bisque3)
.value("Bisque4", tracy::Color::Bisque4)
.value("PeachPuff1", tracy::Color::PeachPuff1)
.value("PeachPuff2", tracy::Color::PeachPuff2)
.value("PeachPuff3", tracy::Color::PeachPuff3)
.value("PeachPuff4", tracy::Color::PeachPuff4)
.value("NavajoWhite1", tracy::Color::NavajoWhite1)
.value("NavajoWhite2", tracy::Color::NavajoWhite2)
.value("NavajoWhite3", tracy::Color::NavajoWhite3)
.value("NavajoWhite4", tracy::Color::NavajoWhite4)
.value("LemonChiffon1", tracy::Color::LemonChiffon1)
.value("LemonChiffon2", tracy::Color::LemonChiffon2)
.value("LemonChiffon3", tracy::Color::LemonChiffon3)
.value("LemonChiffon4", tracy::Color::LemonChiffon4)
.value("Cornsilk1", tracy::Color::Cornsilk1)
.value("Cornsilk2", tracy::Color::Cornsilk2)
.value("Cornsilk3", tracy::Color::Cornsilk3)
.value("Cornsilk4", tracy::Color::Cornsilk4)
.value("Ivory1", tracy::Color::Ivory1)
.value("Ivory2", tracy::Color::Ivory2)
.value("Ivory3", tracy::Color::Ivory3)
.value("Ivory4", tracy::Color::Ivory4)
.value("Honeydew1", tracy::Color::Honeydew1)
.value("Honeydew2", tracy::Color::Honeydew2)
.value("Honeydew3", tracy::Color::Honeydew3)
.value("Honeydew4", tracy::Color::Honeydew4)
.value("LavenderBlush1", tracy::Color::LavenderBlush1)
.value("LavenderBlush2", tracy::Color::LavenderBlush2)
.value("LavenderBlush3", tracy::Color::LavenderBlush3)
.value("LavenderBlush4", tracy::Color::LavenderBlush4)
.value("MistyRose1", tracy::Color::MistyRose1)
.value("MistyRose2", tracy::Color::MistyRose2)
.value("MistyRose3", tracy::Color::MistyRose3)
.value("MistyRose4", tracy::Color::MistyRose4)
.value("Azure1", tracy::Color::Azure1)
.value("Azure2", tracy::Color::Azure2)
.value("Azure3", tracy::Color::Azure3)
.value("Azure4", tracy::Color::Azure4)
.value("SlateBlue1", tracy::Color::SlateBlue1)
.value("SlateBlue2", tracy::Color::SlateBlue2)
.value("SlateBlue3", tracy::Color::SlateBlue3)
.value("SlateBlue4", tracy::Color::SlateBlue4)
.value("RoyalBlue1", tracy::Color::RoyalBlue1)
.value("RoyalBlue2", tracy::Color::RoyalBlue2)
.value("RoyalBlue3", tracy::Color::RoyalBlue3)
.value("RoyalBlue4", tracy::Color::RoyalBlue4)
.value("Blue1", tracy::Color::Blue1)
.value("Blue2", tracy::Color::Blue2)
.value("Blue3", tracy::Color::Blue3)
.value("Blue4", tracy::Color::Blue4)
.value("DodgerBlue1", tracy::Color::DodgerBlue1)
.value("DodgerBlue2", tracy::Color::DodgerBlue2)
.value("DodgerBlue3", tracy::Color::DodgerBlue3)
.value("DodgerBlue4", tracy::Color::DodgerBlue4)
.value("SteelBlue1", tracy::Color::SteelBlue1)
.value("SteelBlue2", tracy::Color::SteelBlue2)
.value("SteelBlue3", tracy::Color::SteelBlue3)
.value("SteelBlue4", tracy::Color::SteelBlue4)
.value("DeepSkyBlue1", tracy::Color::DeepSkyBlue1)
.value("DeepSkyBlue2", tracy::Color::DeepSkyBlue2)
.value("DeepSkyBlue3", tracy::Color::DeepSkyBlue3)
.value("DeepSkyBlue4", tracy::Color::DeepSkyBlue4)
.value("SkyBlue1", tracy::Color::SkyBlue1)
.value("SkyBlue2", tracy::Color::SkyBlue2)
.value("SkyBlue3", tracy::Color::SkyBlue3)
.value("SkyBlue4", tracy::Color::SkyBlue4)
.value("LightSkyBlue1", tracy::Color::LightSkyBlue1)
.value("LightSkyBlue2", tracy::Color::LightSkyBlue2)
.value("LightSkyBlue3", tracy::Color::LightSkyBlue3)
.value("LightSkyBlue4", tracy::Color::LightSkyBlue4)
.value("SlateGray1", tracy::Color::SlateGray1)
.value("SlateGray2", tracy::Color::SlateGray2)
.value("SlateGray3", tracy::Color::SlateGray3)
.value("SlateGray4", tracy::Color::SlateGray4)
.value("LightSteelBlue1", tracy::Color::LightSteelBlue1)
.value("LightSteelBlue2", tracy::Color::LightSteelBlue2)
.value("LightSteelBlue3", tracy::Color::LightSteelBlue3)
.value("LightSteelBlue4", tracy::Color::LightSteelBlue4)
.value("LightBlue1", tracy::Color::LightBlue1)
.value("LightBlue2", tracy::Color::LightBlue2)
.value("LightBlue3", tracy::Color::LightBlue3)
.value("LightBlue4", tracy::Color::LightBlue4)
.value("LightCyan1", tracy::Color::LightCyan1)
.value("LightCyan2", tracy::Color::LightCyan2)
.value("LightCyan3", tracy::Color::LightCyan3)
.value("LightCyan4", tracy::Color::LightCyan4)
.value("PaleTurquoise1", tracy::Color::PaleTurquoise1)
.value("PaleTurquoise2", tracy::Color::PaleTurquoise2)
.value("PaleTurquoise3", tracy::Color::PaleTurquoise3)
.value("PaleTurquoise4", tracy::Color::PaleTurquoise4)
.value("CadetBlue1", tracy::Color::CadetBlue1)
.value("CadetBlue2", tracy::Color::CadetBlue2)
.value("CadetBlue3", tracy::Color::CadetBlue3)
.value("CadetBlue4", tracy::Color::CadetBlue4)
.value("Turquoise1", tracy::Color::Turquoise1)
.value("Turquoise2", tracy::Color::Turquoise2)
.value("Turquoise3", tracy::Color::Turquoise3)
.value("Turquoise4", tracy::Color::Turquoise4)
.value("Cyan1", tracy::Color::Cyan1)
.value("Cyan2", tracy::Color::Cyan2)
.value("Cyan3", tracy::Color::Cyan3)
.value("Cyan4", tracy::Color::Cyan4)
.value("DarkSlateGray1", tracy::Color::DarkSlateGray1)
.value("DarkSlateGray2", tracy::Color::DarkSlateGray2)
.value("DarkSlateGray3", tracy::Color::DarkSlateGray3)
.value("DarkSlateGray4", tracy::Color::DarkSlateGray4)
.value("Aquamarine1", tracy::Color::Aquamarine1)
.value("Aquamarine2", tracy::Color::Aquamarine2)
.value("Aquamarine3", tracy::Color::Aquamarine3)
.value("Aquamarine4", tracy::Color::Aquamarine4)
.value("DarkSeaGreen1", tracy::Color::DarkSeaGreen1)
.value("DarkSeaGreen2", tracy::Color::DarkSeaGreen2)
.value("DarkSeaGreen3", tracy::Color::DarkSeaGreen3)
.value("DarkSeaGreen4", tracy::Color::DarkSeaGreen4)
.value("SeaGreen1", tracy::Color::SeaGreen1)
.value("SeaGreen2", tracy::Color::SeaGreen2)
.value("SeaGreen3", tracy::Color::SeaGreen3)
.value("SeaGreen4", tracy::Color::SeaGreen4)
.value("PaleGreen1", tracy::Color::PaleGreen1)
.value("PaleGreen2", tracy::Color::PaleGreen2)
.value("PaleGreen3", tracy::Color::PaleGreen3)
.value("PaleGreen4", tracy::Color::PaleGreen4)
.value("SpringGreen1", tracy::Color::SpringGreen1)
.value("SpringGreen2", tracy::Color::SpringGreen2)
.value("SpringGreen3", tracy::Color::SpringGreen3)
.value("SpringGreen4", tracy::Color::SpringGreen4)
.value("Green1", tracy::Color::Green1)
.value("Green2", tracy::Color::Green2)
.value("Green3", tracy::Color::Green3)
.value("Green4", tracy::Color::Green4)
.value("Chartreuse1", tracy::Color::Chartreuse1)
.value("Chartreuse2", tracy::Color::Chartreuse2)
.value("Chartreuse3", tracy::Color::Chartreuse3)
.value("Chartreuse4", tracy::Color::Chartreuse4)
.value("OliveDrab1", tracy::Color::OliveDrab1)
.value("OliveDrab2", tracy::Color::OliveDrab2)
.value("OliveDrab3", tracy::Color::OliveDrab3)
.value("OliveDrab4", tracy::Color::OliveDrab4)
.value("DarkOliveGreen1", tracy::Color::DarkOliveGreen1)
.value("DarkOliveGreen2", tracy::Color::DarkOliveGreen2)
.value("DarkOliveGreen3", tracy::Color::DarkOliveGreen3)
.value("DarkOliveGreen4", tracy::Color::DarkOliveGreen4)
.value("Khaki1", tracy::Color::Khaki1)
.value("Khaki2", tracy::Color::Khaki2)
.value("Khaki3", tracy::Color::Khaki3)
.value("Khaki4", tracy::Color::Khaki4)
.value("LightGoldenrod1", tracy::Color::LightGoldenrod1)
.value("LightGoldenrod2", tracy::Color::LightGoldenrod2)
.value("LightGoldenrod3", tracy::Color::LightGoldenrod3)
.value("LightGoldenrod4", tracy::Color::LightGoldenrod4)
.value("LightYellow1", tracy::Color::LightYellow1)
.value("LightYellow2", tracy::Color::LightYellow2)
.value("LightYellow3", tracy::Color::LightYellow3)
.value("LightYellow4", tracy::Color::LightYellow4)
.value("Yellow1", tracy::Color::Yellow1)
.value("Yellow2", tracy::Color::Yellow2)
.value("Yellow3", tracy::Color::Yellow3)
.value("Yellow4", tracy::Color::Yellow4)
.value("Gold1", tracy::Color::Gold1)
.value("Gold2", tracy::Color::Gold2)
.value("Gold3", tracy::Color::Gold3)
.value("Gold4", tracy::Color::Gold4)
.value("Goldenrod1", tracy::Color::Goldenrod1)
.value("Goldenrod2", tracy::Color::Goldenrod2)
.value("Goldenrod3", tracy::Color::Goldenrod3)
.value("Goldenrod4", tracy::Color::Goldenrod4)
.value("DarkGoldenrod1", tracy::Color::DarkGoldenrod1)
.value("DarkGoldenrod2", tracy::Color::DarkGoldenrod2)
.value("DarkGoldenrod3", tracy::Color::DarkGoldenrod3)
.value("DarkGoldenrod4", tracy::Color::DarkGoldenrod4)
.value("RosyBrown1", tracy::Color::RosyBrown1)
.value("RosyBrown2", tracy::Color::RosyBrown2)
.value("RosyBrown3", tracy::Color::RosyBrown3)
.value("RosyBrown4", tracy::Color::RosyBrown4)
.value("IndianRed1", tracy::Color::IndianRed1)
.value("IndianRed2", tracy::Color::IndianRed2)
.value("IndianRed3", tracy::Color::IndianRed3)
.value("IndianRed4", tracy::Color::IndianRed4)
.value("Sienna1", tracy::Color::Sienna1)
.value("Sienna2", tracy::Color::Sienna2)
.value("Sienna3", tracy::Color::Sienna3)
.value("Sienna4", tracy::Color::Sienna4)
.value("Burlywood1", tracy::Color::Burlywood1)
.value("Burlywood2", tracy::Color::Burlywood2)
.value("Burlywood3", tracy::Color::Burlywood3)
.value("Burlywood4", tracy::Color::Burlywood4)
.value("Wheat1", tracy::Color::Wheat1)
.value("Wheat2", tracy::Color::Wheat2)
.value("Wheat3", tracy::Color::Wheat3)
.value("Wheat4", tracy::Color::Wheat4)
.value("Tan1", tracy::Color::Tan1)
.value("Tan2", tracy::Color::Tan2)
.value("Tan3", tracy::Color::Tan3)
.value("Tan4", tracy::Color::Tan4)
.value("Chocolate1", tracy::Color::Chocolate1)
.value("Chocolate2", tracy::Color::Chocolate2)
.value("Chocolate3", tracy::Color::Chocolate3)
.value("Chocolate4", tracy::Color::Chocolate4)
.value("Firebrick1", tracy::Color::Firebrick1)
.value("Firebrick2", tracy::Color::Firebrick2)
.value("Firebrick3", tracy::Color::Firebrick3)
.value("Firebrick4", tracy::Color::Firebrick4)
.value("Brown1", tracy::Color::Brown1)
.value("Brown2", tracy::Color::Brown2)
.value("Brown3", tracy::Color::Brown3)
.value("Brown4", tracy::Color::Brown4)
.value("Salmon1", tracy::Color::Salmon1)
.value("Salmon2", tracy::Color::Salmon2)
.value("Salmon3", tracy::Color::Salmon3)
.value("Salmon4", tracy::Color::Salmon4)
.value("LightSalmon1", tracy::Color::LightSalmon1)
.value("LightSalmon2", tracy::Color::LightSalmon2)
.value("LightSalmon3", tracy::Color::LightSalmon3)
.value("LightSalmon4", tracy::Color::LightSalmon4)
.value("Orange1", tracy::Color::Orange1)
.value("Orange2", tracy::Color::Orange2)
.value("Orange3", tracy::Color::Orange3)
.value("Orange4", tracy::Color::Orange4)
.value("DarkOrange1", tracy::Color::DarkOrange1)
.value("DarkOrange2", tracy::Color::DarkOrange2)
.value("DarkOrange3", tracy::Color::DarkOrange3)
.value("DarkOrange4", tracy::Color::DarkOrange4)
.value("Coral1", tracy::Color::Coral1)
.value("Coral2", tracy::Color::Coral2)
.value("Coral3", tracy::Color::Coral3)
.value("Coral4", tracy::Color::Coral4)
.value("Tomato1", tracy::Color::Tomato1)
.value("Tomato2", tracy::Color::Tomato2)
.value("Tomato3", tracy::Color::Tomato3)
.value("Tomato4", tracy::Color::Tomato4)
.value("OrangeRed1", tracy::Color::OrangeRed1)
.value("OrangeRed2", tracy::Color::OrangeRed2)
.value("OrangeRed3", tracy::Color::OrangeRed3)
.value("OrangeRed4", tracy::Color::OrangeRed4)
.value("Red1", tracy::Color::Red1)
.value("Red2", tracy::Color::Red2)
.value("Red3", tracy::Color::Red3)
.value("Red4", tracy::Color::Red4)
.value("DeepPink1", tracy::Color::DeepPink1)
.value("DeepPink2", tracy::Color::DeepPink2)
.value("DeepPink3", tracy::Color::DeepPink3)
.value("DeepPink4", tracy::Color::DeepPink4)
.value("HotPink1", tracy::Color::HotPink1)
.value("HotPink2", tracy::Color::HotPink2)
.value("HotPink3", tracy::Color::HotPink3)
.value("HotPink4", tracy::Color::HotPink4)
.value("Pink1", tracy::Color::Pink1)
.value("Pink2", tracy::Color::Pink2)
.value("Pink3", tracy::Color::Pink3)
.value("Pink4", tracy::Color::Pink4)
.value("LightPink1", tracy::Color::LightPink1)
.value("LightPink2", tracy::Color::LightPink2)
.value("LightPink3", tracy::Color::LightPink3)
.value("LightPink4", tracy::Color::LightPink4)
.value("PaleVioletRed1", tracy::Color::PaleVioletRed1)
.value("PaleVioletRed2", tracy::Color::PaleVioletRed2)
.value("PaleVioletRed3", tracy::Color::PaleVioletRed3)
.value("PaleVioletRed4", tracy::Color::PaleVioletRed4)
.value("Maroon1", tracy::Color::Maroon1)
.value("Maroon2", tracy::Color::Maroon2)
.value("Maroon3", tracy::Color::Maroon3)
.value("Maroon4", tracy::Color::Maroon4)
.value("VioletRed1", tracy::Color::VioletRed1)
.value("VioletRed2", tracy::Color::VioletRed2)
.value("VioletRed3", tracy::Color::VioletRed3)
.value("VioletRed4", tracy::Color::VioletRed4)
.value("Magenta1", tracy::Color::Magenta1)
.value("Magenta2", tracy::Color::Magenta2)
.value("Magenta3", tracy::Color::Magenta3)
.value("Magenta4", tracy::Color::Magenta4)
.value("Orchid1", tracy::Color::Orchid1)
.value("Orchid2", tracy::Color::Orchid2)
.value("Orchid3", tracy::Color::Orchid3)
.value("Orchid4", tracy::Color::Orchid4)
.value("Plum1", tracy::Color::Plum1)
.value("Plum2", tracy::Color::Plum2)
.value("Plum3", tracy::Color::Plum3)
.value("Plum4", tracy::Color::Plum4)
.value("MediumOrchid1", tracy::Color::MediumOrchid1)
.value("MediumOrchid2", tracy::Color::MediumOrchid2)
.value("MediumOrchid3", tracy::Color::MediumOrchid3)
.value("MediumOrchid4", tracy::Color::MediumOrchid4)
.value("DarkOrchid1", tracy::Color::DarkOrchid1)
.value("DarkOrchid2", tracy::Color::DarkOrchid2)
.value("DarkOrchid3", tracy::Color::DarkOrchid3)
.value("DarkOrchid4", tracy::Color::DarkOrchid4)
.value("Purple1", tracy::Color::Purple1)
.value("Purple2", tracy::Color::Purple2)
.value("Purple3", tracy::Color::Purple3)
.value("Purple4", tracy::Color::Purple4)
.value("MediumPurple1", tracy::Color::MediumPurple1)
.value("MediumPurple2", tracy::Color::MediumPurple2)
.value("MediumPurple3", tracy::Color::MediumPurple3)
.value("MediumPurple4", tracy::Color::MediumPurple4)
.value("Thistle1", tracy::Color::Thistle1)
.value("Thistle2", tracy::Color::Thistle2)
.value("Thistle3", tracy::Color::Thistle3)
.value("Thistle4", tracy::Color::Thistle4)
.value("Gray0", tracy::Color::Gray0)
.value("Grey0", tracy::Color::Grey0)
.value("Gray1", tracy::Color::Gray1)
.value("Grey1", tracy::Color::Grey1)
.value("Gray2", tracy::Color::Gray2)
.value("Grey2", tracy::Color::Grey2)
.value("Gray3", tracy::Color::Gray3)
.value("Grey3", tracy::Color::Grey3)
.value("Gray4", tracy::Color::Gray4)
.value("Grey4", tracy::Color::Grey4)
.value("Gray5", tracy::Color::Gray5)
.value("Grey5", tracy::Color::Grey5)
.value("Gray6", tracy::Color::Gray6)
.value("Grey6", tracy::Color::Grey6)
.value("Gray7", tracy::Color::Gray7)
.value("Grey7", tracy::Color::Grey7)
.value("Gray8", tracy::Color::Gray8)
.value("Grey8", tracy::Color::Grey8)
.value("Gray9", tracy::Color::Gray9)
.value("Grey9", tracy::Color::Grey9)
.value("Gray10", tracy::Color::Gray10)
.value("Grey10", tracy::Color::Grey10)
.value("Gray11", tracy::Color::Gray11)
.value("Grey11", tracy::Color::Grey11)
.value("Gray12", tracy::Color::Gray12)
.value("Grey12", tracy::Color::Grey12)
.value("Gray13", tracy::Color::Gray13)
.value("Grey13", tracy::Color::Grey13)
.value("Gray14", tracy::Color::Gray14)
.value("Grey14", tracy::Color::Grey14)
.value("Gray15", tracy::Color::Gray15)
.value("Grey15", tracy::Color::Grey15)
.value("Gray16", tracy::Color::Gray16)
.value("Grey16", tracy::Color::Grey16)
.value("Gray17", tracy::Color::Gray17)
.value("Grey17", tracy::Color::Grey17)
.value("Gray18", tracy::Color::Gray18)
.value("Grey18", tracy::Color::Grey18)
.value("Gray19", tracy::Color::Gray19)
.value("Grey19", tracy::Color::Grey19)
.value("Gray20", tracy::Color::Gray20)
.value("Grey20", tracy::Color::Grey20)
.value("Gray21", tracy::Color::Gray21)
.value("Grey21", tracy::Color::Grey21)
.value("Gray22", tracy::Color::Gray22)
.value("Grey22", tracy::Color::Grey22)
.value("Gray23", tracy::Color::Gray23)
.value("Grey23", tracy::Color::Grey23)
.value("Gray24", tracy::Color::Gray24)
.value("Grey24", tracy::Color::Grey24)
.value("Gray25", tracy::Color::Gray25)
.value("Grey25", tracy::Color::Grey25)
.value("Gray26", tracy::Color::Gray26)
.value("Grey26", tracy::Color::Grey26)
.value("Gray27", tracy::Color::Gray27)
.value("Grey27", tracy::Color::Grey27)
.value("Gray28", tracy::Color::Gray28)
.value("Grey28", tracy::Color::Grey28)
.value("Gray29", tracy::Color::Gray29)
.value("Grey29", tracy::Color::Grey29)
.value("Gray30", tracy::Color::Gray30)
.value("Grey30", tracy::Color::Grey30)
.value("Gray31", tracy::Color::Gray31)
.value("Grey31", tracy::Color::Grey31)
.value("Gray32", tracy::Color::Gray32)
.value("Grey32", tracy::Color::Grey32)
.value("Gray33", tracy::Color::Gray33)
.value("Grey33", tracy::Color::Grey33)
.value("Gray34", tracy::Color::Gray34)
.value("Grey34", tracy::Color::Grey34)
.value("Gray35", tracy::Color::Gray35)
.value("Grey35", tracy::Color::Grey35)
.value("Gray36", tracy::Color::Gray36)
.value("Grey36", tracy::Color::Grey36)
.value("Gray37", tracy::Color::Gray37)
.value("Grey37", tracy::Color::Grey37)
.value("Gray38", tracy::Color::Gray38)
.value("Grey38", tracy::Color::Grey38)
.value("Gray39", tracy::Color::Gray39)
.value("Grey39", tracy::Color::Grey39)
.value("Gray40", tracy::Color::Gray40)
.value("Grey40", tracy::Color::Grey40)
.value("Gray41", tracy::Color::Gray41)
.value("Grey41", tracy::Color::Grey41)
.value("Gray42", tracy::Color::Gray42)
.value("Grey42", tracy::Color::Grey42)
.value("Gray43", tracy::Color::Gray43)
.value("Grey43", tracy::Color::Grey43)
.value("Gray44", tracy::Color::Gray44)
.value("Grey44", tracy::Color::Grey44)
.value("Gray45", tracy::Color::Gray45)
.value("Grey45", tracy::Color::Grey45)
.value("Gray46", tracy::Color::Gray46)
.value("Grey46", tracy::Color::Grey46)
.value("Gray47", tracy::Color::Gray47)
.value("Grey47", tracy::Color::Grey47)
.value("Gray48", tracy::Color::Gray48)
.value("Grey48", tracy::Color::Grey48)
.value("Gray49", tracy::Color::Gray49)
.value("Grey49", tracy::Color::Grey49)
.value("Gray50", tracy::Color::Gray50)
.value("Grey50", tracy::Color::Grey50)
.value("Gray51", tracy::Color::Gray51)
.value("Grey51", tracy::Color::Grey51)
.value("Gray52", tracy::Color::Gray52)
.value("Grey52", tracy::Color::Grey52)
.value("Gray53", tracy::Color::Gray53)
.value("Grey53", tracy::Color::Grey53)
.value("Gray54", tracy::Color::Gray54)
.value("Grey54", tracy::Color::Grey54)
.value("Gray55", tracy::Color::Gray55)
.value("Grey55", tracy::Color::Grey55)
.value("Gray56", tracy::Color::Gray56)
.value("Grey56", tracy::Color::Grey56)
.value("Gray57", tracy::Color::Gray57)
.value("Grey57", tracy::Color::Grey57)
.value("Gray58", tracy::Color::Gray58)
.value("Grey58", tracy::Color::Grey58)
.value("Gray59", tracy::Color::Gray59)
.value("Grey59", tracy::Color::Grey59)
.value("Gray60", tracy::Color::Gray60)
.value("Grey60", tracy::Color::Grey60)
.value("Gray61", tracy::Color::Gray61)
.value("Grey61", tracy::Color::Grey61)
.value("Gray62", tracy::Color::Gray62)
.value("Grey62", tracy::Color::Grey62)
.value("Gray63", tracy::Color::Gray63)
.value("Grey63", tracy::Color::Grey63)
.value("Gray64", tracy::Color::Gray64)
.value("Grey64", tracy::Color::Grey64)
.value("Gray65", tracy::Color::Gray65)
.value("Grey65", tracy::Color::Grey65)
.value("Gray66", tracy::Color::Gray66)
.value("Grey66", tracy::Color::Grey66)
.value("Gray67", tracy::Color::Gray67)
.value("Grey67", tracy::Color::Grey67)
.value("Gray68", tracy::Color::Gray68)
.value("Grey68", tracy::Color::Grey68)
.value("Gray69", tracy::Color::Gray69)
.value("Grey69", tracy::Color::Grey69)
.value("Gray70", tracy::Color::Gray70)
.value("Grey70", tracy::Color::Grey70)
.value("Gray71", tracy::Color::Gray71)
.value("Grey71", tracy::Color::Grey71)
.value("Gray72", tracy::Color::Gray72)
.value("Grey72", tracy::Color::Grey72)
.value("Gray73", tracy::Color::Gray73)
.value("Grey73", tracy::Color::Grey73)
.value("Gray74", tracy::Color::Gray74)
.value("Grey74", tracy::Color::Grey74)
.value("Gray75", tracy::Color::Gray75)
.value("Grey75", tracy::Color::Grey75)
.value("Gray76", tracy::Color::Gray76)
.value("Grey76", tracy::Color::Grey76)
.value("Gray77", tracy::Color::Gray77)
.value("Grey77", tracy::Color::Grey77)
.value("Gray78", tracy::Color::Gray78)
.value("Grey78", tracy::Color::Grey78)
.value("Gray79", tracy::Color::Gray79)
.value("Grey79", tracy::Color::Grey79)
.value("Gray80", tracy::Color::Gray80)
.value("Grey80", tracy::Color::Grey80)
.value("Gray81", tracy::Color::Gray81)
.value("Grey81", tracy::Color::Grey81)
.value("Gray82", tracy::Color::Gray82)
.value("Grey82", tracy::Color::Grey82)
.value("Gray83", tracy::Color::Gray83)
.value("Grey83", tracy::Color::Grey83)
.value("Gray84", tracy::Color::Gray84)
.value("Grey84", tracy::Color::Grey84)
.value("Gray85", tracy::Color::Gray85)
.value("Grey85", tracy::Color::Grey85)
.value("Gray86", tracy::Color::Gray86)
.value("Grey86", tracy::Color::Grey86)
.value("Gray87", tracy::Color::Gray87)
.value("Grey87", tracy::Color::Grey87)
.value("Gray88", tracy::Color::Gray88)
.value("Grey88", tracy::Color::Grey88)
.value("Gray89", tracy::Color::Gray89)
.value("Grey89", tracy::Color::Grey89)
.value("Gray90", tracy::Color::Gray90)
.value("Grey90", tracy::Color::Grey90)
.value("Gray91", tracy::Color::Gray91)
.value("Grey91", tracy::Color::Grey91)
.value("Gray92", tracy::Color::Gray92)
.value("Grey92", tracy::Color::Grey92)
.value("Gray93", tracy::Color::Gray93)
.value("Grey93", tracy::Color::Grey93)
.value("Gray94", tracy::Color::Gray94)
.value("Grey94", tracy::Color::Grey94)
.value("Gray95", tracy::Color::Gray95)
.value("Grey95", tracy::Color::Grey95)
.value("Gray96", tracy::Color::Gray96)
.value("Grey96", tracy::Color::Grey96)
.value("Gray97", tracy::Color::Gray97)
.value("Grey97", tracy::Color::Grey97)
.value("Gray98", tracy::Color::Gray98)
.value("Grey98", tracy::Color::Grey98)
.value("Gray99", tracy::Color::Gray99)
.value("Grey99", tracy::Color::Grey99)
.value("Gray100", tracy::Color::Gray100)
.value("Grey100", tracy::Color::Grey100)
.value("DarkGrey", tracy::Color::DarkGrey)
.value("DarkGray", tracy::Color::DarkGray)
.value("DarkBlue", tracy::Color::DarkBlue)
.value("DarkCyan", tracy::Color::DarkCyan)
.value("DarkMagenta", tracy::Color::DarkMagenta)
.value("DarkRed", tracy::Color::DarkRed)
.value("LightGreen", tracy::Color::LightGreen)
.value("Crimson", tracy::Color::Crimson)
.value("Indigo", tracy::Color::Indigo)
.value("Olive", tracy::Color::Olive)
.value("RebeccaPurple", tracy::Color::RebeccaPurple)
.value("Silver", tracy::Color::Silver)
.value("Teal", tracy::Color::Teal)
.export_values();
m.def(
"program_name",
[](const std::string &name) {
if (!tracy::IsEnabled()) return false;
auto entry = NameBuffer::Add(name);
if (!entry.first) return false;
TracySetProgramName(entry.second);
return true;
},
"name"_a.none(false));
m.def(
"thread_name",
[](const std::string &name) {
if (!tracy::IsEnabled()) return;
tracy::SetThreadName(name.c_str());
},
"name"_a.none(false));
m.def(
"app_info",
[](const std::string &text) {
if (!tracy::IsEnabled()) return false;
if (text.size() >= std::numeric_limits<uint16_t>::max()) return false;
TracyAppInfo(text.c_str(), text.size());
return true;
},
"text"_a.none(false));
m.def(
"message",
[](const std::string &message) {
if (!tracy::IsEnabled()) return false;
if (message.size() >= std::numeric_limits<uint16_t>::max())
return false;
TracyMessage(message.c_str(), message.size());
return true;
},
"message"_a.none(false));
m.def(
"message",
[](const std::string &message, uint32_t pColor) {
if (!tracy::IsEnabled()) return false;
if (message.size() >= std::numeric_limits<uint16_t>::max())
return false;
TracyMessageC(message.c_str(), message.size(), pColor);
return true;
},
"message"_a.none(false), "color"_a.none(false));
m.def("frame_mark", []() { FrameMark; });
m.def(
"frame_mark_start",
[](const std::string &name) {
if (!tracy::IsEnabled())
return static_cast<OptionalNumber>(std::nullopt);
auto entry = NameBuffer::Add(name);
if (!entry.first) return static_cast<OptionalNumber>(std::nullopt);
FrameMarkStart(entry.second);
return entry.first;
},
"name"_a.none(false));
m.def(
"frame_mark_end",
[](std::size_t id) {
if (!tracy::IsEnabled()) return false;
auto ptr = NameBuffer::Get(id);
if (!ptr) return false;
FrameMarkEnd(ptr);
return true;
},
"name"_a.none(false));
m.def(
"frame_image",
[](const py::bytes &image, uint16_t width, uint16_t height,
uint8_t offset = 0, bool flip = false) {
if (!tracy::IsEnabled()) return false;
if (width % 4 != 0 || height % 4 != 0) return false;
TracyCFrameImage(std::string(image).data(), width, height, offset,
flip);
return true;
},
"data"_a.none(false), "width"_a.none(false), "height"_a.none(false),
"offset"_a.none(false) = 0, "flip"_a.none(false) = false);
py::class_<PyScopedZone, std::shared_ptr<PyScopedZone>>(m, "_ScopedZone")
.def(py::init<const OptionalString &, uint32_t, OptionalInt, bool,
const std::string &, const std::string &, uint32_t>(),
"name"_a, "color"_a.none(false), "depth"_a, "active"_a.none(false),
"function"_a.none(false), "file"_a.none(false), "line"_a.none(false))
.def_property_readonly("is_active", &PyScopedZone::IsActive)
.def("text", &PyScopedZone::Text<std::string>, "text"_a.none(false))
.def("text", &PyScopedZone::Text<py::object>, "text"_a.none(false))
.def("name", &PyScopedZone::Name, "name"_a.none(false))
.def("_color", &PyScopedZone::Color, "color"_a.none(false))
.def("enter", &PyScopedZone::Enter)
.def("exit", &PyScopedZone::Exit);
m.def("alloc", &MemoryAllocate<>, "ptr"_a.none(false), "size"_a.none(false),
"name"_a = static_cast<OptionalString>(std::nullopt),
"id"_a = static_cast<OptionalNumber>(std::nullopt),
"depth"_a = static_cast<OptionalInt>(std::nullopt));
m.def("alloc", &MemoryAllocate<py::object>, "object"_a.none(false),
"size"_a.none(false),
"name"_a = static_cast<OptionalString>(std::nullopt),
"id"_a = static_cast<OptionalNumber>(std::nullopt),
"depth"_a = static_cast<OptionalInt>(std::nullopt));
m.def("free", &MemoryFree<>, "ptr"_a.none(false),
"id"_a = static_cast<OptionalNumber>(std::nullopt),
"depth"_a = static_cast<OptionalInt>(std::nullopt));
m.def("free", &MemoryFree<py::object>, "object"_a.none(false),
"id"_a = static_cast<OptionalNumber>(std::nullopt),
"depth"_a = static_cast<OptionalInt>(std::nullopt));
m.def(
"_plot_config",
[](const std::string &name, int type, bool step, bool fill,
uint32_t color = 0) {
if (!tracy::IsEnabled())
return static_cast<OptionalNumber>(std::nullopt);
auto entry = NameBuffer::Add(name);
if (!entry.first) return static_cast<OptionalNumber>(std::nullopt);
TracyCPlotConfig(entry.second, type, step, fill, color);
return entry.first;
},
"name"_a.none(false), "type"_a.none(false), "step"_a.none(false),
"fill"_a.none(false), "color"_a.none(false));
py::enum_<tracy::PlotFormatType>(m, "PlotFormatType")
.value("Number", tracy::PlotFormatType::Number)
.value("Memory", tracy::PlotFormatType::Memory)
.value("Percentage", tracy::PlotFormatType::Percentage)
.export_values();
m.def(
"plot",
[](std::size_t id, double value) {
if (!tracy::IsEnabled()) return false;
auto ptr = NameBuffer::Get(id);
if (!ptr) return false;
TracyCPlot(ptr, value);
return true;
},
"id"_a.none(false), "value"_a.none(false));
m.def(
"plot",
[](std::size_t id, float value) {
if (!tracy::IsEnabled()) return false;
auto ptr = NameBuffer::Get(id);
if (!ptr) return false;
TracyCPlotF(ptr, value);
return true;
},
"id"_a.none(false), "value"_a.none(false));
m.def(
"plot",
[](std::size_t id, int64_t value) {
if (!tracy::IsEnabled()) return false;
auto ptr = NameBuffer::Get(id);
if (!ptr) return false;
TracyCPlotI(ptr, value);
return true;
},
"id"_a.none(false), "value"_a.none(false));
}

View File

@ -0,0 +1,59 @@
#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];
}
};

View File

@ -0,0 +1,122 @@
#pragma once
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
using namespace pybind11::literals;
#include <optional>
#include <string>
#include "tracy/Tracy.hpp"
#ifdef TRACY_ENABLE
template <typename Type = std::string>
bool SetText(const Type& text, tracy::ScopedZone* zone) {
return SetText<std::string>(py::str(text), zone);
}
template <>
bool SetText(const std::string& text, tracy::ScopedZone* zone) {
if (!zone || text.size() >= std::numeric_limits<uint16_t>::max())
return false;
zone->Text(text.c_str(), text.size());
return true;
}
#endif
class PyScopedZone {
public:
PyScopedZone(const std::optional<std::string>& name, uint32_t color,
std::optional<int> depth, bool active,
const std::string& function, const std::string& source,
uint32_t line)
: m_name(name),
m_color(color),
m_depth(depth),
m_active(active),
m_function(function),
m_source(source),
m_line(line) {
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
if (!depth) depth = TRACY_CALLSTACK;
#endif
}
virtual ~PyScopedZone() { Exit(); };
bool IsActive() const {
#ifdef TRACY_ENABLE
if (!m_zone) return m_active;
return m_zone->IsActive();
#else
return false;
#endif
}
template <typename Type>
bool Text(const Type& text) {
#ifdef TRACY_ENABLE
return SetText(text, m_zone);
#else
static_cast<void>(text); // unused
#endif
}
bool Name(const std::string& name) {
#ifdef TRACY_ENABLE
if (name.size() >= std::numeric_limits<uint16_t>::max()) return false;
m_name = name;
if (!m_zone) return true;
m_zone->Name(m_name->c_str(), m_name->size());
return true;
#else
static_cast<void>(name); // unused
#endif
}
void Color(uint32_t color) {
#ifdef TRACY_ENABLE
m_color = color;
if (!m_zone) return;
m_zone->Color(m_color);
#else
static_cast<void>(color); // unused
#endif
}
void Enter() {
#ifdef TRACY_ENABLE
if (m_depth)
m_zone = new tracy::ScopedZone(
m_line, m_source.c_str(), m_source.size(), m_function.c_str(),
m_function.size(), m_name ? m_name->c_str() : nullptr,
m_name ? m_name->size() : 0ul, m_color, *m_depth, m_active);
else
m_zone = new tracy::ScopedZone(
m_line, m_source.c_str(), m_source.size(), m_function.c_str(),
m_function.size(), m_name ? m_name->c_str() : nullptr,
m_name ? m_name->size() : 0ul, m_color, m_active);
#endif
}
void Exit() {
#ifdef TRACY_ENABLE
if (m_zone) delete m_zone;
m_zone = nullptr;
#endif
}
private:
std::optional<std::string> m_name;
uint32_t m_color;
std::optional<int> m_depth;
bool m_active;
std::string m_function;
std::string m_source;
uint32_t m_line;
#ifdef TRACY_ENABLE
tracy::ScopedZone* m_zone;
#endif
};

57
python/setup.py Normal file
View File

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
import glob
import os
import shutil
from typing import List
from setuptools import setup, find_namespace_packages, Extension
from setuptools.command.build_ext import build_ext
MODULE_NAME = "tracy_client"
def find_files(pattern: str) -> List[str]:
return glob.glob(os.path.join(MODULE_NAME, pattern), recursive=True)
class ManualExtension(Extension):
def __init__(self) -> None:
super().__init__(name=MODULE_NAME, sources=[])
class DummyBuild(build_ext):
def build_extension(self, ext) -> None:
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
extdir = os.path.join(extdir, MODULE_NAME)
for entry in find_files("*cpython*"):
shutil.copy(
os.path.abspath(entry),
os.path.join(extdir, os.path.basename(entry)),
)
setup(
name=MODULE_NAME,
version="0.10.0",
author="Bartosz Taudul",
author_email="wolf@nereid.pl",
description="A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.",
long_description="This package contains the client code only. See the documentation for further details.",
url="https://github.com/wolfpld/tracy",
ext_modules=[ManualExtension()],
cmdclass={"build_ext": DummyBuild},
package_dir={"": "."},
packages=find_namespace_packages(where="."),
package_data={"": ["py.typed"]},
data_files=[
("lib", find_files("lib*")),
("include/client", find_files("client/*.h*")),
("include/common", find_files("common/*.h*")),
("include/tracy", find_files("tracy/*.h*")),
],
include_package_data=True,
zip_safe=False,
)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from tracy_client.tracy import *

View File

View File

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
import sys
from functools import wraps
from typing import Callable, Optional, Union
from tracy_client.TracyClientBindings import (
is_enabled,
_ScopedZone,
ColorType,
frame_mark_start,
frame_mark_end,
)
Color = Union[int, ColorType]
class ScopedZone(_ScopedZone):
def __init__(
self,
name: Optional[str] = None,
color: Color = 0,
depth: Optional[int] = None,
active: bool = True,
) -> None:
frame = sys._getframe(1)
_ScopedZone.__init__(
self,
name,
int(color),
depth,
active,
frame.f_code.co_name,
frame.f_code.co_filename,
frame.f_lineno,
)
def color(self, color: Color) -> None:
self._color(int(color))
def __enter__(self):
self.enter()
return self
def __exit__(self, *args):
self.exit()
def ScopedZoneDecorator(
name: Optional[str] = None,
color: Color = 0,
depth: Optional[int] = None,
active: bool = True,
class_name: Optional[str] = None,
):
def decorator(function: Callable):
if not is_enabled():
return function
source = function.__name__
if class_name is not None:
source = f"{class_name}:{source}"
zone = _ScopedZone(
name,
int(color),
depth,
active,
source,
function.__code__.co_filename,
function.__code__.co_firstlineno,
)
@wraps(function)
def wrapped(*args, **kwargs):
zone.enter()
value = function(*args, **kwargs)
zone.exit()
return value
return wrapped
return decorator
class ScopedFrame:
def __init__(self, name: str) -> None:
self.__name = name
self.__id: Optional[int] = None
def __enter__(self):
self.__id = frame_mark_start(self.__name)
return self
def __exit__(self, *args):
if self.__id is None:
return
frame_mark_end(self.__id)
def ScopedFrameDecorator(name: str):
def decorator(function: Callable):
if not is_enabled():
return function
@wraps(function)
def wrapped(*args, **kwargs):
frame_id = frame_mark_start(name)
value = function(*args, **kwargs)
if frame_id is not None:
frame_mark_end(frame_id)
return value
return wrapped
return decorator

View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
from typing import Optional, Union
from tracy_client.TracyClientBindings import (
is_enabled,
program_name,
thread_name,
app_info,
ColorType,
PlotFormatType,
frame_mark,
frame_mark_start,
frame_mark_end,
frame_image,
alloc,
free,
message,
plot,
_plot_config,
)
from tracy_client.scoped import (
Color,
ScopedZone,
ScopedFrame,
ScopedZoneDecorator,
ScopedFrameDecorator,
)
PlotType = Union[int, PlotFormatType]
def plot_config(
name: str, type: PlotType, step: bool = False, flip: bool = False, color: Color = 0
) -> Optional[int]:
return _plot_config(name, int(type), step, flip, int(color))