5 Jul 10:08
[test] RFC: speed up BOOST_CHECK by not formatting the check description if it isn't written anywhere
From: =??B?Smn47SBQYWxl6GVr?= <jpalecek <at> web.de>
Subject: [test] RFC: speed up BOOST_CHECK by not formatting the check description if it isn't written anywhere
Newsgroups: gmane.comp.lib.boost.devel
Date: 2008-07-05 08:09:55 GMT
Subject: [test] RFC: speed up BOOST_CHECK by not formatting the check description if it isn't written anywhere
Newsgroups: gmane.comp.lib.boost.devel
Date: 2008-07-05 08:09:55 GMT
Hello,
I have a test that uses many BOOST_CHECKs (~ 10 thousands or so). Running that test is very slow and I have
noticed most of the time is spent by formatting the description string to be passed to check_impl, only to
be ignored, because I don't want to log successful checks (and they are successful).
I have improved this by using some kind of expression template for this (called lazy_output). It works like this:
lazy_output is a class that implements an expression template for "x << y << z" expressions. The expression
o << a << b << c << (make_lazy_output() << x << y << z)
is the same as
o << a << b << c << x << y << z
which is similar to
o << a << b << c << (wrap_stringstream().ref() << x << y << z).ref()
The difference is that, in the call f(make_lazy_output() << x << y << z), the data is formatted only if f
outputs them to an ostream.
This reduced the time needed for running my test from ~12 minutes to ~7 minutes. There is more room for
similar (but more complicated) improvements.
Any comments or suggestions?
Regards
Jiri Palecek
=== boost/test/lazy_output.hpp
==================================================================
--- boost/test/lazy_output.hpp (revision 4821)
+++ boost/test/lazy_output.hpp (revision 4822)
@@ -0,0 +1,74 @@
+#ifndef BOOST_TEST_LAZY_OUTPUT_HPP
+#define BOOST_TEST_LAZY_OUTPUT_HPP
+
+#include <iostream>
+
+namespace boost {
+ namespace unit_test {
+
+ class lazy_output
+ {
+ virtual void output(std::ostream& o) const=0;
+ public:
+ friend std::ostream& operator <<(std::ostream& o, const lazy_output& lo) {
+ lo.output(o);
+ return o;
+ }
+ };
+
+ class lazy_output_0 : public lazy_output
+ {
+ void output(std::ostream&) const {}
+ };
+
+ template <class T>
+ class lazy_output_1 : public lazy_output
+ {
+ const T& t_;
+ void output(std::ostream& o) const;
+ public:
+ lazy_output_1(const T& t) : t_(t) {}
+ };
+
+ template <class T, class Prev>
+ class lazy_output_2 : public lazy_output
+ {
+ const T& t_;
+ Prev p_;
+ void output(std::ostream& o) const;
+ public:
+ lazy_output_2(const T& t, const Prev& p) : t_(t), p_(p) {}
+ };
+
+ template <class T>
+ void lazy_output_1<T>::output(std::ostream& o) const {
+ o << t_;
+ }
+
+ template <class T, class Prev>
+ void lazy_output_2<T, Prev>::output(std::ostream& o) const {
+ o << p_;
+ o << t_;
+ }
+
+ lazy_output_0 make_lazy_output() { return lazy_output_0(); }
+
+ template <class T>
+ lazy_output_1<T> operator<<(lazy_output_0, const T& t) {
+ return lazy_output_1<T>(t);
+ }
+
+ template <class T, class U>
+ lazy_output_2<T, lazy_output_1<U> > operator<<(const lazy_output_1<U>& l, const T& t) {
+ return lazy_output_2<T, lazy_output_1<U> >(t, l);
+ }
+
+ template <class T, class U, class Prev>
+ lazy_output_2<T, lazy_output_2<U, Prev> > operator<<(const lazy_output_2<U, Prev>& l, const T& t) {
+ return lazy_output_2<T, lazy_output_2<U, Prev> >(t, l);
+ }
+
+ }
+}
+
+#endif
=== boost/test/impl/test_tools.ipp
==================================================================
--- boost/test/impl/test_tools.ipp (revision 4821)
+++ boost/test/impl/test_tools.ipp (revision 4822)
@@ -62,7 +62,7 @@
// ************************************************************************** //
void
-check_impl( predicate_result const& pr, wrap_stringstream& check_descr,
+check_impl( predicate_result const& pr, const lazy_output& check_descr,
const_string file_name, std::size_t line_num,
tool_level tl, check_type ct,
std::size_t num_of_args, ... )
@@ -107,7 +107,7 @@
switch( ct ) {
case CHECK_PRED:
unit_test_log << unit_test::log::begin( file_name, line_num )
- << ll << prefix << check_descr.str() << suffix;
+ << ll << prefix << check_descr << suffix;
if( !pr.has_empty_message() )
unit_test_log << ". " << pr.message();
@@ -119,9 +119,9 @@
unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
if( tl == PASS )
- unit_test_log << prefix << "'" << check_descr.str() << "'" << suffix;
+ unit_test_log << prefix << "'" << check_descr << "'" << suffix;
else
- unit_test_log << check_descr.str();
+ unit_test_log << check_descr;
if( !pr.has_empty_message() )
unit_test_log << ". " << pr.message();
@@ -216,7 +216,7 @@
case CHECK_PRED_WITH_ARGS: {
unit_test_log << unit_test::log::begin( file_name, line_num )
- << ll << prefix << check_descr.str();
+ << ll << prefix << check_descr;
// print predicate call description
{
=== boost/test/impl/unit_test_log.ipp
==================================================================
--- boost/test/impl/unit_test_log.ipp (revision 4821)
+++ boost/test/impl/unit_test_log.ipp (revision 4822)
@@ -352,6 +352,16 @@
return *this;
}
+unit_test_log_t&
+unit_test_log_t::operator<<( const lazy_output& value )
+{
+ if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level) {
+ return (*this) << (wrap_stringstream().ref() << value).str();
+ }
+
+ return *this;
+}
+
//____________________________________________________________________________//
void
=== boost/test/unit_test_log.hpp
==================================================================
--- boost/test/unit_test_log.hpp (revision 4821)
+++ boost/test/unit_test_log.hpp (revision 4822)
@@ -27,6 +27,7 @@
#include <boost/test/utils/wrap_stringstream.hpp>
#include <boost/test/utils/trivial_singleton.hpp>
+#include <boost/test/lazy_output.hpp>
// Boost
#include <boost/utility.hpp>
@@ -119,6 +120,7 @@
unit_test_log_t& operator<<( log::end const& ); // end entry
unit_test_log_t& operator<<( log_level ); // set entry level
unit_test_log_t& operator<<( const_string ); // log entry value
+ unit_test_log_t& operator<<( const lazy_output& ); // log entry value
ut_detail::entry_value_collector operator()( log_level ); // initiate entry collection
=== boost/test/test_tools.hpp
==================================================================
--- boost/test/test_tools.hpp (revision 4821)
+++ boost/test/test_tools.hpp (revision 4822)
@@ -49,6 +49,8 @@
#include <boost/test/detail/suppress_warnings.hpp>
+#include <boost/test/lazy_output.hpp>
+
//____________________________________________________________________________//
// ************************************************************************** //
@@ -69,7 +71,7 @@
#define BOOST_TEST_TOOL_IMPL( func, P, check_descr, TL, CT ) \
::boost::test_tools::tt_detail::func( \
P, \
- ::boost::wrap_stringstream().ref() << check_descr, \
+ make_lazy_output() << check_descr, \
BOOST_TEST_L(__FILE__), \
(std::size_t)__LINE__, \
::boost::test_tools::tt_detail::TL, \
@@ -460,7 +462,7 @@
// ************************************************************************** //
BOOST_TEST_DECL
-void check_impl( predicate_result const& pr, wrap_stringstream& check_descr,
+void check_impl( predicate_result const& pr, const boost::unit_test::lazy_output& check_descr,
const_string file_name, std::size_t line_num,
tool_level tl, check_type ct,
std::size_t num_args, ... );
@@ -486,7 +488,7 @@
template<typename Pred \
BOOST_PP_REPEAT_ ## z( BOOST_PP_ADD( n, 1 ), TEMPL_PARAMS, _ )> \
inline void \
-check_frwd( Pred P, wrap_stringstream& check_descr, \
+ check_frwd( Pred P, const boost::unit_test::lazy_output& check_descr, \
const_string file_name, std::size_t line_num, \
tool_level tl, check_type ct \
BOOST_PP_REPEAT_ ## z( BOOST_PP_ADD( n, 1 ), FUNC_PARAMS, _ ) \
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RSS Feed