X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fstructure%2Fsubsystem_mgr.cxx;h=1e1425528e1a94f595e7b4de4e088c188b15d9a3;hb=a60d293759ef26d03d3dc7198561808e56db9b61;hp=1385d8eab493a5181e2b94f837be431bfeb22eb4;hpb=7e7ce2f38e87d6244e05730fa4382da088bb25f1;p=simgear.git diff --git a/simgear/structure/subsystem_mgr.cxx b/simgear/structure/subsystem_mgr.cxx index 1385d8ea..1e142552 100644 --- a/simgear/structure/subsystem_mgr.cxx +++ b/simgear/structure/subsystem_mgr.cxx @@ -1,3 +1,26 @@ +// Written by David Megginson, started 2000-12 +// +// Copyright (C) 2000 David Megginson, david@megginson.com +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif #include #include @@ -5,12 +28,19 @@ #include "exception.hxx" #include "subsystem_mgr.hxx" +#include +#include "SGSmplstat.hxx" + +const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4; + +using std::string; - //////////////////////////////////////////////////////////////////////// // Implementation of SGSubsystem //////////////////////////////////////////////////////////////////////// +SGSubsystemTimingCb SGSubsystem::reportTimingCb = NULL; +void* SGSubsystem::reportTimingUserData = NULL; SGSubsystem::SGSubsystem () : _suspended(false) @@ -26,6 +56,13 @@ SGSubsystem::init () { } +SGSubsystem::InitStatus +SGSubsystem::incrementalInit () +{ + init(); + return INIT_DONE; +} + void SGSubsystem::postinit () { @@ -36,6 +73,11 @@ SGSubsystem::reinit () { } +void +SGSubsystem::shutdown () +{ +} + void SGSubsystem::bind () { @@ -70,28 +112,6 @@ SGSubsystem::is_suspended () const return _suspended; } - -void -SGSubsystem::printTimingInformation () -{ - SGTimeStamp startTime; - for ( eventTimeVecIterator i = timingInfo.begin(); - i != timingInfo.end(); - i++) { - if (i == timingInfo.begin()) { - startTime = i->getTime(); - } else { - SGTimeStamp endTime = i->getTime(); - SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp : " - << i->getName() << " takes " << endTime - startTime - << " sec."); - startTime = endTime; - } - } -} - - - void SGSubsystem::stamp(const string& name) { timingInfo.push_back(TimingInfo(name, SGTimeStamp::now())); @@ -102,16 +122,44 @@ void SGSubsystem::stamp(const string& name) // Implementation of SGSubsystemGroup. //////////////////////////////////////////////////////////////////////// -SGSubsystemGroup::SGSubsystemGroup () +class SGSubsystemGroup::Member +{ +private: + Member (const Member &member); +public: + Member (); + virtual ~Member (); + + virtual void update (double delta_time_sec); + + void reportTiming(void) { if (reportTimingCb) reportTimingCb(reportTimingUserData, name, &timeStat); } + void updateExecutionTime(double time) { timeStat += time;} + + SampleStatistic timeStat; + std::string name; + SGSubsystem * subsystem; + double min_step_sec; + double elapsed_sec; + bool collectTimeStats; + int exceptionCount; + int initTime; +}; + + + +SGSubsystemGroup::SGSubsystemGroup () : + _fixedUpdateTime(-1.0), + _updateTimeRemainder(0.0), + _initPosition(0) { } SGSubsystemGroup::~SGSubsystemGroup () { - for (unsigned int i = 0; i < _members.size(); i++) + // reverse order to prevent order dependency problems + for (unsigned int i = _members.size(); i > 0; i--) { - _members[i]->printTimingStatistics(); - delete _members[i]; + delete _members[i-1]; } } @@ -122,6 +170,23 @@ SGSubsystemGroup::init () _members[i]->subsystem->init(); } +SGSubsystem::InitStatus +SGSubsystemGroup::incrementalInit() +{ + if (_initPosition >= _members.size()) + return INIT_DONE; + + SGTimeStamp st; + st.stamp(); + InitStatus memberStatus = _members[_initPosition]->subsystem->incrementalInit(); + _members[_initPosition]->initTime += st.elapsedMSec(); + + if (memberStatus == INIT_DONE) + ++_initPosition; + + return INIT_CONTINUE; +} + void SGSubsystemGroup::postinit () { @@ -136,6 +201,15 @@ SGSubsystemGroup::reinit () _members[i]->subsystem->reinit(); } +void +SGSubsystemGroup::shutdown () +{ + // reverse order to prevent order dependency problems + for (unsigned int i = _members.size(); i > 0; i--) + _members[i-1]->subsystem->shutdown(); + _initPosition = 0; +} + void SGSubsystemGroup::bind () { @@ -146,33 +220,50 @@ SGSubsystemGroup::bind () void SGSubsystemGroup::unbind () { - for (unsigned int i = 0; i < _members.size(); i++) - _members[i]->subsystem->unbind(); + // reverse order to prevent order dependency problems + for (unsigned int i = _members.size(); i > 0; i--) + _members[i-1]->subsystem->unbind(); } void SGSubsystemGroup::update (double delta_time_sec) { - for (unsigned int i = 0; i < _members.size(); i++) - { - SGTimeStamp timeStamp = SGTimeStamp::now(); - _members[i]->update(delta_time_sec); // indirect call - timeStamp = timeStamp - SGTimeStamp::now(); - double b = timeStamp.toUSecs(); - _members[i]->updateExecutionTime(b); - double threshold = _members[i]->getTimeWarningThreshold(); - if (( b > threshold ) && (b > 10000)) { - _members[i]->printTimingInformation(b); - } + int loopCount = 1; + // if dt == 0.0, we are paused, so we need to run one iteration + // of our members; if we have a fixed update time, we compute a + // loop count, and locally adjust dt + if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) { + double localDelta = delta_time_sec + _updateTimeRemainder; + loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime); + _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime); + delta_time_sec = _fixedUpdateTime; } + + bool recordTime = (reportTimingCb != NULL); + SGTimeStamp timeStamp; + while (loopCount-- > 0) { + for (unsigned int i = 0; i < _members.size(); i++) + { + if (recordTime) + timeStamp = SGTimeStamp::now(); + + _members[i]->update(delta_time_sec); // indirect call + + if ((recordTime)&&(reportTimingCb)) + { + timeStamp = SGTimeStamp::now() - timeStamp; + _members[i]->updateExecutionTime(timeStamp.toUSecs()); + } + } + } // of multiple update loop } -void -SGSubsystemGroup::collectDebugTiming(bool collect) +void +SGSubsystemGroup::reportTiming(void) { - for (unsigned int i = 0; i < _members.size(); i++) + for (unsigned int i = _members.size(); i > 0; i--) { - _members[i]->collectDebugTiming(collect); + _members[i-1]->reportTiming(); } } @@ -190,6 +281,16 @@ SGSubsystemGroup::resume () _members[i]->subsystem->resume(); } +string_list +SGSubsystemGroup::member_names() const +{ + string_list result; + for (unsigned int i = 0; i < _members.size(); i++) + result.push_back( _members[i]->name ); + + return result; +} + bool SGSubsystemGroup::is_suspended () const { @@ -230,25 +331,11 @@ SGSubsystemGroup::remove_subsystem (const string &name) } void -SGSubsystemGroup::Member::printTimingStatistics () +SGSubsystemGroup::set_fixed_update_time(double dt) { - if (collectTimeStats) { - double minTime = timeStat.min() / 1000; - double maxTime = timeStat.max() / 1000; - double meanTime = timeStat.mean() / 1000; - double stddev = timeStat.stdDev() / 1000; - - char buffer[256]; - snprintf(buffer, 256, "Timing summary for %20s.\n" - "- mean time: %04.2f ms.\n" - "- min time : %04.2f ms.\n" - "- max time : %04.2f ms.\n" - "- stddev : %04.2f ms.\n", name.c_str(), meanTime, minTime, maxTime, stddev); - SG_LOG(SG_GENERAL, SG_ALERT, buffer); - } + _fixedUpdateTime = dt; } - bool SGSubsystemGroup::has_subsystem (const string &name) const { @@ -283,7 +370,8 @@ SGSubsystemGroup::Member::Member () subsystem(0), min_step_sec(0), elapsed_sec(0), - collectTimeStats(false) + exceptionCount(0), + initTime(0) { } @@ -301,101 +389,119 @@ void SGSubsystemGroup::Member::update (double delta_time_sec) { elapsed_sec += delta_time_sec; - if (elapsed_sec >= min_step_sec) { - if (!subsystem->is_suspended()) { - subsystem->update(elapsed_sec); - elapsed_sec = 0; - } + if (elapsed_sec < min_step_sec) { + return; } -} - - -void -SGSubsystemGroup::Member::printTimingInformation(double time) -{ - if (collectTimeStats) { - SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert : " << time << " " << name); - subsystem->printTimingInformation(); - } -} - -double SGSubsystemGroup::Member::getTimeWarningThreshold() -{ - return (timeStat.mean() + 3 * timeStat.stdDev()); -} - -void SGSubsystemGroup::Member::updateExecutionTime(double time) -{ - if (collectTimeStats) { - timeStat += time; + + if (subsystem->is_suspended()) { + return; + } + + try { + subsystem->update(elapsed_sec); + elapsed_sec = 0; + } catch (sg_exception& e) { + SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name + << "\nmessage:" << e.getMessage()); + + if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) { + SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount << + ", suspending)"); + subsystem->suspend(); + } } } - - - //////////////////////////////////////////////////////////////////////// // Implementation of SGSubsystemMgr. //////////////////////////////////////////////////////////////////////// -SGSubsystemMgr::SGSubsystemMgr () +SGSubsystemMgr::SGSubsystemMgr () : + _initPosition(0) { + for (int i = 0; i < MAX_GROUPS; i++) { + _groups[i] = new SGSubsystemGroup; + } } SGSubsystemMgr::~SGSubsystemMgr () { + // ensure get_subsystem returns NULL from now onwards, + // before the SGSubsystemGroup destructors are run + _subsystem_map.clear(); + + for (int i = 0; i < MAX_GROUPS; i++) { + delete _groups[i]; + } } void SGSubsystemMgr::init () { for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].init(); + _groups[i]->init(); +} + +SGSubsystem::InitStatus +SGSubsystemMgr::incrementalInit() +{ + if (_initPosition >= MAX_GROUPS) + return INIT_DONE; + + InitStatus memberStatus = _groups[_initPosition]->incrementalInit(); + if (memberStatus == INIT_DONE) + ++_initPosition; + + return INIT_CONTINUE; } void SGSubsystemMgr::postinit () { for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].postinit(); + _groups[i]->postinit(); } void SGSubsystemMgr::reinit () { for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].reinit(); + _groups[i]->reinit(); } void -SGSubsystemMgr::bind () +SGSubsystemMgr::shutdown () { - for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].bind(); + // reverse order to prevent order dependency problems + for (int i = MAX_GROUPS-1; i >= 0; i--) + _groups[i]->shutdown(); + + _initPosition = 0; } + void -SGSubsystemMgr::unbind () +SGSubsystemMgr::bind () { for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].unbind(); + _groups[i]->bind(); } void -SGSubsystemMgr::update (double delta_time_sec) +SGSubsystemMgr::unbind () { - for (int i = 0; i < MAX_GROUPS; i++) { - _groups[i].update(delta_time_sec); - } + // reverse order to prevent order dependency problems + for (int i = MAX_GROUPS-1; i >= 0; i--) + _groups[i]->unbind(); } -void -SGSubsystemMgr::collectDebugTiming(bool collect) +void +SGSubsystemMgr::update (double delta_time_sec) { for (int i = 0; i < MAX_GROUPS; i++) { - _groups[i].collectDebugTiming(collect); + _groups[i]->update(delta_time_sec); } } @@ -403,14 +509,14 @@ void SGSubsystemMgr::suspend () { for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].suspend(); + _groups[i]->suspend(); } void SGSubsystemMgr::resume () { for (int i = 0; i < MAX_GROUPS; i++) - _groups[i].resume(); + _groups[i]->resume(); } bool @@ -433,16 +539,39 @@ SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem, _subsystem_map[name] = subsystem; } +SGSubsystem* +SGSubsystemMgr::remove(const char* name) +{ + SubsystemDict::iterator s =_subsystem_map.find(name); + if (s == _subsystem_map.end()) { + return NULL; + } + + SGSubsystem* sub = s->second; + _subsystem_map.erase(s); + +// tedious part - we don't know which group the subsystem belongs too + for (int i = 0; i < MAX_GROUPS; i++) { + if (_groups[i]->get_subsystem(name) == sub) { + _groups[i]->remove_subsystem(name); + break; + } + } // of groups iteration + + return sub; +} + + SGSubsystemGroup * SGSubsystemMgr::get_group (GroupType group) { - return &(_groups[group]); + return _groups[group]; } SGSubsystem * -SGSubsystemMgr::get_subsystem (const string &name) +SGSubsystemMgr::get_subsystem (const string &name) const { - map::iterator s =_subsystem_map.find(name); + SubsystemDict::const_iterator s =_subsystem_map.find(name); if (s == _subsystem_map.end()) return 0; @@ -450,4 +579,13 @@ SGSubsystemMgr::get_subsystem (const string &name) return s->second; } -// end of fgfs.cxx +/** Trigger the timing callback to report data for all subsystems. */ +void +SGSubsystemMgr::reportTiming() +{ + for (int i = 0; i < MAX_GROUPS; i++) { + _groups[i]->reportTiming(); + } // of groups iteration +} + +// end of subsystem_mgr.cxx