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
- Tracking Allocator: mem.tracking_allocator
- Source Locations: #location intrinsic
- High-Resolution Timing: core:time
- Allocator Composition: Karl Zylinski - Tracking Allocator
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
- Reproduce the simplest happy-path scenario.
- Build the smallest working version of the core feature.
- Add input validation and error handling.
- Add instrumentation/logging to confirm behavior.
- 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