Skip to content

Commit

Permalink
add optimization to elide uploading of empty update messages
Browse files Browse the repository at this point in the history
  • Loading branch information
nmm0 committed Dec 5, 2023
1 parent 60313d1 commit 5272d12
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 36 deletions.
34 changes: 24 additions & 10 deletions src/bvh/collision_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ namespace bvh

vt::debug( "objgroup make_collective {:x}\n", m_impl->objgroup.getProxy() );
});

m_impl->local_patches.resize( m_impl->overdecomposition );
}

collision_object::collision_object( collision_object && ) noexcept = default;
Expand All @@ -112,6 +114,8 @@ namespace bvh

m_impl->num_splits = m_impl->splits.extent( 0 );

std::swap( m_impl->last_step_local_patches, m_impl->local_patches );

m_impl->local_patches.clear();
m_impl->local_patches.resize( od_factor );

Expand Down Expand Up @@ -161,16 +165,26 @@ namespace bvh
// Update the data; od_factor should be identical across nodes
std::size_t offset = rank * od_factor;
m_impl->chainset.nextStep( "broadphase_patch_step", [this, rank, offset]( vt_index _local ) {
auto msg = ::vt::makeMessage< broadphase_patch_msg >();
msg->patch = m_impl->local_patches.at( _local.x() );
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() );
return m_impl->broadphase_patch_collection_proxy[vt_index{ _local.x() + offset }]
.sendMsg< broadphase_patch_msg, &details::set_broadphase_patches >( msg.get() );
const auto &local_patch = m_impl->local_patches.at( _local.x() );
const auto &last_step_local_patch = m_impl->last_step_local_patches.at( _local.x() );

// A patch may become empty and we need to update it
// But if it was empty last time step and it's empty this time step, don't update
// We could also do a more complete diff against the patch
if ( !local_patch.empty() || !last_step_local_patch.empty()
|| ( last_step_local_patch.global_id() == static_cast< broadphase_patch_type::index_type >( -1 ) ) )
{
auto msg = ::vt::makeMessage< broadphase_patch_msg >();
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() );
return m_impl->broadphase_patch_collection_proxy[vt_index{ _local.x() + offset }]
.sendMsg< broadphase_patch_msg, &details::set_broadphase_patches >( msg.get() );
} else {
return pending_send{ nullptr };
}
} );

// Right now use top down algorithm
Expand Down
1 change: 1 addition & 0 deletions src/bvh/collision_object/impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ namespace bvh
std::size_t collision_idx;

std::vector< broadphase_patch_type > local_patches;
std::vector< broadphase_patch_type > last_step_local_patches;
std::vector< ::vt::MsgPtr< collision_object_impl::narrowphase_patch_msg > > narrowphase_patch_messages;
std::vector< std::size_t > local_data_indices;

Expand Down
27 changes: 19 additions & 8 deletions src/bvh/collision_object/top_down.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ namespace bvh

tree_reduction() = default;

tree_reduction( collision_object_proxy_type _collision_object )
: m_collision_object_proxy( _collision_object ),
m_snapshots{}
{}

tree_reduction( entity_snapshot _initial, collision_object_proxy_type _collision_object )
: m_collision_object_proxy( _collision_object ),
m_snapshots{ _initial }
Expand All @@ -63,6 +68,7 @@ namespace bvh
tree_reduction &operator+=( const tree_reduction &_other )
{
// The collision object proxies should be the same so no need to reduce those
debug_assert( m_collision_object_proxy.getProxy() == _other.m_collision_object_proxy.getProxy(), "collision objects must match" );
m_snapshots += _other.m_snapshots;
return *this;
}
Expand Down Expand Up @@ -96,23 +102,28 @@ namespace bvh

void tree_build_reduce( const tree_reduction &_reduc )
{
// Build the tree
auto msg = ::vt::makeMessage< broadphase_tree_msg >();
msg->tree = build_tree_top_down< tree_type >( _reduc.snapshots() );
// Build the tree
auto msg = ::vt::makeMessage< broadphase_tree_msg >();
msg->tree = build_tree_top_down< tree_type >( _reduc.snapshots() );

// Broadcast to every element of the collision object objgroup
_reduc.collision_object_proxy().broadcastMsg< broadphase_tree_msg, &collision_object_holder::delegate< broadphase_tree_msg, &set_broadphase_trees > >( msg );
// Broadcast to every element of the collision object objgroup
_reduc.collision_object_proxy().broadcastMsg< broadphase_tree_msg, &collision_object_holder::delegate< broadphase_tree_msg, &set_broadphase_trees > >( msg );
}

void tree_build_broadcast( broadphase_patch_collection_type *_patch, tree_build_broadcast_msg *_msg )
{
auto snap = make_snapshot( _patch->patch, static_cast< std::size_t >( _patch->getIndex().x() ) );

using ::vt::collective::reduce::makeStamp;
using ::vt::collective::reduce::StrongUserID;
auto stamp = makeStamp<StrongUserID>(static_cast<uint64_t>(::vt::thePhase()->getCurrentPhase()));

_patch->getCollectionProxy().reduce< tree_build_reduce, ::vt::collective::PlusOp >( 0, tree_reduction{ snap, _msg->coll_obj }, stamp );
// Don't build a snapshot of an empty patch
if ( !_patch->patch.empty() )
{
auto snap = make_snapshot( _patch->patch, static_cast< std::size_t >( _patch->getIndex().x() ) );
_patch->getCollectionProxy().reduce< tree_build_reduce, ::vt::collective::PlusOp >( 0, tree_reduction{ snap, _msg->coll_obj }, stamp );
} else {
_patch->getCollectionProxy().reduce< tree_build_reduce, ::vt::collective::PlusOp >( 0, tree_reduction{ _msg->coll_obj }, stamp );
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/bvh/collision_object/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ namespace bvh
vt_msg_serialize_required();

broadphase_patch_type patch;
::vt::NodeType origin_node;
vt_index local_idx;
::vt::NodeType origin_node = {};
vt_index local_idx = {};

template< typename Serializer >
void serialize( Serializer &_s )
Expand Down
43 changes: 27 additions & 16 deletions tests/collision_object_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,29 @@ struct test_sing_trees
{
auto nranks = ::vt::theContext()->getNumNodes();
REQUIRE( _tree.count() == od_factor * nranks );
}

for ( auto &&l : _tree.leafs() )
{
REQUIRE( l.kdop().centroid() == bvh::m::vec3d::zeros() );
}
std::size_t od_factor;
};

struct test_empty_trees
{
void operator()( const bvh::snapshot_tree &_tree )
{
auto nranks = ::vt::theContext()->getNumNodes();
REQUIRE( _tree.count() == 0 );
}

std::size_t od_factor;
};

std::size_t test_od_factor = 0;

void verify_num_elements( std::size_t _count )
{
bvh::vt::debug("{}: count: {}\n", ::vt::theContext()->getNode(), _count );
REQUIRE( _count == 12 * ::vt::theContext()->getNumNodes() );
// Cube test_od_factor because each dimension is multiplied...
REQUIRE( _count == 12 * ::vt::theContext()->getNumNodes() * test_od_factor * test_od_factor * test_od_factor );
};

void
Expand All @@ -90,12 +99,13 @@ verify_empty_elements( std::size_t _count )
TEST_CASE( "collision_object init", "[vt]")
{
std::size_t od_factor = GENERATE( 1, 2, 4, 32, 64 );
test_od_factor = od_factor;
bvh::collision_world world( od_factor );

auto &obj = world.create_collision_object();

auto rank = ::vt::theContext()->getNode();
auto elements = build_element_grid( 2, 3, 2, rank * 12 );
auto elements = build_element_grid( 2 * od_factor, 3 * od_factor, 2 * od_factor, rank * 12 * od_factor );
const std::array bound_vers{ bvh::m::vec3d{ 0.0, 0.0, 0.0 },
bvh::m::vec3d{ 0.0, 0.0, 1.0 },
bvh::m::vec3d{ 0.0, 1.0, 0.0 },
Expand All @@ -105,16 +115,17 @@ TEST_CASE( "collision_object init", "[vt]")
bvh::m::vec3d{ 1.0, 1.0, 0.0 },
bvh::m::vec3d{ 1.0, 1.0, 1.0 } };
const auto bounds = Element::kdop_type::from_vertices( bound_vers.begin(), bound_vers.end() );
const std::array update_bounds_vers{ bvh::m::vec3d{ 0.0, 0.0, 0.0 } };
const std::array update_bounds_vers{ bvh::m::vec3d{ 10.0, 10.0, 10.0 },
bvh::m::vec3d{ 10.0, 10.0, 11.0 },
bvh::m::vec3d{ 10.0, 11.0, 10.0 },
bvh::m::vec3d{ 10.0, 11.0, 11.0 },
bvh::m::vec3d{ 11.0, 10.0, 10.0 },
bvh::m::vec3d{ 11.0, 10.0, 11.0 },
bvh::m::vec3d{ 11.0, 11.0, 10.0 },
bvh::m::vec3d{ 11.0, 11.0, 11.0 } };
const auto update_bounds = Element::kdop_type::from_vertices( update_bounds_vers.begin(), update_bounds_vers.end() );
bvh::vt::debug( "{}: bounds: {}\n", ::vt::theContext()->getNode(), bounds );
auto update_elements = bvh::view< Element * >{ "sing_vec", 12 };
Kokkos::parallel_for(
12, KOKKOS_LAMBDA( int _i ) {
update_elements( _i ).setVertices( bvh::m::vec3d::zeros(), bvh::m::vec3d::zeros(), bvh::m::vec3d::zeros(),
bvh::m::vec3d::zeros(), bvh::m::vec3d::zeros(), bvh::m::vec3d::zeros(),
bvh::m::vec3d::zeros(), bvh::m::vec3d::zeros() );
} );
auto update_elements = build_element_grid( 2 * od_factor, 3 * od_factor, 2 * od_factor, rank * 12 * od_factor, 10.0 );

auto split_method
= GENERATE( bvh::split_algorithm::geom_axis, bvh::split_algorithm::ml_geom_axis, bvh::split_algorithm::clustering );
Expand Down Expand Up @@ -199,7 +210,7 @@ TEST_CASE( "collision_object init", "[vt]")
obj.set_entity_data( empty_elements, split_method );
obj.init_broadphase();

obj.for_each_tree( test_trees{ od_factor } );
obj.for_each_tree( test_empty_trees{ od_factor } );
} );

vt::runInEpochCollective( "set_data.init.check", [&]() {
Expand All @@ -218,7 +229,7 @@ TEST_CASE( "collision_object init", "[vt]")
obj.set_entity_data( empty_elements, split_method );
obj.init_broadphase();

obj.for_each_tree( test_sing_trees{ od_factor } );
obj.for_each_tree( test_empty_trees{ od_factor } );
} );

vt::runInEpochCollective( "set_data.update.check", [&]() {
Expand Down

0 comments on commit 5272d12

Please sign in to comment.