[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] Parallel blues
From: |
Greg Chicares |
Subject: |
Re: [lmi] Parallel blues |
Date: |
Thu, 22 Jun 2017 13:32:53 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 |
On 2017-06-21 12:50, Vadim Zeitlin wrote:
> On Wed, 21 Jun 2017 12:26:36 +0000 Greg Chicares <address@hidden> wrote:
[...]
> GC> Then I realized that I could implement
> GC> bool is_null_stream(std::ostream&);
> GC> and use that to conditionalize stream output in 'zero.hpp', and its
> GC> effect on calendar_date_test's speed is the same as using #ifdef.
>
> [...] OTOH, forgetting to use is_null_stream() will almost
> certainly go unnoticed and just result in much poorer performance during
> run-time, even in production code. This doesn't seem like a good trade off
> to me.
Yes, we can do better. Referring back to earlier messages in this thread:
On 2017-06-21 12:26, Greg Chicares wrote:
> On 2017-06-20 23:28, Vadim Zeitlin wrote:
[...]
>> And we do need to be able to test for stream absence because
>> otherwise we wouldn't be able to get rid of value_cast<> calls overhead
>> which is probably more significant here than that of actually inserting
>> into the stream. And to avoid it, we simply must make the calls to
>> operator<<() conditional, hence we need something to test for.
>
> Indeed. My first attempt was to set the null stream's 'badbit', which I
> thought would block operator<<() because no sentry object is created;
> but that didn't help, because in a '<<' chain like
> os << foo() << bar()
> foo() and bar() are still called.
Setting 'badbit' works quite nicely, though, if we use only built-in
stream formatting. In HEAD, 'zero.hpp' has code like:
iteration_stream
<< "iteration " << number_of_iterations++
<< " iterand " << value_cast<std::string>(a)
<< " value " << value_cast<std::string>(fa)
<< std::endl
;
where, even if 'badbit' is set, value_cast<>() is always called.
But we don't really need value_cast<>() here, because this trace
is just as useful if we do this instead[0]:
iteration_stream.precision(DECIMAL_DIG);
to make sure no precision is lost. Then, if we add
+ iteration_stream.setstate(std::ios::badbit);
to the patch below[0] (as a careless expedient, knowing that badbit
really should be set in the null_stream() implementation), we get
almost all the benefit of #ifdef:
On 2017-06-20 23:10, Greg Chicares wrote:
> with iteration_stream #ifdef'd out in 'calendar_date_test.cpp'
[...]
> ..and now each TestBirthdateLimitsExhaustively() call takes about
> one-sixth of a second instead of two and a half seconds, so that
> function runs fifteen times faster.
because we observe that each such call takes about one-third of a
second. That's only about seven times faster--it saves only 87% of
the overhead instead of 93%--but it lets us write clean code that
just works (as long as we avoid calling free functions like
value_cast<>(), and let the iostreams library handle formatting
instead). If we set 'badbit' as a postcondition of null_stream(),
then we can't forget to do it whenever we use a null stream.
Examining the other cases where null_stream() is used:
'progress_meter_cli.cpp': we do have
os_ << progress_message() << std::flush;
but that virtual function has this default implementation:
return ".";
so it shouldn't be too costly.
'system_command_wx.cpp': this is cheap anyway, and probably is
optimized away:
statusbar_if_available << "Running..." << std::flush;
and this is pretty cheap (and it's only called once):
statusbar_if_available << timer.stop().elapsed_msec_str() << std::flush;
---------
[0] "do this instead", "the patch below":
diff --git a/zero.hpp b/zero.hpp
index 7ac9f1b..8800bb8 100644
--- a/zero.hpp
+++ b/zero.hpp
@@ -26,8 +26,8 @@
#include "null_stream.hpp"
#include "round_to.hpp"
-#include "value_cast.hpp"
+#include <cfloat> // DECIMAL_DIG
#include <cmath>
#include <limits>
#include <ostream>
@@ -241,6 +241,7 @@ root_type decimal_root
,std::ostream& iteration_stream = null_stream()
)
{
+ iteration_stream.precision(DECIMAL_DIG);
static double const epsilon = std::numeric_limits<double>::epsilon();
int number_of_iterations = 0;
@@ -255,8 +256,8 @@ root_type decimal_root
double fa = static_cast<double>(f(a));
iteration_stream
<< "iteration " << number_of_iterations++
- << " iterand " << value_cast<std::string>(a)
- << " value " << value_cast<std::string>(fa)
+ << " iterand " << a
+ << " value " << fa
<< std::endl
;
if(0.0 == fa)
@@ -267,8 +268,8 @@ root_type decimal_root
double fb = static_cast<double>(f(b));
iteration_stream
<< "iteration " << number_of_iterations++
- << " iterand " << value_cast<std::string>(b)
- << " value " << value_cast<std::string>(fb)
+ << " iterand " << b
+ << " value " << fb
<< std::endl
;
double last_evaluated_iterand = b; // Note 1.
@@ -401,8 +402,8 @@ root_type decimal_root
last_evaluated_iterand = b;
iteration_stream
<< "iteration " << number_of_iterations++
- << " iterand " << value_cast<std::string>(b)
- << " value " << value_cast<std::string>(fb)
+ << " iterand " << b
+ << " value " << fb
<< std::endl
;
}
- Re: [lmi] Parallel blues, Greg Chicares, 2017/06/20
- Re: [lmi] Parallel blues, Vadim Zeitlin, 2017/06/20
- Re: [lmi] Parallel blues, Greg Chicares, 2017/06/20
- Re: [lmi] Parallel blues, Vadim Zeitlin, 2017/06/20
- Re: [lmi] Parallel blues, Greg Chicares, 2017/06/21
- Re: [lmi] Parallel blues, Vadim Zeitlin, 2017/06/21
- Re: [lmi] Parallel blues,
Greg Chicares <=
- Re: [lmi] Parallel blues, Vadim Zeitlin, 2017/06/22
- Re: [lmi] Parallel blues, Greg Chicares, 2017/06/27
- Re: [lmi] Parallel blues, Vadim Zeitlin, 2017/06/27