diff --git a/src/libCom/test/cvtFastPerform.cpp b/src/libCom/test/cvtFastPerform.cpp index 164643965..cb0d64c9d 100644 --- a/src/libCom/test/cvtFastPerform.cpp +++ b/src/libCom/test/cvtFastPerform.cpp @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #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; }