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>
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)
315 // This shouldn't be called due to subsystem pointer ownership issues.
316 SGSubsystemGroup::Member::Member (const Member &)
320 SGSubsystemGroup::Member::~Member ()
326 SGSubsystemGroup::Member::update (double delta_time_sec)
328 elapsed_sec += delta_time_sec;
329 if (elapsed_sec >= min_step_sec) {
330 if (!subsystem->is_suspended()) {
331 subsystem->update(elapsed_sec);
339 SGSubsystemGroup::Member::printTimingInformation(double time)
341 if (collectTimeStats) {
342 SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert : " << time << " " << name);
343 subsystem->printTimingInformation();
347 double SGSubsystemGroup::Member::getTimeWarningThreshold()
349 return (timeStat.mean() + 3 * timeStat.stdDev());
352 void SGSubsystemGroup::Member::updateExecutionTime(double time)
354 if (collectTimeStats) {
363 ////////////////////////////////////////////////////////////////////////
364 // Implementation of SGSubsystemMgr.
365 ////////////////////////////////////////////////////////////////////////
368 SGSubsystemMgr::SGSubsystemMgr ()
372 SGSubsystemMgr::~SGSubsystemMgr ()
377 SGSubsystemMgr::init ()
379 for (int i = 0; i < MAX_GROUPS; i++)
384 SGSubsystemMgr::postinit ()
386 for (int i = 0; i < MAX_GROUPS; i++)
387 _groups[i].postinit();
391 SGSubsystemMgr::reinit ()
393 for (int i = 0; i < MAX_GROUPS; i++)
398 SGSubsystemMgr::bind ()
400 for (int i = 0; i < MAX_GROUPS; i++)
405 SGSubsystemMgr::unbind ()
407 // reverse order to prevent order dependency problems
408 for (int i = MAX_GROUPS-1; i >= 0; i--)
413 SGSubsystemMgr::update (double delta_time_sec)
415 for (int i = 0; i < MAX_GROUPS; i++) {
416 _groups[i].update(delta_time_sec);
421 SGSubsystemMgr::collectDebugTiming(bool collect)
423 for (int i = 0; i < MAX_GROUPS; i++) {
424 _groups[i].collectDebugTiming(collect);
429 SGSubsystemMgr::suspend ()
431 for (int i = 0; i < MAX_GROUPS; i++)
432 _groups[i].suspend();
436 SGSubsystemMgr::resume ()
438 for (int i = 0; i < MAX_GROUPS; i++)
443 SGSubsystemMgr::is_suspended () const
449 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
450 GroupType group, double min_time_sec)
452 SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
453 get_group(group)->set_subsystem(name, subsystem, min_time_sec);
455 if (_subsystem_map.find(name) != _subsystem_map.end()) {
456 SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
457 throw sg_exception("duplicate subsystem");
459 _subsystem_map[name] = subsystem;
463 SGSubsystemMgr::get_group (GroupType group)
465 return &(_groups[group]);
469 SGSubsystemMgr::get_subsystem (const string &name)
471 map<string,SGSubsystem *>::iterator s =_subsystem_map.find(name);
473 if (s == _subsystem_map.end())