]> git.mxchange.org Git - simgear.git/commitdiff
Refined debug timing control:
authordurk <durk>
Sat, 17 Nov 2007 09:16:58 +0000 (09:16 +0000)
committerdurk <durk>
Sat, 17 Nov 2007 09:16:58 +0000 (09:16 +0000)
 - 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).

simgear/structure/Makefile.am
simgear/structure/SGSmplhist.cxx [new file with mode: 0644]
simgear/structure/SGSmplhist.hxx [new file with mode: 0644]
simgear/structure/SGSmplstat.cxx [new file with mode: 0644]
simgear/structure/SGSmplstat.hxx [new file with mode: 0644]
simgear/structure/subsystem_mgr.cxx
simgear/structure/subsystem_mgr.hxx

index 5468f2b72b900463c22f8a5fcca3d46dda486940..15a31033c9a7774bd1235addee746c0e89322a0c 100644 (file)
@@ -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 (file)
index 0000000..73b3f55
--- /dev/null
@@ -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 <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;
+       }
+    }
+}
diff --git a/simgear/structure/SGSmplhist.hxx b/simgear/structure/SGSmplhist.hxx
new file mode 100644 (file)
index 0000000..d56d669
--- /dev/null
@@ -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 <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
diff --git a/simgear/structure/SGSmplstat.cxx b/simgear/structure/SGSmplstat.cxx
new file mode 100644 (file)
index 0000000..6c1afde
--- /dev/null
@@ -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 <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));
+}
diff --git a/simgear/structure/SGSmplstat.hxx b/simgear/structure/SGSmplstat.hxx
new file mode 100644 (file)
index 0000000..1d1e8d5
--- /dev/null
@@ -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
index 2adf0e7841176c00bbe93bb5e960c929fb0a8437..00f17b38acefee08a24c03af5ea797e3d98b8021 100644 (file)
@@ -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;
+    }
+}
+
+
+
 
 \f
 ////////////////////////////////////////////////////////////////////////
@@ -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 ()
 {
index a4844903c4f2e897cf9efa00d7292fdb7cea9860..c5823e9a25bfc23939897069bc73de880c1a6b1a 100644 (file)
@@ -47,6 +47,7 @@ SG_USING_STD(string);
 
 #include <simgear/props/props.hxx>
 #include <simgear/timing/timestamp.hxx>
+#include "SGSmplstat.hxx"
 
 
 class TimingInfo
@@ -256,9 +257,34 @@ public:
    */
   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:
@@ -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];