]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.cxx
std:: namespace fixes, and sink some code from the subsystem header into the implemen...
[simgear.git] / simgear / structure / subsystem_mgr.cxx
1 // Written by David Megginson, started 2000-12
2 //
3 // Copyright (C) 2000  David Megginson, david@megginson.com
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 // $Id$
20
21 #ifdef HAVE_CONFIG_H
22 #  include <simgear_config.h>
23 #endif
24
25 #include <simgear/debug/logstream.hxx>
26 #include <simgear/timing/timestamp.hxx>
27
28 #include "exception.hxx"
29 #include "subsystem_mgr.hxx"
30
31 #include <simgear/math/SGMath.hxx>
32 #include "SGSmplstat.hxx"
33
34 const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;\f
35 ////////////////////////////////////////////////////////////////////////
36 // Implementation of SGSubsystem
37 ////////////////////////////////////////////////////////////////////////
38
39
40 SGSubsystem::SGSubsystem ()
41   : _suspended(false)
42 {
43 }
44
45 SGSubsystem::~SGSubsystem ()
46 {
47 }
48
49 void
50 SGSubsystem::init ()
51 {
52 }
53
54 void
55 SGSubsystem::postinit ()
56 {
57 }
58
59 void
60 SGSubsystem::reinit ()
61 {
62 }
63
64 void
65 SGSubsystem::shutdown ()
66 {
67 }
68
69 void
70 SGSubsystem::bind ()
71 {
72 }
73
74 void
75 SGSubsystem::unbind ()
76 {
77 }
78
79 void
80 SGSubsystem::suspend ()
81 {
82   _suspended = true;
83 }
84
85 void
86 SGSubsystem::suspend (bool suspended)
87 {
88   _suspended = suspended;
89 }
90
91 void
92 SGSubsystem::resume ()
93 {
94   _suspended = false;
95 }
96
97 bool
98 SGSubsystem::is_suspended () const
99 {
100   return _suspended;
101 }
102
103
104 void
105 SGSubsystem::printTimingInformation ()
106 {
107    SGTimeStamp startTime;
108    for ( eventTimeVecIterator i = timingInfo.begin();
109           i != timingInfo.end();
110           ++i) {
111        if (i == timingInfo.begin()) {
112            startTime = i->getTime();
113        } else {
114            SGTimeStamp endTime = i->getTime();
115            SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp :   "
116                   << i->getName() << " takes " << endTime - startTime
117                   << " sec.");
118            startTime = endTime;
119        }
120    }
121 }
122
123
124
125 void SGSubsystem::stamp(const string& name)
126 {
127     timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
128 }
129
130 \f
131 ////////////////////////////////////////////////////////////////////////
132 // Implementation of SGSubsystemGroup.
133 ////////////////////////////////////////////////////////////////////////
134
135 class SGSubsystemGroup::Member
136 {    
137 private:
138     Member (const Member &member);
139 public:
140     Member ();
141     virtual ~Member ();
142     
143     virtual void update (double delta_time_sec);
144     void printTimingInformation(double time);
145     void printTimingStatistics(double minMaxTime=0.0,double minJitter=0.0);
146     void updateExecutionTime(double time);
147     double getTimeWarningThreshold();
148     void collectDebugTiming (bool collect) { collectTimeStats = collect; };
149     
150     SampleStatistic timeStat;
151     std::string name;
152     SGSubsystem * subsystem;
153     double min_step_sec;
154     double elapsed_sec;
155     bool collectTimeStats;
156     int exceptionCount;
157 };
158
159
160
161 SGSubsystemGroup::SGSubsystemGroup () :
162   _fixedUpdateTime(-1.0),
163   _updateTimeRemainder(0.0)
164 {
165 }
166
167 SGSubsystemGroup::~SGSubsystemGroup ()
168 {
169     printTimingStatistics();
170
171     // reverse order to prevent order dependency problems
172     for (unsigned int i = _members.size(); i > 0; i--)
173     {
174         delete _members[i-1];
175     }
176 }
177
178 void
179 SGSubsystemGroup::init ()
180 {
181     for (unsigned int i = 0; i < _members.size(); i++)
182         _members[i]->subsystem->init();
183 }
184
185 void
186 SGSubsystemGroup::postinit ()
187 {
188     for (unsigned int i = 0; i < _members.size(); i++)
189         _members[i]->subsystem->postinit();
190 }
191
192 void
193 SGSubsystemGroup::reinit ()
194 {
195     for (unsigned int i = 0; i < _members.size(); i++)
196         _members[i]->subsystem->reinit();
197 }
198
199 void
200 SGSubsystemGroup::shutdown ()
201 {
202     // reverse order to prevent order dependency problems
203     for (unsigned int i = _members.size(); i > 0; i--)
204         _members[i-1]->subsystem->shutdown();
205 }
206
207 void
208 SGSubsystemGroup::bind ()
209 {
210     for (unsigned int i = 0; i < _members.size(); i++)
211         _members[i]->subsystem->bind();
212 }
213
214 void
215 SGSubsystemGroup::unbind ()
216 {
217     // reverse order to prevent order dependency problems
218     for (unsigned int i = _members.size(); i > 0; i--)
219        _members[i-1]->subsystem->unbind();
220 }
221
222 void
223 SGSubsystemGroup::update (double delta_time_sec)
224 {
225     int loopCount = 1;
226     // if dt == 0.0, we are paused, so we need to run one iteration
227     // of our members; if we have a fixed update time, we compute a
228     // loop count, and locally adjust dt
229     if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
230       double localDelta = delta_time_sec + _updateTimeRemainder;
231       loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
232       _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
233       delta_time_sec = _fixedUpdateTime;
234     }
235
236     while (loopCount-- > 0) {
237       for (unsigned int i = 0; i < _members.size(); i++)
238       {
239            SGTimeStamp timeStamp = SGTimeStamp::now();
240            _members[i]->update(delta_time_sec); // indirect call
241            timeStamp = SGTimeStamp::now() - timeStamp;
242            double b = timeStamp.toUSecs();
243            _members[i]->updateExecutionTime(b);
244            double threshold = _members[i]->getTimeWarningThreshold();
245            if (( b > threshold ) && (b > 10000)) {
246                _members[i]->printTimingInformation(b);
247            }
248       }
249     } // of multiple update loop
250 }
251
252 void 
253 SGSubsystemGroup::collectDebugTiming(bool collect)
254 {
255     for (unsigned int i = 0; i < _members.size(); i++)
256     {
257         _members[i]->collectDebugTiming(collect);
258     }
259 }
260
261 void 
262 SGSubsystemGroup::printTimingStatistics(double minMaxTime,double minJitter)
263 {
264     for (unsigned int i = _members.size(); i > 0; i--)
265     {
266         _members[i-1]->printTimingStatistics(minMaxTime, minJitter);
267         _members[i-1]->timeStat.reset();
268     }
269 }
270
271 void
272 SGSubsystemGroup::suspend ()
273 {
274     for (unsigned int i = 0; i < _members.size(); i++)
275         _members[i]->subsystem->suspend();
276 }
277
278 void
279 SGSubsystemGroup::resume ()
280 {
281     for (unsigned int i = 0; i < _members.size(); i++)
282         _members[i]->subsystem->resume();
283 }
284
285 bool
286 SGSubsystemGroup::is_suspended () const
287 {
288     return false;
289 }
290
291 void
292 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
293                                  double min_step_sec)
294 {
295     Member * member = get_member(name, true);
296     if (member->subsystem != 0)
297         delete member->subsystem;
298     member->name = name;
299     member->subsystem = subsystem;
300     member->min_step_sec = min_step_sec;
301 }
302
303 SGSubsystem *
304 SGSubsystemGroup::get_subsystem (const string &name)
305 {
306     Member * member = get_member(name);
307     if (member != 0)
308         return member->subsystem;
309     else
310         return 0;
311 }
312
313 void
314 SGSubsystemGroup::remove_subsystem (const string &name)
315 {
316     for (unsigned int i = 0; i < _members.size(); i++) {
317         if (name == _members[i]->name) {
318             _members.erase(_members.begin() + i);
319             return;
320         }
321     }
322 }
323
324 void
325 SGSubsystemGroup::set_fixed_update_time(double dt)
326 {
327   _fixedUpdateTime = dt;
328 }
329
330 /**
331  * Print timing statistics.
332  * Only show data if jitter exceeds minJitter or
333  * maximum time exceeds minMaxTime. 
334  */
335 void
336 SGSubsystemGroup::Member::printTimingStatistics(double minMaxTime,double minJitter)
337 {
338     if (collectTimeStats) {
339         double minTime = timeStat.min()   / 1000;
340         double maxTime = timeStat.max()   / 1000;
341         double meanTime = timeStat.mean() / 1000;
342         double stddev   = timeStat.stdDev()   / 1000;
343
344         if ((maxTime - minTime >= minJitter)||
345             (maxTime >= minMaxTime))
346         {
347             char buffer[256];
348             snprintf(buffer, 256, "Timing summary for %20s.\n"
349                                   "-  mean time: %04.2f ms.\n"
350                                   "-  min time : %04.2f ms.\n"
351                                   "-  max time : %04.2f ms.\n"
352                                   "-  stddev   : %04.2f ms.\n", name.c_str(), meanTime, minTime, maxTime, stddev);
353             SG_LOG(SG_GENERAL, SG_ALERT, buffer);
354         }
355     }
356 }
357
358
359 bool
360 SGSubsystemGroup::has_subsystem (const string &name) const
361 {
362     return (((SGSubsystemGroup *)this)->get_member(name) != 0);
363 }
364
365 SGSubsystemGroup::Member *
366 SGSubsystemGroup::get_member (const string &name, bool create)
367 {
368     for (unsigned int i = 0; i < _members.size(); i++) {
369         if (_members[i]->name == name)
370             return _members[i];
371     }
372     if (create) {
373         Member * member = new Member;
374         _members.push_back(member);
375         return member;
376     } else {
377         return 0;
378     }
379 }
380
381
382 \f
383 ////////////////////////////////////////////////////////////////////////
384 // Implementation of SGSubsystemGroup::Member
385 ////////////////////////////////////////////////////////////////////////
386
387
388 SGSubsystemGroup::Member::Member ()
389     : name(""),
390       subsystem(0),
391       min_step_sec(0),
392       elapsed_sec(0),
393       collectTimeStats(false),
394       exceptionCount(0)
395 {
396 }
397
398 // This shouldn't be called due to subsystem pointer ownership issues.
399 SGSubsystemGroup::Member::Member (const Member &)
400 {
401 }
402
403 SGSubsystemGroup::Member::~Member ()
404 {
405     delete subsystem;
406 }
407
408 void
409 SGSubsystemGroup::Member::update (double delta_time_sec)
410 {
411     elapsed_sec += delta_time_sec;
412     if (elapsed_sec < min_step_sec) {
413         return;
414     }
415     
416     if (subsystem->is_suspended()) {
417         return;
418     }
419     
420     try {
421       subsystem->update(elapsed_sec);
422       elapsed_sec = 0;
423     } catch (sg_exception& e) {
424       SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
425         << "\nmessage:" << e.getMessage());
426       
427       if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
428         SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
429           ", suspending)");
430         subsystem->suspend();
431       }
432     }
433 }
434
435
436 void 
437 SGSubsystemGroup::Member::printTimingInformation(double time)
438 {
439      if (collectTimeStats) {
440          SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert, subsystem \"" << name << "\": " << time/1000.0 << "ms");
441          subsystem->printTimingInformation();
442      }
443 }
444
445 double SGSubsystemGroup::Member::getTimeWarningThreshold()
446 {
447     return (timeStat.mean() + 3 * timeStat.stdDev());
448 }
449
450 void SGSubsystemGroup::Member::updateExecutionTime(double time)
451 {
452     if (collectTimeStats) {
453         timeStat += time;
454     }
455 }
456
457
458
459
460 \f
461 ////////////////////////////////////////////////////////////////////////
462 // Implementation of SGSubsystemMgr.
463 ////////////////////////////////////////////////////////////////////////
464
465
466 SGSubsystemMgr::SGSubsystemMgr ()
467 {
468   for (int i = 0; i < MAX_GROUPS; i++) {
469     _groups[i] = new SGSubsystemGroup;
470   }
471 }
472
473 SGSubsystemMgr::~SGSubsystemMgr ()
474 {
475   // ensure get_subsystem returns NULL from now onwards,
476   // before the SGSubsystemGroup destructors are run
477   _subsystem_map.clear();
478   
479   for (int i = 0; i < MAX_GROUPS; i++) {
480     delete _groups[i];
481   }
482 }
483
484 void
485 SGSubsystemMgr::init ()
486 {
487     for (int i = 0; i < MAX_GROUPS; i++)
488             _groups[i]->init();
489 }
490
491 void
492 SGSubsystemMgr::postinit ()
493 {
494     for (int i = 0; i < MAX_GROUPS; i++)
495             _groups[i]->postinit();
496 }
497
498 void
499 SGSubsystemMgr::reinit ()
500 {
501     for (int i = 0; i < MAX_GROUPS; i++)
502             _groups[i]->reinit();
503 }
504
505 void
506 SGSubsystemMgr::shutdown ()
507 {
508     // reverse order to prevent order dependency problems
509     for (int i = MAX_GROUPS-1; i >= 0; i--)
510         _groups[i]->shutdown();
511 }
512
513
514 void
515 SGSubsystemMgr::bind ()
516 {
517     for (int i = 0; i < MAX_GROUPS; i++)
518         _groups[i]->bind();
519 }
520
521 void
522 SGSubsystemMgr::unbind ()
523 {
524     // reverse order to prevent order dependency problems
525     for (int i = MAX_GROUPS-1; i >= 0; i--)
526         _groups[i]->unbind();
527 }
528
529 void
530 SGSubsystemMgr::update (double delta_time_sec)
531 {
532     for (int i = 0; i < MAX_GROUPS; i++) {
533         _groups[i]->update(delta_time_sec);
534     }
535 }
536
537 void 
538 SGSubsystemMgr::collectDebugTiming(bool collect)
539 {
540     for (int i = 0; i < MAX_GROUPS; i++) {
541         _groups[i]->collectDebugTiming(collect);
542     }
543 }
544
545 void
546 SGSubsystemMgr::suspend ()
547 {
548     for (int i = 0; i < MAX_GROUPS; i++)
549         _groups[i]->suspend();
550 }
551
552 void
553 SGSubsystemMgr::resume ()
554 {
555     for (int i = 0; i < MAX_GROUPS; i++)
556         _groups[i]->resume();
557 }
558
559 bool
560 SGSubsystemMgr::is_suspended () const
561 {
562     return false;
563 }
564
565 void
566 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
567                      GroupType group, double min_time_sec)
568 {
569     SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
570     get_group(group)->set_subsystem(name, subsystem, min_time_sec);
571
572     if (_subsystem_map.find(name) != _subsystem_map.end()) {
573         SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
574         throw sg_exception("duplicate subsystem");
575     }
576     _subsystem_map[name] = subsystem;
577 }
578
579 SGSubsystem* 
580 SGSubsystemMgr::remove(const char* name)
581 {
582   SubsystemDict::iterator s =_subsystem_map.find(name);
583   if (s == _subsystem_map.end()) {
584     return NULL;
585   }
586   
587   SGSubsystem* sub = s->second;
588   _subsystem_map.erase(s);
589   
590 // tedious part - we don't know which group the subsystem belongs too
591   for (int i = 0; i < MAX_GROUPS; i++) {
592     if (_groups[i]->get_subsystem(name) == sub) {
593       _groups[i]->remove_subsystem(name);
594       break;
595     }
596   } // of groups iteration
597   
598   return sub;
599 }
600
601
602 SGSubsystemGroup *
603 SGSubsystemMgr::get_group (GroupType group)
604 {
605     return _groups[group];
606 }
607
608 SGSubsystem *
609 SGSubsystemMgr::get_subsystem (const string &name) const
610 {
611     SubsystemDict::const_iterator s =_subsystem_map.find(name);
612
613     if (s == _subsystem_map.end())
614         return 0;
615     else
616         return s->second;
617 }
618
619 void
620 SGSubsystemMgr::printTimingStatistics(double minMaxTime,double minJitter)
621 {
622     for (int i = 0; i < MAX_GROUPS; i++) {
623         _groups[i]->printTimingStatistics(minMaxTime, minJitter);
624     } // of groups iteration
625 }
626
627 // end of subsystem_mgr.cxx