#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