From: durk Date: Sat, 17 Nov 2007 09:16:58 +0000 (+0000) Subject: Refined debug timing control: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=240ed6f0b11d8b7ff84ca101078ef17ac6123784;p=simgear.git Refined debug timing control: - Added a SampleStatistic class (from the old deprecated libg++) library. - Make time statistics and printing conditionable - Added an interface function to switch time stamp collection and printing on and off from the application (defaults to off). --- diff --git a/simgear/structure/Makefile.am b/simgear/structure/Makefile.am index 5468f2b7..15a31033 100644 --- a/simgear/structure/Makefile.am +++ b/simgear/structure/Makefile.am @@ -11,7 +11,9 @@ include_HEADERS = \ SGAtomic.hxx \ SGBinding.hxx \ SGReferenced.hxx \ - SGSharedPtr.hxx + SGSharedPtr.hxx \ + SGSmplhist.hxx \ + SGSmplstat.hxx libsgstructure_a_SOURCES = \ commands.cxx \ @@ -19,7 +21,9 @@ libsgstructure_a_SOURCES = \ event_mgr.cxx\ subsystem_mgr.cxx \ SGAtomic.cxx \ - SGBinding.cxx + SGBinding.cxx \ + SGSmplhist.cxx \ + SGSmplstat.cxx INCLUDES = -I$(top_srcdir) diff --git a/simgear/structure/SGSmplhist.cxx b/simgear/structure/SGSmplhist.cxx new file mode 100644 index 00000000..73b3f553 --- /dev/null +++ b/simgear/structure/SGSmplhist.cxx @@ -0,0 +1,122 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988 Free Software Foundation + written by Dirk Grunwald (grunwald@cs.uiuc.edu) + +This file is part of the GNU C++ Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library 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 Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifdef __GNUG__ +#pragma implementation +#endif +#include +#include +#include "SGSmplhist.hxx" +#include + +#ifndef HUGE_VAL +#ifdef HUGE +#define HUGE_VAL HUGE +#else +#include +#define HUGE_VAL DBL_MAX +#endif +#endif + +const int SampleHistogramMinimum = -2; +const int SampleHistogramMaximum = -1; + +SampleHistogram::SampleHistogram (double low, double high, double width) +{ + if (high < low) + { + double t = high; + high = low; + low = t; + } + + if (width == -1) + { + width = (high - low) / 10; + } + + howManyBuckets = int ((high - low) / width) + 2; + bucketCount = new int[howManyBuckets]; + bucketLimit = new double[howManyBuckets]; + double lim = low; + for (int i = 0; i < howManyBuckets; i++) + { + bucketCount[i] = 0; + bucketLimit[i] = lim; + lim += width; + } + bucketLimit[howManyBuckets - 1] = HUGE_VAL; /* from math.h */ +} + +SampleHistogram::~SampleHistogram () +{ + if (howManyBuckets > 0) + { + delete[]bucketCount; + delete[]bucketLimit; + } +} + +void SampleHistogram::operator += (double value) +{ + int i; + for (i = 0; i < howManyBuckets; i++) + { + if (value < bucketLimit[i]) + break; + } + bucketCount[i]++; + this->SampleStatistic::operator += (value); +} + +int SampleHistogram::similarSamples (double d) +{ + int i; + for (i = 0; i < howManyBuckets; i++) + { + if (d < bucketLimit[i]) + return (bucketCount[i]); + } + return (0); +} + +void SampleHistogram::printBuckets (ostream & s) +{ + for (int i = 0; i < howManyBuckets; i++) + { + if (bucketLimit[i] >= HUGE_VAL) + { + s << "< max : " << bucketCount[i] << "\n"; + } + else + { + s << "< " << bucketLimit[i] << " : " << bucketCount[i] << "\n"; + } + } +} + +void SampleHistogram::reset () +{ + this->SampleStatistic::reset (); + if (howManyBuckets > 0) + { + for (register int i = 0; i < howManyBuckets; i++) + { + bucketCount[i] = 0; + } + } +} diff --git a/simgear/structure/SGSmplhist.hxx b/simgear/structure/SGSmplhist.hxx new file mode 100644 index 00000000..d56d6693 --- /dev/null +++ b/simgear/structure/SGSmplhist.hxx @@ -0,0 +1,83 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988 Free Software Foundation + written by Dirk Grunwald (grunwald@cs.uiuc.edu) + +This file is part of the GNU C++ Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library 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 Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifndef SampleHistogram_h +#ifdef __GNUG__ +#pragma interface +#endif +#define SampleHistogram_h 1 + +#include +#include +#include "SGSmplstat.hxx" + +using namespace std; + +extern const int SampleHistogramMinimum; +extern const int SampleHistogramMaximum; + +class SampleHistogram:public SampleStatistic +{ +protected: + short howManyBuckets; + int *bucketCount; + double *bucketLimit; + +public: + + SampleHistogram (double low, double hi, double bucketWidth = -1.0); + + ~SampleHistogram (); + + virtual void reset (); + virtual void operator += (double); + + int similarSamples (double); + + int buckets (); + + double bucketThreshold (int i); + int inBucket (int i); + void printBuckets (ostream &); + +}; + + +inline int SampleHistogram::buckets () +{ + return (howManyBuckets); +}; + +inline double SampleHistogram::bucketThreshold (int i) +{ + if (i < 0 || i >= howManyBuckets) + error ("invalid bucket access"); + return (bucketLimit[i]); +} + +inline int SampleHistogram::inBucket (int i) +{ + if (i < 0 || i >= howManyBuckets) + error ("invalid bucket access"); + return (bucketCount[i]); +} + +#endif diff --git a/simgear/structure/SGSmplstat.cxx b/simgear/structure/SGSmplstat.cxx new file mode 100644 index 00000000..6c1afde7 --- /dev/null +++ b/simgear/structure/SGSmplstat.cxx @@ -0,0 +1,152 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988 Free Software Foundation + written by Dirk Grunwald (grunwald@cs.uiuc.edu) + +This file is part of the GNU C++ Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library 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 Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifdef __GNUG__ +#pragma implementation +#endif + +#include + +#ifndef HUGE_VAL +#ifdef HUGE +#define HUGE_VAL HUGE +#else +#include +#define HUGE_VAL DBL_MAX +#endif +#endif + + +#include +#include +#include +#include "SGSmplstat.hxx" + + +void SampleStatistic::error (const char *msg) +{ + SG_LOG(SG_GENERAL, SG_ALERT, msg); +} + +// t-distribution: given p-value and degrees of freedom, return t-value +// adapted from Peizer & Pratt JASA, vol63, p1416 + +double tval (double p, int df) +{ + double t; + int positive = p >= 0.5; + p = (positive) ? 1.0 - p : p; + if (p <= 0.0 || df <= 0) + t = HUGE_VAL; + else if (p == 0.5) + t = 0.0; + else if (df == 1) + t = 1.0 / tan ((p + p) * 1.57079633); + else if (df == 2) + t = sqrt (1.0 / ((p + p) * (1.0 - p)) - 2.0); + else + { + double ddf = df; + double a = sqrt (log (1.0 / (p * p))); + double aa = a * a; + a = a - ((2.515517 + (0.802853 * a) + (0.010328 * aa)) / + (1.0 + (1.432788 * a) + (0.189269 * aa) + + (0.001308 * aa * a))); + t = ddf - 0.666666667 + 1.0 / (10.0 * ddf); + t = sqrt (ddf * (exp (a * a * (ddf - 0.833333333) / (t * t)) - 1.0)); + } + return (positive) ? t : -t; +} + +void SampleStatistic::reset () +{ + n = 0; + x = x2 = 0.0; + maxValue = -HUGE_VAL; + minValue = HUGE_VAL; +} + +void SampleStatistic::operator += (double value) +{ + n += 1; + x += value; + x2 += (value * value); + if (minValue > value) + minValue = value; + if (maxValue < value) + maxValue = value; +} + +double SampleStatistic::mean () const +{ + if (n > 0) + { + return (x / n); + } + else + { + return (0.0); + } +} + +double SampleStatistic::var () const +{ + if (n > 1) + { + return ((x2 - ((x * x) / n)) / (n - 1)); + } + else + { + return (0.0); + } +} + +double SampleStatistic::stdDev () const +{ + if (n <= 0 || this->var () <= 0) + { + return (0); + } + else + { + return ((double) sqrt (var ())); + } +} + +double SampleStatistic::confidence (int interval) const +{ + int df = n - 1; + if (df <= 0) + return HUGE_VAL; + double t = tval (double (100 + interval) * 0.005, df); + if (t == HUGE_VAL) + return t; + else + return (t * stdDev ()) / sqrt (double (n)); +} + +double SampleStatistic::confidence (double p_value) const +{ + int df = n - 1; + if (df <= 0) + return HUGE_VAL; + double t = tval ((1.0 + p_value) * 0.5, df); + if (t == HUGE_VAL) + return t; + else + return (t * stdDev ()) / sqrt (double (n)); +} diff --git a/simgear/structure/SGSmplstat.hxx b/simgear/structure/SGSmplstat.hxx new file mode 100644 index 00000000..1d1e8d57 --- /dev/null +++ b/simgear/structure/SGSmplstat.hxx @@ -0,0 +1,84 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988 Free Software Foundation + written by Dirk Grunwald (grunwald@cs.uiuc.edu) + +This file is part of the GNU C++ Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library 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 Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef SampleStatistic_h +#ifdef __GNUG__ +#pragma interface +#endif +#define SampleStatistic_h 1 + + +#undef min +#undef max + +using namespace std; + +class SampleStatistic +{ +protected: + int n; + double x; + double x2; + double minValue, maxValue; + +public: SampleStatistic (); + inline virtual ~ SampleStatistic (); + virtual void reset (); + + virtual void operator += (double); + int samples () const; + double mean () const; + double stdDev () const; + double var () const; + double min () const; + double max () const; + double confidence (int p_percentage) const; + double confidence (double p_value) const; + + void error (const char *msg); +}; + +// error handlers + +//extern void default_SampleStatistic_error_handler (const char *); +//extern one_arg_error_handler_t SampleStatistic_error_handler; + +//extern one_arg_error_handler_t +//set_SampleStatistic_error_handler (one_arg_error_handler_t f); + +inline SampleStatistic::SampleStatistic () +{ + reset (); +} +inline int SampleStatistic::samples () const +{ + return (n); +} +inline double SampleStatistic::min () const +{ + return (minValue); +} +inline double SampleStatistic::max () const +{ + return (maxValue); +} + +inline SampleStatistic::~SampleStatistic () +{ +} + +#endif diff --git a/simgear/structure/subsystem_mgr.cxx b/simgear/structure/subsystem_mgr.cxx index 2adf0e78..00f17b38 100644 --- a/simgear/structure/subsystem_mgr.cxx +++ b/simgear/structure/subsystem_mgr.cxx @@ -90,6 +90,8 @@ SGSubsystem::printTimingInformation () } } + + void SGSubsystem::stamp(string name) { SGTimeStamp now; @@ -109,7 +111,10 @@ SGSubsystemGroup::SGSubsystemGroup () SGSubsystemGroup::~SGSubsystemGroup () { for (unsigned int i = 0; i < _members.size(); i++) + { + _members[i]->printTimingStatistics(); delete _members[i]; + } } void @@ -157,14 +162,23 @@ SGSubsystemGroup::update (double delta_time_sec) _members[i]->update(delta_time_sec); // indirect call now.stamp(); long b = ( now - start ); - if ( b > 10000 ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem Timing Alert : " << b << " " << _members[i]->name); - //int a = 1; - _members[i]->printTimingInformation(); + _members[i]->updateExecutionTime(b); + double threshold = _members[i]->getTimeWarningThreshold(); + if (( b > threshold ) && (b > 10000)) { + _members[i]->printTimingInformation(b); } } } +void +SGSubsystemGroup::collectDebugTiming(bool collect) +{ + for (unsigned int i = 0; i < _members.size(); i++) + { + _members[i]->collectDebugTiming(collect); + } +} + void SGSubsystemGroup::suspend () { @@ -218,6 +232,26 @@ SGSubsystemGroup::remove_subsystem (const string &name) } } +void +SGSubsystemGroup::Member::printTimingStatistics () +{ + 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); + } +} + + bool SGSubsystemGroup::has_subsystem (const string &name) const { @@ -251,7 +285,8 @@ SGSubsystemGroup::Member::Member () : name(""), subsystem(0), min_step_sec(0), - elapsed_sec(0) + elapsed_sec(0), + collectTimeStats(false) { } @@ -279,11 +314,28 @@ SGSubsystemGroup::Member::update (double delta_time_sec) void -SGSubsystemGroup::Member::printTimingInformation() +SGSubsystemGroup::Member::printTimingInformation(double time) { - subsystem->printTimingInformation(); + 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; + } +} + + + //////////////////////////////////////////////////////////////////////// @@ -342,6 +394,14 @@ SGSubsystemMgr::update (double delta_time_sec) } } +void +SGSubsystemMgr::collectDebugTiming(bool collect) +{ + for (int i = 0; i < MAX_GROUPS; i++) { + _groups[i].collectDebugTiming(collect); + } +} + void SGSubsystemMgr::suspend () { diff --git a/simgear/structure/subsystem_mgr.hxx b/simgear/structure/subsystem_mgr.hxx index a4844903..c5823e9a 100644 --- a/simgear/structure/subsystem_mgr.hxx +++ b/simgear/structure/subsystem_mgr.hxx @@ -47,6 +47,7 @@ SG_USING_STD(string); #include #include +#include "SGSmplstat.hxx" class TimingInfo @@ -256,9 +257,34 @@ public: */ virtual bool is_suspended () const; + + /** + * Keep track of execution time. + * + *

This method keeps track of timing statistics for each subsystem.

+ * + * @param time execution time in ms of last call. + */ + void updateExecutionTime(double time); + + /** + * Print details of execution time. + * + *

For debugging purposes, developers can place stamp() calls + * at strategic points in the update() function of each subsystem, which + * record the time between the successive calls to stamp. This method, + * printExecutionTime() is called after exectution of the subsystem + * update function itself to conduct a post-hoc analysis of excecution + * time

+ */ void printTimingInformation(); + /** + * Place time stamps at strategic points in the execution of subsystems + * update() member functions. Predominantly for debugging purposes. + */ void stamp(string name); + protected: @@ -299,6 +325,7 @@ public: virtual void remove_subsystem (const string &name); virtual bool has_subsystem (const string &name) const; + void collectDebugTiming(bool collect); private: @@ -309,12 +336,18 @@ private: virtual ~Member (); virtual void update (double delta_time_sec); - void printTimingInformation(); + void printTimingInformation(double time); + void printTimingStatistics(); + void updateExecutionTime(double time); + double getTimeWarningThreshold(); + void collectDebugTiming (bool collect) { collectTimeStats = collect; }; + SampleStatistic timeStat; string name; SGSubsystem * subsystem; double min_step_sec; double elapsed_sec; + bool collectTimeStats; }; Member * get_member (const string &name, bool create = false); @@ -376,6 +409,8 @@ public: virtual SGSubsystem * get_subsystem(const string &name); + void collectDebugTiming(bool collect); + private: SGSubsystemGroup _groups[MAX_GROUPS];