- 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).
SGAtomic.hxx \
SGBinding.hxx \
SGReferenced.hxx \
- SGSharedPtr.hxx
+ SGSharedPtr.hxx \
+ SGSmplhist.hxx \
+ SGSmplstat.hxx
libsgstructure_a_SOURCES = \
commands.cxx \
event_mgr.cxx\
subsystem_mgr.cxx \
SGAtomic.cxx \
- SGBinding.cxx
+ SGBinding.cxx \
+ SGSmplhist.cxx \
+ SGSmplstat.cxx
INCLUDES = -I$(top_srcdir)
--- /dev/null
+// 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 <iostream>
+#include <fstream>
+#include "SGSmplhist.hxx"
+#include <math.h>
+
+#ifndef HUGE_VAL
+#ifdef HUGE
+#define HUGE_VAL HUGE
+#else
+#include <float.h>
+#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;
+ }
+ }
+}
--- /dev/null
+// 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 <simgear_config.h>
+#endif
+#ifndef SampleHistogram_h
+#ifdef __GNUG__
+#pragma interface
+#endif
+#define SampleHistogram_h 1
+
+#include <iostream>
+#include <fstream>
+#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
--- /dev/null
+// 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 <math.h>
+
+#ifndef HUGE_VAL
+#ifdef HUGE
+#define HUGE_VAL HUGE
+#else
+#include <float.h>
+#define HUGE_VAL DBL_MAX
+#endif
+#endif
+
+
+#include <iostream>
+#include <fstream>
+#include <simgear/debug/logstream.hxx>
+#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));
+}
--- /dev/null
+// 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
}
}
+
+
void SGSubsystem::stamp(string name)
{
SGTimeStamp now;
SGSubsystemGroup::~SGSubsystemGroup ()
{
for (unsigned int i = 0; i < _members.size(); i++)
+ {
+ _members[i]->printTimingStatistics();
delete _members[i];
+ }
}
void
_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 ()
{
}
}
+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
{
: name(""),
subsystem(0),
min_step_sec(0),
- elapsed_sec(0)
+ elapsed_sec(0),
+ collectTimeStats(false)
{
}
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;
+ }
+}
+
+
+
\f
////////////////////////////////////////////////////////////////////////
}
}
+void
+SGSubsystemMgr::collectDebugTiming(bool collect)
+{
+ for (int i = 0; i < MAX_GROUPS; i++) {
+ _groups[i].collectDebugTiming(collect);
+ }
+}
+
void
SGSubsystemMgr::suspend ()
{
#include <simgear/props/props.hxx>
#include <simgear/timing/timestamp.hxx>
+#include "SGSmplstat.hxx"
class TimingInfo
*/
virtual bool is_suspended () const;
+
+ /**
+ * Keep track of execution time.
+ *
+ * <p>This method keeps track of timing statistics for each subsystem.</p>
+ *
+ * @param time execution time in ms of last call.
+ */
+ void updateExecutionTime(double time);
+
+ /**
+ * Print details of execution time.
+ *
+ * <p>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</p>
+ */
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:
virtual void remove_subsystem (const string &name);
virtual bool has_subsystem (const string &name) const;
+ void collectDebugTiming(bool collect);
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);
virtual SGSubsystem * get_subsystem(const string &name);
+ void collectDebugTiming(bool collect);
+
private:
SGSubsystemGroup _groups[MAX_GROUPS];