Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proof of concept for Tracy integration #2061

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

nixxquality
Copy link

@nixxquality nixxquality commented Apr 24, 2024

This is not a real pull request, but just a proof of concept for now. Tracy is an incredible profiler which is perfect for games because it's real time and has native support for concepts like frames.

I'll say right away that I have very limited experience with CMake and the current way to build this is incredibly stupid.

Here's how to make this build:

  1. Download the source code for Tracy v0.10: https://github.com/wolfpld/tracy/archive/refs/tags/v0.10.zip
  2. Grab the public folder and unzip it as src/libraries/tracy
  3. Add this to the top of src/libraries/tracy/TracyClient.cpp:
#undef TRACY_IMPORTS
#define TRACY_EXPORTS

So, what do you get with this? Well, Tracy is an instrumentation based profiler, so by instrumenting all the little Lua wrappers we can immediately provide incredibly helpful information for all lövers - with no work on their part.
For lövers that want to instrument their Lua code, Tracy actually has built-in support for Lua.
All we need is that tracy::LuaRegister(L); call and now we can use the tracy library.

Here is an example main.lua:

function love.update(dt)
    tracy.ZoneBegin()

    tracy.Message("Testing")

    tracy.ZoneEnd()
end

function love.draw()
    tracy.ZoneBegin()

    love.graphics.print("Hello world!", 10, 10)

    o = love.graphics.newImage("O.png")
    love.graphics.draw(o, 400, 300)

    tracy.ZoneEnd()
end

As you can see, I've made a terrible mistake here - I'm calling newImage inside love.draw.
I've attached the resulting .tracy trace file here: love_overusing_newImage.zip
(Note that Tracy files are locked to the version it was made in, in this case 0.10)
To view this saved trace, either

As you can see, we have a nice frame counter at the top and if we zoom in we can see what's taking so long inside our draw function:
2024-04-24_12-29-13

If we then move that to a love.load we can use the Compare function inside Tracy to see how much faster our draw function is now:
2024-04-24_12-47-42


Right now, Tracy is set to be "on-demand", that is, it should have a very minimal impact on performance until a profiler is connected. Ideally this could just be in every love.exe, but there are some questions like network discovery (because Tracy can work over the network) and such that doesn't make sense to enable for everyone...
Perhaps a separate executable should be shipped, love_tracy or something like that which can be used when a developer wants to profile a game.
The Tracy API provides a function tracy::LuaRemove(char* script) which can be used to automatically strip any Lua calls to tracy before the code is loaded, for example, when launching in an executable where Tracy is disabled.
Ideally the default love.run should include the tracy.Zone.... markings for load, draw and update so you don't need to write it yourself.
Tracy also supports grabbing graphical frame data which it can display in the log. The default example on the website linked above shows this feature off. I did not add this in the proof of concept.
To prevent profiling from being used unless called for, Perhaps a new item can be added to love.conf such as tracy_mode:

  • "disabled" (default) Do not connect to any profiler
  • "on_demand" Start running as normal and connect to a profiler if one requests it
  • "wait" Wait until a profiler is connected before starting the game (for when you need to debug your love.load or something)

Finally, I would like to show you this excellent video which goes into way more detail into what Tracy is and what makes it awesome.
https://www.youtube.com/watch?v=ghXk3Bk5F2U (slides: https://github.com/CppCon/CppCon2023/blob/main/Presentations/Tracy_Profiler_2024.pdf)
That also goes into why building it in a special way is necessary here.

# tracy
#

add_definitions(-DTRACY_ENABLE -DTRACY_IMPORTS -DTRACY_ON_DEMAND)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing this unconditionally, you could check with cmake if there is a specific file present inside the src/libraries/tracy folder, if you want people to allow skipping tracy.
Additionally, another idea would be to always include the clientside part of tracy in the libraries folder, but choosing between those two is up to the maintainers of this library.

@slime73
Copy link
Member

slime73 commented Apr 24, 2024

If you have a standalone dll of Tracy, you should be able to use LuaJIT's FFI to call the functions in TracyC.h directly from inside your Lua code - or you could make a Lua C module dll and load that with require.

Editing love's source isn't needed to use Tracy as far as I can tell.

@nixxquality
Copy link
Author

To clarify on the build process, I refer to one of the slides in the presentation I linked.
image
So yes, TracyClient.cpp should always be linked in as a library, however if you do not define TRACY_ENABLE then you will have a build where all the instrumentation disappears.
For Lua code, this requires more work, see the LuaRemove comment above, but I'd say that's a valid tradeoff. You'd only need to edit all game code once while loading, and the method seems sound.

As for slime's comment, this is not about adding Tracy to one game. This is about providing a massive value add for all developers who use LÖVE. If the LÖVE source code is instrumented, then they will have excellent performance info for free and can then choose to further instrument Lua-specific hotspots in their code if they would like to.
It will also improve the health of the community, where instead of someone wondering "Why is my game running slow?" with no further information they can immediately run their game with a profile-enabled executable and zoom right in to the hotspots themselves.

Additionally, Tracy supports GPU instrumentation which means that hardware differences could be discovered by having a game developer and a tester coordinate by running a game on multiple machines and seeing if there are any drastic changes that could be down to GPU drivers or something like that.

If you're still not sold on Tracy itself then I must reiterate my recommendation to watch the video I linked. It's an excellent talk.
I also found a list of game developers who already use Tracy on the developer's sponsor page: https://github.com/sponsors/wolfpld

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants