]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.cxx
Make subsystem group destruction explicit, so get_subsystem calls during destruction...
[simgear.git] / simgear / structure / subsystem_mgr.cxx
1
2 #include <simgear/debug/logstream.hxx>
3 #include <simgear/timing/timestamp.hxx>
4
5 #include "exception.hxx"
6 #include "subsystem_mgr.hxx"
7
8 #include <simgear/math/SGMath.hxx>
9
10
11 const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;\f
12 ////////////////////////////////////////////////////////////////////////
13 // Implementation of SGSubsystem
14 ////////////////////////////////////////////////////////////////////////
15
16
17 SGSubsystem::SGSubsystem ()
18   : _suspended(false)
19 {
20 }
21
22 SGSubsystem::~SGSubsystem ()
23 {
24 }
25
26 void
27 SGSubsystem::init ()
28 {
29 }
30
31 void
32 SGSubsystem::postinit ()
33 {
34 }
35
36 void
37 SGSubsystem::reinit ()
38 {
39 }
40
41 void
42 SGSubsystem::bind ()
43 {
44 }
45
46 void
47 SGSubsystem::unbind ()
48 {
49 }
50
51 void
52 SGSubsystem::suspend ()
53 {
54   _suspended = true;
55 }
56
57 void
58 SGSubsystem::suspend (bool suspended)
59 {
60   _suspended = suspended;
61 }
62
63 void
64 SGSubsystem::resume ()
65 {
66   _suspended = false;
67 }
68
69 bool
70 SGSubsystem::is_suspended () const
71 {
72   return _suspended;
73 }
74
75
76 void
77 SGSubsystem::printTimingInformation ()
78 {
79    SGTimeStamp startTime;
80    for ( eventTimeVecIterator i = timingInfo.begin();
81           i != timingInfo.end();
82           i++) {
83        if (i == timingInfo.begin()) {
84            startTime = i->getTime();
85        } else {
86            SGTimeStamp endTime = i->getTime();
87            SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp :   "
88                   << i->getName() << " takes " << endTime - startTime
89                   << " sec.");
90            startTime = endTime;
91        }
92    }
93 }
94
95
96
97 void SGSubsystem::stamp(const string& name)
98 {
99     timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
100 }
101
102 \f
103 ////////////////////////////////////////////////////////////////////////
104 // Implementation of SGSubsystemGroup.
105 ////////////////////////////////////////////////////////////////////////
106
107 SGSubsystemGroup::SGSubsystemGroup () :
108   _fixedUpdateTime(-1.0),
109   _updateTimeRemainder(0.0)
110 {
111 }
112
113 SGSubsystemGroup::~SGSubsystemGroup ()
114 {
115     // reverse order to prevent order dependency problems
116     for (unsigned int i = _members.size(); i > 0; i--)
117     {
118         _members[i-1]->printTimingStatistics();
119         delete _members[i-1];
120     }
121 }
122
123 void
124 SGSubsystemGroup::init ()
125 {
126     for (unsigned int i = 0; i < _members.size(); i++)
127         _members[i]->subsystem->init();
128 }
129
130 void
131 SGSubsystemGroup::postinit ()
132 {
133     for (unsigned int i = 0; i < _members.size(); i++)
134         _members[i]->subsystem->postinit();
135 }
136
137 void
138 SGSubsystemGroup::reinit ()
139 {
140     for (unsigned int i = 0; i < _members.size(); i++)
141         _members[i]->subsystem->reinit();
142 }
143
144 void
145 SGSubsystemGroup::bind ()
146 {
147     for (unsigned int i = 0; i < _members.size(); i++)
148         _members[i]->subsystem->bind();
149 }
150
151 void
152 SGSubsystemGroup::unbind ()
153 {
154     // reverse order to prevent order dependency problems
155     for (unsigned int i = _members.size(); i > 0; i--)
156        _members[i-1]->subsystem->unbind();
157 }
158
159 void
160 SGSubsystemGroup::update (double delta_time_sec)
161 {
162     int loopCount = 1;
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;
171     }
172
173     while (loopCount-- > 0) {
174       for (unsigned int i = 0; i < _members.size(); i++)
175       {
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);
184            }
185       }
186     } // of multiple update loop
187 }
188
189 void 
190 SGSubsystemGroup::collectDebugTiming(bool collect)
191 {
192     for (unsigned int i = 0; i < _members.size(); i++)
193     {
194         _members[i]->collectDebugTiming(collect);
195     }
196 }
197
198 void
199 SGSubsystemGroup::suspend ()
200 {
201     for (unsigned int i = 0; i < _members.size(); i++)
202         _members[i]->subsystem->suspend();
203 }
204
205 void
206 SGSubsystemGroup::resume ()
207 {
208     for (unsigned int i = 0; i < _members.size(); i++)
209         _members[i]->subsystem->resume();
210 }
211
212 bool
213 SGSubsystemGroup::is_suspended () const
214 {
215     return false;
216 }
217
218 void
219 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
220                                  double min_step_sec)
221 {
222     Member * member = get_member(name, true);
223     if (member->subsystem != 0)
224         delete member->subsystem;
225     member->name = name;
226     member->subsystem = subsystem;
227     member->min_step_sec = min_step_sec;
228 }
229
230 SGSubsystem *
231 SGSubsystemGroup::get_subsystem (const string &name)
232 {
233     Member * member = get_member(name);
234     if (member != 0)
235         return member->subsystem;
236     else
237         return 0;
238 }
239
240 void
241 SGSubsystemGroup::remove_subsystem (const string &name)
242 {
243     for (unsigned int i = 0; i < _members.size(); i++) {
244         if (name == _members[i]->name) {
245             _members.erase(_members.begin() + i);
246             return;
247         }
248     }
249 }
250
251 void
252 SGSubsystemGroup::set_fixed_update_time(double dt)
253 {
254   _fixedUpdateTime = dt;
255 }
256
257 void
258 SGSubsystemGroup::Member::printTimingStatistics ()
259 {
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;
265
266         char buffer[256];
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);
273     }
274 }
275
276
277 bool
278 SGSubsystemGroup::has_subsystem (const string &name) const
279 {
280     return (((SGSubsystemGroup *)this)->get_member(name) != 0);
281 }
282
283 SGSubsystemGroup::Member *
284 SGSubsystemGroup::get_member (const string &name, bool create)
285 {
286     for (unsigned int i = 0; i < _members.size(); i++) {
287         if (_members[i]->name == name)
288             return _members[i];
289     }
290     if (create) {
291         Member * member = new Member;
292         _members.push_back(member);
293         return member;
294     } else {
295         return 0;
296     }
297 }
298
299
300 \f
301 ////////////////////////////////////////////////////////////////////////
302 // Implementation of SGSubsystemGroup::Member
303 ////////////////////////////////////////////////////////////////////////
304
305
306 SGSubsystemGroup::Member::Member ()
307     : name(""),
308       subsystem(0),
309       min_step_sec(0),
310       elapsed_sec(0),
311       collectTimeStats(false),
312       exceptionCount(0)
313 {
314 }
315
316 // This shouldn't be called due to subsystem pointer ownership issues.
317 SGSubsystemGroup::Member::Member (const Member &)
318 {
319 }
320
321 SGSubsystemGroup::Member::~Member ()
322 {
323     delete subsystem;
324 }
325
326 void
327 SGSubsystemGroup::Member::update (double delta_time_sec)
328 {
329     elapsed_sec += delta_time_sec;
330     if (elapsed_sec < min_step_sec) {
331         return;
332     }
333     
334     if (subsystem->is_suspended()) {
335         return;
336     }
337     
338     try {
339       subsystem->update(elapsed_sec);
340       elapsed_sec = 0;
341     } catch (sg_exception& e) {
342       SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
343         << "\nmessage:" << e.getMessage());
344       
345       if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
346         SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
347           ", suspending)");
348         subsystem->suspend();
349       }
350     }
351 }
352
353
354 void 
355 SGSubsystemGroup::Member::printTimingInformation(double time)
356 {
357      if (collectTimeStats) {
358          SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert : " << time << " " << name);
359          subsystem->printTimingInformation();
360      }
361 }
362
363 double SGSubsystemGroup::Member::getTimeWarningThreshold()
364 {
365     return (timeStat.mean() + 3 * timeStat.stdDev());
366 }
367
368 void SGSubsystemGroup::Member::updateExecutionTime(double time)
369 {
370     if (collectTimeStats) {
371         timeStat += time;
372     }
373 }
374
375
376
377
378 \f
379 ////////////////////////////////////////////////////////////////////////
380 // Implementation of SGSubsystemMgr.
381 ////////////////////////////////////////////////////////////////////////
382
383
384 SGSubsystemMgr::SGSubsystemMgr ()
385 {
386   for (int i = 0; i < MAX_GROUPS; i++) {
387     _groups[i] = new SGSubsystemGroup;
388   }
389 }
390
391 SGSubsystemMgr::~SGSubsystemMgr ()
392 {
393   // ensure get_subsystem returns NULL from now onwards,
394   // before the SGSubsystemGroup destructors are run
395   _subsystem_map.clear();
396   
397   for (int i = 0; i < MAX_GROUPS; i++) {
398     delete _groups[i];
399   }
400 }
401
402 void
403 SGSubsystemMgr::init ()
404 {
405     for (int i = 0; i < MAX_GROUPS; i++)
406             _groups[i]->init();
407 }
408
409 void
410 SGSubsystemMgr::postinit ()
411 {
412     for (int i = 0; i < MAX_GROUPS; i++)
413             _groups[i]->postinit();
414 }
415
416 void
417 SGSubsystemMgr::reinit ()
418 {
419     for (int i = 0; i < MAX_GROUPS; i++)
420             _groups[i]->reinit();
421 }
422
423 void
424 SGSubsystemMgr::bind ()
425 {
426     for (int i = 0; i < MAX_GROUPS; i++)
427         _groups[i]->bind();
428 }
429
430 void
431 SGSubsystemMgr::unbind ()
432 {
433     // reverse order to prevent order dependency problems
434     for (int i = MAX_GROUPS-1; i >= 0; i--)
435         _groups[i]->unbind();
436 }
437
438 void
439 SGSubsystemMgr::update (double delta_time_sec)
440 {
441     for (int i = 0; i < MAX_GROUPS; i++) {
442         _groups[i]->update(delta_time_sec);
443     }
444 }
445
446 void 
447 SGSubsystemMgr::collectDebugTiming(bool collect)
448 {
449     for (int i = 0; i < MAX_GROUPS; i++) {
450         _groups[i]->collectDebugTiming(collect);
451     }
452 }
453
454 void
455 SGSubsystemMgr::suspend ()
456 {
457     for (int i = 0; i < MAX_GROUPS; i++)
458         _groups[i]->suspend();
459 }
460
461 void
462 SGSubsystemMgr::resume ()
463 {
464     for (int i = 0; i < MAX_GROUPS; i++)
465         _groups[i]->resume();
466 }
467
468 bool
469 SGSubsystemMgr::is_suspended () const
470 {
471     return false;
472 }
473
474 void
475 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
476                      GroupType group, double min_time_sec)
477 {
478     SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
479     get_group(group)->set_subsystem(name, subsystem, min_time_sec);
480
481     if (_subsystem_map.find(name) != _subsystem_map.end()) {
482         SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
483         throw sg_exception("duplicate subsystem");
484     }
485     _subsystem_map[name] = subsystem;
486 }
487
488 SGSubsystem* 
489 SGSubsystemMgr::remove(const char* name)
490 {
491   SubsystemDict::iterator s =_subsystem_map.find(name);
492   if (s == _subsystem_map.end()) {
493     return NULL;
494   }
495   
496   SGSubsystem* sub = s->second;
497   _subsystem_map.erase(s);
498   
499 // tedious part - we don't know which group the subsystem belongs too
500   for (int i = 0; i < MAX_GROUPS; i++) {
501     if (_groups[i]->get_subsystem(name) == sub) {
502       _groups[i]->remove_subsystem(name);
503       break;
504     }
505   } // of groups iteration
506   
507   return sub;
508 }
509
510
511 SGSubsystemGroup *
512 SGSubsystemMgr::get_group (GroupType group)
513 {
514     return _groups[group];
515 }
516
517 SGSubsystem *
518 SGSubsystemMgr::get_subsystem (const string &name) const
519 {
520     SubsystemDict::const_iterator s =_subsystem_map.find(name);
521
522     if (s == _subsystem_map.end())
523         return 0;
524     else
525         return s->second;
526 }
527
528 // end of fgfs.cxx