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
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
)
103 static NestedSampleInfoPtr
create(const std::string
& name
)
105 return NestedSampleInfoPtr(new NestedSampleInfo(name
));
110 mStartTime
= OSG::getTimeStamp();
114 OSG::TimeStamp
stop_time(OSG::getTimeStamp());
115 OSG::TimeStamp
sample_time(stop_time
- mStartTime
);
116 addTime(OSG::getTimeStampMsecs(sample_time
));
119 void addTime(Real32 sample
)
121 mTimeSummer
+= sample
;
124 /** Update all our internal values and the settings of children. */
128 * Helper to recalculate the percentage given the average of the parent.
130 void calcPercentage(const Real32 parentAverage
);
133 * "print" the details of this sample and its children to a string that
136 std::string
outString(UInt32 indent
=0, bool detailed
=false);
138 // -- Accessors -- //
139 sample_vector_t
getSamples() const
141 return sample_vector_t(mSamples
.begin(), mSamples
.end());
143 sample_vector_t
getPercentageSamples() const
145 return sample_vector_t(mPctSamples
.begin(), mPctSamples
.end());
147 const std::string
& getName() const
151 Real32
getAverage() const
155 Real32
getPercentage() const
161 std::string mName
; /**< Name of the sample. */
162 subsample_map_t mSubSamples
; /**< Other sample infos below us. map: name --> NestedSampleInfoPtr */
163 Real32 mTimeSummer
; /**< Running time summer. Moved to samples once per frame. */
164 sample_list_t mSamples
; /**< List of samples we have collected. */
165 sample_list_t mPctSamples
; /**< List of percentage samples we have collected. (running list of percentages) */
166 OSG::TimeStamp mStartTime
; /**< The last start time we tried. */
167 Real32 mMax
; /**< The maximum sample. */
168 Real32 mAverage
; /**< Average time in seconds. */
169 Real32 mPercentage
; /**< Percentage of time consumed relative to siblings. */
172 /*! \ingroup GrpBasePerfMon
174 * Performance tracker that tracks the performance of nested calls. This is
175 * useful for later visualization of the performance from these values.
177 class OSG_BASE_DLLMAPPING NestedPerfTracker
184 SamplePair(UInt32 depth_
, NestedSampleInfoPtr sample_
)
190 bool operator==(const SamplePair
& rhs
) const
192 return depth
== rhs
.depth
&& sample
== rhs
.sample
;
196 NestedSampleInfoPtr sample
;
199 typedef std::vector
<NestedSampleInfoPtr
> sample_stack_t
;
200 typedef std::deque
<Real32
> frame_times_list_t
;
201 typedef std::vector
<Real32
> frame_times_vector_t
;
202 typedef std::vector
<SamplePair
> sample_pair_vector_t
;
205 template <class SingletonT
>
206 friend class OSG::SingletonHolder
;
210 , mLastFrameStart(OSG::getTimeStamp())
213 mPerfRoot
= NestedSampleInfo::create("root");
214 mCurSampleStack
.push_back(mPerfRoot
);
218 void enable(bool val
= true)
223 void enter(const std::string
& name
)
230 // Get the current sample we are in and then get it's subsample for
232 NestedSampleInfoPtr cur_sample
= mCurSampleStack
.back();
233 if(cur_sample
->mSubSamples
.find(name
) == cur_sample
->mSubSamples
.end())
235 cur_sample
->mSubSamples
[name
] = NestedSampleInfo::create(name
);
237 NestedSampleInfoPtr sub_sample
= cur_sample
->mSubSamples
[name
];
239 // Start the time and append it to the back of the stack
241 mCurSampleStack
.push_back(sub_sample
);
244 void exit(const std::string
& name
)
251 NestedSampleInfoPtr cur_sample
= mCurSampleStack
.back();
252 OSG_ASSERT(mCurSampleStack
.size() > 1);
254 mCurSampleStack
.pop_back();
258 * Helper method to add a sampled time without using enter and exit.
259 * This is useful when we have data from another source and just want to
262 void addSampledTime(const std::string
& name
, Real32 timeVal
)
269 // Get the current sample we are in and then get it's subsample for
271 NestedSampleInfoPtr cur_sample
= mCurSampleStack
.back();
272 if(! cur_sample
->mSubSamples
.count(name
))
274 cur_sample
->mSubSamples
[name
] = NestedSampleInfo::create(name
);
276 NestedSampleInfoPtr sub_sample
= cur_sample
->mSubSamples
[name
];
277 sub_sample
->addTime(timeVal
);
281 * Update the periodic performance information such as percentages
282 * and anything else that we can calculate continuously.
286 /** "print" the details of this all samples in the tree to a string. */
287 std::string
outString(bool detailed
=false);
290 * Return a flat tree of sample nodes.
291 * [(depth,sample), ...]
293 sample_pair_vector_t
getFlatSampleTree(
295 NestedSampleInfoPtr curNode
= NestedSampleInfoPtr()
298 // --- Accessors --- //
299 bool getEnabled() const
305 * Return the average frame rate.
307 * @param avgOverFrames If 0, then over all frames we know about.
309 Real32
getFrameRate(UInt32 avgOverFrames
= 0) const;
311 frame_times_vector_t
getFrameTimes() const
313 return frame_times_vector_t(mFrameTimes
.begin(), mFrameTimes
.end());
316 UInt32
getMaxSamples() const
322 NestedSampleInfoPtr mPerfRoot
;
324 sample_stack_t mCurSampleStack
;
325 OSG::TimeStamp mLastFrameStart
;
326 frame_times_list_t mFrameTimes
;
329 static UInt32 max_samples
; /**<< The maximum number of samples to collect. */
333 /*! \ingroup GrpBasePerfMon
335 * Central class for all performance monitoring.
336 * This class is a singleton that provides the interface for collecting
337 * performance monitoring data. It makes use of other helper classes to
338 * aggregate and analyze this data as needed.
340 * @note Samples are collected per thread, but in order to reduce sampling
341 * overhead (ie locking), we do not extend the list of available threads
342 * on each sample. Instead, we only update the potential thread list
343 * once per frame. If a new thread is detected, it is added to a new
344 * thread list that is cleared as part of the frame update.
347 * One line per sample. Each list is a list of comma separated values.
348 * <thread id: int>,<timestamp: double>,<type: int>,<metric: double>,<name:"string",<desc: "string">
350 class OSG_BASE_DLLMAPPING PerfMonitorBase
355 ENTER
= 0, /**< Enter a region. */
356 EXIT
= 1, /**< Exit a region. */
357 MARK
= 10, /**< Mark point for something interesting. */
358 METRIC
= 11, /**< Store a metric value. */
359 FRAME
= 100, /**< Store marker for the end/start of a frame. */
364 Data for a single sample.
371 SampleData(OSG::UInt64 tid
, OSG::Real64 timestamp
,
372 SampleType type
, const std::string
& name
,
373 OSG::Real32 metricValue
= 0.0,
374 const std::string
& desc
= "")
376 , timestamp(timestamp
)
378 , metric_value(metricValue
)
384 bool operator==(const SampleData
& rhs
) const
386 return ( (rhs
.thread_id
== thread_id
) &&
387 (rhs
.timestamp
== timestamp
) &&
388 (rhs
.type
== type
) &&
389 (rhs
.metric_value
== metric_value
) &&
390 (rhs
.desc
== desc
) &&
394 OSG::UInt64 thread_id
; /**< unique id of the thread for the sample. */
395 OSG::Real64 timestamp
; /**< timestamp when the sample occured. */
396 SampleType type
; /**< The type of sample collected. */
397 OSG::Real32 metric_value
; /**< Value of any metric collected. */
398 std::string name
; /**< Name for the sample. */
399 std::string desc
; /**< Extended description of the sample. */
402 typedef std::vector
<SampleData
> sample_data_list_t
;
405 template <class SingletonT
>
406 friend class OSG::SingletonHolder
;
409 ~PerfMonitorBase(void);
412 /** Reset the performance collection. */
415 void enable(bool val
= true);
418 * Enter a sample for the performance monitor.
419 * @arg sampleType: The type of sample that we should add.
420 * @arg desc: A text description (name, label, etc) to go with the sample.
422 void sample(SampleType sampleType
, const std::string
& name
,
423 OSG::Real32 metricValue
= 0.0, const std::string
& desc
= "");
425 /** Called once per "frame" to update internal data structures. */
428 // --- Accessors --- //
429 bool getEnabled() const
434 /** Return the id of the current thread. */
435 OSG::UInt64
getThreadId() const;
437 OSG::Real64
getTimeStampMs()
439 return OSG::getTimeStampMsecs(OSG::getTimeStamp()) - mStartTimeMs
;
442 // --- Output Processing --- //
443 /** Set the output file to use for data dumping. */
444 void setOutputFile(const std::string
& filename
);
446 /** Set the output file flush rate. */
447 void setOutputFlushRate(OSG::UInt64 rate
)
449 mFlushingRate
= rate
;
452 /** Periodically called to flush the output file. */
455 /** Helper to print samples to std::out. */
459 bool mEnabled
; /**< Indicates that the performance monitor should be active. */
460 sample_data_list_t mSamples
; /**< Samples collected for all known threads. */
462 /** Must be acquired if updating the data structure of any shared resource. */
463 OSG::LockRefPtr mDataLock
;
465 /** Data flushing. */
466 OSG::UInt64 mCurrentFrameNum
; /**< The current frame number. */
467 OSG::Real64 mStartTimeMs
; /**< The start time for the system in milliseconds. */
468 OSG::UInt64 mFlushingRate
; /**< Number of frames between data flushes. */
469 std::ofstream
* mOutFile
; /**< The output file to use. */
474 template class OSG_BASE_DLLMAPPING SingletonHolder
<PerfMonitorBase
>;
477 typedef SingletonHolder
<PerfMonitorBase
> PerfMonitor
;