2 #include <simgear/debug/logstream.hxx>
3 #include <simgear/timing/timestamp.hxx>
5 #include "exception.hxx"
6 #include "subsystem_mgr.hxx"
8 #include <simgear/math/SGMath.hxx>
11 const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
\f
12 ////////////////////////////////////////////////////////////////////////
13 // Implementation of SGSubsystem
14 ////////////////////////////////////////////////////////////////////////
17 SGSubsystem::SGSubsystem ()
22 SGSubsystem::~SGSubsystem ()
32 SGSubsystem::postinit ()
37 SGSubsystem::reinit ()
47 SGSubsystem::unbind ()
52 SGSubsystem::suspend ()
58 SGSubsystem::suspend (bool suspended)
60 _suspended = suspended;
64 SGSubsystem::resume ()
70 SGSubsystem::is_suspended () const
77 SGSubsystem::printTimingInformation ()
79 SGTimeStamp startTime;
80 for ( eventTimeVecIterator i = timingInfo.begin();
81 i != timingInfo.end();
83 if (i == timingInfo.begin()) {
84 startTime = i->getTime();
86 SGTimeStamp endTime = i->getTime();
87 SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp : "
88 << i->getName() << " takes " << endTime - startTime
97 void SGSubsystem::stamp(const string& name)
99 timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
103 ////////////////////////////////////////////////////////////////////////
104 // Implementation of SGSubsystemGroup.
105 ////////////////////////////////////////////////////////////////////////
107 SGSubsystemGroup::SGSubsystemGroup () :
108 _fixedUpdateTime(-1.0),
109 _updateTimeRemainder(0.0)
113 SGSubsystemGroup::~SGSubsystemGroup ()
115 // reverse order to prevent order dependency problems
116 for (unsigned int i = _members.size(); i > 0; i--)
118 _members[i-1]->printTimingStatistics();
119 delete _members[i-1];
124 SGSubsystemGroup::init ()
126 for (unsigned int i = 0; i < _members.size(); i++)
127 _members[i]->subsystem->init();
131 SGSubsystemGroup::postinit ()
133 for (unsigned int i = 0; i < _members.size(); i++)
134 _members[i]->subsystem->postinit();
138 SGSubsystemGroup::reinit ()
140 for (unsigned int i = 0; i < _members.size(); i++)
141 _members[i]->subsystem->reinit();
145 SGSubsystemGroup::bind ()
147 for (unsigned int i = 0; i < _members.size(); i++)
148 _members[i]->subsystem->bind();
152 SGSubsystemGroup::unbind ()
154 // reverse order to prevent order dependency problems
155 for (unsigned int i = _members.size(); i > 0; i--)
156 _members[i-1]->subsystem->unbind();
160 SGSubsystemGroup::update (double delta_time_sec)
163 // if dt == 0.0, we are paused, so we need to run one iteration
164 // of our members; if we have a fixed update time, we compute a
165 // loop count, and locally adjust dt
166 if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
167 double localDelta = delta_time_sec + _updateTimeRemainder;
168 loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
169 _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
170 delta_time_sec = _fixedUpdateTime;
173 while (loopCount-- > 0) {
174 for (unsigned int i = 0; i < _members.size(); i++)
176 SGTimeStamp timeStamp = SGTimeStamp::now();
177 _members[i]->update(delta_time_sec); // indirect call
178 timeStamp = timeStamp - SGTimeStamp::now();
179 double b = timeStamp.toUSecs();
180 _members[i]->updateExecutionTime(b);
181 double threshold = _members[i]->getTimeWarningThreshold();
182 if (( b > threshold ) && (b > 10000)) {
183 _members[i]->printTimingInformation(b);
186 } // of multiple update loop
190 SGSubsystemGroup::collectDebugTiming(bool collect)
192 for (unsigned int i = 0; i < _members.size(); i++)
194 _members[i]->collectDebugTiming(collect);
199 SGSubsystemGroup::suspend ()
201 for (unsigned int i = 0; i < _members.size(); i++)
202 _members[i]->subsystem->suspend();
206 SGSubsystemGroup::resume ()
208 for (unsigned int i = 0; i < _members.size(); i++)
209 _members[i]->subsystem->resume();
213 SGSubsystemGroup::is_suspended () const
219 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
222 Member * member = get_member(name, true);
223 if (member->subsystem != 0)
224 delete member->subsystem;
226 member->subsystem = subsystem;
227 member->min_step_sec = min_step_sec;
231 SGSubsystemGroup::get_subsystem (const string &name)
233 Member * member = get_member(name);
235 return member->subsystem;
241 SGSubsystemGroup::remove_subsystem (const string &name)
243 for (unsigned int i = 0; i < _members.size(); i++) {
244 if (name == _members[i]->name) {
245 _members.erase(_members.begin() + i);
252 SGSubsystemGroup::set_fixed_update_time(double dt)
254 _fixedUpdateTime = dt;
258 SGSubsystemGroup::Member::printTimingStatistics ()
260 if (collectTimeStats) {
261 double minTime = timeStat.min() / 1000;
262 double maxTime = timeStat.max() / 1000;
263 double meanTime = timeStat.mean() / 1000;
264 double stddev = timeStat.stdDev() / 1000;
267 snprintf(buffer, 256, "Timing summary for %20s.\n"
268 "- mean time: %04.2f ms.\n"
269 "- min time : %04.2f ms.\n"
270 "- max time : %04.2f ms.\n"
271 "- stddev : %04.2f ms.\n", name.c_str(), meanTime, minTime, maxTime, stddev);
272 SG_LOG(SG_GENERAL, SG_ALERT, buffer);
278 SGSubsystemGroup::has_subsystem (const string &name) const
280 return (((SGSubsystemGroup *)this)->get_member(name) != 0);
283 SGSubsystemGroup::Member *
284 SGSubsystemGroup::get_member (const string &name, bool create)
286 for (unsigned int i = 0; i < _members.size(); i++) {
287 if (_members[i]->name == name)
291 Member * member = new Member;
292 _members.push_back(member);
301 ////////////////////////////////////////////////////////////////////////
302 // Implementation of SGSubsystemGroup::Member
303 ////////////////////////////////////////////////////////////////////////
306 SGSubsystemGroup::Member::Member ()
311 collectTimeStats(false),
316 // This shouldn't be called due to subsystem pointer ownership issues.
317 SGSubsystemGroup::Member::Member (const Member &)
321 SGSubsystemGroup::Member::~Member ()
327 SGSubsystemGroup::Member::update (double delta_time_sec)
329 elapsed_sec += delta_time_sec;
330 if (elapsed_sec < min_step_sec) {
334 if (subsystem->is_suspended()) {
339 subsystem->update(elapsed_sec);
341 } catch (sg_exception& e) {
342 SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
343 << "\nmessage:" << e.getMessage());
345 if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
346 SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
348 subsystem->suspend();
355 SGSubsystemGroup::Member::printTimingInformation(double time)
357 if (collectTimeStats) {
358 SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert : " << time << " " << name);
359 subsystem->printTimingInformation();
363 double SGSubsystemGroup::Member::getTimeWarningThreshold()
365 return (timeStat.mean() + 3 * timeStat.stdDev());
368 void SGSubsystemGroup::Member::updateExecutionTime(double time)
370 if (collectTimeStats) {
379 ////////////////////////////////////////////////////////////////////////
380 // Implementation of SGSubsystemMgr.
381 ////////////////////////////////////////////////////////////////////////
384 SGSubsystemMgr::SGSubsystemMgr ()
388 SGSubsystemMgr::~SGSubsystemMgr ()
393 SGSubsystemMgr::init ()
395 for (int i = 0; i < MAX_GROUPS; i++)
400 SGSubsystemMgr::postinit ()
402 for (int i = 0; i < MAX_GROUPS; i++)
403 _groups[i].postinit();
407 SGSubsystemMgr::reinit ()
409 for (int i = 0; i < MAX_GROUPS; i++)
414 SGSubsystemMgr::bind ()
416 for (int i = 0; i < MAX_GROUPS; i++)
421 SGSubsystemMgr::unbind ()
423 // reverse order to prevent order dependency problems
424 for (int i = MAX_GROUPS-1; i >= 0; i--)
429 SGSubsystemMgr::update (double delta_time_sec)
431 for (int i = 0; i < MAX_GROUPS; i++) {
432 _groups[i].update(delta_time_sec);
437 SGSubsystemMgr::collectDebugTiming(bool collect)
439 for (int i = 0; i < MAX_GROUPS; i++) {
440 _groups[i].collectDebugTiming(collect);
445 SGSubsystemMgr::suspend ()
447 for (int i = 0; i < MAX_GROUPS; i++)
448 _groups[i].suspend();
452 SGSubsystemMgr::resume ()
454 for (int i = 0; i < MAX_GROUPS; i++)
459 SGSubsystemMgr::is_suspended () const
465 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
466 GroupType group, double min_time_sec)
468 SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
469 get_group(group)->set_subsystem(name, subsystem, min_time_sec);
471 if (_subsystem_map.find(name) != _subsystem_map.end()) {
472 SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
473 throw sg_exception("duplicate subsystem");
475 _subsystem_map[name] = subsystem;
479 SGSubsystemMgr::get_group (GroupType group)
481 return &(_groups[group]);
485 SGSubsystemMgr::get_subsystem (const string &name)
487 map<string,SGSubsystem *>::iterator s =_subsystem_map.find(name);
489 if (s == _subsystem_map.end())