More cvtFastPerform changes
Added a converter using std::streambuf (slow!) Pass buffer size to converters Added verbose flag and # numbers to measure Do the small number tests first
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
|
||||
#include "epicsStdio.h"
|
||||
#include "cvtFast.h"
|
||||
@@ -17,7 +19,7 @@ class PerfConverter {
|
||||
public:
|
||||
virtual const char *_name(void) const = 0;
|
||||
virtual int _maxPrecision(void) const = 0;
|
||||
virtual void _target (double srcD, float srcF, char *pDst, int prec) const = 0;
|
||||
virtual void _target (double srcD, float srcF, char *dst, size_t len, int prec) const = 0;
|
||||
virtual void _add(int prec, double elapsed) = 0;
|
||||
virtual double _total(int prec) const = 0;
|
||||
virtual ~PerfConverter () {};
|
||||
@@ -28,7 +30,7 @@ public:
|
||||
Perf ( int maxConverters );
|
||||
virtual ~Perf ();
|
||||
void addConverter( PerfConverter * c );
|
||||
void execute ();
|
||||
void execute (int count, bool verbose);
|
||||
void report (const char *title, int count);
|
||||
protected:
|
||||
static unsigned const _nUnrolled = 10;
|
||||
@@ -39,6 +41,7 @@ protected:
|
||||
PerfConverter **_converters;
|
||||
int _nConverters;
|
||||
int _maxPrecision;
|
||||
bool _verbose;
|
||||
|
||||
void _measure ( double srcD, float srcF, int prec );
|
||||
|
||||
@@ -75,11 +78,24 @@ void Perf :: addConverter(PerfConverter *c)
|
||||
_maxPrecision = prec;
|
||||
}
|
||||
|
||||
void Perf :: execute ()
|
||||
void Perf :: execute (int count, bool verbose)
|
||||
{
|
||||
const int count = 10;
|
||||
_verbose = verbose;
|
||||
|
||||
for ( unsigned i = 0; i < count; i++ ) {
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
double srcDbl = rand ();
|
||||
srcDbl /= (RAND_MAX + 1.0);
|
||||
srcDbl *= 20.0;
|
||||
srcDbl -= 10.0;
|
||||
float srcFlt = (float) srcDbl;
|
||||
|
||||
for ( int prec = 0; prec <= _maxPrecision; prec++ ) {
|
||||
_measure (srcFlt, srcDbl, prec);
|
||||
}
|
||||
}
|
||||
report ( "Small numbers, -10..+10", count );
|
||||
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
double mVal = rand ();
|
||||
mVal /= (RAND_MAX + 1.0);
|
||||
double eVal = rand ();
|
||||
@@ -96,47 +112,34 @@ void Perf :: execute ()
|
||||
_measure (srcFlt, srcDbl, prec);
|
||||
}
|
||||
}
|
||||
report ( "Random Exponent", count );
|
||||
|
||||
for ( unsigned i = 0; i < count; i++ ) {
|
||||
double srcDbl = rand ();
|
||||
srcDbl /= (RAND_MAX + 1.0);
|
||||
srcDbl *= 10.0;
|
||||
srcDbl -= 5.0;
|
||||
float srcFlt = (float) srcDbl;
|
||||
|
||||
for ( int prec = 0; prec <= _maxPrecision; prec++ ) {
|
||||
_measure (srcFlt, srcDbl, prec);
|
||||
}
|
||||
}
|
||||
report ( "-5..+5", count );
|
||||
report ( "Random mantissa+exponent", count );
|
||||
}
|
||||
|
||||
void Perf :: report (const char *title, int count)
|
||||
{
|
||||
printf( "\n%s\n\nprec\t", title );
|
||||
for ( int j = 0; j < _nConverters; j++ )
|
||||
printf( "%-17s ", _converters[j]->_name() );
|
||||
printf( "%-16s ", _converters[j]->_name() );
|
||||
|
||||
for (int prec = 0; prec < _maxPrecision; prec++ ) {
|
||||
printf( "\n %2d\t", prec );
|
||||
for (int prec = 0; prec <= _maxPrecision; prec++ ) {
|
||||
printf( "\n %2d\t", prec );
|
||||
for (int j = 0; j < _nConverters; j++ ) {
|
||||
PerfConverter *c = _converters[j];
|
||||
if (prec > c->_maxPrecision())
|
||||
printf( "%11s ", "-" );
|
||||
else {
|
||||
double total = c->_total(prec);
|
||||
printf( "%11.9f sec ", c->_total(prec) / count );
|
||||
c->_add(prec, -total); // Reset counter
|
||||
}
|
||||
}
|
||||
if (prec > c->_maxPrecision())
|
||||
printf( "%11s ", "-" );
|
||||
else {
|
||||
double total = c->_total(prec);
|
||||
printf( "%11.9f sec ", c->_total(prec) / count );
|
||||
c->_add(prec, -total); // Reset counter
|
||||
}
|
||||
}
|
||||
}
|
||||
printf( "\n\n" );
|
||||
}
|
||||
|
||||
void Perf :: _measure (double srcD, float srcF, int prec)
|
||||
{
|
||||
char pDst[40];
|
||||
char buf[40];
|
||||
|
||||
for ( int j = 0; j < _nConverters; j++ ) {
|
||||
PerfConverter *c = _converters[j];
|
||||
@@ -144,17 +147,21 @@ void Perf :: _measure (double srcD, float srcF, int prec)
|
||||
if (prec > c->_maxPrecision())
|
||||
continue;
|
||||
|
||||
std::memset(buf, 0, sizeof(buf));
|
||||
|
||||
epicsTime beg = epicsTime :: getCurrent ();
|
||||
for ( unsigned i = 0; i < _nIterations; i++ ) {
|
||||
c->_target (srcD, srcF, pDst, prec);
|
||||
c->_target (srcD, srcF, buf, sizeof(buf), prec);
|
||||
}
|
||||
epicsTime end = epicsTime :: getCurrent ();
|
||||
|
||||
double elapsed = end - beg;
|
||||
elapsed /= _nIterations * _nUnrolled;
|
||||
c->_add( prec, elapsed );
|
||||
// printf ( "%17s: %11.9f sec, prec=%2i '%s'\n",
|
||||
// c->_name (), elapsed, prec, pDst );
|
||||
c->_add( prec, elapsed );
|
||||
|
||||
if (_verbose)
|
||||
printf ( "%17s: %11.9f sec, prec=%2i '%s'\n",
|
||||
c->_name (), elapsed, prec, buf );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,19 +169,19 @@ class PerfCvtFastFloat : public PerfConverter {
|
||||
public:
|
||||
const char *_name (void) const { return "cvtFloatToString"; }
|
||||
int _maxPrecision (void) const { return 12; }
|
||||
void _target (double srcD, float srcF, char *pDst, int prec) const
|
||||
void _target (double srcD, float srcF, char *dst, size_t len, int prec) const
|
||||
{
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, pDst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
cvtFloatToString ( srcF, dst, prec );
|
||||
}
|
||||
void _add(int prec, double elapsed) { _measured[prec] += elapsed; }
|
||||
double _total (int prec) const { return _measured[prec]; }
|
||||
@@ -187,19 +194,19 @@ class PerfCvtFastDouble : public PerfConverter {
|
||||
public:
|
||||
const char *_name (void) const { return "cvtDoubleToString"; }
|
||||
int _maxPrecision (void) const { return 17; }
|
||||
void _target (double srcD, float srcF, char *pDst, int prec) const
|
||||
void _target (double srcD, float srcF, char *dst, size_t len, int prec) const
|
||||
{
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, pDst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
cvtDoubleToString ( srcD, dst, prec );
|
||||
}
|
||||
void _add(int prec, double elapsed) { _measured[prec] += elapsed; }
|
||||
double _total (int prec) const { return _measured[prec]; }
|
||||
@@ -212,19 +219,66 @@ class PerfSNPrintf : public PerfConverter {
|
||||
public:
|
||||
const char *_name (void) const { return "epicsSnprintf"; }
|
||||
int _maxPrecision (void) const { return 17; }
|
||||
void _target (double srcD, float srcF, char *pDst, int prec) const
|
||||
void _target (double srcD, float srcF, char *dst, size_t len, int prec) const
|
||||
{
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( pDst, 39, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
epicsSnprintf ( dst, len, "%.*g", prec, srcD );
|
||||
}
|
||||
void _add(int prec, double elapsed) { _measured[prec] += elapsed; }
|
||||
double _total (int prec) const { return _measured[prec]; }
|
||||
private:
|
||||
double _measured[18];
|
||||
};
|
||||
|
||||
|
||||
// This is a quick-and-dirty std::streambuf converter that writes directly
|
||||
// into the output buffer. Performance is slower than epicsSnprintf().
|
||||
|
||||
struct membuf: public std::streambuf {
|
||||
membuf(char *array, size_t size) {
|
||||
this->setp(array, array + size - 1);
|
||||
}
|
||||
};
|
||||
|
||||
struct omemstream: virtual membuf, std::ostream {
|
||||
omemstream(char *array, size_t size):
|
||||
membuf(array, size),
|
||||
std::ostream(this) {
|
||||
}
|
||||
};
|
||||
|
||||
static void ossConvertD(char *dst, size_t len, int prec, double src) {
|
||||
omemstream oss(dst, len);
|
||||
oss.precision(prec);
|
||||
oss << src << ends;
|
||||
}
|
||||
|
||||
class PerfStreamBuf : public PerfConverter {
|
||||
public:
|
||||
const char *_name (void) const { return "std::streambuf"; }
|
||||
int _maxPrecision (void) const { return 17; }
|
||||
void _target (double srcD, float srcF, char *dst, size_t len, int prec) const
|
||||
{
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
ossConvertD ( dst, len, prec, srcD );
|
||||
}
|
||||
void _add(int prec, double elapsed) { _measured[prec] += elapsed; }
|
||||
double _total (int prec) const { return _measured[prec]; }
|
||||
@@ -235,13 +289,16 @@ private:
|
||||
|
||||
MAIN(cvtFastPerform)
|
||||
{
|
||||
Perf t(3);
|
||||
Perf t(4);
|
||||
|
||||
t.addConverter( new PerfCvtFastFloat );
|
||||
t.addConverter( new PerfCvtFastDouble );
|
||||
t.addConverter( new PerfSNPrintf );
|
||||
t.addConverter( new PerfStreamBuf );
|
||||
|
||||
t.execute ();
|
||||
// count = number of different random numbers to measure
|
||||
// verbose = whether to display individual measurements
|
||||
t.execute (10, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user