Nirtcpp 2.1.0
Nirtcpp is a high-performance c++ graphics engine.
Loading...
Searching...
No Matches
IProfiler.hpp
1// This file is part of the "Irrlicht Engine".
2// For conditions of distribution and use, see copyright notice in nirtcpp/nirtcpp.hpp
3// Written by Michael Zeilfelder
4
5#ifndef NIRT_I_PROFILER_HPP_INCLUDED
6#define NIRT_I_PROFILER_HPP_INCLUDED
7
8#include <nirtcpp/core/engine/NirtCompileConfig.hpp>
9#include <nirtcpp/core/engine/irrString.hpp>
10#include <nirtcpp/core/engine/irrArray.hpp>
11#include <nirtcpp/core/engine/ITimer.hpp>
12#include <limits.h> // for INT_MAX (we should have a S32_MAX...)
13
14namespace nirt
15{
16
17class ITimer;
18
21{
22public:
23 friend class IProfiler;
24
25public:
27 {
28 GroupIndex = 0;
29 reset();
30 }
31
32public:
33 bool operator<(const SProfileData& pd) const
34 {
35 return Id < pd.Id;
36 }
37
38 bool operator==(const SProfileData& pd) const
39 {
40 return Id == pd.Id;
41 }
42
43 u32 getGroupIndex() const
44 {
45 return GroupIndex;
46 }
47
48 const core::stringw& getName() const
49 {
50 return Name;
51 }
52
55 {
56 return CountCalls;
57 }
58
61 {
62 return LongestTime;
63 }
64
67 {
68 return TimeSum;
69 }
70
71private:
72
73 // just to be used for searching as it does no initialization besides id
74 SProfileData(u32 id) : Id(id) {}
75
76 void reset()
77 {
78 CountCalls = 0;
79 LongestTime = 0;
80 TimeSum = 0;
81 LastTimeStarted = 0;
82 StartStopCounter = 0;
83 }
84
85 s32 Id;
86 u32 GroupIndex;
87 core::stringw Name;
88
89 s32 StartStopCounter; // 0 means stopped > 0 means it runs.
90 u32 CountCalls;
91 u32 LongestTime;
92 u32 TimeSum;
93
94 u32 LastTimeStarted;
95};
96
98// Implementer notes:
99// The design is all about allowing to use the central start/stop mechanism with minimal time overhead.
100// This is why the class works without a virtual functions interface contrary to the usual Nirtcpp design.
101// And also why it works with id's instead of strings in the start/stop functions even if it makes using
102// the class slightly harder.
103// The class comes without reference-counting because the profiler instance is never released (TBD).
105{
106public:
108 IProfiler() : Timer(0), NextAutoId(INT_MAX)
109 {}
110
111 virtual ~IProfiler()
112 {}
113
115
120 inline void add(s32 id, const core::stringw &name, const core::stringw &groupName);
121
123
127 inline s32 add(const core::stringw &name, const core::stringw &groupName);
128
131 {
132 return ProfileDatas.size();
133 }
134
136
139 inline bool findDataIndex(u32 & result, const core::stringw &name) const;
140
142
144 {
145 return ProfileDatas[index];
146 }
147
149
151 inline const SProfileData* getProfileDataById(u32 id);
152
154
155 inline u32 getGroupCount() const
156 {
157 return ProfileGroups.size();
158 }
159
161
162 inline const SProfileData& getGroupData(u32 index) const
163 {
164 return ProfileGroups[index];
165 }
166
168
171 inline bool findGroupIndex(u32 & result, const core::stringw &name) const;
172
173
175
178 inline void start(s32 id);
179
181
185 inline void stop(s32 id);
186
188 inline void resetDataById(s32 id);
189
191 inline void resetDataByIndex(u32 index);
192
194 inline void resetGroup(u32 index);
195
197
198 inline void resetAll();
199
201
204 virtual void printAll(core::stringw &result, bool includeOverview=false,bool suppressUncalled=true) const = 0;
205
207
209 virtual void printGroup(core::stringw &result, u32 groupIndex, bool suppressUncalled) const = 0;
210
211protected:
212
213 inline u32 addGroup(const core::stringw &name);
214
215 // I would prefer using os::Timer, but os.h is not in the public interface so far.
216 // Timer must be initialized by the implementation.
217 ITimer * Timer;
218 core::array<SProfileData> ProfileDatas;
219 core::array<SProfileData> ProfileGroups;
220
221private:
222 s32 NextAutoId; // for giving out id's automatically
223};
224
226
230NIRTCPP_API IProfiler& IRRCALLCONV getProfiler();
231
233
237{
238public:
240
243 : Id(id), Profiler(getProfiler())
244 {
245 Profiler.start(Id);
246 }
247
249
253 CProfileScope(s32 id, const core::stringw &name, const core::stringw &groupName)
254 : Id(id), Profiler(getProfiler())
255 {
256 Profiler.add(Id, name, groupName);
257 Profiler.start(Id);
258 }
259
261
264 CProfileScope(const core::stringw &name, const core::stringw &groupName)
265 : Profiler(getProfiler())
266 {
267 Id = Profiler.add(name, groupName);
268 Profiler.start(Id);
269 }
270
272 {
273 Profiler.stop(Id);
274 }
275
276protected:
277 s32 Id;
278 IProfiler& Profiler;
279};
280
281
282// IMPLEMENTATION for in-line stuff
283
285{
286 s32 idx = ProfileDatas.binary_search(SProfileData(id));
287 if ( idx >= 0 && Timer )
288 {
289 ++ProfileDatas[idx].StartStopCounter;
290 if (ProfileDatas[idx].StartStopCounter == 1 )
291 ProfileDatas[idx].LastTimeStarted = Timer->getRealTime();
292 }
293}
294
296{
297 if ( Timer )
298 {
299 const u32 timeNow = Timer->getRealTime();
300 const s32 idx = ProfileDatas.binary_search(SProfileData(id));
301 if ( idx >= 0 )
302 {
303 SProfileData &data = ProfileDatas[idx];
304 --ProfileDatas[idx].StartStopCounter;
305 if ( data.LastTimeStarted != 0 && ProfileDatas[idx].StartStopCounter == 0)
306 {
307 // update data for this id
308 ++data.CountCalls;
309 const u32 diffTime = timeNow - data.LastTimeStarted;
310 data.TimeSum += diffTime;
311 if ( diffTime > data.LongestTime )
312 data.LongestTime = diffTime;
313 data.LastTimeStarted = 0;
314
315 // update data of it's group
316 SProfileData & group = ProfileGroups[data.GroupIndex];
317 ++group.CountCalls;
318 group.TimeSum += diffTime;
319 if ( diffTime > group.LongestTime )
320 group.LongestTime = diffTime;
321 group.LastTimeStarted = 0;
322 }
323 else if ( ProfileDatas[idx].StartStopCounter < 0 )
324 {
325 // ignore additional stop calls
326 ProfileDatas[idx].StartStopCounter = 0;
327 }
328 }
329 }
330}
331
332s32 IProfiler::add(const core::stringw &name, const core::stringw &groupName)
333{
334 u32 index;
335 if ( findDataIndex(index, name) )
336 {
337 add( ProfileDatas[index].Id, name, groupName );
338 return ProfileDatas[index].Id;
339 }
340 else
341 {
342 const s32 id = NextAutoId;
343 --NextAutoId;
344 add( id, name, groupName );
345 return id;
346 }
347}
348
349void IProfiler::add(s32 id, const core::stringw &name, const core::stringw &groupName)
350{
351 u32 groupIdx;
352 if ( !findGroupIndex(groupIdx, groupName) )
353 {
354 groupIdx = addGroup(groupName);
355 }
356
357 SProfileData data(id);
358 s32 idx = ProfileDatas.binary_search(data);
359 if ( idx < 0 )
360 {
361 data.reset();
362 data.GroupIndex = groupIdx;
363 data.Name = name;
364
365 ProfileDatas.push_back(data);
366 ProfileDatas.sort();
367 }
368 else
369 {
370 // only reset on group changes, otherwise we want to keep the data or coding CProfileScope would become tricky.
371 if ( groupIdx != ProfileDatas[idx].GroupIndex )
372 {
373 resetDataByIndex((u32)idx);
374 ProfileDatas[idx].GroupIndex = groupIdx;
375 }
376 ProfileDatas[idx].Name = name;
377 }
378}
379
380u32 IProfiler::addGroup(const core::stringw &name)
381{
382 SProfileData group;
383 group.Id = -1; // Id for groups doesn't matter so far
384 group.Name = name;
385 ProfileGroups.push_back(group);
386 return ProfileGroups.size()-1;
387}
388
389bool IProfiler::findDataIndex(u32 & result, const core::stringw &name) const
390{
391 for ( u32 i=0; i < ProfileDatas.size(); ++i )
392 {
393 if ( ProfileDatas[i].Name == name )
394 {
395 result = i;
396 return true;
397 }
398 }
399
400 return false;
401}
402
404{
405 SProfileData data(id);
406 const s32 idx = ProfileDatas.binary_search(data);
407 if ( idx >= 0 )
408 return &ProfileDatas[idx];
409 return NULL;
410}
411
412bool IProfiler::findGroupIndex(u32 & result, const core::stringw &name) const
413{
414 for ( u32 i=0; i < ProfileGroups.size(); ++i )
415 {
416 if ( ProfileGroups[i].Name == name )
417 {
418 result = i;
419 return true;
420 }
421 }
422
423 return false;
424}
425
427{
428 s32 idx = ProfileDatas.binary_search(SProfileData(id));
429 if ( idx >= 0 )
430 {
431 resetDataByIndex((u32)idx);
432 }
433}
434
436{
437 SProfileData &data = ProfileDatas[index];
438
439 SProfileData & group = ProfileGroups[data.GroupIndex];
440 group.CountCalls -= data.CountCalls;
441 group.TimeSum -= data.TimeSum;
442
443 data.reset();
444}
445
448{
449 for ( u32 i=0; i<ProfileDatas.size(); ++i )
450 {
451 if ( ProfileDatas[i].GroupIndex == index )
452 ProfileDatas[i].reset();
453 }
454 if ( index < ProfileGroups.size() )
455 ProfileGroups[index].reset();
456}
457
459{
460 for ( u32 i=0; i<ProfileDatas.size(); ++i )
461 {
462 ProfileDatas[i].reset();
463 }
464
465 for ( u32 i=0; i<ProfileGroups.size(); ++i )
466 {
467 ProfileGroups[i].reset();
468 }
469}
470
475#ifdef _NIRT_COMPILE_WITH_PROFILING_
476 #define NIRT_PROFILE(X) X
477#else
478 #define NIRT_PROFILE(X)
479#endif // NIRT_PROFILE
480
481} // namespace nirt
482
483#endif // NIRT_I_PROFILER_HPP_INCLUDED
Class where the objects profile their own life-time.
Definition IProfiler.hpp:237
CProfileScope(s32 id)
Construct with an known id.
Definition IProfiler.hpp:242
CProfileScope(s32 id, const core::stringw &name, const core::stringw &groupName)
Object will create the given name, groupName combination for the id if it doesn't exist already.
Definition IProfiler.hpp:253
CProfileScope(const core::stringw &name, const core::stringw &groupName)
Object will create an id for the given name, groupName combination if they don't exist already.
Definition IProfiler.hpp:264
Code-profiler. Please check the example in the Nirtcpp examples folder about how to use it.
Definition IProfiler.hpp:105
const SProfileData & getGroupData(u32 index) const
Get profile data for a group.
Definition IProfiler.hpp:162
void resetGroup(u32 index)
Reset profile data for a whole group.
Definition IProfiler.hpp:447
u32 getProfileDataCount() const
Return the number of profile data blocks. There is one for each id.
Definition IProfiler.hpp:130
bool findGroupIndex(u32 &result, const core::stringw &name) const
Find the group index by the group-name.
Definition IProfiler.hpp:412
const SProfileData * getProfileDataById(u32 id)
Get the profile data.
Definition IProfiler.hpp:403
void stop(s32 id)
Stop profile-timing for the given id.
Definition IProfiler.hpp:295
void add(s32 id, const core::stringw &name, const core::stringw &groupName)
Add an id with given name and group which can be used for profiling with start/stop.
Definition IProfiler.hpp:349
void start(s32 id)
Start profile-timing for the given id.
Definition IProfiler.hpp:284
bool findDataIndex(u32 &result, const core::stringw &name) const
Search for the index of the profile data by name.
Definition IProfiler.hpp:389
const SProfileData & getProfileDataByIndex(u32 index) const
Get the profile data.
Definition IProfiler.hpp:143
IProfiler()
Constructor. You could use this to create a new profiler, but usually getProfiler() is used to access...
Definition IProfiler.hpp:108
void resetAll()
Reset all profile data.
Definition IProfiler.hpp:458
void resetDataByIndex(u32 index)
Reset profile data for the given index.
Definition IProfiler.hpp:435
virtual void printGroup(core::stringw &result, u32 groupIndex, bool suppressUncalled) const =0
Write the profile data of one group into a string.
void resetDataById(s32 id)
Reset profile data for the given id.
Definition IProfiler.hpp:426
u32 getGroupCount() const
Get the number of profile groups. Will be at least 1.
Definition IProfiler.hpp:155
virtual void printAll(core::stringw &result, bool includeOverview=false, bool suppressUncalled=true) const =0
Write all profile-data into a string.
Interface for getting and manipulating the virtual time.
Definition ITimer.hpp:15
virtual u32 getRealTime() const =0
Returns current real time in milliseconds of the system.
Used to store the profile data (and also used for profile group data).
Definition IProfiler.hpp:21
u32 getLongestTime() const
Longest time a profile call for this id took from start until it was stopped again.
Definition IProfiler.hpp:60
u32 getCallsCounter() const
Each time profiling for this data is stopped it increases the counter by 1.
Definition IProfiler.hpp:54
u32 getTimeSum() const
Time spend between start/stop.
Definition IProfiler.hpp:66
Axis aligned bounding box in 3d dimensional space.
Definition aabbox3d.hpp:22
void reset(T x, T y, T z)
Resets the bounding box to a one-point box.
Definition aabbox3d.hpp:50
Very simple string class with some useful features.
Definition irrString.hpp:94
string< wchar_t > stringw
using type alias for wide character strings
Definition irrString.hpp:1460
As of Nirtcpp 1.6, position2d is a synonym for vector2d.
Definition vector3d.hpp:11
signed int s32
32 bit signed variable.
Definition irrTypes.hpp:72
unsigned int u32
32 bit unsigned variable.
Definition irrTypes.hpp:64
NIRTCPP_API IProfiler &IRRCALLCONV getProfiler()
Access the Nirtcpp profiler object.

Nirtcpp    @cppfx.xyz

Esvcpp    esv::print