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).
This commit is contained in:
durk
2007-11-17 09:16:58 +00:00
parent 084a24e958
commit 240ed6f0b1
7 changed files with 550 additions and 10 deletions

View 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)

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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

View 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;
}
}
////////////////////////////////////////////////////////////////////////
@@ -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 ()
{

View 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];