Porting Sean Barrett's iprof from OpenGL to raylib on Linux
- YT :: https://www.youtube.com/watch?v=DaJWWePhRsM
- Original title :: Reviving Win32 C code from 2003 on Linux
Tsoding takes iprof — Sean Barrett's 2003 Win32 interactive profiler — and ports it to Linux. He also removes its hard dependency on OpenGL so that rendering goes through user-supplied callbacks, as in Jonathan Blow's Jai module inspired by it. After a long hunt for a crash, he gets the profiler running on raylib, with live, navigable per-zone timings.
Motivation
- iprof only needs a tiny set of graphics primitives: text, text width, rectangles and lines.
- Text output and input are already callbacks; only rectangles and lines are hard-wired to OpenGL 1.1 immediate mode.
- The Jai version abstracts all of this into a config struct of draw callbacks (draw text, text width, rectangle, line, with colors). The goal is the same in C, so any backend — raw GL, SDL or raylib — can plug in.
- References: iprof (silverspaceship.com/src/iprof), RAD Debugger, the result at github.com/tsoding/iprof-nogl.
Getting it to compile on Linux
- Add a
prof_linux.h/prof_linux.cplatform layer, mirroring the Win32 one: - define
Prof_Int64viastdint.h; - provide a timestamp through the
__rdtscintrinsic (needs clang); - provide a seconds timer through
clock_gettime(CLOCK_MONOTONIC), which replacesQueryPerformanceCounter. - Old-code friction:
- case-insensitive Windows include names;
- non-standard
strdupthat leaks every frame for a "SpeedStep" warning; - unused-variable and missing-field-initializer warnings;
abs()applied to a float.- Multiple-definition linker errors came from a timestamp helper defined in a header. Marking it
staticmakes each translation unit keep its own copy. - He puts the pristine source under git before refactoring, so the diff shows exactly what changed.
Refactoring out OpenGL
- The graph routine:
- the
glBegin/glColor/glVertexsequence becomes adraw_line(x0, y0, x1, y1, r, g, b, a)callback; - colors change from 0–255 ubyte to 0–1 floats;
- a "previous point" variable turns the line-strip into individual segments.
- A callback-of-a-callback mess is flattened. The graph location becomes a global, and the graph function is called directly with
draw_line. draw_rectanglebecomes a callback too, and text and rectangle callbacks now take an RGBA color instead of relying on the implicit current GL color.- An Emacs regexp query-replace rewrites the many inline color tuples into separate assignments.
- GL state management — texture enable/disable, face culling, blending — is simply deleted; that's the caller's business.
- Aside: the "current color" in GL is implicit global state that
glVertexreads, which is whyglColorworks outsideglBegin/glEnd. Immediate mode is so pleasant that people keep reimplementing it on top of retained-mode APIs.
Wiring it to raylib
- The raylib callbacks map almost one-to-one:
DrawTextandMeasureTextfor text;DrawRectanglewithColorFromNormalizedfor rectangles;DrawLinefor lines.- Text first rendered off-screen. The fix was to use a positive line spacing, because y grows downward in raylib.
- Usage: bracket the frame with
Prof_Begin(frame)/Prof_End, callProf_update(record)once per frame, then call the draw function.
The crash hunt
- With recording on,
Prof_updatesegfaulted on the second frame. - He built and tried the RAD Debugger on Linux — good first impression, fast build, smooth onboarding — and also used gf2. The fault was an unmapped pointer in the zone-history update.
- Chat suspected stray semicolons after the
Prof_Beginmacros. That was wrong. - The real cause was
Prof_MAX_PROFILING_ZONES, which the old code base defines inconsistently between files. Defining it explicitly fixed the crash. - Lesson: the docs explain instrumentation at length but never show one complete main-loop example. He plans to publish a raylib example with the port.
Result
- Live zone timings render in raylib, with highlight animation.
- Navigation works once keys are mapped to iprof's actions (move cursor, select). Input was already abstracted; only lines and rectangles were missing, and that was the last step to OpenGL independence.
- He couldn't get a hierarchical display working despite trying the report modes.
- Asides:
- Working with code older than your programming career feels like executable archaeology.
- DuckDuckGo search quality is poor.
- grep.app and OpenGrok-style indexes are invaluable for finding real-world usage.
- On LLMs: they might make migrations like Python 2 → 3 much less painful.