Boost logo

Boost Users :

Subject: [Boost-users] [Foreach] tweaked for speed -- a kludge worth refining?
From: Paul Tuinenga (p2nenga_at_[hidden])
Date: 2012-07-09 23:57:48


I admire the tight machine code BOOST_FOREACH teases compilers into
generating. So what could be my problem? More speed!

I have a situation with gathering floating-point data that may be of such
low interest it's not worth pursuing for the library. In any case, I have
my work-around (described below) that gets the job done. In this case, the
need to accumulate:
1) using vectors of indices into another data vector (very NUMA) i.e.
data[index]
2) there is always at least one index
3) majority of cases are two indices
4) but there may be several indices

Obviously, it is best to go ahead and immediately process the (guaranteed)
first index. This hides the cost of increment and loop-test in the
latency of data fetch, even from L1 cache. But BOOST_FOREACH does not do
that. So I hacked the macro. Works great! Creates the tightest machine
code, boosting 2-element cases to the hardware limit (SSE/AVX
instructions). Yes, there is the curly braces thing -- "crude but
effective" is all I'm claiming.

I'm sure there are better ways to alter the macro and/or use model; I'm
interested to hear about that.
- paul

Example use:

    double accum = 0;
    ORG_BOOST_FOREACH(unsigned i, index)
        accum += data[i];

    double temp, accum = 0;
    MOD_BOOST_FOREACH(unsigned i, index, temp = data[i])
        accum += temp;
        temp = data[i];
        }
    accum += temp;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define ORG_BOOST_FOREACH(VAR,
COL)
\

BOOST_FOREACH_PREAMBLE()
\
    if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) =
BOOST_FOREACH_CONTAIN(COL)) \

{}
\
    else if (boost::foreach_detail_::auto_any_t
BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) \

{}
\
    else if (boost::foreach_detail_::auto_any_t
BOOST_FOREACH_ID(_foreach_end) = BOOST_FOREACH_END(COL)) \

{}
\

else
\
        for (bool BOOST_FOREACH_ID(_foreach_continue) =
true; \
                BOOST_FOREACH_ID(_foreach_continue) &&
!BOOST_FOREACH_DONE(COL); \
                BOOST_FOREACH_ID(_foreach_continue) ?
BOOST_FOREACH_NEXT(COL) : (void)0) \
            if
(boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue)))
\

{}
\

else
\
                for (VAR = BOOST_FOREACH_DEREF(COL);
!BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) =
true)

#define MOD_BOOST_FOREACH(VAR, COL,
TMP) \

BOOST_FOREACH_PREAMBLE()
\
    if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) =
BOOST_FOREACH_CONTAIN(COL)) \

{}
\
    else if (boost::foreach_detail_::auto_any_t
BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) \

{}
\
    else if (boost::foreach_detail_::auto_any_t
BOOST_FOREACH_ID(_foreach_end) = BOOST_FOREACH_END(COL)) \

{}
\
    else if (bool BOOST_FOREACH_ID(_foreach_continue) =
false) \

{}
\

else
\

{
\
        /* some kind of BOOST-MPL "assert" here (debug only) to insure
there is one item at least */ \
        for (VAR = BOOST_FOREACH_DEREF(COL);
!BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) =
true) \

TMP;
\
        for (BOOST_FOREACH_ID(_foreach_continue) ? BOOST_FOREACH_NEXT(COL)
: (void)0; \
                BOOST_FOREACH_ID(_foreach_continue) &&
!BOOST_FOREACH_DONE(COL); \
                BOOST_FOREACH_ID(_foreach_continue) ?
BOOST_FOREACH_NEXT(COL) : (void)0) \
            if
(boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue)))
\

{}
\

else
\
                for (VAR = BOOST_FOREACH_DEREF(COL);
!BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) =
true)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net