Project 9: Custom Profiler with Tracking Allocator

A profiling tool that wraps Odin’s tracking allocator, records all allocations with call stacks, measures timing of code sections, and generates reports—like a mini Valgrind/Instruments.

Quick Reference

Attribute Value
Primary Language Odin
Alternative Languages C++, Rust
Difficulty Level 3: Advanced
Time Estimate 1-2 weeks
Knowledge Area Profiling / Memory Analysis
Tooling Odin’s tracking allocator + custom
Prerequisites Project 1 (Arena Allocator), understanding of call stacks

What You Will Build

A profiling tool that wraps Odin’s tracking allocator, records all allocations with call stacks, measures timing of code sections, and generates reports—like a mini Valgrind/Instruments.

Why It Matters

This project builds core skills that appear repeatedly in real-world systems and tooling.

Core Challenges

  • Wrapping allocators → maps to allocator composition
  • Capturing source locations → maps to #location intrinsic
  • Timing code sections → maps to defer for measurement
  • Generating useful reports → maps to data aggregation

Key Concepts

Real-World Outcome

$ odin run game -define:PROFILING=true

[Profiler] Recording enabled

[Game runs for 30 seconds, then exits]

=== MEMORY REPORT ===

Leak Summary:
  Total leaked: 2,456 bytes across 3 allocations

Leaks:
  1. 2048 bytes at game/entities.odin:47 (create_enemy)
     └─ Called from game/spawner.odin:123 (spawn_wave)
     └─ Called from game/game.odin:89 (update)
     Note: Allocated 15 times, freed 14 times

  2. 256 bytes at game/particles.odin:28 (emit_particle)
     └─ Allocated 1,247 times, freed 1,246 times

  3. 152 bytes at core:strings/builder.odin:34
     └─ Called from game/ui.odin:67 (draw_score)

Bad Frees:
  1. Double free at game/cleanup.odin:12
     Original allocation: game/entities.odin:47

=== TIMING REPORT ===

Section                    Calls    Total     Avg      Max
---------------------------------------------------------
game_update               1,800    892ms    0.50ms   2.3ms
  └─ physics_step         1,800    423ms    0.24ms   1.1ms
  └─ entity_update       45,000    312ms    0.007ms  0.2ms
  └─ collision_detect     1,800    145ms    0.08ms   0.9ms
game_render               1,800    756ms    0.42ms   1.8ms
  └─ draw_entities       45,000    534ms    0.012ms  0.3ms
  └─ draw_particles     127,000    198ms    0.002ms  0.1ms

Hot spots (by total time):
  1. draw_entities: 534ms (35.4%)
  2. physics_step: 423ms (28.0%)
  3. entity_update: 312ms (20.7%)

Implementation Guide

  1. Reproduce the simplest happy-path scenario.
  2. Build the smallest working version of the core feature.
  3. Add input validation and error handling.
  4. Add instrumentation/logging to confirm behavior.
  5. Refactor into clean modules with tests.

Milestones

  • Milestone 1: Minimal working program that runs end-to-end.
  • Milestone 2: Correct outputs for typical inputs.
  • Milestone 3: Robust handling of edge cases.
  • Milestone 4: Clean structure and documented usage.

Validation Checklist

  • Output matches the real-world outcome example
  • Handles invalid inputs safely
  • Provides clear errors and exit codes
  • Repeatable results across runs

References

  • Main guide: LEARN_ODIN_PROGRAMMING_LANGUAGE.md
  • “The Art of Debugging” by Matloff & Salzman