diff --git a/CMakeLists.txt b/CMakeLists.txt index 0537c31..e1f2209 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,8 @@ target_include_directories(bvh INTERFACE $ ) +add_subdirectory(tpl) + # Various default compiler options target_compile_options(bvh PUBLIC $<$:-O0 -ggdb3 -fno-inline>) @@ -107,6 +109,9 @@ endif() set_property(TARGET bvh PROPERTY CXX_STANDARD ${Kokkos_CXX_STANDARD}) target_link_libraries(bvh PUBLIC Kokkos::kokkos) +find_package(spdlog 1.13 REQUIRED) +target_link_libraries(bvh PUBLIC spdlog::spdlog) + option(BVH_ENABLE_TRACING "Enable detailed performance tracing (may have an impact on performance" OFF) if (BVH_ENABLE_TRACING) find_package(perf REQUIRED) diff --git a/cmake/bvhConfig.cmake.in b/cmake/bvhConfig.cmake.in index 466b217..922404f 100644 --- a/cmake/bvhConfig.cmake.in +++ b/cmake/bvhConfig.cmake.in @@ -7,15 +7,14 @@ if (@VTK_FOUND@) find_dependency(VTK REQUIRED HINTS @VTK_DIR@) endif() -# VT optional dependency -if (@vt_FOUND@) - find_dependency(vt REQUIRED HINTS @vt_DIR@) -endif() +# VT +find_dependency(vt REQUIRED HINTS @vt_DIR@) -# Kokkos optional dependency -if (@Kokkos_FOUND@) - find_dependency(Kokkos REQUIRED NO_CMAKE_PACKAGE_REGISTRY HINTS @Kokkos_DIR@) -endif() +# Kokkos +find_dependency(Kokkos REQUIRED NO_CMAKE_PACKAGE_REGISTRY HINTS @Kokkos_DIR@) + +# spdlog +find_dependency(spdlog REQUIRED) if (@perf_FOUND@) find_dependency(perf REQUIRED HINTS @perf_DIR@) diff --git a/src/bvh/collision_object.cpp b/src/bvh/collision_object.cpp index 0ea587a..ab3ba97 100644 --- a/src/bvh/collision_object.cpp +++ b/src/bvh/collision_object.cpp @@ -77,11 +77,16 @@ namespace bvh collision_object::collision_object( collision_world &_world, std::size_t _idx, std::size_t _overdecomposition ) : m_impl{ std::make_unique< impl >( _world, _idx ) } { - bvh_splitting_geom_axis_ = ::vt::theTrace()->registerUserEventColl("bvh_splitting_geom_axis_"); - bvh_splitting_ml_ = ::vt::theTrace()->registerUserEventColl("bvh_splitting_ml_"); - bvh_set_entity_data_impl_ = ::vt::theTrace()->registerUserEventColl("bvh_set_entity_data_impl_"); - bvh_clustering_ = ::vt::theTrace()->registerUserEventColl("bvh_clustering_"); - bvh_build_trees_ = ::vt::theTrace()->registerUserEventColl("bvh_build_trees_"); + bvh_splitting_geom_axis_ = ::vt::theTrace()->registerUserEventColl( "bvh_splitting_geom_axis_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_splitting_geom_axis_", m_impl->collision_idx ); + bvh_splitting_ml_ = ::vt::theTrace()->registerUserEventColl( "bvh_splitting_ml_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_splitting_ml_", m_impl->collision_idx ); + bvh_set_entity_data_impl_ = ::vt::theTrace()->registerUserEventColl( "bvh_set_entity_data_impl_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_set_entity_data_impl_", m_impl->collision_idx ); + bvh_clustering_ = ::vt::theTrace()->registerUserEventColl( "bvh_clustering_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_clustering_", m_impl->collision_idx ); + bvh_build_trees_ = ::vt::theTrace()->registerUserEventColl( "bvh_build_trees_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_build_trees_", m_impl->collision_idx ); m_impl->overdecomposition = static_cast< int >( _overdecomposition ); @@ -90,15 +95,19 @@ namespace bvh m_impl->chainset.addIndex( vt_index{ i } ); } + m_impl->logger->trace( "obj={} adding {} local indices", m_impl->collision_idx, m_impl->overdecomposition ); + // Initialize objgroup for per-node data ::vt::runInEpochCollective( "collision_object.make_objgroup", [&](){ - m_impl->objgroup = ::vt::theObjGroup()->makeCollective( fmt::vt::format( "collision_object {}", _idx ) ); + m_impl->objgroup = ::vt::theObjGroup()->makeCollective( fmt::format( "collision_object {}", _idx ) ); m_impl->objgroup.get()->self = this; - vt::debug( "objgroup make_collective {:x}\n", m_impl->objgroup.getProxy() ); + m_impl->logger->debug( "obj={} objgroup make_collective {:x}", m_impl->collision_idx, m_impl->objgroup.getProxy() ); }); m_impl->local_patches.resize( m_impl->overdecomposition ); + + m_impl->logger->info( "initialized collision object {}", m_impl->collision_idx ); } collision_object::collision_object( collision_object && ) noexcept = default; @@ -119,7 +128,10 @@ namespace bvh m_impl->local_patches.clear(); m_impl->local_patches.resize( od_factor ); - always_assert( m_impl->num_splits + 1 == od_factor, "error during splitting process, splits {} do not match od factor {}\n", m_impl->num_splits + 1, od_factor ); + BVH_ASSERT_ALWAYS( m_impl->num_splits + 1 == od_factor, + logger(), + "error during splitting process, splits {} do not match od factor {}\n", m_impl->num_splits + 1, + od_factor ); // Preallocate local data buffers. Do this lazily m_impl->narrowphase_patch_messages.resize( od_factor, nullptr ); @@ -135,12 +147,14 @@ namespace bvh const auto sbeg = ( i == 0 ) ? 0 : m_impl->splits_h( i - 1 ); const auto send = ( i == m_impl->num_splits ) ? m_impl->split_indices_h.extent( 0 ) : m_impl->splits_h( i ); const std::size_t nelements = send - sbeg; - ::bvh::vt::debug( "{}: creating broadphase patch for body {} size {} from offset {}\n", ::vt::theContext()->getNode(), m_impl->collision_idx, nelements, sbeg ); + logger().debug( "creating broadphase patch for body {} size {} from offset {}", m_impl->collision_idx, nelements, sbeg ); m_impl->local_patches[i] = broadphase_patch_type( i + rank * od_factor, span< const entity_snapshot >( m_impl->snapshots.data() + sbeg, nelements ) ); } - always_assert( m_impl->local_patches.size() == od_factor, "wrong number of patches\n" ); + BVH_ASSERT_ALWAYS( m_impl->local_patches.size() == od_factor, + logger(), + "wrong number of patches\n" ); } void collision_object::init_broadphase() const @@ -157,8 +171,13 @@ namespace bvh auto coll_size = vt_index{ static_cast< std::size_t >( od_factor * ::vt::theContext()->getNumNodes() ) }; if ( m_impl->broadphase_patch_collection_proxy.getProxy() == ::vt::no_vrt_proxy ) { + logger().info( "lazily constructing broadphase patch collection with {} elements", coll_size ); m_impl->broadphase_patch_collection_proxy = ::vt::makeCollection< broadphase_patch_collection_type >().bounds( coll_size ).bulkInsert().wait(); - m_impl->narrowphase_patch_collection_proxy = ::vt::makeCollection< narrowphase_patch_collection_type >().bounds( coll_size ).bulkInsert().wait(); + logger().info( "lazily constructing narrophase patch collection with {} elements", coll_size ); + m_impl->narrowphase_patch_collection_proxy = ::vt::makeCollection< narrowphase_patch_collection_type >() + .elementConstructor( [this]( narrowphase_patch_collection_type::IndexType ){ return std::make_unique< narrowphase_patch_collection_type >( m_impl->objgroup ); } ) + .bounds( coll_size ).bulkInsert().wait(); + logger().info( "lazily constructing narrowphase collection with dynamic membership" ); m_impl->narrowphase_collection_proxy = ::vt::makeCollection< narrowphase_collection_type >().dynamicMembership( true ).wait(); } @@ -178,8 +197,11 @@ namespace bvh msg->patch = local_patch; msg->origin_node = rank; msg->local_idx = _local; - ::bvh::vt::debug( "{}: sending broadphase patch {} for body {} size {}\n", ::vt::theContext()->getNode(), - vt_index{ _local.x() + offset }, m_impl->collision_idx, msg->patch.size() ); + logger().debug( " obj={} initialize broadphase patch {} size {}", + vt_index{ _local.x() + offset }, + m_impl->collision_idx, + _local.x() + offset, + msg->patch.size() ); return m_impl->broadphase_patch_collection_proxy[vt_index{ _local.x() + offset }] .sendMsg< broadphase_patch_msg, &details::set_broadphase_patches >( msg.get() ); } else { @@ -194,8 +216,10 @@ namespace bvh ::vt::trace::TraceScopedEvent scope(bvh_build_trees_); // Tree build needs to be done collectively, everyone needs to finish before the next step m_impl->chainset.nextStepCollective( "build_tree_step", [this, offset]( vt_index _idx ) { - ::bvh::vt::debug( "{}: building tree reduction for patch {} for body {}\n", ::vt::theContext()->getNode(), - vt_index{ _idx.x() + offset }, m_impl->collision_idx ); + logger().debug( " obj={} building tree reduction for patch {}", + vt_index{ _idx.x() + offset }, + m_impl->collision_idx, + _idx.x() + offset ); return collision_object_impl::build_trees_top_down( vt_index{ _idx.x() + offset }, m_impl->objgroup, m_impl->broadphase_patch_collection_proxy ); } ); @@ -243,9 +267,11 @@ namespace bvh m_impl->chainset.nextStepCollective( "start broadphase insertion", [this, &_other]( vt_index _local_idx) { if ( _local_idx.x() == 0 ) { - ::bvh::vt::debug( "{}: starting broadphase between body {} and {}\n", - ::vt::theContext()->getNode(), m_impl->collision_idx, _other.m_impl->collision_idx ); + broadphase_logger().info( "starting broadphase between body {} and {}", + m_impl->collision_idx, _other.m_impl->collision_idx ); auto msg = ::vt::makeMessage< collision_object_impl::messages::modify_msg >(); + broadphase_logger().trace( " obj={} begin_narrowphase_modification", + ::vt::theContext()->getNode(), id() ); return m_impl->objgroup[::vt::theContext()->getNode()].sendMsg< collision_object_impl::messages::modify_msg, &collision_object_impl::collision_object_holder::begin_narrowphase_modification >( msg ); } else return pending_send{ nullptr }; @@ -254,14 +280,19 @@ namespace bvh using chainset_type = ::vt::messaging::CollectionChainSet< vt_index >; chainset_type::mergeStepCollective( "broadphase_step",m_impl->chainset, _other.m_impl->chainset, [this, rank, offset, &_other]( vt_index _idx ) { - return collision_object_impl::broadphase( - vt_index{ _idx.x() + offset }, vt_index{ _idx.x() }, rank, - m_impl->broadphase_patch_collection_proxy, m_impl->objgroup, - _other.m_impl->objgroup ); + broadphase_logger().trace( " obj={} target_obj={} start broadphase", + vt_index{ _idx.x() + offset }, id(), _other.id() ); + return collision_object_impl::broadphase( + vt_index{ _idx.x() + offset }, vt_index{ _idx.x() }, rank, + m_impl->broadphase_patch_collection_proxy, m_impl->objgroup, + _other.m_impl->objgroup ); } ); m_impl->chainset.nextStepCollective( "finalize broadphase insertion", [this]( vt_index _local_idx) { - if ( _local_idx.x() == 0 ) { + if ( _local_idx.x() == 0 ) + { + broadphase_logger().trace( " obj={} finish_narrowphase_modification", + ::vt::theContext()->getNode(), id() ); auto msg = ::vt::makeMessage< collision_object_impl::messages::modify_msg >(); return m_impl->objgroup[::vt::theContext()->getNode()].sendMsg< collision_object_impl::messages::modify_msg, &collision_object_impl::collision_object_holder::finish_narrowphase_modification >( msg ); } else @@ -448,4 +479,22 @@ namespace bvh Kokkos::deep_copy( m_impl->split_indices_h, indices_view ); } + spdlog::logger & + collision_object::logger() const noexcept + { + return *m_impl->logger; + } + + spdlog::logger & + collision_object::broadphase_logger() const noexcept + { + return *m_impl->broadphase_logger; + } + + spdlog::logger & + collision_object::narrowphase_logger() const noexcept + { + return *m_impl->narrowphase_logger; + } + } // namespace bvh diff --git a/src/bvh/collision_object.hpp b/src/bvh/collision_object.hpp index 60bb3b5..0385ff1 100644 --- a/src/bvh/collision_object.hpp +++ b/src/bvh/collision_object.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "snapshot.hpp" #include "split/split.hpp" @@ -98,7 +99,7 @@ namespace bvh const auto od_factor = this->overdecomposition_factor(); const auto num_splits = od_factor - 1; - ::bvh::vt::debug( "{}: clustering {} elements\n", ::vt::theContext()->getNode(), n ); + logger().debug( "obj={} clustering {} elements\n", id(), n ); if ( n != m_clusterer.size() ) { m_clusterer.resize( n ); @@ -189,6 +190,10 @@ namespace bvh span< const patch<> > local_patches() const noexcept; + spdlog::logger &logger() const noexcept; + spdlog::logger &broadphase_logger() const noexcept; + spdlog::logger &narrowphase_logger() const noexcept; + private: friend class collision_world; diff --git a/src/bvh/collision_object/broadphase.cpp b/src/bvh/collision_object/broadphase.cpp index 052eeb5..3f5cb3e 100644 --- a/src/bvh/collision_object/broadphase.cpp +++ b/src/bvh/collision_object/broadphase.cpp @@ -86,15 +86,25 @@ namespace bvh // tmp_idx[1] = static_cast( tree_obj->get_impl().collision_idx ); // - query_tree( tree, patch, [&_msg, local_idx, origin_node, &patch_obj, &tree_obj, &tok]( std::size_t _p, std::size_t _q ){ + + auto &logger = patch_obj->broadphase_logger(); + logger.debug( "(objp={}, size={}) (objq={}, count={}) starting broadphase", patch_obj->id(), patch.size(), tree_obj->id(), tree.count() ); + + query_tree( tree, patch, [&_msg, &logger, local_idx, origin_node, &patch_obj, &tree_obj, &tok]( std::size_t _p, std::size_t _q ){ collision_object_impl::narrowphase_index idx( static_cast< int >( _p ), static_cast( tree_obj->get_impl().collision_idx ), static_cast< int >( _q ) ); + logger.trace( "found broadphase contact <{}, {}, {}, {}>", + patch_obj->id(), _p, tree_obj->id(), _q ); + logger.trace( "obj={} inserting {} into narrowphase collection", patch_obj->id(), idx ); patch_obj->get_impl().narrowphase_collection_proxy[idx].insert( tok ); + logger.trace( "obj={} adding {} to active narrowphase indices", patch_obj->id(), idx ); patch_obj->get_impl().active_narrowphase_indices.emplace_back( idx ); // auto activate_narrowphase_index_msg = ::vt::makeMessage< active_narrowphase_local_index_msg >(); activate_narrowphase_index_msg->idx = local_idx; + logger.trace( " obj={} insert_active_narrow_local_index local_idx={}", + origin_node, patch_obj->id(), local_idx ); patch_obj->get_impl().objgroup[origin_node].sendMsg< active_narrowphase_local_index_msg, &collision_object_impl::collision_object_holder::insert_active_narrow_local_index >( activate_narrowphase_index_msg ); // // Note that the global index `_q` may not be managed by VT on this rank @@ -102,6 +112,8 @@ namespace bvh // auto tree_msg = ::vt::makeMessage< flag_active_narrowpatch_msg >(); tree_msg->patch_obj = _msg->tree_obj; + logger.trace( " obj={} flag_active_narrowpatch", + _q, patch_obj->id() ); tree_obj->get_impl().broadphase_patch_collection_proxy[_q].sendMsg< flag_active_narrowpatch_msg, &flag_active_narrowpatch >( tree_msg ); } ); } diff --git a/src/bvh/collision_object/impl.cpp b/src/bvh/collision_object/impl.cpp index d64f26d..bcf9980 100644 --- a/src/bvh/collision_object/impl.cpp +++ b/src/bvh/collision_object/impl.cpp @@ -32,117 +32,130 @@ */ #include "impl.hpp" #include "narrowphase.hpp" +#include namespace bvh { collision_object::impl::impl( collision_world &_world, std::size_t _idx ) - : world( &_world ), collision_idx( _idx ), + : world( &_world ), + collision_idx( _idx ), snapshots( fmt::format( "contact entity {} snapshot", _idx ), 0 ), split_indices( fmt::format( "contact entity {} split indices", _idx ), 0 ), splits( fmt::format( "contact entity {} splits", _idx ), 0 ), split_indices_h( fmt::format( "contact entity host {} split indices", _idx ), 0 ), - splits_h( fmt::format( "contact entity host {} splits", _idx ), 0 ) - { - } + splits_h( fmt::format( "contact entity host {} splits", _idx ), 0 ), + logger( _world.collision_object_logger() ), + broadphase_logger( _world.collision_object_broadphase_logger() ), + narrowphase_logger( _world.collision_object_narrowphase_logger() ) + {} - namespace collision_object_impl { + namespace collision_object_impl + { // // Define member functions for the class 'collision_object_impl::collision_object_holder' // declared in `types.hpp` // - void collision_object_holder::insert_active_narrow_local_index(active_narrowphase_local_index_msg *_msg ) + void collision_object_holder::insert_active_narrow_local_index( active_narrowphase_local_index_msg *_msg ) { self->get_impl().active_narrowphase_local_index.insert( _msg->idx.x() ); } - void - collision_object_holder::setup_narrowphase(setup_narrowphase_msg *_msg ) + void collision_object_holder::setup_narrowphase( setup_narrowphase_msg *_msg ) { + auto &logger = self->broadphase_logger(); auto &impl = self->get_impl(); auto rank = static_cast< int >( ::vt::theContext()->getNode() ); const auto od_factor = impl.overdecomposition; const std::size_t od_offset = rank * od_factor; auto &patches = impl.narrowphase_patch_collection_proxy; + logger.debug( "obj={}, setting up {} narrowphase patches marked as ready to activate", self->id(), + impl.active_narrowphase_indices.size() ); for ( const auto idx : impl.active_narrowphase_local_index ) { auto send_msg = impl.prepare_local_patch_for_sending( idx, rank ); - patches[od_offset + idx].sendMsg< narrowphase_patch_msg, &collision_object_impl::narrowphase_patch_copy >( send_msg ); + logger.trace( " obj={} narrowphase_patch_copy", od_offset + idx, self->id() ); + patches[od_offset + idx].sendMsg< narrowphase_patch_msg, &collision_object_impl::narrowphase_patch_copy >( + send_msg ); } } - void - collision_object_holder::activate_narrowphase( - start_activate_narrowphase_msg *_msg ) + void collision_object_holder::activate_narrowphase( start_activate_narrowphase_msg *_msg ) { + auto &logger = self->narrowphase_logger(); auto &impl = self->get_impl(); + + logger.debug( "obj={}, activating {} narrowphase patches", self->id(), impl.active_narrowphase_indices.size() ); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< activate_narrowphase_msg >(); - impl.narrowphase_collection_proxy[idx].sendMsg< activate_narrowphase_msg, &collision_object_impl::activate_narrowphase >( msg.get() ); + msg->this_obj = self->get_impl().objgroup; + logger.trace( " obj={} activate_narrowphase", idx, self->id() ); + impl.narrowphase_collection_proxy[idx] + .sendMsg< activate_narrowphase_msg, &collision_object_impl::activate_narrowphase >( msg.get() ); } } - void - collision_object_holder::request_ghosts( - start_ghosting_msg *_msg ) + void collision_object_holder::request_ghosts( start_ghosting_msg *_msg ) { + auto &logger = self->narrowphase_logger(); auto &impl = self->get_impl(); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< start_ghosting_msg >(); msg->this_obj = _msg->this_obj; msg->other_obj = _msg->other_obj; - impl.narrowphase_collection_proxy[idx].sendMsg< start_ghosting_msg, &collision_object_impl::start_ghosting >( msg.get() ); + logger.trace( " objp={}, objq={} start_ghosting", idx, _msg->this_obj.get()->self->id(), + _msg->other_obj.get()->self->id() ); + impl.narrowphase_collection_proxy[idx].sendMsg< start_ghosting_msg, &collision_object_impl::start_ghosting >( + msg.get() ); } } - void - collision_object_holder::start_narrowphase( - start_narrowphase_msg *_msg ) + void collision_object_holder::start_narrowphase( start_narrowphase_msg *_msg ) { auto &impl = self->get_impl(); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< start_narrowphase_msg >(); - impl.narrowphase_collection_proxy[idx].sendMsg< start_narrowphase_msg, &collision_object_impl::start_narrowphase >( msg.get() ); + impl.narrowphase_collection_proxy[idx] + .sendMsg< start_narrowphase_msg, &collision_object_impl::start_narrowphase >( msg.get() ); } } - void - collision_object_holder::clear_narrowphase( - clear_narrowphase_msg *_msg ) + void collision_object_holder::clear_narrowphase( clear_narrowphase_msg *_msg ) { auto &impl = self->get_impl(); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< clear_narrowphase_msg >(); - impl.narrowphase_collection_proxy[idx].sendMsg< clear_narrowphase_msg, &collision_object_impl::clear_narrowphase >( msg.get() ); + impl.narrowphase_collection_proxy[idx] + .sendMsg< clear_narrowphase_msg, &collision_object_impl::clear_narrowphase >( msg.get() ); } } - void - collision_object_holder::begin_narrowphase_modification( messages::modify_msg * ) - { - ::vt::theMsg()->pushEpoch( ::vt::term::any_epoch_sentinel ); - self->get_impl().narrowphase_modification_token = self->get_impl().narrowphase_collection_proxy.beginModification( "broadphase contact insertion" ); - ::vt::theMsg()->popEpoch( ::vt::term::any_epoch_sentinel ); - } + void collision_object_holder::begin_narrowphase_modification( messages::modify_msg * ) + { + ::vt::theMsg()->pushEpoch( ::vt::term::any_epoch_sentinel ); + self->get_impl().narrowphase_modification_token + = self->get_impl().narrowphase_collection_proxy.beginModification( "broadphase contact insertion" ); + ::vt::theMsg()->popEpoch( ::vt::term::any_epoch_sentinel ); + } - void - collision_object_holder::finish_narrowphase_modification( messages::modify_msg * ) - { - self->get_impl().narrowphase_collection_proxy.finishModification( std::move( *self->get_impl().narrowphase_modification_token ) ); - self->get_impl().narrowphase_modification_token = {}; - } + void collision_object_holder::finish_narrowphase_modification( messages::modify_msg * ) + { + self->get_impl().narrowphase_collection_proxy.finishModification( + std::move( *self->get_impl().narrowphase_modification_token ) ); + self->get_impl().narrowphase_modification_token = {}; + } - void - collision_object_holder::cache_patch( ghost_msg *_msg ) + void collision_object_holder::cache_patch( ghost_msg *_msg ) { - ::bvh::vt::debug( "{}: caching patch idx {}\n", ::vt::theContext()->getNode(), _msg->idx ); auto &impl = self->get_impl(); + auto &logger = self->narrowphase_logger(); + logger.debug( "obj={} caching patch idx {}", impl.collision_idx, _msg->idx ); auto &ent = impl.narrowphase_patch_cache[_msg->idx]; @@ -151,19 +164,22 @@ namespace bvh ent.patch_data = _msg->patch_data; } - void - collision_object_holder::set_result( result_msg *_msg ) + void collision_object_holder::set_result( result_msg *_msg ) { self->get_impl().local_results.emplace_back( _msg->result ); } - - void activate_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, activate_narrowphase_msg * ) + void activate_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, activate_narrowphase_msg *_msg ) { + const auto &this_obj = *_msg->this_obj.get()->self; + auto &logger = this_obj.narrowphase_logger(); + auto idx = _narrow->getIndex(); + logger.trace( "marking <{}, {}, {}, {}> as active (epoch={:x})", this_obj.id(), idx[0], idx[1], idx[2], ::vt::envelopeGetEpoch( _msg->env ) ); _narrow->active = true; } - namespace detail { + namespace detail + { struct ghost_request_msg : ::vt::CollectionMessage< collision_object_impl::narrowphase_patch_collection_type > { @@ -174,9 +190,11 @@ namespace bvh void request_ghost( collision_object_impl::narrowphase_patch_collection_type *_patch, ghost_request_msg *_msg ) { + const auto &obj = _patch->collision_object.get()->self; + auto &logger = obj->narrowphase_logger(); // Find destination node for the narrowphase collection element auto dst = _msg->dest_node; - ::bvh::vt::debug( "{}: requesting ghost for index {} to node {}\n", ::vt::theContext()->getNode(), _patch->getIndex(), dst ); + logger.debug( "obj={} requesting ghost for index {} to node {}", obj->id(), _patch->getIndex(), dst ); // Build up ghost_destination list/group. In ghosting step, // this element will be transferred to every node in ghost_destination. @@ -184,72 +202,83 @@ namespace bvh _patch->ghost_destinations.emplace( dst ); } - } // namespace detail + } // namespace detail void start_ghosting( collision_object_impl::narrowphase_collection_type *_narrow, start_ghosting_msg *_msg ) { auto idx = _narrow->getIndex(); auto &this_obj = _msg->this_obj.get()->self; auto &other_obj = _msg->other_obj.get()->self; + auto &logger = this_obj->narrowphase_logger(); // Only do anything if this is active to prev ent residual elements // from earlier iterations if ( !_narrow->active ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- not active\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- not active", this_obj->id(), idx[0], idx[1], idx[2] ); return; } // Only run if we are looking at the right "other obj" if ( other_obj->get_impl().collision_idx != static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- mismatched index\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- mismatched index", this_obj->id(), idx[0], idx[1], idx[2] ); return; } // Ignore self collisions (this will usually be caught by the above condition) if ( this_obj->get_impl().collision_idx == static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- self collision\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "{}: skipping <{}, {}, {}, {}> -- self collision", this_obj->id(), idx[0], idx[1], idx[2] ); return; } _narrow->this_proxy = _msg->this_obj; _narrow->other_proxy = _msg->other_obj; - ::bvh::vt::debug( "{}: start_ghosting ({}, {}, {}, {})\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.debug( "start ghosting <{}, {}, {}, {}>", this_obj->id(), idx[0], idx[1], idx[2] ); auto rank = ::vt::theContext()->getNode(); // Send ghost request to this obj auto msg = ::vt::makeMessage< detail::ghost_request_msg >(); msg->idx = idx; msg->proxy = _narrow->getCollectionProxy(); - //msg->ordering = 0; + // msg->ordering = 0; msg->dest_node = rank; auto this_idx = collision_object_impl::vt_index{ static_cast< std::size_t >( idx[0] ) }; - this_obj->get_impl().narrowphase_patch_collection_proxy[this_idx].sendMsg< detail::ghost_request_msg, &detail::request_ghost >( msg.get() ); + logger.trace( " obj={} requesting primary patch {} from object {}", this_idx, this_obj->id(), this_idx.x(), + this_obj->id() ); + this_obj->get_impl() + .narrowphase_patch_collection_proxy[this_idx] + .sendMsg< detail::ghost_request_msg, &detail::request_ghost >( msg.get() ); // Send ghost request to other obj auto other_msg = ::vt::makeMessage< detail::ghost_request_msg >(); other_msg->idx = idx; other_msg->proxy = _narrow->getCollectionProxy(); other_msg->dest_node = rank; - //other_msg->ordering = 1; + // other_msg->ordering = 1; auto other_idx = collision_object_impl::vt_index{ static_cast< std::size_t >( idx[2] ) }; - other_obj->get_impl().narrowphase_patch_collection_proxy[other_idx].sendMsg< detail::ghost_request_msg, &detail::request_ghost >( other_msg.get() ); + logger.trace( " obj={} requesting secondary patch {} from object {}", other_idx, this_obj->id(), other_idx.x(), + other_obj->id() ); + other_obj->get_impl() + .narrowphase_patch_collection_proxy[other_idx] + .sendMsg< detail::ghost_request_msg, &detail::request_ghost >( other_msg.get() ); } - void - start_narrowphase( narrowphase_collection_type *_narrow, start_narrowphase_msg * ) + void start_narrowphase( narrowphase_collection_type *_narrow, start_narrowphase_msg * ) { auto idx = _narrow->getIndex(); - ::bvh::vt::debug( "{}: narrowphase ({}, {}, {}) epoch={}\n", ::vt::theContext()->getNode(), idx[0], idx[1], idx[2], ::vt::theMsg()->getEpoch() ); auto &this_obj = *_narrow->this_proxy.get()->self; auto &other_obj = *_narrow->other_proxy.get()->self; auto &this_impl = this_obj.get_impl(); auto &other_impl = other_obj.get_impl(); + auto &logger = this_obj.narrowphase_logger(); + logger.debug( "executing narrowphase <{}, {}, {}, {}> in epoch={}", this_obj.id(), idx[0], idx[1], + idx[2], ::vt::theMsg()->getEpoch() ); + // Run actual narrowphase functor auto &world = *this_obj.get_impl().world; auto &world_impl = get_impl( world ); @@ -260,25 +289,29 @@ namespace bvh // Only run if we are looking at the right "other obj" if ( other_obj.get_impl().collision_idx != static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- mismatched index\n", ::vt::theContext()->getNode(), this_obj.get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- mismatched index", + this_obj.id(), idx[0], idx[1], idx[2] ); return; } // Ignore self collisions (this will usually be caught by the above condition) if ( this_obj.get_impl().collision_idx == static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- self collision\n", ::vt::theContext()->getNode(), this_obj.get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- self collision", + this_obj.id(), idx[0], idx[1], idx[2] ); return; } - always_assert(this_impl.narrowphase_patch_cache.find( this_index ) != this_impl.narrowphase_patch_cache.end(), - " Rank {} this_index {} - not present in `narrowphase_patch_cache`\n", ::vt::theContext()->getNode(), - this_index); + BVH_ASSERT_ALWAYS( this_impl.narrowphase_patch_cache.find( this_index ) != this_impl.narrowphase_patch_cache.end(), + logger, + "this_index={} - not present in `narrowphase_patch_cache`", + this_index ); const auto &this_cache = this_impl.narrowphase_patch_cache.at( this_index ); - always_assert(other_impl.narrowphase_patch_cache.find( other_index ) != other_impl.narrowphase_patch_cache.end(), - " Rank {} other_index {} - not present in `narrowphase_patch_cache`\n", ::vt::theContext()->getNode(), - other_index); + BVH_ASSERT_ALWAYS( other_impl.narrowphase_patch_cache.find( other_index ) != other_impl.narrowphase_patch_cache.end(), + logger, + "other_index={} - not present in `narrowphase_patch_cache`", + other_index ); const auto &other_cache = other_impl.narrowphase_patch_cache.at( other_index ); ::vt::NodeType left_node = this_cache.origin_node; @@ -286,30 +319,45 @@ namespace bvh if ( world_impl.functor ) { - ::vt::trace::TraceScopedEvent scope(world_impl.bvh_impl_functor_); - auto r = world_impl.functor( this_obj, this_cache.meta, static_cast< std::size_t >( idx[0] ), this_cache.patch_data.data(), this_cache.patch_data.size(), - other_obj, other_cache.meta, static_cast< std::size_t >( idx[2] ), other_cache.patch_data.data(), other_cache.patch_data.size() ); + ::vt::trace::TraceScopedEvent scope( world_impl.bvh_impl_functor_ ); + auto r = world_impl.functor( this_obj, this_cache.meta, static_cast< std::size_t >( idx[0] ), + this_cache.patch_data.data(), this_cache.patch_data.size(), other_obj, + other_cache.meta, static_cast< std::size_t >( idx[2] ), + other_cache.patch_data.data(), other_cache.patch_data.size() ); if ( r.a.size() > 0 ) { auto lmsg = ::vt::makeMessage< result_msg >(); lmsg->result = std::move( r.a ); - this_obj.get_impl().objgroup[left_node].sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( lmsg ); + logger.trace( " result from <{}, {}, {}, {}>", + left_node, this_obj.id(), idx[0], idx[1], idx[2] ); + this_obj.get_impl() + .objgroup[left_node] + .sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( lmsg ); } if ( r.b.size() > 0 ) { auto rmsg = ::vt::makeMessage< result_msg >(); rmsg->result = std::move( r.b ); - this_obj.get_impl().objgroup[right_node].sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( rmsg ); + logger.trace( " result from <{}, {}, {}, {}>", + right_node, this_obj.id(), idx[0], idx[1], idx[2] ); + this_obj.get_impl() + .objgroup[right_node] + .sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( rmsg ); } } } - void clear_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, clear_narrowphase_msg* ) + void clear_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, clear_narrowphase_msg * ) { + auto &this_obj = *_narrow->this_proxy.get()->self; + auto &logger = this_obj.narrowphase_logger(); + const auto idx = _narrow->getIndex(); + logger.trace( "clearing narrowphase index <{}, {}, {}, {}>", + this_obj.id(), idx[0], idx[1], idx[2] ); _narrow->active = false; } - } // namespace collision_object_impl -} // namespace bvh + } // namespace collision_object_impl +} // namespace bvh diff --git a/src/bvh/collision_object/impl.hpp b/src/bvh/collision_object/impl.hpp index 026031d..b3d5889 100644 --- a/src/bvh/collision_object/impl.hpp +++ b/src/bvh/collision_object/impl.hpp @@ -51,6 +51,10 @@ namespace bvh narrowphase_patch_copy( collision_object_impl::narrowphase_patch_collection_type *_patch, narrowphase_patch_msg *_msg ) { + const auto &obj = *_patch->collision_object.get()->self; + auto &logger = obj.narrowphase_logger(); + auto idx = _patch->getIndex(); + logger.debug( "late initializing narrowphase patch {} with {} bytes", idx.x(), _msg->data_size ); _patch->ghost_destinations.clear(); _patch->patch_meta = _msg->patch_meta; _patch->bytes.resize(_msg->data_size); @@ -86,6 +90,8 @@ namespace bvh ::vt::MsgPtr< collision_object_impl::narrowphase_patch_msg > prepare_local_patch_for_sending( std::size_t _local_idx, int _rank ) { + auto &logger = *broadphase_logger; + using narrowphase_patch_msg = collision_object_impl::narrowphase_patch_msg; const auto idx = _local_idx; @@ -100,8 +106,8 @@ namespace bvh send_msg->data_size = chunk_data_size; std::size_t offset = 0; - ::bvh::vt::debug( "{}: sending narrowphase patch {} for body {} size {}\n", ::vt::theContext()->getNode(), - vt_index{ _local_idx + rank * overdecomposition }, collision_idx, nelements ); + logger.debug( "obj={} sending narrowphase patch {} with {} num elements", + collision_idx, vt_index{ _local_idx + rank * overdecomposition }, nelements ); // Should be replaced with VT serialization for (std::size_t j = sbeg; j < send; ++j) { @@ -175,6 +181,11 @@ namespace bvh host_view< std::size_t * > split_indices_h; host_view< std::size_t * > splits_h; std::size_t num_splits = 0; ///< The number of actual splits -- may be les than splits.extent( 0 ) + + // Loggers + std::shared_ptr< spdlog::logger > logger; + std::shared_ptr< spdlog::logger > broadphase_logger; + std::shared_ptr< spdlog::logger > narrowphase_logger; }; namespace collision_object_impl diff --git a/src/bvh/collision_object/narrowphase.cpp b/src/bvh/collision_object/narrowphase.cpp index 3178c5f..fb68393 100644 --- a/src/bvh/collision_object/narrowphase.cpp +++ b/src/bvh/collision_object/narrowphase.cpp @@ -41,8 +41,6 @@ namespace bvh { namespace collision_object_impl { - void (*narrowphase_patch_collection_type::migrate_hook)( narrowphase_patch_collection_type * ) = nullptr; - pending_send activate_narrowphase( vt_index _local_idx, collision_object_proxy_type _this_obj ) { auto msg = ::vt::makeMessage< start_activate_narrowphase_msg >(); @@ -95,9 +93,11 @@ namespace bvh { auto &this_obj = _this_obj.get()->self; auto &other_obj = _other_obj.get()->self; + auto &logger = this_obj->narrowphase_logger(); auto msg = ::vt::makeMessage< start_ghosting_msg >(); msg->this_obj = this_obj->get_impl().objgroup; msg->other_obj = other_obj->get_impl().objgroup; + logger.debug( " requesting ghosts for objects {} and {} in potential collision", this_obj->id(), other_obj->id() ); return _this_obj[::vt::theContext()->getNode()].sendMsg< start_ghosting_msg, &collision_object_impl::collision_object_holder::request_ghosts >( msg ); } @@ -111,10 +111,12 @@ namespace bvh void send_ghost( collision_object_impl::narrowphase_patch_collection_type *_patch, send_ghost_msg *_msg ) { - ::bvh::vt::debug( "{}: index {} has {} destinations\n", ::vt::theContext()->getNode(), _patch->getIndex(), _patch->ghost_destinations.size() ); + const auto &obj = *_patch->collision_object.get()->self; + auto &logger = obj.narrowphase_logger(); + logger.debug( "obj={} index {} has {} destinations", obj.id(), _patch->getIndex(), _patch->ghost_destinations.size() ); for ( auto &&d : _patch->ghost_destinations ) { - ::bvh::vt::debug( "{}: sending ghost for idx {} to node {}\n", ::vt::theContext()->getNode(), _patch->getIndex(), d ); + logger.debug( " obj={} sending ghost for idx {}", d, obj.id(), _patch->getIndex() ); auto msg = ::vt::makeMessage< ghost_msg >(); msg->meta = _patch->patch_meta; msg->patch_data = _patch->bytes; diff --git a/src/bvh/collision_object/types.hpp b/src/bvh/collision_object/types.hpp index 4690082..b3499d1 100644 --- a/src/bvh/collision_object/types.hpp +++ b/src/bvh/collision_object/types.hpp @@ -36,6 +36,7 @@ #include "../tree.hpp" #include "../serialization/bvh_serialize.hpp" #include "../patch.hpp" +#include #include #include #include @@ -105,44 +106,6 @@ namespace bvh } }; - struct narrowphase_patch_collection_type : ::vt::Collection< narrowphase_patch_collection_type, vt_index > - { - static void ( * migrate_hook )( narrowphase_patch_collection_type * ); - - using MessageParentType = ::vt::Collection< narrowphase_patch_collection_type, vt_index >; - vt_msg_serialize_required(); - - patch<> patch_meta; - std::vector< unsigned char > bytes; - ::vt::NodeType origin_node = ::vt::uninitialized_destination; - std::unordered_set< ::vt::NodeType > ghost_destinations; - - void epiMigrateIn() override - { - if ( migrate_hook ) - migrate_hook( this ); - } - - template< typename Serializer > - void serialize( Serializer &_s ) - { - MessageParentType::serialize( _s ); - _s | patch_meta | bytes | origin_node | ghost_destinations; - } - }; - - // Byte serializable - struct narrowphase_patch_msg : ::vt::CollectionMessage< narrowphase_patch_collection_type > - { - patch<> patch_meta; - ::vt::NodeType origin_node = ::vt::uninitialized_destination; - std::size_t data_size = 0; - - // Used with makeMessageSz, invalid otherwise! - unsigned char *user_data() { return reinterpret_cast< unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); } - const unsigned char *user_data() const { return reinterpret_cast< const unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); } - }; - struct result_msg : ::vt::Message { using MessageParentType = ::vt::Message; @@ -219,6 +182,48 @@ namespace bvh using collision_object_proxy_type = ::vt::objgroup::ObjGroupManager::ProxyType< collision_object_holder >; + struct narrowphase_patch_collection_type : ::vt::Collection< narrowphase_patch_collection_type, vt_index > + { + using MessageParentType = ::vt::Collection< narrowphase_patch_collection_type, vt_index >; + vt_msg_serialize_required(); + + narrowphase_patch_collection_type() = default; + explicit narrowphase_patch_collection_type( collision_object_proxy_type _coll_obj ) + : collision_object( _coll_obj ) + {} + + patch<> patch_meta; + std::vector< unsigned char > bytes; + ::vt::NodeType origin_node = ::vt::uninitialized_destination; + std::unordered_set< ::vt::NodeType > ghost_destinations; + collision_object_proxy_type collision_object; + + template< typename Serializer > void serialize( Serializer &_s ) + { + MessageParentType::serialize( _s ); + _s | patch_meta | bytes | origin_node | ghost_destinations | collision_object; + } + }; + + // Byte serializable + struct narrowphase_patch_msg : ::vt::CollectionMessage< narrowphase_patch_collection_type > + { + patch<> patch_meta; + ::vt::NodeType origin_node = ::vt::uninitialized_destination; + std::size_t data_size = 0; + + // Used with makeMessageSz, invalid otherwise! + unsigned char *user_data() + { + return reinterpret_cast< unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); + } + + const unsigned char *user_data() const + { + return reinterpret_cast< const unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); + } + }; + /** * 3D index -- first dimension references the patch id, * the second index references the object id, of the colliding obj, @@ -233,7 +238,6 @@ namespace bvh narrowphase_collection_type() : active( false ) { - ::bvh::vt::debug( "{}: constructing narrowphase entry\n", ::vt::theContext()->getNode() ); } bool active = false; @@ -255,7 +259,9 @@ namespace bvh { }; struct activate_narrowphase_msg : ::vt::CollectionMessage< collision_object_impl::narrowphase_collection_type > - { }; + { + collision_object_proxy_type this_obj; + }; struct start_ghosting_msg : ::vt::CollectionMessage< collision_object_impl::narrowphase_collection_type > { diff --git a/src/bvh/collision_world.cpp b/src/bvh/collision_world.cpp index 04ddf22..0e978e9 100644 --- a/src/bvh/collision_world.cpp +++ b/src/bvh/collision_world.cpp @@ -33,17 +33,35 @@ #include "collision_world.hpp" #include "collision_object.hpp" #include "collision_world/impl.hpp" +#include "logging.hpp" +#include +#include #include #include namespace bvh { - collision_world::collision_world( std::size_t _overdecomposition_factor ) + collision_world::collision_world( std::size_t _overdecomposition_factor, const world_config &_cfg ) : m_impl( std::make_unique< impl >() ) { + auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_st >(); + stdout_sink->set_level( spdlog::level::trace ); + m_impl->collision_world_logger = logging::make_logger( "collision_world", stdout_sink, _cfg ); + m_impl->collision_world_logger->trace( "Initialized collision world logger" ); + m_impl->collision_object_logger = logging::make_logger( "collision_object", stdout_sink, _cfg ); + m_impl->collision_world_logger->trace( "Initialized collision object logger" ); + m_impl->collision_object_broadphase_logger = logging::make_logger( "collision_object.broadphase", stdout_sink, _cfg ); + m_impl->collision_world_logger->trace( "Initialized collision object broadphase logger" ); + m_impl->collision_object_narrowphase_logger = logging::make_logger( "collision_object.narrowphase", stdout_sink, _cfg ); + m_impl->collision_world_logger->trace( "Initialized collision object narrowphase logger" ); + m_impl->overdecomposition = _overdecomposition_factor; - m_impl->bvh_impl_functor_ = ::vt::theTrace()->registerUserEventColl("bvh_impl_functor_"); + auto user_event_name = "bvh_impl_functor_"; + m_impl->bvh_impl_functor_ = ::vt::theTrace()->registerUserEventColl( user_event_name); + m_impl->collision_world_logger->trace( "registered user tracing event {}", user_event_name ); + + m_impl->collision_world_logger->info( "Initialized collision world with overdecomposition factor {}", _overdecomposition_factor ); } collision_world::~collision_world() = default; @@ -105,4 +123,22 @@ namespace bvh m_impl->epoch = ::vt::no_epoch; } + + std::shared_ptr< spdlog::logger > + collision_world::collision_object_logger() const + { + return m_impl->collision_object_logger; + } + + std::shared_ptr< spdlog::logger > + collision_world::collision_object_broadphase_logger() const + { + return m_impl->collision_object_broadphase_logger; + } + + std::shared_ptr< spdlog::logger > + collision_world::collision_object_narrowphase_logger() const + { + return m_impl->collision_object_narrowphase_logger; + } } diff --git a/src/bvh/collision_world.hpp b/src/bvh/collision_world.hpp index b0f9f7d..6d4ee32 100644 --- a/src/bvh/collision_world.hpp +++ b/src/bvh/collision_world.hpp @@ -39,11 +39,18 @@ #include "snapshot.hpp" #include "util/functional.hpp" #include "tree_build.hpp" +#include namespace bvh { class collision_object; + struct world_config + { + spdlog::level::level_enum log_levels = spdlog::level::trace; + spdlog::level::level_enum flush_level = spdlog::level::trace; + }; + class collision_world { public: @@ -51,7 +58,7 @@ namespace bvh template< typename T > using narrowphase_functor = std::function< narrowphase_result_pair( const broadphase_collision< T > &, const broadphase_collision< T > & ) >; - explicit collision_world( std::size_t _overdecomposition_factor ); + explicit collision_world( std::size_t _overdecomposition_factor, const world_config &_cfg = {} ); ~collision_world(); collision_world( const collision_world & ) = delete; @@ -89,6 +96,10 @@ namespace bvh void start_iteration(); void finish_iteration(); + std::shared_ptr< spdlog::logger > collision_object_logger() const; + std::shared_ptr< spdlog::logger > collision_object_broadphase_logger() const; + std::shared_ptr< spdlog::logger > collision_object_narrowphase_logger() const; + private: struct impl; diff --git a/src/bvh/collision_world/impl.hpp b/src/bvh/collision_world/impl.hpp index 2dcc02d..92d9f52 100644 --- a/src/bvh/collision_world/impl.hpp +++ b/src/bvh/collision_world/impl.hpp @@ -37,6 +37,9 @@ #include #include +#include +#include + namespace bvh { @@ -60,6 +63,10 @@ namespace bvh ::vt::trace::UserEventIDType bvh_impl_functor_ = ::vt::trace::no_user_event_id; + std::shared_ptr< spdlog::logger > collision_world_logger; + std::shared_ptr< spdlog::logger > collision_object_logger; + std::shared_ptr< spdlog::logger > collision_object_broadphase_logger; + std::shared_ptr< spdlog::logger > collision_object_narrowphase_logger; }; } diff --git a/src/bvh/debug/assert.hpp b/src/bvh/debug/assert.hpp index b6f319a..298a0be 100644 --- a/src/bvh/debug/assert.hpp +++ b/src/bvh/debug/assert.hpp @@ -37,6 +37,7 @@ #include #include #include "../vt/print.hpp" +#include namespace bvh { @@ -45,7 +46,7 @@ namespace bvh #else constexpr int assert_debug_level = 0; #endif - + namespace detail { template< bool Enable > @@ -57,7 +58,7 @@ namespace bvh // Do nothing } }; - + template<> struct debug_assert_impl< true > { @@ -72,7 +73,7 @@ namespace bvh } }; } - + template< int DebugLevel, typename... Args > void debug_assert_level( bool _val, const std::string &_msg, Args &&... _args ) { @@ -97,7 +98,25 @@ namespace bvh { always_assert( false, _msg, std::forward< Args >( _args )... ); } + + namespace detail + { + inline void assert_die( spdlog::logger &_logger, const char *_file, unsigned int _line, const char *_assertion, + const std::string &_msg ) + { + _logger.critical( "assertion failed at {}:{}: {} ({})", _file, _line, _assertion, _msg ); + std::terminate(); + } + + inline void assert_die( std::shared_ptr< spdlog::logger > _logger, const char *_file, unsigned int _line, + const char *_assertion, const std::string &_msg ) + { + assert_die( *_logger, _file, _line, _assertion, _msg ); + } + } // namespace detail } +#define BVH_ASSERT_ALWAYS( expr, logger, ... ) \ + ( static_cast< bool >( expr ) ? void( 0 ) : ::bvh::detail::assert_die( logger, __FILE__, __LINE__, #expr, fmt::format( __VA_ARGS__ ) ) ) #endif // INC_BVH_DEBUG_ASSERT_HPP diff --git a/src/bvh/kdop.hpp b/src/bvh/kdop.hpp index d2bfd42..a91b76c 100644 --- a/src/bvh/kdop.hpp +++ b/src/bvh/kdop.hpp @@ -43,6 +43,7 @@ #include "util/attributes.hpp" #include "util/kokkos.hpp" #include "iterators/transform_iterator.hpp" +#include namespace bvh { @@ -714,4 +715,45 @@ namespace bvh }; } +template< typename T > +struct fmt::formatter< bvh::extent< T > > : nested_formatter< T > +{ + auto format( bvh::extent< T > _ext, format_context &_ctx ) const + { + return this->write_padded( _ctx, [=]( auto out ) { + return format_to( out, "[{}, {}]", this->nested( _ext.min ), this->nested( _ext.max ) ); + } ); + } +}; + +template< typename T, int K, typename D > +struct fmt::formatter< bvh::kdop_base< T, K, D > > : nested_formatter< bvh::extent< T > > +{ + auto format( const bvh::kdop_base< T, K, D > &_kd, format_context &_ctx ) const + { + return this->write_padded( _ctx, [=]( auto out ) { + if constexpr ( K <= 0 ) + return format_to( out, "{}-dop: ", K ); + + auto pos = format_to( out, "{}-dop: {}", K, this->nested( _kd.extents[0] ) ); + for ( int i = 1; i < K / 2; ++i ) + pos = format_to( pos, ", {}", this->nested( _kd.extents[i] ) ); + + return pos; + } ); + } +}; + +template< typename T > +struct fmt::formatter< bvh::dop_6< T > > : fmt::formatter< bvh::kdop_base< T, 6, bvh::dop_6< T > > > +{}; + +template< typename T > +struct fmt::formatter< bvh::dop_18< T > > : fmt::formatter< bvh::kdop_base< T, 18, bvh::dop_18< T > > > +{}; + +template< typename T > +struct fmt::formatter< bvh::dop_26< T > > : fmt::formatter< bvh::kdop_base< T, 26, bvh::dop_26< T > > > +{}; + #endif // INC_BVH_KDOP_HPP diff --git a/src/bvh/logging.hpp b/src/bvh/logging.hpp new file mode 100644 index 0000000..ee8d398 --- /dev/null +++ b/src/bvh/logging.hpp @@ -0,0 +1,52 @@ +#ifndef INC_BVH_LOGGING_HPP +#define INC_BVH_LOGGING_HPP + +#include +#include +#include +#include +#include +#include +#include "collision_world.hpp" + +namespace bvh::logging +{ + class rank_formatter_flag : public spdlog::custom_flag_formatter + { + public: + + void + format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &_dest ) override + { + std::string rank_str = std::to_string( ::vt::theContext()->getNode() ); + _dest.append( rank_str.data(), rank_str.data() + rank_str.size() ); + } + + std::unique_ptr< spdlog::custom_flag_formatter > + clone() const override + { + return std::make_unique< rank_formatter_flag >(); + } + }; + + inline std::unique_ptr< spdlog::pattern_formatter > + make_formatter() + { + auto ret = std::make_unique< spdlog::pattern_formatter >(); + ret->add_flag< rank_formatter_flag >( 'N' ).set_pattern( "[%N] %+" ); + return ret; + } + + inline std::shared_ptr< spdlog::logger > make_logger( std::string _name, spdlog::sink_ptr _sink, + const world_config &_cfg ) + { + auto ret = std::make_shared< spdlog::logger >( std::move( _name ), std::move( _sink ) ); + ret->set_formatter( make_formatter() ); + ret->set_level( _cfg.log_levels ); + ret->flush_on( _cfg.flush_level ); + + return ret; + } +} + +#endif // INC_BVH_LOGGING_HPP diff --git a/src/bvh/math/vec.hpp b/src/bvh/math/vec.hpp index 2266820..bddbea6 100644 --- a/src/bvh/math/vec.hpp +++ b/src/bvh/math/vec.hpp @@ -46,6 +46,7 @@ #include "../util/kokkos.hpp" #include "named_access.hpp" #include "ops/vec_ops.hpp" +#include namespace bvh { @@ -342,4 +343,22 @@ namespace bvh } // namespace m } // namespace bvh +template< typename T, unsigned N > +struct fmt::formatter< bvh::m::vec< T, N > > : nested_formatter< T > +{ + auto format( bvh::m::vec< T, N > _vec, format_context &_ctx ) const + { + return this->write_padded( _ctx, [=]( auto out ) { + if constexpr ( N == 0 ) + return format_to( out, "<>" ); + + auto pos = format_to( out, "< {}", this->nested( _vec[0] ) ); + for ( unsigned i = 1; i < N; ++i ) + pos = format_to( pos, ", {}", this->nested( _vec[i] ) ); + + return format_to( pos, " >" ); + } ); + } +}; + #endif // INC_BVH_MATH_VEC_HPP diff --git a/tests/SerializerTest.cpp b/tests/SerializerTest.cpp index 2ea90b9..4046fdf 100644 --- a/tests/SerializerTest.cpp +++ b/tests/SerializerTest.cpp @@ -55,7 +55,7 @@ TEMPLATE_TEST_CASE("a single value can be serialized", "[serializer]", int, doub REQUIRE( serialized->getSize() == sizeof( T ) + 12 ); auto b = *checkpoint::deserialize< T >( serialized->getBuffer() ); - + REQUIRE( b == T{5} ); } @@ -188,7 +188,6 @@ TEST_CASE("narrowphase_patches collection serialization", "[serializer][collisio using narrowphase_patch_collection_type = bvh::collision_object_impl::narrowphase_patch_collection_type; if ( ::vt::theContext()->getNumNodes() > 1 ) { - narrowphase_patch_collection_type::migrate_hook = &narrowphase_patch_check; auto coll_size = vt_index{ static_cast< std::size_t >( 4 * ::vt::theContext()->getNumNodes() ) }; auto ep = ::vt::theTerm()->makeEpochCollective( "narrowphase_patch_test" ); ::vt::theMsg()->pushEpoch( ep ); @@ -227,7 +226,6 @@ TEST_CASE("narrowphase_patches collection serialization", "[serializer][collisio ::vt::theMsg()->popEpoch(); ::vt::theTerm()->finishedEpoch( ep ); ::vt::runSchedulerThrough( ep ); - narrowphase_patch_collection_type::migrate_hook = nullptr; } } @@ -241,7 +239,7 @@ TEMPLATE_TEST_CASE("multiple values can be serialized", "[serializer]", int, dou s << T{ 17 } << static_cast< T >( 21.3 ) << static_cast< T >( 3.9 ); s >> a >> b >> c; - + REQUIRE( a == T{ 17 } ); REQUIRE( b == static_cast< T >( 21.3 ) ); REQUIRE( c == static_cast< T >( 3.9 ) ); @@ -251,13 +249,13 @@ TEST_CASE("multiple differently-typed values can be serialized", "[serializer]") { bvh::serializer s; s << 5 << 3.7 << 1.1f; - + int a; double b; float c; - + s >> a >> b >> c; - + REQUIRE( a == 5 ); REQUIRE( b == 3.7 ); REQUIRE( c == 1.1f ); @@ -283,7 +281,7 @@ TEST_CASE("strings can be serialized", "[serializer]") TEST_CASE("char array literals can be serialized and deserialized as strings", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; s << "hello, " << "world"; @@ -300,19 +298,19 @@ TEST_CASE("char array literals can be serialized and deserialized as strings", " TEST_CASE("a simple vector can be serialized", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< int >{ 1, 2, 3 }; - + s << v; std::vector< int > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i] == v[i] ); } @@ -321,9 +319,9 @@ struct NonTrivial { NonTrivial() = default; NonTrivial( int _m ) : m( _m ) {} - + int m; - + virtual ~NonTrivial() {} }; @@ -332,7 +330,7 @@ bvh::serializer_interface< Serializer > & operator<<( bvh::serializer_interface< Serializer > &_serializer, const NonTrivial &_nt ) { _serializer << _nt.m; - + return _serializer; } @@ -341,26 +339,26 @@ bvh::serializer_interface< Serializer > & operator>>( bvh::serializer_interface< Serializer > &_serializer, NonTrivial &_nt ) { _serializer >> _nt.m; - + return _serializer; } TEST_CASE("vectors of custom serialized types can be serialized", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< NonTrivial >{ 1, 2, 3 }; - + s << v; std::vector< NonTrivial > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i].m == v[i].m ); } @@ -368,19 +366,19 @@ TEST_CASE("vectors of custom serialized types can be serialized", "[serializer]" TEST_CASE("a nontrivial vector that wraps an int can be identically deserialized as a vector of ints", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< NonTrivial >{ 1, 2, 3 }; - + s << v; std::vector< int > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i] == v[i].m ); } @@ -388,19 +386,19 @@ TEST_CASE("a nontrivial vector that wraps an int can be identically deserialized TEST_CASE("a vector of ints can be identically deserialized as nontrivial wrapper type", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< int >{ 1, 2, 3 }; - + s << v; std::vector< NonTrivial > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i].m == v[i] ); } @@ -408,35 +406,35 @@ TEST_CASE("a vector of ints can be identically deserialized as nontrivial wrappe TEST_CASE("a dop26d can be serialized", "[serializer]") { auto kdop = bvh::dop_26d::from_sphere( 0.0, 0.0, 0.0, 1.0 ); - + bvh::serializer s; - + s << kdop; - + bvh::dop_26d kdop2; - + s >> kdop2; - + REQUIRE( kdop == kdop2 ); } TEST_CASE("an empty tree can be serialized", "[serializer]") { auto tree = bvh::snapshot_tree_26d< Element >{}; - + bvh::serializer s; - + s << tree; - + auto tree2 = bvh::snapshot_tree_26d< Element >{}; - + s >> tree2; - + REQUIRE( tree2.debug_validate() ); - + REQUIRE( tree2.count() == 0 ); REQUIRE( tree.count() == tree2.count() ); - + REQUIRE( tree == tree2 ); } @@ -444,20 +442,20 @@ TEST_CASE("a tree can be serialized", "[serializer]") { auto elements = buildElementGrid( 2, 2, 2 ); auto tree = bvh::build_snapshot_tree_top_down(elements ); - + bvh::serializer s; - + s << tree; - + auto tree2 = bvh::snapshot_tree_26d< Element >{}; - + s >> tree2; - + REQUIRE_NOTHROW( tree2.debug_validate() ); - + REQUIRE( tree2.count() == elements.size() ); REQUIRE( tree.count() == tree2.count() ); - + REQUIRE( tree == tree2 ); } @@ -465,20 +463,20 @@ TEST_CASE("a tree with a single element can be serialized", "[serializer]") { auto elements = buildElementGrid( 1, 1, 1 ); auto tree = bvh::build_snapshot_tree_top_down(elements ); - + bvh::serializer s; - + s << tree; - + auto tree2 = bvh::snapshot_tree_26d< Element >{}; - + s >> tree2; - + REQUIRE_NOTHROW( tree2.debug_validate() ); - + REQUIRE( tree2.count() == elements.size() ); REQUIRE( tree.count() == tree2.count() ); - + REQUIRE( tree == tree2 ); } #endif diff --git a/tpl/CMakeLists.txt b/tpl/CMakeLists.txt new file mode 100644 index 0000000..e69de29