fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / Base / PerfMonitor / OSGPerfMonitor.cpp
blob84c9f99c21af1bd386444fc0fef7420226a8525d
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
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. *
18 * *
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. *
23 * *
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. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 #include "OSGConfig.h"
41 #include <sstream>
43 #include "OSGPerfMonitor.h"
44 #include <boost/format.hpp>
45 #include "OSGBaseInitFunctions.h"
46 #include "OSGSingletonHolder.ins"
47 #include "OSGBaseFunctions.h"
48 #include "OSGThread.h"
50 OSG_USING_NAMESPACE
51 OSG_BEGIN_NAMESPACE
53 OSG_SINGLETON_INST(PerfMonitorBase, addPostFactoryExitFunction)
55 void NestedSampleInfo::updateFrame()
57 typedef subsample_map_t::iterator iter_type;
59 // Update the children
60 for (iter_type i = mSubSamples.begin(); i != mSubSamples.end(); ++i)
62 (*i).second->updateFrame();
65 // Compute the limit on number of samples to hold
66 UInt32 sample_limit = NestedPerfTracker::max_samples;
68 // Compute my sample value and average
69 mSamples.push_front(mTimeSummer);
70 mTimeSummer = 0.0;
71 while(mSamples.size() > sample_limit)
73 mSamples.pop_back();
76 // Compute max and average
77 mMax = 0.0f;
78 Real32 total(0.0f);
79 for(UInt32 i=0;i<mSamples.size();++i)
81 Real32 val(mSamples[i]);
82 total += val;
83 if (val > mMax)
85 mMax = val;
88 if (mSamples.size() > 0)
90 mAverage = total / static_cast<Real32>(mSamples.size());
93 // Calculate the percentages of averages for each subsample
94 for (iter_type i = mSubSamples.begin(); i != mSubSamples.end(); ++i)
96 NestedSampleInfoPtr child((*i).second);
97 child->calcPercentage(mAverage);
101 void NestedSampleInfo::calcPercentage(const Real32 parentAverage)
103 if(parentAverage == 0.0f)
105 mPercentage = 0.0;
107 else
109 mPercentage = mAverage/parentAverage;
112 // Add the percentage to the list
113 mPctSamples.push_front(mPercentage);
114 while(mPctSamples.size() > NestedPerfTracker::max_samples)
116 mPctSamples.pop_back();
120 std::string NestedSampleInfo::outString(UInt32 indent, bool detailed)
122 std::ostringstream ostring;
123 //std::string indent_str(indent*2, ' ');
124 std::string indent_str(" ");
125 ostring << indent_str << mName << "[" << mPercentage << "] [" << mAverage
126 << "]\n";
127 // boost::format("[%.4f] [%.4f]\n")%mPercentage%mAverage;
128 if (detailed)
130 ostring << " samples:[";
131 typedef sample_list_t::iterator iter_type;
132 for (iter_type i = mSamples.begin(); i != mSamples.end(); ++i)
134 ostring << (*i) << ", ";
136 ostring << "]\n";
139 std::string ret_string = ostring.str();
140 typedef subsample_map_t::iterator iter_type;
141 for (iter_type i = mSubSamples.begin(); i != mSubSamples.end(); ++i)
143 ret_string += (*i).second->outString(indent + 1, detailed);
145 return ret_string;
148 void NestedPerfTracker::updateFrame()
150 // Update the entire tree
151 mPerfRoot->updateFrame();
153 // Compute average for root
154 mPerfRoot->mAverage = 0.0;
155 typedef NestedSampleInfo::subsample_map_t::iterator iter_type;
156 for(iter_type i = mPerfRoot->mSubSamples.begin();
157 i != mPerfRoot->mSubSamples.end(); ++i)
159 mPerfRoot->mAverage += (*i).second->mAverage;
162 // Compute overall framerate
163 OSG::TimeStamp cur_time(OSG::getTimeStamp());
164 Real32 frame_time = OSG::getTimeStampMsecs(cur_time-mLastFrameStart);
165 mLastFrameStart = cur_time;
166 mFrameTimes.push_front(frame_time);
167 while (mFrameTimes.size() > max_samples)
169 mFrameTimes.pop_back();
171 Real32 av_frame_time = std::accumulate(mFrameTimes.begin(),
172 mFrameTimes.end(), 0.0)
173 / static_cast<Real32>(mFrameTimes.size());
174 mFrameRate = 1.0 / av_frame_time;
177 std::string NestedPerfTracker::outString(bool detailed)
179 std::string ret_val = mPerfRoot->outString(1, detailed);
180 return ret_val;
183 NestedPerfTracker::sample_pair_vector_t NestedPerfTracker::getFlatSampleTree(
184 UInt32 depth,
185 NestedSampleInfoPtr curNode
188 NestedPerfTracker::sample_pair_vector_t sample_list;
189 if (curNode.get() == NULL)
191 curNode = mPerfRoot;
193 sample_list.push_back(SamplePair(depth, curNode));
195 typedef NestedSampleInfo::subsample_map_t::iterator iter_type;
196 for(iter_type i = curNode->mSubSamples.begin();
197 i != curNode->mSubSamples.end(); ++i)
199 NestedPerfTracker::sample_pair_vector_t sub_sample_list =
200 getFlatSampleTree(depth+1, (*i).second);
201 sample_list.insert(sample_list.end(),
202 sub_sample_list.begin(), sub_sample_list.end());
204 return sample_list;
207 Real32 NestedPerfTracker::getFrameRate(UInt32 avgOverFrames) const
209 if (0 == avgOverFrames)
211 return mFrameRate;
213 else
215 avgOverFrames = OSG::osgMin(avgOverFrames,
216 static_cast<UInt32>(mFrameTimes.size()));
217 Real32 av_frame_time =
218 std::accumulate(mFrameTimes.begin(),
219 mFrameTimes.begin() + avgOverFrames, 0.0)
220 / static_cast<Real32>(avgOverFrames);
221 Real32 frame_rate = 1.0 / av_frame_time;
222 return frame_rate;
226 UInt32 NestedPerfTracker::max_samples = 500;
229 PerfMonitorBase::PerfMonitorBase()
230 : mEnabled(false)
231 , mSamples()
232 , mDataLock(NULL)
233 , mCurrentFrameNum(0)
234 , mStartTimeMs(0.0)
235 , mFlushingRate(600)
236 , mOutFile(NULL)
238 mDataLock = OSG::Lock::get("PerfMonitor::mDataLock", false);
239 mStartTimeMs = OSG::getTimeStampMsecs(OSG::getTimeStamp());
242 PerfMonitorBase::~PerfMonitorBase(void)
244 mDataLock = NULL;
247 void PerfMonitorBase::reset()
249 mDataLock->acquire();
250 mFlushingRate = 600;
251 setOutputFile(""); // Clear the output file
252 mSamples.clear();
253 mDataLock->release();
256 void PerfMonitorBase::enable(bool val)
258 mEnabled = val;
261 void PerfMonitorBase::sample(SampleType sampleType, const std::string& name,
262 OSG::Real32 metricValue, const std::string& desc)
264 if(! mEnabled)
266 return;
269 OSG::Real64 sample_time = getTimeStampMs();
270 OSG::UInt64 tid = getThreadId();
272 SampleData sample_data(tid, sample_time, sampleType, name, metricValue,
273 desc);
275 // XXX: This is expensive. We need a better way to do this
276 // that allows for lock-free collection of samples.
277 mDataLock->acquire();
278 mSamples.push_back(sample_data);
279 mDataLock->release();
281 // TODO: Update helpers
285 /** Called once per "frame" to update internal data structures. */
286 void PerfMonitorBase::updateFrame()
288 mCurrentFrameNum += 1;
289 sample(FRAME, "frame", mCurrentFrameNum);
291 mDataLock->acquire();
293 // TODO: Update helpers
295 // Flush as needed
296 if (mSamples.size() >= mFlushingRate)
298 flushOutput();
299 mSamples.clear();
302 mDataLock->release();
305 /** Return the id of the current thread. */
306 OSG::UInt64 PerfMonitorBase::getThreadId() const
308 #ifdef WIN32
309 return OSG::UInt64(GetCurrentThreadId());
310 #else
311 return OSG::UInt64(pthread_self());
312 #endif
315 void PerfMonitorBase::setOutputFile(const std::string& filename)
317 // Close up old file if needed
318 if (mOutFile != NULL)
320 mOutFile->close();
321 delete mOutFile;
322 mOutFile = NULL;
325 if (filename != "")
327 // Open the file if needed
328 mOutFile = new std::ofstream(filename.c_str(), std::ios_base::trunc);
332 void PerfMonitorBase::flushOutput()
334 if (NULL == mOutFile)
336 return;
339 for(UInt32 i = 0; i < mSamples.size(); ++i)
341 SampleData cur_sample = mSamples[i];
342 (*mOutFile) << cur_sample.thread_id << ","
343 << std::setprecision(20) << std::fixed
344 << cur_sample.timestamp << ","
345 << static_cast<UInt32>(cur_sample.type) << ","
346 << std::scientific << std::setprecision(20)
347 << cur_sample.metric_value << ","
348 << '"' << cur_sample.name << '"' << ","
349 << '"' << cur_sample.desc << '"' << std::endl;
352 mOutFile->flush();
355 void PerfMonitorBase::printSamples()
357 for(UInt32 i = 0; i < mSamples.size(); ++i)
359 SampleData cur_sample = mSamples[i];
360 std::cout << i << ": "
361 << " tid: " << cur_sample.thread_id
362 << " ts: " << cur_sample.timestamp
363 << " type: " << static_cast<UInt32>(cur_sample.type)
364 << " metric: " << cur_sample.metric_value
365 << " name: " << cur_sample.name
366 << " desc: " << cur_sample.desc << std::endl;
370 OSG_END_NAMESPACE