Skip to content
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ if (TTG_ENABLE_ASAN)
add_link_options(-fsanitize=address)
endif (TTG_ENABLE_ASAN)

# someone thought it was a brilliant idea to automatically enable thread-parallel BLAS
set(use_openmp OFF)

set(TTG_HIP_PLATFORM "__HIP_PLATFORM_AMD__" CACHE STRING "Which platform to use when compiling HIP-related code (default: __HIP_PLATFORM_AMD__)")
##########################
#### prerequisites
Expand Down
8 changes: 4 additions & 4 deletions cmake/modules/ExternalDependenciesVersions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

set(TTG_TRACKED_VG_CMAKE_KIT_TAG 256d9462bb765787f5acb69be154b26d6efba8b6) # provides FindOrFetchLinalgPP and "real" FindOrFetchBoost
set(TTG_TRACKED_CATCH2_VERSION 3.5.0)
set(TTG_TRACKED_MADNESS_TAG a50e8d440fc2a1718a1ba0140af6866f49813d14)
set(TTG_TRACKED_MADNESS_TAG fe58bba88857ceeb530a1ef3bdf8744516d80452)
set(TTG_TRACKED_PARSEC_TAG parsec-for-ttg)
set(TTG_TRACKED_UMPIRE_CXX_ALLOCATOR_TAG a48ad360e20b9733263768b54aa24afe5894faa4)
set(TTG_TRACKED_BTAS_TAG c25b0a11d2a76190bfb13fa72f9e9dc3e57c3c2f)
set(TTG_TRACKED_TILEDARRAY_TAG 42e0d65df9400469d29ebeb929b045be1caaf3d6)
set(TTG_TRACKED_UMPIRE_CXX_ALLOCATOR_TAG 1ba7f5f0aa99438826dd1c6bc1cd396080b9d608)
set(TTG_TRACKED_BTAS_TAG 74ee8a27386c746b36f0455cd5a0e3c33bd5f4d2)
set(TTG_TRACKED_TILEDARRAY_TAG c4a8927845e0c4503ecacf85ce8e73243ab48a62)

# need Boost.CallableTraits (header only, part of Boost 1.66 released in Dec 2017) for wrap.h to work
# BUT if will be building examples, inherit the oldest version from the pickiest Boost consumer (TA and/or BSPMM)
Expand Down
2 changes: 1 addition & 1 deletion ttg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ if (TARGET MADworld)
# N.B. ttg-mad can use MADNESS serialization only
add_ttg_library(ttg-mad "${ttg-mad-headers}"
PUBLIC_HEADER "${ttg-mad-headers}"
LINK_LIBRARIES "ttg;MADworld;ttg-serialization-madness"
LINK_LIBRARIES "ttg;MADworld;MADmisc;ttg-serialization-madness"
COMPILE_DEFINITIONS "WORLD_INSTANTIATE_STATIC_TEMPLATES=1"
COMPILE_DEFINITIONS TTG_USE_MADNESS=1)
endif(TARGET MADworld)
Expand Down
66 changes: 47 additions & 19 deletions ttg/ttg/device/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ namespace ttg::device {
}
} // namespace detail

/**
* A collection of input buffer objects to be used in a device task.
*
* TODO:
* - Filter out empty buffers. They can cause problems if empty flows appear between non-empty flows.
* - Filter out or error out on duplicated buffers.
*/
struct Input {
private:
std::vector<detail::device_input_data_t> m_data;
Expand Down Expand Up @@ -328,7 +335,7 @@ namespace ttg::device {

template<typename T, typename Enabler = void>
struct broadcast_keylist_trait {
using type = T;
using key_type = T;
};

/* overload for iterable types that extracts the type of the first element */
Expand Down Expand Up @@ -500,41 +507,62 @@ namespace ttg::device {
valueT &&value,
std::tuple<ttg::Out<out_keysT, out_valuesT>...> &t) {
ttg::detail::value_copy_handler<Runtime> copy_handler;
return detail::send_t{
detail::broadcast_coro<I, Is...>(std::forward<rangeT>(keylist),
copy_handler(std::forward<valueT>(value)),
t, std::move(copy_handler))};
if constexpr (ttg::meta::is_tuple_v<rangeT>) {
return detail::send_t{
detail::broadcast_coro<I, Is...>(std::forward<rangeT>(keylist),
copy_handler(std::forward<valueT>(value)),
t, std::move(copy_handler))};
} else {
return detail::send_t{
detail::broadcast_coro<I, Is...>(std::tie(keylist),
copy_handler(std::forward<valueT>(value)),
t, std::move(copy_handler))};
}
}

/* overload with implicit terminals and keylist passed by const reference */
template <size_t i, typename rangeT, typename valueT,
template <size_t I, size_t... Is, typename RangesT, typename valueT,
ttg::Runtime Runtime = ttg::ttg_runtime>
inline detail::send_t broadcast(rangeT &&keylist, valueT &&value) {
inline detail::send_t broadcast(RangesT &&keylist, valueT &&value) {
ttg::detail::value_copy_handler<Runtime> copy_handler;
return detail::send_t{detail::broadcast_coro<i>(std::tie(keylist),
copy_handler(std::forward<valueT>(value)),
std::move(copy_handler))};
if constexpr (ttg::meta::is_tuple_v<RangesT>) {
return detail::send_t{detail::broadcast_coro<I, Is...>(std::forward<RangesT>(keylist),
copy_handler(std::forward<valueT>(value)),
std::move(copy_handler))};
} else if constexpr(std::is_rvalue_reference_v<decltype(keylist)>) {
return detail::send_t{detail::broadcast_coro<I, Is...>(std::make_tuple(std::forward<RangesT>(keylist)),
copy_handler(std::forward<valueT>(value)),
std::move(copy_handler))};
} else {
return detail::send_t{detail::broadcast_coro<I, Is...>(std::tie(keylist),
copy_handler(std::forward<valueT>(value)),
std::move(copy_handler))};
}
}

/* overload with explicit terminals and keylist passed by const reference */
template <size_t I, size_t... Is, typename rangeT, typename... out_keysT, typename... out_valuesT,
template <size_t I, size_t... Is, typename RangesT, typename... out_keysT, typename... out_valuesT,
ttg::Runtime Runtime = ttg::ttg_runtime>
[[nodiscard]]
inline detail::send_t broadcastk(rangeT &&keylist,
inline detail::send_t broadcastk(RangesT &&keylist,
std::tuple<ttg::Out<out_keysT, out_valuesT>...> &t) {
ttg::detail::value_copy_handler<Runtime> copy_handler;
return detail::send_t{
detail::broadcastk_coro<I, Is...>(std::forward<rangeT>(keylist), t)};
if constexpr (ttg::meta::is_tuple_v<RangesT>) {
return detail::send_t{detail::broadcastk_coro<I, Is...>(std::forward<RangesT>(keylist), t)};
} else {
return detail::send_t{
detail::broadcastk_coro<I, Is...>(std::tie(keylist), t)};
}
}

/* overload with implicit terminals and keylist passed by const reference */
template <size_t i, typename rangeT,
template <size_t I, size_t... Is, typename RangesT,
ttg::Runtime Runtime = ttg::ttg_runtime>
inline detail::send_t broadcastk(rangeT &&keylist) {
if constexpr (std::is_rvalue_reference_v<decltype(keylist)>) {
return detail::send_t{detail::broadcastk_coro<i>(std::forward<rangeT>(keylist))};
inline detail::send_t broadcastk(RangesT &&keylist) {
if constexpr (ttg::meta::is_tuple_v<RangesT>) {
return detail::send_t{detail::broadcastk_coro<I, Is...>(std::forward<RangesT>(keylist))};
} else {
return detail::send_t{detail::broadcastk_coro<i>(std::tie(keylist))};
return detail::send_t{detail::broadcastk_coro<I, Is...>(std::tie(keylist))};
}
}

Expand Down
5 changes: 3 additions & 2 deletions ttg/ttg/parsec/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ namespace ttg_parsec {
struct stream_info_t {
std::size_t goal;
std::size_t size;
parsec_lifo_t reduce_copies;
std::mutex reduce_copies_lock;
std::vector<ttg_data_copy_t*> reduce_copies;
std::atomic<std::size_t> reduce_count;
};

Expand All @@ -108,7 +109,7 @@ namespace ttg_parsec {
if (std::get<i>(tt->input_reducers)) {
streams[i].goal = tt->static_stream_goal[i];
streams[i].size = 0;
PARSEC_OBJ_CONSTRUCT(&streams[i].reduce_copies, parsec_lifo_t);
streams[i].reduce_copies.clear();
streams[i].reduce_count.store(0, std::memory_order_relaxed);
}
/* recursion */
Expand Down
40 changes: 26 additions & 14 deletions ttg/ttg/parsec/ttg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1710,18 +1710,16 @@ namespace ttg_parsec {
nullptr;
#endif // TTG_HAVE_COROUTINE
//std::cout << "static_op: suspended_task_address " << suspended_task_address << std::endl;
ttT *baseobj = task->tt;
derivedT *obj = static_cast<derivedT *>(baseobj);
if constexpr (!ttg::meta::is_void_v<keyT>)
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : ", task->key, ": executing");
else
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : executing");
if (suspended_task_address == nullptr) { // task is a coroutine that has not started or an ordinary function

ttT *baseobj = task->tt;
derivedT *obj = static_cast<derivedT *>(baseobj);
assert(detail::parsec_ttg_caller == nullptr);
detail::parsec_ttg_caller = static_cast<detail::parsec_ttg_task_base_t*>(task);
if (obj->tracing()) {
if constexpr (!ttg::meta::is_void_v<keyT>)
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : ", task->key, ": executing");
else
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : executing");
}

if constexpr (!ttg::meta::is_void_v<keyT> && !ttg::meta::is_empty_tuple_v<input_values_tuple_type>) {
auto input = make_tuple_of_ref_from_array(task, std::make_index_sequence<numinvals>{});
Expand Down Expand Up @@ -1890,12 +1888,12 @@ namespace ttg_parsec {
if (rtask->is_first) {
if (0 == (parent_task->streams[i].reduce_count.fetch_sub(1, std::memory_order_acq_rel)-1)) {
/* we were the first and there is nothing to be done */
if (obj->tracing()) {
//if (obj->tracing()) {
if constexpr (!ttg::meta::is_void_v<keyT>)
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : ", parent_task->key, ": first reducer empty");
else
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : first reducer empty");
}
//}

return PARSEC_HOOK_RETURN_DONE;
}
Expand All @@ -1908,13 +1906,19 @@ namespace ttg_parsec {
if constexpr(!val_is_void) {
/* the copies to reduce out of */
detail::ttg_data_copy_t *source_copy;
parsec_list_item_t *item;
item = parsec_lifo_pop(&parent_task->streams[i].reduce_copies);
detail::ttg_data_copy_t *item = nullptr;
{
std::lock_guard<std::mutex> lock(parent_task->streams[i].reduce_copies_lock);
if (!parent_task->streams[i].reduce_copies.empty()) {
item = parent_task->streams[i].reduce_copies.back();
parent_task->streams[i].reduce_copies.pop_back();
}
}
if (nullptr == item) {
// maybe someone is changing the goal right now
break;
}
source_copy = ((detail::ttg_data_copy_self_t *)(item))->self;
source_copy = item;
assert(target_copy->num_readers() == target_copy->mutable_tag);
assert(source_copy->num_readers() > 0);
reducer(*reinterpret_cast<std::decay_t<value_t> *>(target_copy->get_ptr()),
Expand All @@ -1935,6 +1939,11 @@ namespace ttg_parsec {
//std::cout << "static_reducer_op size " << size
// << " of " << parent_task->streams[i].goal << " complete " << complete
// << " c " << c << std::endl;
if constexpr (!ttg::meta::is_void_v<keyT>) {
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), " : ", parent_task->key, ": size ", size, " of ", parent_task->streams[i].goal, " complete ", complete, " c ", c);
} else {
ttg::trace(obj->get_world().rank(), ":", obj->get_name(), ": size ", size, " of ", parent_task->streams[i].goal, " complete ", complete, " c ", c);
}
if (complete && c == 0) {
if constexpr(input_is_const) {
/* make the consumer task a reader if its input is const */
Expand Down Expand Up @@ -2595,7 +2604,10 @@ namespace ttg_parsec {
detail::ttg_data_copy_t *copy = get_copy_fn(task, std::forward<Value>(value), true);

/* enqueue the data copy to be reduced */
parsec_lifo_push(&task->streams[i].reduce_copies, &copy->super);
{
std::lock_guard<std::mutex> lock(task->streams[i].reduce_copies_lock);
task->streams[i].reduce_copies.push_back(copy);
}
submit_reducer_task(task);
}
} else {
Expand Down
Loading