1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 #ifndef _OSG_PERF_MONITOR_
40 #define _OSG_PERF_MONITOR_
42 #include "OSGConfig.h"
43 #include "OSGBaseDef.h"
46 #include "OSGConfig.h"
47 #include "OSGSingletonHolder.h"
50 #include <boost/shared_ptr.hpp>
58 #include "OSGDeprecatedCPP.h"
62 class NestedSampleInfo
;
63 typedef boost::shared_ptr
<NestedSampleInfo
> NestedSampleInfoPtr
;
65 /*! \ingroup BaseGrpPerfMon
67 * Helper class to hold samples and sub samples.
68 * A node in the "performance tree".
70 class OSG_BASE_DLLMAPPING NestedSampleInfo
73 #ifdef OSG_STL_HAS_HASH_MAP
74 #if !defined(WIN32) && !defined(_LIBCPP_VERSION)
78 size_t operator()(const std::string
&s
) const
80 return OSG_STDEXTENSION_NAMESPACE::__stl_hash_string(s
.c_str());
84 typedef OSG_STDEXTENSION_NAMESPACE::hash_map
<std::string
, NestedSampleInfoPtr
,string_hash
> subsample_map_t
;
86 typedef OSG_STDEXTENSION_NAMESPACE::hash_map
<std::string
, NestedSampleInfoPtr
> subsample_map_t
;
89 typedef std::map
<std::string
, NestedSampleInfoPtr
> subsample_map_t
;
91 typedef std::deque
<Real32
> sample_list_t
;
92 typedef std::vector
<Real32
> sample_vector_t
;
94 NestedSampleInfo(const std::string
& name
)
106 static NestedSampleInfoPtr
create(const std::string
& name
)
108 return NestedSampleInfoPtr(new NestedSampleInfo(name
));
113 mStartTime
= OSG::getTimeStamp();
117 OSG::TimeStamp
stop_time(OSG::getTimeStamp());
118 OSG::TimeStamp
sample_time(stop_time
- mStartTime
);
119 addTime(OSG::getTimeStampMsecs(sample_time
));
122 void addTime(Real32 sample
)
124 mTimeSummer
+= sample
;
127 /** Update all our internal values and the settings of children. */
131 * Helper to recalculate the percentage given the average of the parent.
133 void calcPercentage(const Real32 parentAverage
);
136 * "print" the details of this sample and its children to a string that
139 std::string
outString(UInt32 indent
=0, bool detailed
=false);
141 // -- Accessors -- //
142 sample_vector_t
getSamples() const
144 return sample_vector_t(mSamples
.begin(), mSamples
.end());
146 sample_vector_t
getPercentageSamples() const
148 return sample_vector_t(mPctSamples
.begin(), mPctSamples
.end());
150 const std::string
& getName() const
154 Real32
getAverage() const
158 Real32
getPercentage() const
164 std::string mName
; /**< Name of the sample. */
165 subsample_map_t mSubSamples
; /**< Other sample infos below us. map: name --> NestedSampleInfoPtr */
166 Real32 mTimeSummer
; /**< Running time summer. Moved to samples once per frame. */
167 sample_list_t mSamples
; /**< List of samples we have collected. */
168 sample_list_t mPctSamples
; /**< List of percentage samples we have collected. (running list of percentages) */
169 OSG::TimeStamp mStartTime
; /**< The last start time we tried. */
170 Real32 mMax
; /**< The maximum sample. */
171 Real32 mAverage
; /**< Average time in seconds. */
172 Real32 mPercentage
; /**< Percentage of time consumed relative to siblings. */
175 /*! \ingroup GrpBasePerfMon
177 * Performance tracker that tracks the performance of nested calls. This is
178 * useful for later visualization of the performance from these values.
180 class OSG_BASE_DLLMAPPING NestedPerfTracker
187 SamplePair(UInt32 depth_
, NestedSampleInfoPtr sample_
)
193 bool operator==(const SamplePair
& rhs
) const
195 return depth
== rhs
.depth
&& sample
== rhs
.sample
;
199 NestedSampleInfoPtr sample
;
202 typedef std::vector
<NestedSampleInfoPtr
> sample_stack_t
;
203 typedef std::deque
<Real32
> frame_times_list_t
;
204 typedef std::vector
<Real32
> frame_times_vector_t
;
205 typedef std::vector
<SamplePair
> sample_pair_vector_t
;
208 template <class SingletonT
>
209 friend class OSG::SingletonHolder
;
215 , mLastFrameStart(OSG::getTimeStamp())
219 mPerfRoot
= NestedSampleInfo::create("root");
220 mCurSampleStack
.push_back(mPerfRoot
);
224 void enable(bool val
= true)
229 void enter(const std::string
& name
)
236 // Get the current sample we are in and then get it's subsample for
238 NestedSampleInfoPtr cur_sample
= mCurSampleStack
.back();
239 if(cur_sample
->mSubSamples
.find(name
) == cur_sample
->mSubSamples
.end())
241 cur_sample
->mSubSamples
[name
] = NestedSampleInfo::create(name
);
243 NestedSampleInfoPtr sub_sample
= cur_sample
->mSubSamples
[name
];
245 // Start the time and append it to the back of the stack
247 mCurSampleStack
.push_back(sub_sample
);
250 void exit(const std::string
& name
)
257 NestedSampleInfoPtr cur_sample
= mCurSampleStack
.back();
258 OSG_ASSERT(mCurSampleStack
.size() > 1);
260 mCurSampleStack
.pop_back();
264 * Helper method to add a sampled time without using enter and exit.
265 * This is useful when we have data from another source and just want to
268 void addSampledTime(const std::string
& name
, Real32 timeVal
)
275 // Get the current sample we are in and then get it's subsample for
277 NestedSampleInfoPtr cur_sample
= mCurSampleStack
.back();
278 if(! cur_sample
->mSubSamples
.count(name
))
280 cur_sample
->mSubSamples
[name
] = NestedSampleInfo::create(name
);
282 NestedSampleInfoPtr sub_sample
= cur_sample
->mSubSamples
[name
];
283 sub_sample
->addTime(timeVal
);
287 * Update the periodic performance information such as percentages
288 * and anything else that we can calculate continuously.
292 /** "print" the details of this all samples in the tree to a string. */
293 std::string
outString(bool detailed
=false);
296 * Return a flat tree of sample nodes.
297 * [(depth,sample), ...]
299 sample_pair_vector_t
getFlatSampleTree(
301 NestedSampleInfoPtr curNode
= NestedSampleInfoPtr()
304 // --- Accessors --- //
305 bool getEnabled() const
311 * Return the average frame rate.
313 * @param avgOverFrames If 0, then over all frames we know about.
315 Real32
getFrameRate(UInt32 avgOverFrames
= 0) const;
317 frame_times_vector_t
getFrameTimes() const
319 return frame_times_vector_t(mFrameTimes
.begin(), mFrameTimes
.end());
322 UInt32
getMaxSamples() const
328 NestedSampleInfoPtr mPerfRoot
;
330 sample_stack_t mCurSampleStack
;
331 OSG::TimeStamp mLastFrameStart
;
332 frame_times_list_t mFrameTimes
;
335 static UInt32 max_samples
; /**<< The maximum number of samples to collect. */
339 /*! \ingroup GrpBasePerfMon
341 * Central class for all performance monitoring.
342 * This class is a singleton that provides the interface for collecting
343 * performance monitoring data. It makes use of other helper classes to
344 * aggregate and analyze this data as needed.
346 * @note Samples are collected per thread, but in order to reduce sampling
347 * overhead (ie locking), we do not extend the list of available threads
348 * on each sample. Instead, we only update the potential thread list
349 * once per frame. If a new thread is detected, it is added to a new
350 * thread list that is cleared as part of the frame update.
353 * One line per sample. Each list is a list of comma separated values.
354 * <thread id: int>,<timestamp: double>,<type: int>,<metric: double>,<name:"string",<desc: "string">
356 class OSG_BASE_DLLMAPPING PerfMonitorBase
361 ENTER
= 0, /**< Enter a region. */
362 EXIT
= 1, /**< Exit a region. */
363 MARK
= 10, /**< Mark point for something interesting. */
364 METRIC
= 11, /**< Store a metric value. */
365 FRAME
= 100, /**< Store marker for the end/start of a frame. */
370 Data for a single sample.
374 SampleData(OSG::UInt64 tid
, OSG::Real64 rTimestamp
,
375 SampleType eType
, const std::string
& szName
,
376 OSG::Real32 metricValue
= 0.0,
377 const std::string
& szDesc
= "")
379 , timestamp(rTimestamp
)
381 , metric_value(metricValue
)
387 bool operator==(const SampleData
& rhs
) const
389 return ( (rhs
.thread_id
== thread_id
) &&
390 (rhs
.timestamp
== timestamp
) &&
391 (rhs
.type
== type
) &&
392 (rhs
.metric_value
== metric_value
) &&
393 (rhs
.desc
== desc
) &&
397 OSG::UInt64 thread_id
; /**< unique id of the thread for the sample. */
398 OSG::Real64 timestamp
; /**< timestamp when the sample occured. */
399 SampleType type
; /**< The type of sample collected. */
400 OSG::Real32 metric_value
; /**< Value of any metric collected. */
401 std::string name
; /**< Name for the sample. */
402 std::string desc
; /**< Extended description of the sample. */
405 typedef std::vector
<SampleData
> sample_data_list_t
;
408 template <class SingletonT
>
409 friend class OSG::SingletonHolder
;
412 ~PerfMonitorBase(void);
416 PerfMonitorBase(const PerfMonitorBase
&other
);
417 void operator =(const PerfMonitorBase
&rhs
);
420 /** Reset the performance collection. */
423 void enable(bool val
= true);
426 * Enter a sample for the performance monitor.
427 * @arg sampleType: The type of sample that we should add.
428 * @arg desc: A text description (name, label, etc) to go with the sample.
430 void sample(SampleType sampleType
, const std::string
& name
,
431 OSG::Real32 metricValue
= 0.0, const std::string
& desc
= "");
433 /** Called once per "frame" to update internal data structures. */
436 // --- Accessors --- //
437 bool getEnabled() const
442 /** Return the id of the current thread. */
443 OSG::UInt64
getThreadId() const;
445 OSG::Real64
getTimeStampMs()
447 return OSG::getTimeStampMsecs(OSG::getTimeStamp()) - mStartTimeMs
;
450 // --- Output Processing --- //
451 /** Set the output file to use for data dumping. */
452 void setOutputFile(const std::string
& filename
);
454 /** Set the output file flush rate. */
455 void setOutputFlushRate(OSG::UInt64 rate
)
457 mFlushingRate
= rate
;
460 /** Periodically called to flush the output file. */
463 /** Helper to print samples to std::out. */
467 bool mEnabled
; /**< Indicates that the performance monitor should be active. */
468 sample_data_list_t mSamples
; /**< Samples collected for all known threads. */
470 /** Must be acquired if updating the data structure of any shared resource. */
471 OSG::LockRefPtr mDataLock
;
473 /** Data flushing. */
474 OSG::UInt64 mCurrentFrameNum
; /**< The current frame number. */
475 OSG::Real64 mStartTimeMs
; /**< The start time for the system in milliseconds. */
476 OSG::UInt64 mFlushingRate
; /**< Number of frames between data flushes. */
477 std::ofstream
* mOutFile
; /**< The output file to use. */
482 template class OSG_BASE_DLLMAPPING SingletonHolder
<PerfMonitorBase
>;
485 typedef SingletonHolder
<PerfMonitorBase
> PerfMonitor
;