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 ()
42 SGSubsystem::shutdown ()
52 SGSubsystem::unbind ()
57 SGSubsystem::suspend ()
63 SGSubsystem::suspend (bool suspended)
65 _suspended = suspended;
69 SGSubsystem::resume ()
75 SGSubsystem::is_suspended () const
82 SGSubsystem::printTimingInformation ()
84 SGTimeStamp startTime;
85 for ( eventTimeVecIterator i = timingInfo.begin();
86 i != timingInfo.end();
88 if (i == timingInfo.begin()) {
89 startTime = i->getTime();
91 SGTimeStamp endTime = i->getTime();
92 SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp : "
93 << i->getName() << " takes " << endTime - startTime
102 void SGSubsystem::stamp(const string& name)
104 timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
108 ////////////////////////////////////////////////////////////////////////
109 // Implementation of SGSubsystemGroup.
110 ////////////////////////////////////////////////////////////////////////
112 SGSubsystemGroup::SGSubsystemGroup () :
113 _fixedUpdateTime(-1.0),
114 _updateTimeRemainder(0.0)
118 SGSubsystemGroup::~SGSubsystemGroup ()
120 // reverse order to prevent order dependency problems
121 for (unsigned int i = _members.size(); i > 0; i--)
123 _members[i-1]->printTimingStatistics();
124 delete _members[i-1];
129 SGSubsystemGroup::init ()
131 for (unsigned int i = 0; i < _members.size(); i++)
132 _members[i]->subsystem->init();
136 SGSubsystemGroup::postinit ()
138 for (unsigned int i = 0; i < _members.size(); i++)
139 _members[i]->subsystem->postinit();
143 SGSubsystemGroup::reinit ()
145 for (unsigned int i = 0; i < _members.size(); i++)
146 _members[i]->subsystem->reinit();
150 SGSubsystemGroup::shutdown ()
152 // reverse order to prevent order dependency problems
153 for (unsigned int i = _members.size(); i > 0; i--)
154 _members[i-1]->subsystem->shutdown();
158 SGSubsystemGroup::bind ()
160 for (unsigned int i = 0; i < _members.size(); i++)
161 _members[i]->subsystem->bind();
165 SGSubsystemGroup::unbind ()
167 // reverse order to prevent order dependency problems
168 for (unsigned int i = _members.size(); i > 0; i--)
169 _members[i-1]->subsystem->unbind();
173 SGSubsystemGroup::update (double delta_time_sec)
176 // if dt == 0.0, we are paused, so we need to run one iteration
177 // of our members; if we have a fixed update time, we compute a
178 // loop count, and locally adjust dt
179 if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
180 double localDelta = delta_time_sec + _updateTimeRemainder;
181 loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
182 _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
183 delta_time_sec = _fixedUpdateTime;
186 while (loopCount-- > 0) {
187 for (unsigned int i = 0; i < _members.size(); i++)
189 SGTimeStamp timeStamp = SGTimeStamp::now();
190 _members[i]->update(delta_time_sec); // indirect call
191 timeStamp = timeStamp - SGTimeStamp::now();
192 double b = timeStamp.toUSecs();
193 _members[i]->updateExecutionTime(b);
194 double threshold = _members[i]->getTimeWarningThreshold();
195 if (( b > threshold ) && (b > 10000)) {
196 _members[i]->printTimingInformation(b);
199 } // of multiple update loop
203 SGSubsystemGroup::collectDebugTiming(bool collect)
205 for (unsigned int i = 0; i < _members.size(); i++)
207 _members[i]->collectDebugTiming(collect);
212 SGSubsystemGroup::suspend ()
214 for (unsigned int i = 0; i < _members.size(); i++)
215 _members[i]->subsystem->suspend();
219 SGSubsystemGroup::resume ()
221 for (unsigned int i = 0; i < _members.size(); i++)
222 _members[i]->subsystem->resume();
226 SGSubsystemGroup::is_suspended () const
232 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
235 Member * member = get_member(name, true);
236 if (member->subsystem != 0)
237 delete member->subsystem;
239 member->subsystem = subsystem;
240 member->min_step_sec = min_step_sec;
244 SGSubsystemGroup::get_subsystem (const string &name)
246 Member * member = get_member(name);
248 return member->subsystem;
254 SGSubsystemGroup::remove_subsystem (const string &name)
256 for (unsigned int i = 0; i < _members.size(); i++) {
257 if (name == _members[i]->name) {
258 _members.erase(_members.begin() + i);
265 SGSubsystemGroup::set_fixed_update_time(double dt)
267 _fixedUpdateTime = dt;
271 SGSubsystemGroup::Member::printTimingStatistics ()
273 if (collectTimeStats) {
274 double minTime = timeStat.min() / 1000;
275 double maxTime = timeStat.max() / 1000;
276 double meanTime = timeStat.mean() / 1000;
277 double stddev = timeStat.stdDev() / 1000;
280 snprintf(buffer, 256, "Timing summary for %20s.\n"
281 "- mean time: %04.2f ms.\n"
282 "- min time : %04.2f ms.\n"
283 "- max time : %04.2f ms.\n"
284 "- stddev : %04.2f ms.\n", name.c_str(), meanTime, minTime, maxTime, stddev);
285 SG_LOG(SG_GENERAL, SG_ALERT, buffer);
291 SGSubsystemGroup::has_subsystem (const string &name) const
293 return (((SGSubsystemGroup *)this)->get_member(name) != 0);
296 SGSubsystemGroup::Member *
297 SGSubsystemGroup::get_member (const string &name, bool create)
299 for (unsigned int i = 0; i < _members.size(); i++) {
300 if (_members[i]->name == name)
304 Member * member = new Member;
305 _members.push_back(member);
314 ////////////////////////////////////////////////////////////////////////
315 // Implementation of SGSubsystemGroup::Member
316 ////////////////////////////////////////////////////////////////////////
319 SGSubsystemGroup::Member::Member ()
324 collectTimeStats(false),
329 // This shouldn't be called due to subsystem pointer ownership issues.
330 SGSubsystemGroup::Member::Member (const Member &)
334 SGSubsystemGroup::Member::~Member ()
340 SGSubsystemGroup::Member::update (double delta_time_sec)
342 elapsed_sec += delta_time_sec;
343 if (elapsed_sec < min_step_sec) {
347 if (subsystem->is_suspended()) {
352 subsystem->update(elapsed_sec);
354 } catch (sg_exception& e) {
355 SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
356 << "\nmessage:" << e.getMessage());
358 if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
359 SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
361 subsystem->suspend();
368 SGSubsystemGroup::Member::printTimingInformation(double time)
370 if (collectTimeStats) {
371 SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert : " << time << " " << name);
372 subsystem->printTimingInformation();
376 double SGSubsystemGroup::Member::getTimeWarningThreshold()
378 return (timeStat.mean() + 3 * timeStat.stdDev());
381 void SGSubsystemGroup::Member::updateExecutionTime(double time)
383 if (collectTimeStats) {
392 ////////////////////////////////////////////////////////////////////////
393 // Implementation of SGSubsystemMgr.
394 ////////////////////////////////////////////////////////////////////////
397 SGSubsystemMgr::SGSubsystemMgr ()
399 for (int i = 0; i < MAX_GROUPS; i++) {
400 _groups[i] = new SGSubsystemGroup;
404 SGSubsystemMgr::~SGSubsystemMgr ()
406 // ensure get_subsystem returns NULL from now onwards,
407 // before the SGSubsystemGroup destructors are run
408 _subsystem_map.clear();
410 for (int i = 0; i < MAX_GROUPS; i++) {
416 SGSubsystemMgr::init ()
418 for (int i = 0; i < MAX_GROUPS; i++)
423 SGSubsystemMgr::postinit ()
425 for (int i = 0; i < MAX_GROUPS; i++)
426 _groups[i]->postinit();
430 SGSubsystemMgr::reinit ()
432 for (int i = 0; i < MAX_GROUPS; i++)
433 _groups[i]->reinit();
437 SGSubsystemMgr::shutdown ()
439 // reverse order to prevent order dependency problems
440 for (int i = MAX_GROUPS-1; i >= 0; i--)
441 _groups[i]->shutdown();
446 SGSubsystemMgr::bind ()
448 for (int i = 0; i < MAX_GROUPS; i++)
453 SGSubsystemMgr::unbind ()
455 // reverse order to prevent order dependency problems
456 for (int i = MAX_GROUPS-1; i >= 0; i--)
457 _groups[i]->unbind();
461 SGSubsystemMgr::update (double delta_time_sec)
463 for (int i = 0; i < MAX_GROUPS; i++) {
464 _groups[i]->update(delta_time_sec);
469 SGSubsystemMgr::collectDebugTiming(bool collect)
471 for (int i = 0; i < MAX_GROUPS; i++) {
472 _groups[i]->collectDebugTiming(collect);
477 SGSubsystemMgr::suspend ()
479 for (int i = 0; i < MAX_GROUPS; i++)
480 _groups[i]->suspend();
484 SGSubsystemMgr::resume ()
486 for (int i = 0; i < MAX_GROUPS; i++)
487 _groups[i]->resume();
491 SGSubsystemMgr::is_suspended () const
497 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
498 GroupType group, double min_time_sec)
500 SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
501 get_group(group)->set_subsystem(name, subsystem, min_time_sec);
503 if (_subsystem_map.find(name) != _subsystem_map.end()) {
504 SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
505 throw sg_exception("duplicate subsystem");
507 _subsystem_map[name] = subsystem;
511 SGSubsystemMgr::remove(const char* name)
513 SubsystemDict::iterator s =_subsystem_map.find(name);
514 if (s == _subsystem_map.end()) {
518 SGSubsystem* sub = s->second;
519 _subsystem_map.erase(s);
521 // tedious part - we don't know which group the subsystem belongs too
522 for (int i = 0; i < MAX_GROUPS; i++) {
523 if (_groups[i]->get_subsystem(name) == sub) {
524 _groups[i]->remove_subsystem(name);
527 } // of groups iteration
534 SGSubsystemMgr::get_group (GroupType group)
536 return _groups[group];
540 SGSubsystemMgr::get_subsystem (const string &name) const
542 SubsystemDict::const_iterator s =_subsystem_map.find(name);
544 if (s == _subsystem_map.end())