From 21545b1c9dc0432b6e8d926d5cb7d3e8a5e507e7 Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Fri, 10 Jan 2025 01:46:13 +0400 Subject: [PATCH] Add profiling to the game --- build_hot_reload.sh | 4 +-- game/assets/assets.odin | 21 ++++++++++++ game/game.odin | 10 ++++++ main_hot_reload/main_hot_reload.odin | 48 ++++++++++++++++++---------- ols.json | 1 + 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/build_hot_reload.sh b/build_hot_reload.sh index e90397d..64d2beb 100755 --- a/build_hot_reload.sh +++ b/build_hot_reload.sh @@ -35,7 +35,7 @@ esac # Build the game. echo "Building game$DLL_EXT" -odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug +odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -define:TRACY_ENABLE=true -collection:libs=./libs -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug # Need to use a temp file on Linux because it first writes an empty `game.so`, which the game will load before it is actually fully written. mv game_tmp$DLL_EXT game$DLL_EXT @@ -47,5 +47,5 @@ if pgrep -f game_hot_reload.bin > /dev/null; then exit 1 else echo "Building game_hot_reload.bin" - odin build main_hot_reload -out:game_hot_reload.bin -strict-style -vet -debug + odin build main_hot_reload -define:TRACY_ENABLE=true -collection:libs=./libs -out:game_hot_reload.bin -strict-style -vet -debug fi diff --git a/game/assets/assets.odin b/game/assets/assets.odin index ab5eda8..0f75797 100644 --- a/game/assets/assets.odin +++ b/game/assets/assets.odin @@ -5,6 +5,7 @@ import "core:log" import "core:math" import lg "core:math/linalg" import "game:physics/bvh" +import "libs:tracy" import rl "vendor:raylib" Loaded_Texture :: struct { @@ -26,6 +27,8 @@ Loaded_BVH :: struct { } destroy_loaded_bvh :: proc(loaded_bvh: Loaded_BVH) { + tracy.Zone() + for &mesh_bvh in loaded_bvh.bvhs { bvh.destroy_bvh(&mesh_bvh) } @@ -39,6 +42,8 @@ Asset_Manager :: struct { } get_texture :: proc(assetman: ^Asset_Manager, path: cstring) -> rl.Texture2D { + tracy.Zone() + modtime := rl.GetFileModTime(path) existing, ok := assetman.textures[path] @@ -73,6 +78,8 @@ get_model_ex :: proc( modtime: c.long, reloaded: bool, ) { + tracy.Zone() + new_modtime := rl.GetFileModTime(path) existing, ok := assetman.models[path] @@ -109,11 +116,23 @@ get_model :: proc(assetman: ^Asset_Manager, path: cstring) -> rl.Model { null_bvhs: []bvh.BVH get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH { + tracy.Zone() + loaded_bvh, ok := assetman.bvhs[path] model, modtime, reloaded := get_model_ex(assetman, path, loaded_bvh.modtime) should_recreate := reloaded || !ok + log.debugf( + "model %v\nmodtime %v\nreloaded %v\nok %v\nshould_recreate %v\nref_modtime %v", + model, + modtime, + reloaded, + ok, + should_recreate, + loaded_bvh.modtime, + ) + if ok && should_recreate { destroy_loaded_bvh(loaded_bvh) delete_key(&assetman.bvhs, path) @@ -155,6 +174,8 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH { } shutdown :: proc(assetman: ^Asset_Manager) { + tracy.Zone() + for _, texture in assetman.textures { rl.UnloadTexture(texture.texture) } diff --git a/game/game.odin b/game/game.odin index 329c04f..8957785 100644 --- a/game/game.odin +++ b/game/game.odin @@ -22,6 +22,7 @@ import "core:math" import "core:math/linalg" import "game:physics" import "game:physics/bvh" +import "libs:tracy" import rl "vendor:raylib" import "vendor:raylib/rlgl" @@ -371,6 +372,8 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) { } update :: proc() { + tracy.Zone() + if rl.IsKeyPressed(.TAB) { g_mem.editor = !g_mem.editor } @@ -446,6 +449,8 @@ catmull_rom :: proc(a, b, c, d: rl.Vector3, t: f32) -> rl.Vector3 { } draw :: proc() { + tracy.Zone() + rl.BeginDrawing() defer rl.EndDrawing() rl.ClearBackground(rl.BLACK) @@ -778,6 +783,9 @@ spline_handle :: proc( @(export) game_update :: proc() -> bool { + tracy.Zone() + defer tracy.FrameMark() + update() draw() return !rl.WindowShouldClose() @@ -785,6 +793,8 @@ game_update :: proc() -> bool { @(export) game_init_window :: proc() { + tracy.SetThreadName("Main") + rl.SetConfigFlags({.WINDOW_RESIZABLE, .VSYNC_HINT}) rl.InitWindow(1280, 720, "Odin + Raylib + Hot Reload template!") rl.SetExitKey(.KEY_NULL) diff --git a/main_hot_reload/main_hot_reload.odin b/main_hot_reload/main_hot_reload.odin index 50701ad..39e9818 100644 --- a/main_hot_reload/main_hot_reload.odin +++ b/main_hot_reload/main_hot_reload.odin @@ -2,12 +2,13 @@ package main +import "core:c/libc" import "core:dynlib" import "core:fmt" -import "core:c/libc" -import "core:os" import "core:log" import "core:mem" +import "core:os" +import "libs:tracy" when ODIN_OS == .Windows { DLL_EXT :: ".dll" @@ -17,6 +18,8 @@ when ODIN_OS == .Windows { DLL_EXT :: ".so" } +TRACY_ENABLE :: #config(TRACY_ENABLE, false) + // We copy the DLL because using it directly would lock it, which would prevent // the compiler from writing to it. copy_dll :: proc(to: string) -> bool { @@ -36,19 +39,19 @@ copy_dll :: proc(to: string) -> bool { } Game_API :: struct { - lib: dynlib.Library, - init_window: proc(), - init: proc(), - update: proc() -> bool, - shutdown: proc(), - shutdown_window: proc(), - memory: proc() -> rawptr, - memory_size: proc() -> int, - hot_reloaded: proc(mem: rawptr), - force_reload: proc() -> bool, - force_restart: proc() -> bool, + lib: dynlib.Library, + init_window: proc(), + init: proc(), + update: proc() -> bool, + shutdown: proc(), + shutdown_window: proc(), + memory: proc() -> rawptr, + memory_size: proc() -> int, + hot_reloaded: proc(mem: rawptr), + force_reload: proc() -> bool, + force_restart: proc() -> bool, modification_time: os.File_Time, - api_version: int, + api_version: int, } load_game_api :: proc(api_version: int) -> (api: Game_API, ok: bool) { @@ -62,7 +65,11 @@ load_game_api :: proc(api_version: int) -> (api: Game_API, ok: bool) { } // NOTE: this needs to be a relative path for Linux to work. - game_dll_name := fmt.tprintf("{0}game_{1}" + DLL_EXT, "./" when ODIN_OS != .Windows else "", api_version) + game_dll_name := fmt.tprintf( + "{0}game_{1}" + DLL_EXT, + "./" when ODIN_OS != .Windows else "", + api_version, + ) copy_dll(game_dll_name) or_return // This proc matches the names of the fields in Game_API to symbols in the @@ -95,6 +102,14 @@ unload_game_api :: proc(api: ^Game_API) { main :: proc() { context.logger = log.create_console_logger() + when TRACY_ENABLE { + context.allocator = tracy.MakeProfiledAllocator( + self = &tracy.ProfiledAllocatorData{}, + callstack_size = 5, + backing_allocator = context.allocator, + secure = true, + ) + } default_allocator := context.allocator tracking_allocator: mem.Tracking_Allocator mem.tracking_allocator_init(&tracking_allocator, default_allocator) @@ -142,7 +157,8 @@ main :: proc() { new_game_api, new_game_api_ok := load_game_api(game_api_version) if new_game_api_ok { - force_restart = force_restart || game_api.memory_size() != new_game_api.memory_size() + force_restart = + force_restart || game_api.memory_size() != new_game_api.memory_size() if !force_restart { // This does the normal hot reload diff --git a/ols.json b/ols.json index 44b6fe9..633c31a 100644 --- a/ols.json +++ b/ols.json @@ -3,6 +3,7 @@ "collections": [ { "name": "common", "path": "./common" }, { "name": "game", "path": "./game" }, + { "name": "libs", "path": "./libs" } ], "enable_semantic_tokens": false, "enable_document_symbols": true,