Top ! alpha build 0.0.3

Martin Fouilleul  —  1 year, 7 months ago

This month I mainly worked on a debugging/profiling infrastructure for Top !, in order to, uh well, debug and profile stuff.
It will enable me to track down some bugs and to identify hotspots more conveniently, and maybe provide a base for a small built-in performance diagnostic tool (eg. showing DSP load, plug-ins processing time, file access/buffering overhead, etc...).

This means there is little visible change overall, but I thought it was worth putting on new build online anyway, as it comes along with some bug fixes and minor changes :

  • Fixed various thread related bugs crashing the audio when relinking files / consolidating in the files manager.
  • Fixed a bug causing Top to sometimes crash when deleting a group cue.
  • Fixed a bug causing playlist to crash when the cue pointed to by the playlist selector was deleted while playing.
  • Fixed a bug where the cue view and the matrix view were not properly refreshed after a cue was selected with the mouse.
  • Added auto-scroll to the cuelist and the matrix (ie. when you're moving through the cuelist or matrix with the keyboard, these views will autoscroll to always display the selected cue or cell).
  • Slightly improved performance for dynamic texts rendering. (Speaking of text rendering, the font measurements appears to be broken on OSX 10.13, resulting in texts being misplaced. I'm currently developping on 10.9... didn't have the time and the will to upgrade yet ! It will be investigated and fixed as soon as possible)

Now for the debug system

It's heavily inspired from Casey's early debug infrastructure in Handmade Hero, with some variants. It's a log-based system where "debug markers" macros can be put at convenient places to generate some code that will log an event each time it is run. The log is periodically collected to build simple statistics about the events and present them in a convenient hierarchical form.

In each C file I #define DEBUG_TRANSLATION_UNIT to be the name of that translation unit, then include top_debug.h, and at the end of the file I use the macro DEBUG_MARKER_ARRAY_DEF. This macro will define an array named after the translation unit name, large enough to hold the information about all debug markers present in this file. I also add a DEBUG_END_OF_FRAME macro once at the end of the run loop, to periodically collect the data logged by the markers.

I can then put debug markers in the code with debug markers macros :
  • DEBUG_BLOCK() is used to trace and/or time functions or blocks of code, and can take an optional identifier argument and an optional verbosity level argument.
  • DEBUG_VALUE() is used to sample the value of a primitive type variable, and takes the name of the variable to sample, and an optional verbosity level argument.
  • DEBUG_POST(), DEBUG_ERROR(), DEBUG_WARNING() are used to print out messages to the debug console with various verbosity level and take a printf-like format string and subsequent arguments.

The first time these markers are encountered when the program is run, the infos about the location (function, file, line number) and type of marker are stored into the debug marker array at an index defined at compile-time by using the predefined __COUNTER__ macro. Then the marker is referred to by a pointer into that array. This avoids recomputing these informations each time the marker is executed. Debug markers encounters are logged in a global buffer, and all the logged events are collected when the end of frame is encountered. A tree hierarchy is constructed/updated from the collected markers (resulting in a call-stack like tree, but only for those functions containing block markers).

I can either continually update the debug hierarchy and compute average running time of functions, accumulated hit counts, percentage time of parent function, or start with an empty hierarchy and stop when one pass through the hierarchy is complete, which allows to trace the calls generated by a particular event or UI interaction. In particular, I can choose to trace only those block marker with a specific identifier, which allows, for instance, to distinguish between calls of the same function made by different callers.

I can also see a log of all debug messages generated by message macros.

The debug console

All the interaction with the debug system is done through a debug console which specific implementation is separated from the debug code, which means it could be displayed in a regular terminal using printf calls or curses, or in a native window belonging to the application (which is what I did in Top!).
The console can receive text commands such as "set verbosity error" or "trace TopRenderMatrixTraversal" and display three different panels (the tracing panel, which show one pass of a hierarchy rooted to a specific function, the profiling panel, which shows the entire hierarchy with timing statistics, and the message panel, which shows all the debug messages).

Next months' plans

Last month I talked about the debug infrastructure and also mentionned dsp optimization. After giving some thoughts to it, it may be a bit prematurate, as the interface between cue-specific audio rendering and the global mixing system is not stable yet. So I will probably keep it slow and dumb a little longer.

One thing I started to prototype this month is a simple vector graphics component that outputs vertex data to be passed to OpenGL. So far I've been able to stroke paths with various line width and joint types, triangulate and fill non intersecting polygons with solid color or gradient textures, and render texture-baked fonts. So maybe I could push it further in order to replace cairo software rendering altogether. As cairo is currently eating a bunch of processing time just rendering a few rounded rectangles and text, I would be glad to implement this accelerated version of the renderer. Don't know if it will show up in the next build, but I will certainly try to push things in that direction.

On the other hand, there's still a lot of things to consolidate in the cuelist and transport system so I should spend some time on them :

  • I have to simplify the insertion of cues after a group cue (as for now the cue will be added into the group, so you have to explicitly insert it outside and move it right after the group).
  • There's some testing needed regarding the transport system, in particular inside nested playlists/timelines, ensuring all counters and synchronization works as expected.
  • There's a choice to be made about what kind of counter should be displayed for Free groups (eg. counter of the last started cue ? over which length ?).
  • A bit more work/testing is required to ensure everythings runs smooth and well defined in edge case, such as when we try to delete playing cues, add or remove cues from a playing group, delete targets of a running mix cue, etc...
  • The autoloc feature is currently only relevant for audio cues and timeline groups, but I want it to be extended to playlists as well.
  • A 'pause' control would be great to complement the autoloc feature.
  • Control cues should be extended to have control over group option (floating cues, auto-follow, ...), the autoloc option, and loading/swapping files in audio cues.

Thanks for reading ! Cheers,

Log in to comment