diff --git a/manual/tracy.tex b/manual/tracy.tex index 2c586caf..e8758262 100644 --- a/manual/tracy.tex +++ b/manual/tracy.tex @@ -1590,6 +1590,7 @@ To set a category for the section, start the section with the \texttt{TracySecti You can describe each of the categories you want to use with the \texttt{TracySectionSetup(category, fmt, ...)} macro. Section categories with no name set will automatically be assigned a name based on the identifier (e.g., \emph{Category 0}). \subsection{Marking locks} +\label{markinglocks} Modern programs must use multi-threading to achieve the full performance capability of the CPU. However, correct execution requires claiming exclusive access to data shared between threads. When many threads want to simultaneously enter the same critical section, the application's multi-threaded performance advantage nullifies. To help solve this problem, Tracy can collect and display lock interactions in threads. diff --git a/profiler/CMakeLists.txt b/profiler/CMakeLists.txt index 1a87448a..1fcf5f33 100644 --- a/profiler/CMakeLists.txt +++ b/profiler/CMakeLists.txt @@ -218,6 +218,7 @@ Embed(PROFILER_FILES TextInstrumentationStatistics src/achievements/Instrumentat Embed(PROFILER_FILES TextInstrumentFrames src/achievements/InstrumentFrames.md TEXT) Embed(PROFILER_FILES TextIntro src/achievements/Intro.md TEXT) Embed(PROFILER_FILES TextLoadTrace src/achievements/LoadTrace.md TEXT) +Embed(PROFILER_FILES TextLocks src/achievements/Locks.md TEXT) Embed(PROFILER_FILES TextManual src/achievements/Manual.md TEXT) Embed(PROFILER_FILES TextMemory src/achievements/Memory.md TEXT) Embed(PROFILER_FILES TextPlots src/achievements/Plots.md TEXT) diff --git a/profiler/src/achievements/Locks.md b/profiler/src/achievements/Locks.md new file mode 100644 index 00000000..6e6d7563 --- /dev/null +++ b/profiler/src/achievements/Locks.md @@ -0,0 +1,13 @@ +# Watch locks + +When something runs slowly, the thread may not be working at all: it could be waiting on a mutex. To see that, declare your synchronization objects with the [Tracy wrappers](#markinglocks) instead of the raw type: `TracyLockable( std::mutex, resourceMutex )` for exclusive locks and `TracySharedLockable( std::shared_mutex, assetLock )` for shared ones. The `*N` variants, such as `TracyLockableN( std::mutex, resourceMutex, "Assets" )`, let you pick the name the lock is displayed under. Code that receives a lock reference works with the wrappers through `LockableBase`/`SharedLockableBase`: + +```c++ +void Update( LockableBase( std::mutex )& mutex ) +{ + std::lock_guard guard( mutex ); + // ... +} +``` + +Instrumented locks show up as lanes in each thread's timeline row. Hover over a lock event to see the important information, for example which threads are blocking it and which ones it blocks, then left-click the event to open the [Lock info window](#lockwindow), with the lock's location, type, and event count. Middle-click an event to zoom the view to its extent. Wrap a few of your mutexes, profile the application, and click through your first lock. Try it out! diff --git a/profiler/src/profiler/TracyAchievementData.cpp b/profiler/src/profiler/TracyAchievementData.cpp index 3b0ff875..25f06cce 100644 --- a/profiler/src/profiler/TracyAchievementData.cpp +++ b/profiler/src/profiler/TracyAchievementData.cpp @@ -14,6 +14,7 @@ #include "data/TextInstrumentationStatistics.hpp" #include "data/TextIntro.hpp" #include "data/TextLoadTrace.hpp" +#include "data/TextLocks.hpp" #include "data/TextManual.hpp" #include "data/TextMemory.hpp" #include "data/TextPlots.hpp" @@ -62,6 +63,15 @@ AchievementItem ai_trackMemory = { AchievementItem* ac_memoryItems[] = { &ai_trackMemory, nullptr }; AchievementCategory ac_memory = { "memory", "Memory", ac_memoryItems }; +AchievementItem ai_watchLocks = { + .id = "watchLocks", + .name = "Watch locks", + .text = Unpack( TextLocks ) +}; + +AchievementItem* ac_locksItems[] = { &ai_watchLocks, nullptr }; +AchievementCategory ac_locks = { "locks", "Locks", ac_locksItems }; + AchievementItem ai_100million = { .id = "100million", @@ -109,7 +119,7 @@ AchievementItem* ac_instrumentationIntroItems[] = { nullptr }; -AchievementItem* ac_instrumentationIntroUnlock[] = { &ai_trackMemory, nullptr }; +AchievementItem* ac_instrumentationIntroUnlock[] = { &ai_trackMemory, &ai_watchLocks, nullptr }; AchievementItem ai_instrumentationIntro = { .id = "instrumentationIntro", @@ -217,6 +227,7 @@ AchievementCategory* AchievementCategories[] = { &ac_instrumentation, &ac_sampling, &ac_memory, + &ac_locks, nullptr }; diff --git a/profiler/src/profiler/TracyView_Locks.cpp b/profiler/src/profiler/TracyView_Locks.cpp index e6cf27d2..0c5a7f5e 100644 --- a/profiler/src/profiler/TracyView_Locks.cpp +++ b/profiler/src/profiler/TracyView_Locks.cpp @@ -125,6 +125,7 @@ void View::DrawLockHeader( uint32_t id, const LockMap& lockmap, const SourceLoca if( IsMouseClicked( ImGuiMouseButton_Left ) ) { + if( s_config.achievements ) Achieve( "watchLocks" ); m_lockInfoWindow = id; } if( IsMouseClicked( ImGuiMouseButton_Middle ) ) @@ -193,6 +194,7 @@ int View::DrawLocks( const TimelineContext& ctx, const std::vector