diff --git a/manual/tracy.tex b/manual/tracy.tex index dd885cad..29633c79 100644 --- a/manual/tracy.tex +++ b/manual/tracy.tex @@ -2000,6 +2000,14 @@ Cost of performing Lua call stack capture is presented in table~\ref{CallstackTi Even if Tracy is disabled, you still have to pay the no-op function call cost. To prevent that, you may want to use the \texttt{tracy::LuaRemove(char* script)} function, which will replace instrumentation calls with white-space. This function does nothing if the profiler is enabled. +\subsubsection{Automatic instrumentation} + +Lua code can be automatically instrumented by using Lua hooks. The \texttt{tracy::LuaHook(lua\_State*, lua\_Debug*)} function may be used as or within a Lua hook. There is a small performance impact from using Lua hooks since the Lua VM will be required to invoke the hook function. + +The Lua hook must have the \texttt{LUA\_HOOKCALL} and \texttt{LUA\_HOOKRET} event mask set. You may either directly set the function as your hook or chain it to your existing hook. + +Use \texttt{lua\_sethook(L, tracy::LuaHook, LUA\_MASKCALL | LUA\_MASKRET, 0)} if you do not already have a Lua hook set or directly call \texttt{tracy::LuaHook(L, ar)} within your hook if you already have one set. + \subsection{C API} \label{capi} diff --git a/public/tracy/TracyLua.hpp b/public/tracy/TracyLua.hpp index 51dead51..5a51c3b5 100644 --- a/public/tracy/TracyLua.hpp +++ b/public/tracy/TracyLua.hpp @@ -120,6 +120,8 @@ static inline void LuaRemove( char* script ) } } +static inline void LuaHook( lua_State* L, lua_Debug* ar ) {} + } #else @@ -439,6 +441,44 @@ static inline void LuaRegister( lua_State* L ) static inline void LuaRemove( char* script ) {} +static inline void LuaHook( lua_State* L, lua_Debug* ar ) +{ + if ( ar->event == LUA_HOOKCALL ) + { +#ifdef TRACY_ON_DEMAND + const auto zoneCnt = GetLuaZoneState().counter++; + if ( zoneCnt != 0 && !GetLuaZoneState().active ) return; + GetLuaZoneState().active = GetProfiler().IsConnected(); + if ( !GetLuaZoneState().active ) return; +#endif + lua_getinfo( L, "Snl", ar ); + + char src[256]; + detail::LuaShortenSrc( src, ar->short_src ); + + const auto srcloc = Profiler::AllocSourceLocation( ar->currentline, src, ar->name ? ar->name : ar->short_src ); + TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLoc ); + MemWrite( &item->zoneBegin.time, Profiler::GetTime() ); + MemWrite( &item->zoneBegin.srcloc, srcloc ); + TracyQueueCommit( zoneBeginThread ); + } + else if (ar->event == LUA_HOOKRET) { +#ifdef TRACY_ON_DEMAND + assert( GetLuaZoneState().counter != 0 ); + GetLuaZoneState().counter--; + if ( !GetLuaZoneState().active ) return; + if ( !GetProfiler().IsConnected() ) + { + GetLuaZoneState().active = false; + return; + } +#endif + TracyQueuePrepare( QueueType::ZoneEnd ); + MemWrite( &item->zoneEnd.time, Profiler::GetTime() ); + TracyQueueCommit( zoneEndThread ); + } +} + } #endif