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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |