blob: 334ad6293605a88feba4ae84f363c7a7cf30a6d8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
#pragma once
#if defined(DEBUG) || defined(PROFILER)
#include "allocator.h"
#include "time.h"
#include "thread.h"
#include "mem.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, (U64)__cur_retaddr() ); \
defer( { __profiler_intern_end( __profiler_intern_id ); } )
#define _profiled PROFILE( __func__ );
struct PROFILER_LIST_ENTRY {
LIST<PROFILER_LIST_ENTRY> children;
const char* name;
U64 duration;
U64 start;
U64 ptr;
FNV1A hash;
PROFILER_LIST_ENTRY* parent;
};
struct PROFILER_GLOBAL {
LIST<PROFILER_LIST_ENTRY> frames;
LIST<PROFILER_LIST_ENTRY> 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 )
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, U64 ptr ) {
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<PROFILER_LIST_ENTRY>();
memset( e.children.data, 0, sizeof(PROFILER_LIST_ENTRY) );
e.duration = 0;
e.start = tick;
e.children = {};
e.parent = gprof.current;
e.hash = fnv;
e.ptr = ptr;
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 );
}
inline void __profiler_intern_trace() {
thread_mutex_lock( &__profiler_intern_mutex );
PROFILER_LIST_ENTRY* entry = gprof.current;
dlog( "======== [ profiler trace ] ==========\n" );
while( entry ) {
dlog( "%s [0x%llx]\n", entry->name, entry->ptr );
}
}
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 )
#define profiler_trace() __profiler_intern_trace()
#else
#define PROFILE( x )
#define _profiled
#define profiler_trace()
#define profiler_init()
#define profiler_draw_tree( x )
#endif
|