From 8329d42d3e592f4cd42cdfa586e2325ddc76c898 Mon Sep 17 00:00:00 2001 From: aura Date: Tue, 10 Mar 2026 01:35:50 +0100 Subject: perf profiler, simplify 2d render, string struct, many small things --- src/util/profiler.h | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/util/profiler.h (limited to 'src/util/profiler.h') diff --git a/src/util/profiler.h b/src/util/profiler.h new file mode 100644 index 0000000..c8eea24 --- /dev/null +++ b/src/util/profiler.h @@ -0,0 +1,139 @@ +#pragma once + +#if defined(DEBUG) || defined(PROFILER) +#include "allocator.h" +#include "time.h" +#include "thread.h" +#include "fnv.h" + +static THREAD_MUTEX __profiler_intern_mutex; + +#ifndef __func__ + #define __func__ __FUNCTION__ +#endif + +#define PROFILE( x ) \ + PROFILER_LIST_ENTRY* __profiler_intern_id = __profiler_intern_start( x ); \ + defer( { __profiler_intern_end( __profiler_intern_id ); } ) + +#define _profiled PROFILE( __func__ ); + + +struct PROFILER_LIST_ENTRY { + LIST children; + const char* name; + U64 duration; + U64 start; + FNV1A hash; + + PROFILER_LIST_ENTRY* parent; +}; + +struct PROFILER_GLOBAL { + LIST frames; + LIST stack; + PROFILER_LIST_ENTRY* current = 0; +}; + +extern struct CVAR* prof_overlay; +extern PROFILER_GLOBAL gprof; + +inline PROFILER_LIST_ENTRY* __profiler_intern_is_root( FNV1A hash ) { + for( auto& it : gprof.stack ) { + if( it.hash == hash ) { + return ⁢ + } + } + return 0; +} + + +inline void __profiler_intern_clear_frame( PROFILER_LIST_ENTRY* entry ) { + entry->children.each( __profiler_intern_clear_frame ); + entry->children.clear(); +} + +inline void __profiler_intern_new_frame_child( PROFILER_LIST_ENTRY* entry ) { + for( auto& it : entry->children ) { + __profiler_intern_new_frame_child( &it ); + it.parent = entry; + } +} + +inline void __profiler_intern_new_frame( PROFILER_LIST_ENTRY* entry ) { + PROFILER_LIST_ENTRY ne = *entry; + U32 i = gprof.frames.idx_where( fn( PROFILER_LIST_ENTRY* pe ) { + return pe->hash == entry->hash; + } ); + + if( i != -1 ) { + __profiler_intern_clear_frame( &gprof.frames.data[i] ); + gprof.frames.erase( i ); + } + + PROFILER_LIST_ENTRY* pne = gprof.frames.push( ne ); + for( auto& it : pne->children ) { + it.parent = pne; + __profiler_intern_new_frame_child( &it ); + } +} + +inline PROFILER_LIST_ENTRY* __profiler_intern_start( const char* name ) { + PROFILER_LIST_ENTRY e; + FNV1A fnv = fnv1a( name ); + U64 tick = u_tick(); + PROFILER_LIST_ENTRY* ep; + + thread_mutex_lock( &__profiler_intern_mutex ); + defer( thread_mutex_unlock( &__profiler_intern_mutex ) ); + if( (ep = __profiler_intern_is_root( fnv )) != 0 ) { + __profiler_intern_new_frame( ep ); + ep->children.clear(); + ep->start = tick; + gprof.current = ep; + return ep; + } + + e.name = name; + e.children = LIST(); + memset( e.children.data, 0, sizeof(PROFILER_LIST_ENTRY) ); + e.duration = 0; + e.start = tick; + e.children = {}; + e.parent = gprof.current; + e.hash = fnv; + + if( gprof.current ) + ep = gprof.current->children.push( e ); + else + ep = gprof.stack.push( e ); + + gprof.current = ep; + return ep; +} + +inline void __profiler_intern_end( PROFILER_LIST_ENTRY* entry ) { + U64 tick = u_tick(); + + thread_mutex_lock( &__profiler_intern_mutex ); + entry->duration = tick - entry->start; + if( gprof.current ) + gprof.current = gprof.current->parent; + thread_mutex_unlock( &__profiler_intern_mutex ); +} + +inline void __profiler_intern_init() { + thread_mutex_init( &__profiler_intern_mutex ); +} + +extern void __profiler_intern_draw_overlay( struct GL_FONT* font ); + +#define profiler_init() __profiler_intern_init() +#define profiler_draw_tree( font ) __profiler_intern_draw_overlay( font ) + +#else +#define PROFILE( x ) +#define _profiled +#define profiler_init() +#define profiler_draw_tree( x ) +#endif -- cgit v1.2.3