Skip to content
Beherith edited this page Dec 23, 2024 · 8 revisions

How to profile the engine using tracy

Preparation steps:

  1. Download Tracy, unzip it anywhere: https://github.com/wolfpld/tracy/releases/tag/v0.9.1

  2. Get the exact engine version we are currently using from https://engine-builds.beyondallreason.dev/index.html

  3. Find the exact engine version folder we are currently using in BAR/data/engine


Method A simple

4A. Rename the old spring.exe to spring_vanilla.exe, and extract spring.exe from the archive to this engine folder.

5A. Start BAR as you would otherwise via the lancher.


Method B advanced

4B. Unzip the engine to BAR/data/engine

5B. Get the BAR Debug Launcher exe file from here: https://github.com/beyond-all-reason/bar_debug_launcher/tree/main . Install it to BAR root folder (next to beyond-all-reason.exe)

6B. In the BAR Debug launcher, select the tracy engine build you unzipped in step 2, and select "Spring-launcher with rapid://byar-chobby:test"

6B. Hit Start in the BAR Debug launcher

image


  1. Launch Tracy.exe, and hit connect. If it throws an instrumentation error, connect again.

image

  1. Analyze profile.

Instrumentation

Tracy can benefit from additional manual instrumentation to allow for very accurate profiling. By default, the engine does provide a good coverage of of zones. On the image below, the yellow zones are mostly from the engine, while the blue zones are generally from BAR's widgethandler.

image

Building the engine with Tracy enabled

Using the provided docker build environment, enable tracy via:

./build.sh -o -t RELEASE -C -DTRACY_ENABLE=1

Adding Zones in Lua

The rules of adding zones are the following:

  1. Always call tracy.ZoneEnd(), if you have multiple return paths from a function, then add tracy.ZoneEnd() to all of them
  2. The lines with tracy.* get removed from the lua files in non-tracy enabled builds, so they dont cost performance.
  3. Remember to name your zones in tracy.ZoneBeginN()

Below is an example of nesting zones:

function gadgetHandler:GameFrame(frameNum)
	-- Since GameGrame should never be called nested ensure here the callinDepth
	-- is ok. We set it to 1 so after the run it will be set to 0 again.
	callinDepth = 1
	tracy.ZoneBeginN("G:GameFrame")
	for _, g in ipairs(self.GameFrameList) do
		tracy.ZoneBeginN("G:GameFrame:" .. g.ghInfo.name)
		g:GameFrame(frameNum)
		tracy.ZoneEnd()
	end
	tracy.ZoneEnd()
	return
end

Here is the result of the above annotation:

image

Note that there are two consecutive G:GameFrame zones, one for synced and one for unsynced.

Adding Messages to Tracy

By default, all messages that go through Recoil's logging system, including Spring.Echo() also generate tracy messages. This is very useful because the exact time stamp and approximate call stack of the message can be inferred from this. Also, messages can be searched.

To use, specify a message in Lua like so:

if tracy then
    tracy.Message(string.format("spawnCreepStructure: Failed to spawn %s at %d*%d*%d ", unitDefName, spawnPosX, spawnPosY, spawnPosZ ))
end

Messages can be viewed and clicked in the messages tab of the Tracy UI, see: image

Adding Plots to Tracy.

You can plot data in an extremely accurate way (and quickly) and view it side-by-side with the traces by initializing and plotting data.

/*** Initialize a plot in Tracy for use in debugging or profiling
 *
 * @function tracy.LuaTracyPlotConfig
 * @string plotName which should be initialized
 * @string[opt] plotFormatType "Number"|"Percentage"|"Memory", default "Number"
 * @bool[opt] step stepwise chart, default true is stepwise
 * @bool[opt] fill color fill, default false is no fill
 * @number[opt] color unit32 number as BGR color, default white
 * @treturn nil
 */

/*** Update a Tracy Plot with a value
 *
 * @function tracy.LuaTracyPlot
 * @string plotName which LuaPlot should be updated (must have been initialized via LuaTracyPlotConfig)
 * @number plotvalue the number to show on the Tracy plot
 * @treturn nil
 */

For example, lets say we wanted to plot the lua memory usage of the engine on every update:

if tracy and tracy.LuaTracyPlotConfig then 
	tracy.LuaTracyPlotConfig("LuaRAM", "memory")
end
function widgetHandler:Update()
	if tracy and tracy.LuaTracyPlot then 
		tracy.LuaTracyPlot("LuaRAM", collectgarbage("count"))
	end
        ...

See a wide view of the plot:

image

See how accurate the plot is, also giving us a delta value on mouseover:

image