5 * Created by damian on 25/5/08.
6 * Copyright 2008 frey damian@frey.co.nz. All rights reserved.
10 #include "FProfiler.h"
16 FProfiler::FProfileContexts
FProfiler::contexts
;
17 FSemaphore
FProfiler::lock
;
19 int FProfileSection::EXEC_ORDER_ID
= 0;
21 FTime
FProfiler::end_time
;
23 FProfileContext::~FProfileContext()
29 FProfileContext
* FProfiler::GetContext()
31 FThreadContext thread_context
;
33 // try to get current thread context
34 for ( FProfileContexts::const_iterator i
= contexts
.begin();
38 if ( thread_context
== ( *i
)->thread_context
)
45 // no context found for this thread: must create a new one
46 FProfileContext
* context
= new FProfileContext();
47 // add it to the vector
48 contexts
.push_back( context
);
50 context
->thread_context
.Set();
51 context
->toplevel
= new FProfileSection();
52 context
->current
= context
->toplevel
;
61 void FProfiler::Clear()
66 for ( int i
=0; i
<contexts
.size(); i
++ )
77 void FProfiler::SectionPush(const std::string
&name
)
79 FProfileContext
* context
= GetContext();
80 assert( context
->current
);
82 // try to grab the section out of the db
83 // we store by name so that we can accumulate results over multiple frames
84 FProfileSection
* s
= context
->current
->children
[name
];
87 s
= new FProfileSection();
88 s
->parent
= context
->current
;
90 context
->current
->children
[name
] = s
;
93 // shift current to us
97 context
->current
->timer
.SetNow();
98 // QueryPerformanceCounter(&s->start_time);
103 void FProfiler::SectionPop()
108 FProfileContext
* context
= GetContext();
109 FProfileSection
* s
= context
->current
;
111 // check we're not popping up too far
112 if ( context
->current
->parent
== NULL
)
115 // get time for this run in ms
116 /* LARGE_INTEGER freq;
117 QueryPerformanceFrequency(&freq);
118 double time = 1000*(double)(stop_time.QuadPart - s->start_time.QuadPart)/(double)freq.QuadPart;
120 double time
= (end_time
-s
->timer
).ToMillis();
121 //double time = end_time.ToMillis()-s->timer.ToMillis();
124 // work out the new avg time and increment the call count
125 double total_time
= time
+ s
->avg_time
* s
->call_count
++;
126 s
->avg_time
= total_time
/(double)s
->call_count
;
127 /*s->avg_time = (s->avg_time*7 + time)/8;
131 context
->current
= context
->current
->parent
;
134 void FProfiler::Display( FProfiler::SORT_BY sort
)
136 printf("---------------------------------------------------------------------------------------\n" );
137 // re-use formatting from individual lines
138 printf( "PRofiler output: sorted by %s\n", (sort
==SORT_EXECUTION
?"execution order":"total time"));
139 printf( "%-50s %10s %10s %6s\n", "name values in ms -> ", "total ", "average ", "count" );
140 printf("---------------------------------------------------------------------------------------\n" );
142 for ( FProfileContexts::iterator i
= contexts
.begin();
146 printf("Thread %x\n", (unsigned int)&((*i
)->thread_context
) );
147 (*i
)->toplevel
->Display("| ", sort
);
150 printf("---------------------------------------------------------------------------------------\n" );
154 FProfileSection::FProfileSection()
159 exec_order_id
= EXEC_ORDER_ID
++;
162 FProfileSection::~FProfileSection()
164 for ( FProfileSections::iterator i
= children
.begin();
173 bool reverse_time_comparator( FProfileSection
* a
, FProfileSection
* b
)
175 return a
->avg_time
*a
->call_count
> b
->avg_time
*b
->call_count
;
178 bool execution_order_comparator( FProfileSection
* a
, FProfileSection
* b
)
180 return a
->exec_order_id
< b
->exec_order_id
;
183 void FProfileSection::Display( const std::string
& prefix
, FProfiler::SORT_BY sort_by
)
185 std::vector
<FProfileSection
* > children_vect
;
186 for ( FProfileSections::iterator i
= children
.begin();
190 children_vect
.push_back( (*i
).second
);
194 if ( sort_by
== FProfiler::SORT_TIME
)
196 std::sort( children_vect
.begin(), children_vect
.end(), reverse_time_comparator
);
198 else if ( sort_by
== FProfiler::SORT_EXECUTION
)
200 std::sort( children_vect
.begin(), children_vect
.end(), execution_order_comparator
);
203 for ( int i
=0; i
<children_vect
.size(); i
++ )
205 FProfileSection
* sect
= children_vect
[i
];
206 // replace '+' with '|';
208 if ( prefix
.size()>1 )
209 name
= prefix
.substr( 0, prefix
.size()-2 ) + std::string("+ ") + sect
->name
;
212 printf( "%-50s %10.2f %10.5f %6d\n", name
.c_str(),
213 sect
->avg_time
* sect
->call_count
,
214 sect
->avg_time
, sect
->call_count
);
216 // if this is the last child,
217 std::string next_prefix
= prefix
;
218 if ( prefix
.size() > 1 && i
==children_vect
.size()-1 )
220 // erase the previous "| " and replace with " "
221 next_prefix
= next_prefix
.substr(0, next_prefix
.size()-2 ) + std::string(" ");
224 sect
->Display( next_prefix
+ "| ", sort_by
);