Multithreading and LazyObject

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Multithreading and LazyObject

Peter Caspers-4
Hi,

I am currently trying to parallelize some computations in some pricing
engines (using the OpenMP API). There is a complication due to calls
to a lazy object model_ within a loop like this

#pragma omp parallel for default(shared) firstprivate(p) if(expiry0>settlement)
            for (Size k = 0; k < (expiry0 > settlement ? npv0.size() : 1);
                 k++) {
[...]
                            model_->zerobond(arguments_.fixedPayDates[l],
                                             expiry0, z[k], discountCurve_);

The problem is that the first call triggers performCalculations() in
model_ and before it has finished a call from another thread might
occur, in which model_ is considered to be computed already, because
in LazyObject the calculated_ flag is set to true right before the
actual computation has started

    inline void LazyObject::calculate() const {
        if (!calculated_ && !frozen_) {
            calculated_ = true;   // prevent infinite recursion in
                                          // case of bootstrapping
            try {
                performCalculations();
            } catch (...) {
                calculated_ = false;
                throw;
            }
        }
    }

Of course it would not be desirable to trigger performCalculations()
from two threads either. We'd rather need a mechanism which makes all
threads wait until the first thread which triggered
performCalculations() has finished (I guess). Also the check of the
calculated_ flag and assignments to this variable would have to be
made thread safe.

I worked around this problem just by ensuring that model_ is
calculated before the parallelized loop by a dummy call (at low
additional cost)

#ifdef _OPENMP
            if(expiry0>settlement)
                model_->numeraire(QL_EPSILON);
#endif

I wonder however if someone has a more general and neater solution for this ?

I am not interested in general multithreading ability at the moment,
but more in this kind of "local" parallelizations, which seem quite
attractive (the bermudan swaption engine above is already faster by a
factor of 5 (on 8 cores), which is ok imo given the small effort to
adapt the code).

Thanks
Peter

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
QuantLib-dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-dev
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading and LazyObject

Luigi Ballabio
Hi Peter,
     good question.  I don't think there's a way to make other
calculations wait for the first, because the whole point of setting
calculated_ to true to begin with was exactly to make the calculation
look like it was completed even though it isn't... I don't think we
can avoid workarounds like yours.

Luigi


On Sun, May 25, 2014 at 8:34 PM, Peter Caspers <[hidden email]> wrote:

> Hi,
>
> I am currently trying to parallelize some computations in some pricing
> engines (using the OpenMP API). There is a complication due to calls
> to a lazy object model_ within a loop like this
>
> #pragma omp parallel for default(shared) firstprivate(p) if(expiry0>settlement)
>             for (Size k = 0; k < (expiry0 > settlement ? npv0.size() : 1);
>                  k++) {
> [...]
>                             model_->zerobond(arguments_.fixedPayDates[l],
>                                              expiry0, z[k], discountCurve_);
>
> The problem is that the first call triggers performCalculations() in
> model_ and before it has finished a call from another thread might
> occur, in which model_ is considered to be computed already, because
> in LazyObject the calculated_ flag is set to true right before the
> actual computation has started
>
>     inline void LazyObject::calculate() const {
>         if (!calculated_ && !frozen_) {
>             calculated_ = true;   // prevent infinite recursion in
>                                           // case of bootstrapping
>             try {
>                 performCalculations();
>             } catch (...) {
>                 calculated_ = false;
>                 throw;
>             }
>         }
>     }
>
> Of course it would not be desirable to trigger performCalculations()
> from two threads either. We'd rather need a mechanism which makes all
> threads wait until the first thread which triggered
> performCalculations() has finished (I guess). Also the check of the
> calculated_ flag and assignments to this variable would have to be
> made thread safe.
>
> I worked around this problem just by ensuring that model_ is
> calculated before the parallelized loop by a dummy call (at low
> additional cost)
>
> #ifdef _OPENMP
>             if(expiry0>settlement)
>                 model_->numeraire(QL_EPSILON);
> #endif
>
> I wonder however if someone has a more general and neater solution for this ?
>
> I am not interested in general multithreading ability at the moment,
> but more in this kind of "local" parallelizations, which seem quite
> attractive (the bermudan swaption engine above is already faster by a
> factor of 5 (on 8 cores), which is ok imo given the small effort to
> adapt the code).
>
> Thanks
> Peter
>
> ------------------------------------------------------------------------------
> "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
> Instantly run your Selenium tests across 300+ browser/OS combos.
> Get unparalleled scalability from the best Selenium testing platform available
> Simple to use. Nothing to install. Get started now for free."
> http://p.sf.net/sfu/SauceLabs
> _______________________________________________
> QuantLib-dev mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/quantlib-dev



--
<https://implementingquantlib.blogspot.com>
<https://twitter.com/lballabio>

------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/NeoTech
_______________________________________________
QuantLib-dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-dev
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading and LazyObject

mkuklik
In reply to this post by Peter Caspers-4
Hey there,

Have you considered using CRITICAL directive in OpenMP? Basically, it specifies a region of code that must be executed by only one thread at a time.

Cheers,

mk
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading and LazyObject

Peter Caspers-4
I briefly thought of declaring the block in LazyObject::calculate()
critical. Is that what you mean ? I did not try, but I would expect
that _all_ calculations on lazy object instances would then go in
single file ? Maybe one could create a lock based on the this ptr and
build a suitable synchronization on that though ?
Peter


On 22 July 2014 13:55, mkuklik <[hidden email]> wrote:

> Hey there,
>
> Have you considered using CRITICAL directive in OpenMP? Basically, it
> specifies a region of code that must be executed by only one thread at a
> time.
>
> Cheers,
>
> mk
>
>
>
> --
> View this message in context: http://quantlib.10058.n7.nabble.com/Multithreading-and-LazyObject-tp15310p15631.html
> Sent from the quantlib-dev mailing list archive at Nabble.com.
>
> ------------------------------------------------------------------------------
> Want fast and easy access to all the code in your enterprise? Index and
> search up to 200,000 lines of code with a free copy of Black Duck
> Code Sight - the same software that powers the world's largest code
> search on Ohloh, the Black Duck Open Hub! Try it now.
> http://p.sf.net/sfu/bds
> _______________________________________________
> QuantLib-dev mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/quantlib-dev

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
QuantLib-dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-dev