diff --git a/INSTALL.md b/INSTALL.md index 97be27fec1..17a3de08c0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -42,7 +42,7 @@ Both methods are supported. However, for most users we _strongly_ recommend to b - Boost.Range: header-only, *only used for unit testing* - [BTAS](http://github.com/ValeevGroup/BTAS), tag e540f265e1d16cc35b1b6726470160ed0046c530 . If usable BTAS installation is not found, TiledArray will download and compile BTAS from source. *This is the recommended way to compile BTAS for all users*. -- [MADNESS](https://github.com/m-a-d-n-e-s-s/madness), tag f9aa38e4f46c5ea6ca6bbceb945beae5230f9ad0 . +- [MADNESS](https://github.com/m-a-d-n-e-s-s/madness), tag b8069a25460b696d21cc8b739a91c9249da26575 . Only the MADworld runtime and BLAS/LAPACK C API component of MADNESS is used by TiledArray. If usable MADNESS installation is not found, TiledArray will download and compile MADNESS from source. *This is the recommended way to compile MADNESS for all users*. diff --git a/external/versions.cmake b/external/versions.cmake index cf0b91c61b..eddea3699d 100644 --- a/external/versions.cmake +++ b/external/versions.cmake @@ -19,8 +19,8 @@ set(TA_INSTALL_EIGEN_PREVIOUS_VERSION 3.3.7) set(TA_INSTALL_EIGEN_URL_HASH b9e98a200d2455f06db9c661c5610496) set(TA_INSTALL_EIGEN_PREVIOUS_URL_HASH b9e98a200d2455f06db9c661c5610496) -set(TA_TRACKED_MADNESS_TAG f9aa38e4f46c5ea6ca6bbceb945beae5230f9ad0) -set(TA_TRACKED_MADNESS_PREVIOUS_TAG 51f0615f094bca5110ea149100e39c0edb25a4f2) +set(TA_TRACKED_MADNESS_TAG b8069a25460b696d21cc8b739a91c9249da26575) +set(TA_TRACKED_MADNESS_PREVIOUS_TAG f9aa38e4f46c5ea6ca6bbceb945beae5230f9ad0) set(TA_TRACKED_MADNESS_VERSION 0.10.1) set(TA_TRACKED_MADNESS_PREVIOUS_VERSION 0.10.1) diff --git a/src/TiledArray/dist_array.h b/src/TiledArray/dist_array.h index eeca4a646f..b60aff3736 100644 --- a/src/TiledArray/dist_array.h +++ b/src/TiledArray/dist_array.h @@ -126,6 +126,9 @@ class DistArray : public madness::archive::ParallelSerializableObject { private: std::shared_ptr pimpl_; ///< Array implementation pointer + bool defer_deleter_to_next_fence_ = + false; ///< if true, the impl object is scheduled to be destroyed in the + ///< next fence static madness::AtomicInt cleanup_counter_; @@ -431,8 +434,26 @@ class DistArray : public madness::archive::ParallelSerializableObject { /// This is a distributed lazy destructor. The object will only be deleted /// after the last reference to the world object on all nodes has been - /// destroyed. - ~DistArray() {} + /// destroyed and there are no outstanding references to the object's data. + /// Use defer_deleter_to_next_fence() to defer the deletion of the destructor + /// to the next fence. + /// \sa defer_deleter_to_next_fence + ~DistArray() { + if (defer_deleter_to_next_fence_) { + madness::detail::deferred_cleanup( + this->world(), pimpl_, + /* do_not_check_that_pimpl_is_unique = */ true); + } + } + + /// Defers deletion to the next fene + + /// By default the destruction of the object's data occurs lazily, when + /// all local references to the object are gone and all _remote_ references + /// to the local object's data are gone. This is not always sufficient; + /// call this at any point during object's lifetime to ensure that the + /// lifetime of the object lasts to (just past)the next fence. + void defer_deleter_to_next_fence() { defer_deleter_to_next_fence_ = true; } /// Create a deep copy of this array @@ -459,6 +480,11 @@ class DistArray : public madness::archive::ParallelSerializableObject { /// \return std::weak_ptr to the nonconst implementation object std::weak_ptr weak_pimpl() { return pimpl_; } + /// Checks if this is a unique handle to the implementation object + + /// \return true if this is a unique handle to the implementation object + bool is_unique() const { return pimpl_.unique(); } + /// Wait for lazy tile cleanup /// This function will wait for cleanup of tile data that has been diff --git a/src/TiledArray/expressions/expr.h b/src/TiledArray/expressions/expr.h index ccb562591c..9cc004aaa6 100644 --- a/src/TiledArray/expressions/expr.h +++ b/src/TiledArray/expressions/expr.h @@ -28,7 +28,6 @@ #include "TiledArray/expressions/fwd.h" - #include "../reduce_task.h" #include "../tile_interface/cast.h" #include "../tile_interface/scale.h" @@ -516,6 +515,10 @@ class Expr { dist_eval.wait(); // Swap the new array with the result array object. result.swap(tsr.array()); + result + .defer_deleter_to_next_fence(); // if tsr.array().impl() is referred to + // by outstanding tasks need to defer + // destruction to the next fence } /// Expression print @@ -873,6 +876,6 @@ class Expr { }; // class Expr -} +} // namespace TiledArray::expressions #endif // TILEDARRAY_EXPRESSIONS_EXPR_H__INCLUDED diff --git a/tests/expressions_impl.h b/tests/expressions_impl.h index c86e10a927..0ffbf4754e 100644 --- a/tests/expressions_impl.h +++ b/tests/expressions_impl.h @@ -26,6 +26,8 @@ #ifndef TILEDARRAY_TEST_EXPRESSIONS_IMPL_H #define TILEDARRAY_TEST_EXPRESSIONS_IMPL_H +constexpr int nrepeats = 5; + BOOST_FIXTURE_TEST_CASE_TEMPLATE(tensor_factories, F, Fixtures, F) { auto& a = F::a; auto& c = F::c; @@ -591,8 +593,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_block, F, Fixtures, F) { c.fill_local(0.0); - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - 2 * a("a,b,c").block({3, 3, 3}, {5, 5, 5})); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + 2 * a("a,b,c").block({3, 3, 3}, {5, 5, 5})); BlockRange block_range(a.trange().tiles_range(), {3, 3, 3}, {5, 5, 5}); @@ -611,9 +614,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_block, F, Fixtures, F) { } } - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - 2 * (a("a,b,c").block({3, 3, 3}, {5, 5, 5}) + - b("a,b,c").block({3, 3, 3}, {5, 5, 5}))); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + 2 * (a("a,b,c").block({3, 3, 3}, {5, 5, 5}) + + b("a,b,c").block({3, 3, 3}, {5, 5, 5}))); for (std::size_t index = 0ul; index < block_range.volume(); ++index) { if (!a.is_zero(block_range.ordinal(index)) || @@ -634,9 +638,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_block, F, Fixtures, F) { } } - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - 2 * (3 * a("a,b,c").block({3, 3, 3}, {5, 5, 5}) + - 4 * b("a,b,c").block({3, 3, 3}, {5, 5, 5}))); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + 2 * + (3 * a("a,b,c").block({3, 3, 3}, {5, 5, 5}) + + 4 * b("a,b,c").block({3, 3, 3}, {5, 5, 5}))); for (std::size_t index = 0ul; index < block_range.volume(); ++index) { if (!a.is_zero(block_range.ordinal(index)) || @@ -669,8 +675,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_permute_block, F, Fixtures, Permutation perm({2, 1, 0}); BlockRange block_range(a.trange().tiles_range(), {3, 3, 3}, {5, 5, 5}); - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - a("c,b,a").block({3, 3, 3}, {5, 5, 5})); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + a("c,b,a").block({3, 3, 3}, {5, 5, 5})); for (std::size_t index = 0ul; index < block_range.volume(); ++index) { // const size_t perm_index = block_range.ordinal(perm * @@ -690,8 +697,9 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_permute_block, F, Fixtures, } } - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - 2 * a("c,b,a").block({3, 3, 3}, {5, 5, 5})); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + 2 * a("c,b,a").block({3, 3, 3}, {5, 5, 5})); for (std::size_t index = 0ul; index < block_range.volume(); ++index) { auto perm_index = perm * block_range.idx(index); @@ -709,9 +717,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_permute_block, F, Fixtures, } } - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - 2 * (3 * a("c,b,a").block({3, 3, 3}, {5, 5, 5}) + - 4 * b("a,b,c").block({3, 3, 3}, {5, 5, 5}))); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + 2 * + (3 * a("c,b,a").block({3, 3, 3}, {5, 5, 5}) + + 4 * b("a,b,c").block({3, 3, 3}, {5, 5, 5}))); for (std::size_t index = 0ul; index < block_range.volume(); ++index) { auto perm_index = perm * block_range.idx(index); @@ -734,9 +744,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_permute_block, F, Fixtures, } } - BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = - 2 * (3 * a("c,b,a").block({3, 3, 3}, {5, 5, 5}) + - 4 * b("c,b,a").block({3, 3, 3}, {5, 5, 5}))); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(c("a,b,c").block({3, 3, 3}, {5, 5, 5}) = + 2 * + (3 * a("c,b,a").block({3, 3, 3}, {5, 5, 5}) + + 4 * b("c,b,a").block({3, 3, 3}, {5, 5, 5}))); for (std::size_t index = 0ul; index < block_range.volume(); ++index) { auto perm_index = perm * block_range.idx(index); @@ -767,9 +779,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_block_contract, F, Fixtures, auto& b = F::b; auto& w = F::w; - BOOST_REQUIRE_NO_THROW(w("a,b").block({3, 3}, {5, 5}) = - a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * - b("c,d,b").block({2, 3, 3}, {5, 5, 5})); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(w("a,b").block({3, 3}, {5, 5}) = + a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * + b("c,d,b").block({2, 3, 3}, {5, 5, 5})); } // TODO need to test the correctness here BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_block_permute_contract, F, @@ -778,9 +791,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_subblock_block_permute_contract, F, auto& b = F::b; auto& w = F::w; - BOOST_REQUIRE_NO_THROW(w("a,b").block({3, 3}, {5, 5}) = - a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * - b("d,c,b").block({3, 2, 3}, {5, 5, 5})); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(w("a,b").block({3, 3}, {5, 5}) = + a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * + b("d,c,b").block({3, 2, 3}, {5, 5, 5})); } // TODO need to test the correctness here BOOST_FIXTURE_TEST_CASE_TEMPLATE(block_contract, F, Fixtures, F) { @@ -788,16 +802,19 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(block_contract, F, Fixtures, F) { auto& b = F::b; auto& w = F::w; - BOOST_REQUIRE_NO_THROW(w("a,b") = a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * - b("c,d,b").block({2, 3, 3}, {5, 5, 5})); + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(w("a,b") = a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * + b("c,d,b").block({2, 3, 3}, {5, 5, 5})); } // TODO need to test the correctness here BOOST_FIXTURE_TEST_CASE_TEMPLATE(block_permute_contract, F, Fixtures, F) { auto& a = F::a; auto& b = F::b; auto& w = F::w; - BOOST_REQUIRE_NO_THROW(w("a,b") = a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * - b("d,c,b").block({3, 2, 3}, {5, 5, 5})); + + for (int repeat = 0; repeat != nrepeats; ++repeat) + BOOST_REQUIRE_NO_THROW(w("a,b") = a("a,c,d").block({3, 2, 3}, {5, 5, 5}) * + b("d,c,b").block({3, 2, 3}, {5, 5, 5})); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(add, F, Fixtures, F) {