From dd042619e9823691e4361860e265111801849e4f Mon Sep 17 00:00:00 2001 From: Till Rathmann Date: Mon, 30 Jul 2018 18:12:42 +0200 Subject: [PATCH 1/2] Support for multi-DLL projects. --- README.md | 8 +++++ TracyClient.cpp | 4 ++- TracyClientDLL.cpp | 73 ++++++++++++++++++++++++++++++++++++++++ client/TracyProfiler.cpp | 53 +++++++++++++++++++++++++++-- client/TracyProfiler.hpp | 2 +- common/TracySystem.cpp | 2 +- 6 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 TracyClientDLL.cpp diff --git a/README.md b/README.md index 155710fb..2c5adc07 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,14 @@ If you don't want to perform a complete application life-time capture, you may d On Unix make sure you are linking your application with libpthread and libdl. +#### Initial client setup for multi-DLL projects + +In projects that consist of multiple DLLs / shared objects things are a bit different. Compiling TracyClient.cpp into every DLL is no option because this would result in several instances of the Tracy objects lying around in the process. We rather need to pass the instances of them to the different DLLs to be reused there. + +For that you need a main DLL to which your executable and the other DLLs link. If that doesn't exist you have to create one explicitly for Tracy. Link the executable and all DLLs which you want to profile to this DLL. + +Add `tracy/TracyClient.cpp` to the source files list of the main DLL and `tracy/TracyClientDLL.cpp` to the source files lists of the executable and the other DLLs. + #### Running the server The easiest way to get going is to build the standalone server, available in the `standalone` directory. You can connect to localhost or remote clients and view the collected data right away. diff --git a/TracyClient.cpp b/TracyClient.cpp index 422f999d..273ccae0 100644 --- a/TracyClient.cpp +++ b/TracyClient.cpp @@ -4,7 +4,9 @@ // // For fast integration, compile and // link with this source file (and none -// other). +// other) in your executable (or in the +// main DLL / shared object on multi-DLL +// projects). // // Define TRACY_ENABLE to enable profiler. diff --git a/TracyClientDLL.cpp b/TracyClientDLL.cpp new file mode 100644 index 00000000..497bd110 --- /dev/null +++ b/TracyClientDLL.cpp @@ -0,0 +1,73 @@ +// +// Tracy profiler +// ---------------- +// +// On multi-DLL projects compile and +// link with this source file (and none +// other) in the executable and in +// DLLs / shared objects that link to +// the main DLL. +// + +// Define TRACY_ENABLE to enable profiler. + +#include "common/TracySystem.cpp" + +#ifdef TRACY_ENABLE + +#include "client/TracyProfiler.hpp" +#include "client/concurrentqueue.h" + +#include "common/TracyQueue.hpp" + +namespace tracy +{ +#ifdef _MSC_VER +# define DLL_IMPORT __declspec(dllimport) +#else +# define DLL_IMPORT +#endif + + DLL_IMPORT moodycamel::ConcurrentQueue::ExplicitProducer* get_token(); + DLL_IMPORT void*(*get_rpmalloc())(size_t size); + DLL_IMPORT void(*get_rpfree())(void* ptr); + DLL_IMPORT Profiler& get_profiler(); + +#if defined TRACY_HW_TIMER && __ARM_ARCH >= 6 + DLL_IMPORT int64_t(*get_GetTimeImpl())(); + + int64_t(*GetTimeImpl)() = get_GetTimeImpl(); +#endif + +#ifdef TRACY_COLLECT_THREAD_NAMES + DLL_IMPORT std::atomic& get_threadNameData(); + DLL_IMPORT void(*get_rpmalloc_thread_initialize())(); + + std::atomic& s_threadNameData = get_threadNameData(); + void(*rpmalloc_thread_initialize_fpt)() = get_rpmalloc_thread_initialize(); + + void rpmalloc_thread_initialize(void) + { + rpmalloc_thread_initialize_fpt(); + } +#endif + + static void*(*rpmalloc_fpt)(size_t size) = get_rpmalloc(); + static void(*rpfree_fpt)(void* ptr) = get_rpfree(); + + RPMALLOC_RESTRICT void* rpmalloc(size_t size) + { + return rpmalloc_fpt(size); + } + + void rpfree(void* ptr) + { + rpfree_fpt(ptr); + } + + Profiler& s_profiler = get_profiler(); + + thread_local ProducerWrapper s_token { get_token() }; +} + +#endif diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp index 464e3aa6..38ecb42f 100644 --- a/client/TracyProfiler.cpp +++ b/client/TracyProfiler.cpp @@ -176,14 +176,63 @@ VkCtxWrapper init_order(104) s_vkCtx { nullptr }; #ifdef TRACY_COLLECT_THREAD_NAMES struct ThreadNameData; -std::atomic init_order(104) s_threadNameData( nullptr ); +std::atomic init_order(104) s_threadNameDataInstance( nullptr ); +std::atomic& s_threadNameData = s_threadNameDataInstance; #endif #ifdef TRACY_ON_DEMAND thread_local LuaZoneState init_order(104) s_luaZoneState { 0, false }; #endif -Profiler init_order(105) s_profiler; +Profiler init_order(105) s_profilerInstance; +Profiler& s_profiler = s_profilerInstance; + +#ifdef _MSC_VER +# define DLL_EXPORT __declspec(dllexport) +#else +# define DLL_EXPORT __attribute__((visibility("default"))) +#endif + +// DLL exports to enable TracyClientDLL.cpp to retrieve the instances of Tracy objects and functions + +DLL_EXPORT moodycamel::ConcurrentQueue::ExplicitProducer* get_token() +{ + return s_token.ptr; +} + +DLL_EXPORT void*(*get_rpmalloc())(size_t size) +{ + return rpmalloc; +} + +DLL_EXPORT void(*get_rpfree())(void* ptr) +{ + return rpfree; +} + +#if defined TRACY_HW_TIMER && __ARM_ARCH >= 6 +DLL_EXPORT int64_t(*get_GetTimeImpl())() +{ + return GetTimeImpl; +} +#endif + +DLL_EXPORT Profiler& get_profiler() +{ + return s_profiler; +} + +#ifdef TRACY_COLLECT_THREAD_NAMES +DLL_EXPORT std::atomic& get_threadNameData() +{ + return s_threadNameData; +} + +DLL_EXPORT void(*get_rpmalloc_thread_initialize())() +{ + return rpmalloc_thread_initialize; +} +#endif enum { BulkSize = TargetFrameSize / QueueItemSize }; diff --git a/client/TracyProfiler.hpp b/client/TracyProfiler.hpp index d51bc124..bb11fb4e 100644 --- a/client/TracyProfiler.hpp +++ b/client/TracyProfiler.hpp @@ -80,7 +80,7 @@ extern int64_t (*GetTimeImpl)(); #endif class Profiler; -extern Profiler s_profiler; +extern Profiler& s_profiler; class Profiler { diff --git a/common/TracySystem.cpp b/common/TracySystem.cpp index fc1d1726..619c631d 100644 --- a/common/TracySystem.cpp +++ b/common/TracySystem.cpp @@ -33,7 +33,7 @@ struct ThreadNameData const char* name; ThreadNameData* next; }; -extern std::atomic s_threadNameData; +extern std::atomic& s_threadNameData; #endif void SetThreadName( std::thread& thread, const char* name ) From 2dcfe5fce09f8b57377e0faee61e14d86ad529db Mon Sep 17 00:00:00 2001 From: Till Rathmann Date: Tue, 31 Jul 2018 13:03:09 +0200 Subject: [PATCH 2/2] Made s_threadNameDataInstance and s_profilerInstance static. --- client/TracyProfiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp index 38ecb42f..33e9c41a 100644 --- a/client/TracyProfiler.cpp +++ b/client/TracyProfiler.cpp @@ -176,7 +176,7 @@ VkCtxWrapper init_order(104) s_vkCtx { nullptr }; #ifdef TRACY_COLLECT_THREAD_NAMES struct ThreadNameData; -std::atomic init_order(104) s_threadNameDataInstance( nullptr ); +static std::atomic init_order(104) s_threadNameDataInstance( nullptr ); std::atomic& s_threadNameData = s_threadNameDataInstance; #endif @@ -184,7 +184,7 @@ std::atomic& s_threadNameData = s_threadNameDataInstance; thread_local LuaZoneState init_order(104) s_luaZoneState { 0, false }; #endif -Profiler init_order(105) s_profilerInstance; +static Profiler init_order(105) s_profilerInstance; Profiler& s_profiler = s_profilerInstance; #ifdef _MSC_VER