Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove systems if their parent entity is removed #2232

Merged
merged 53 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
33f47e8
Remove systems if their parent entity is removed
arjo129 Nov 7, 2023
b932354
Fix vector removal routine.
arjo129 Nov 8, 2023
45c4910
Reduce performace impact by only running when there are entities to
arjo129 Nov 8, 2023
0a7c065
style
arjo129 Nov 8, 2023
1e7416f
style
arjo129 Nov 8, 2023
453b54b
Style
arjo129 Nov 8, 2023
4d9809a
Stopped things from going :boom:
arjo129 Nov 9, 2023
968c3ac
Now the PosePublisher system likes to go :boom:
arjo129 Nov 9, 2023
862ff3d
Debugging inputs
arjo129 Nov 16, 2023
b4e07a3
Remove "optimization"
arjo129 Nov 24, 2023
f67db9e
Style
arjo129 Nov 24, 2023
f16bad1
Adds a container to handle system removal better.
arjo129 Mar 15, 2024
8294888
Add unit tests
arjo129 Mar 18, 2024
53e951a
Style
arjo129 Mar 18, 2024
446e816
Style
arjo129 Mar 18, 2024
7ecefdc
Style
arjo129 Mar 18, 2024
19b418c
Update barrier documentation.
arjo129 Mar 19, 2024
e84d9dc
Rework barrier and add test.
arjo129 Mar 19, 2024
b5878e5
Use the new simplified drop API.
arjo129 Mar 19, 2024
3dd4395
Fixed systemcontainer logic bug.
arjo129 May 7, 2024
4d104ec
Cleaner version of the fix.
arjo129 May 7, 2024
483e19a
Rename according to @scpeters feedback.
arjo129 May 7, 2024
5ded114
Fix spelling error and style
arjo129 May 7, 2024
378399d
Style
arjo129 May 7, 2024
391496f
Remove the use of `std::iterator`
arjo129 May 8, 2024
6114175
Fix thread safety concern
arjo129 May 8, 2024
f486fb8
Style
arjo129 May 8, 2024
574ab2d
Apply suggestions from code review
arjo129 Jun 18, 2024
f5b3878
Rename and update class
arjo129 Jun 19, 2024
5581525
Simplified logic using stl algorithms
arjo129 Jun 19, 2024
3a39ff5
Make cpplint happy
arjo129 Jun 19, 2024
9dafb7d
Destroy system immedately
arjo129 Jun 19, 2024
6eb2d2f
Style
arjo129 Jun 19, 2024
91521b7
Style
arjo129 Jun 19, 2024
36ed0ad
Fix crash and revert pose-publisher changes.
arjo129 Jul 4, 2024
b7a7d8c
Revert debug changes
arjo129 Jul 4, 2024
1e73b05
Style
arjo129 Jul 4, 2024
e0b3a9e
style
arjo129 Jul 8, 2024
2d6f115
style
arjo129 Jul 8, 2024
5e27af8
Avoid cross-thread communication
arjo129 Jul 9, 2024
18d122c
stashing temporarily
arjo129 Jul 9, 2024
ff833ce
Significantly reworked how things work
arjo129 Jul 9, 2024
33d5d4f
Remove unrelated changes
arjo129 Jul 9, 2024
e4174c4
Style
arjo129 Jul 9, 2024
26aa106
Style
arjo129 Jul 9, 2024
8e12607
Merge branch 'main' into arjo/feat/remove_systems_with_entities
scpeters Jul 9, 2024
401e501
Change variable name
arjo129 Jul 10, 2024
21a18cf
Stylistic feedback
arjo129 Jul 10, 2024
7b370c2
Move logical check
arjo129 Jul 10, 2024
b792bfa
Rename Variable
arjo129 Jul 10, 2024
00a6e47
Docstring
arjo129 Jul 10, 2024
7026b57
Use parentEntity available in `systems` instead of storing it for eac…
azeey Jul 12, 2024
ed980d9
Merge branch 'main' into arjo/feat/remove_systems_with_entities
scpeters Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/gz/sim/EntityComponentManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,9 @@ namespace gz
friend class GuiRunner;
friend class SimulationRunner;

// Make SystemManager friend so it has access to removals
friend class SystemManager;

// Make network managers friends so they have control over component
// states. Like the runners, the managers are internal.
friend class NetworkManagerPrimary;
Expand Down
10 changes: 8 additions & 2 deletions src/SimulationRunner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <gz/msgs/world_stats.pb.h>

#include <sdf/Root.hh>
#include <vector>

#include "gz/common/Profiler.hh"
#include "gz/sim/components/Model.hh"
Expand Down Expand Up @@ -533,12 +534,15 @@ void SimulationRunner::ProcessSystemQueue()
{
auto pending = this->systemMgr->PendingCount();

if (0 == pending)
if (0 == pending && !this->threadsNeedCleanUp)
return;

// If additional systems are to be added, stop the existing threads.
// If additional systems are to be added or have been removed,
// stop the existing threads.
this->StopWorkerThreads();

this->threadsNeedCleanUp = false;

this->systemMgr->ActivatePendingSystems();

unsigned int threadCount =
Expand Down Expand Up @@ -922,6 +926,8 @@ void SimulationRunner::Step(const UpdateInfo &_info)
this->ProcessRecreateEntitiesCreate();

// Process entity removals.
this->systemMgr->ProcessRemovedEntities(this->entityCompMgr,
this->threadsNeedCleanUp);
this->entityCompMgr.ProcessRemoveEntityRequests();

// Process components removals
Expand Down
3 changes: 3 additions & 0 deletions src/SimulationRunner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ namespace gz
/// at the appropriate time.
private: std::unique_ptr<msgs::WorldControlState> newWorldControlState;

/// \brief Set if we need to remove systems due to entity removal
private: bool threadsNeedCleanUp;

private: bool resetInitiated{false};
friend class LevelManager;
};
Expand Down
17 changes: 11 additions & 6 deletions src/SimulationRunner_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/

#include <gtest/gtest.h>

#include <tinyxml2.h>

#include <gz/msgs/clock.pb.h>
Expand Down Expand Up @@ -111,7 +110,6 @@ void rootClockCb(const msgs::Clock &_msg)
rootClockMsgs.push_back(_msg);
}


/////////////////////////////////////////////////
TEST_P(SimulationRunnerTest, CreateEntities)
{
Expand Down Expand Up @@ -1484,8 +1482,7 @@ TEST_P(SimulationRunnerTest,
EXPECT_TRUE(runner.EntityCompMgr().EntityHasComponentType(sphereEntity,
componentId)) << componentId;

// Remove entities that have plugin - this is not unloading or destroying
// the plugin though!
// Remove entities that have plugin
auto entityCount = runner.EntityCompMgr().EntityCount();
const_cast<EntityComponentManager &>(
runner.EntityCompMgr()).RequestRemoveEntity(boxEntity);
Expand Down Expand Up @@ -1533,8 +1530,16 @@ TEST_P(SimulationRunnerTest,
SimulationRunner runner(rootWithout.WorldByIndex(0), systemLoader,
serverConfig);

// 1 model plugin from SDF and 2 world plugins from config
ASSERT_EQ(3u, runner.SystemCount());
// 1 model plugin from SDF and 1 world plugin from config
// and 1 model plugin from theconfig
EXPECT_EQ(3u, runner.SystemCount());
runner.SetPaused(false);
runner.Run(1);

// Remove the model. Only 1 world plugin should remain.
EXPECT_TRUE(runner.RequestRemoveEntity("box"));
runner.Run(2);
EXPECT_EQ(1u, runner.SystemCount());
}

/////////////////////////////////////////////////
Expand Down
133 changes: 133 additions & 0 deletions src/SystemManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
*/

#include <list>
#include <mutex>
#include <set>
#include <unordered_set>

#include <gz/common/StringUtils.hh>

#include "SystemInternal.hh"
#include "gz/sim/components/SystemPluginInfo.hh"
#include "gz/sim/Conversions.hh"
#include "SystemManager.hh"
Expand Down Expand Up @@ -122,7 +125,9 @@ size_t SystemManager::ActivatePendingSystems()
this->systemsUpdate.push_back(system.update);

if (system.postupdate)
{
this->systemsPostupdate.push_back(system.postupdate);
}
}

this->pendingSystems.clear();
Expand Down Expand Up @@ -409,3 +414,131 @@ void SystemManager::ProcessPendingEntitySystems()
}
this->systemsToAdd.clear();
}

template <typename T>
struct identity
{
using type = T;
};

//////////////////////////////////////////////////
/// TODO(arjo) - When we move to C++20 we can just use erase_if
/// Removes all items that match the given predicate.
/// This function runs in O(n) time and uses memory in-place
template<typename Tp>
void RemoveFromVectorIf(std::vector<Tp>& vec,
typename identity<std::function<bool(const Tp&)>>::type pred)
{
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}

//////////////////////////////////////////////////
void SystemManager::ProcessRemovedEntities(
const EntityComponentManager &_ecm,
bool &_needsCleanUp)
{
// Note: This function has O(n) time when an entity is removed
// where n is number of systems. Ideally we would only iterate
// over entities marked for removal but that would involve having
// a key value map. This can be marked as a future improvement.
if (!_ecm.HasEntitiesMarkedForRemoval())
{
return;
}

std::unordered_set<ISystemReset *> resetSystemsToBeRemoved;
std::unordered_set<ISystemPreUpdate *> preupdateSystemsToBeRemoved;
std::unordered_set<ISystemUpdate *> updateSystemsToBeRemoved;
std::unordered_set<ISystemPostUpdate *> postupdateSystemsToBeRemoved;
std::unordered_set<ISystemConfigure *> configureSystemsToBeRemoved;
std::unordered_set<ISystemConfigureParameters *>
configureParametersSystemsToBeRemoved;
for (const auto &system : this->systems)
{
if (_ecm.IsMarkedForRemoval(system.parentEntity))
{
if (system.reset)
{
resetSystemsToBeRemoved.insert(system.reset);
}
if (system.preupdate)
{
preupdateSystemsToBeRemoved.insert(system.preupdate);
}
if (system.update)
{
updateSystemsToBeRemoved.insert(system.update);
}
if (system.postupdate)
{
postupdateSystemsToBeRemoved.insert(system.postupdate);
// If system with a PostUpdate is marked for removal
// mark all worker threads for removal.
_needsCleanUp = true;
}
if (system.configure)
{
configureSystemsToBeRemoved.insert(system.configure);
}
if (system.configureParameters)
{
configureParametersSystemsToBeRemoved.insert(
system.configureParameters);
}
}
}

RemoveFromVectorIf(this->systemsReset,
[&](const auto system) {
if (resetSystemsToBeRemoved.count(system)) {
return true;
}
return false;
});
RemoveFromVectorIf(this->systemsPreupdate,
[&](const auto& system) {
if (preupdateSystemsToBeRemoved.count(system)) {
return true;
}
return false;
});
RemoveFromVectorIf(this->systemsUpdate,
[&](const auto& system) {
if (updateSystemsToBeRemoved.count(system)) {
return true;
}
return false;
});

RemoveFromVectorIf(this->systemsPostupdate,
[&](const auto& system) {
if (postupdateSystemsToBeRemoved.count(system)) {
return true;
}
return false;
});
RemoveFromVectorIf(this->systemsConfigure,
[&](const auto& system) {
if (configureSystemsToBeRemoved.count(system)) {
return true;
}
return false;
});
RemoveFromVectorIf(this->systemsConfigureParameters,
[&](const auto& system) {
if (configureParametersSystemsToBeRemoved.count(system)) {
return true;
}
return false;
});
RemoveFromVectorIf(this->systems,
[&](const SystemInternal& _arg) {
return _ecm.IsMarkedForRemoval(_arg.parentEntity);
});

std::lock_guard lock(this->pendingSystemsMutex);
RemoveFromVectorIf(this->pendingSystems,
[&](const SystemInternal& _system) {
return _ecm.IsMarkedForRemoval(_system.parentEntity);
});
}
8 changes: 8 additions & 0 deletions src/SystemManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ namespace gz
/// \brief Process system messages and add systems to entities
public: void ProcessPendingEntitySystems();

/// \brief Remove systems that are attached to removed entities
/// \param[in] _entityCompMgr - ECM with entities marked for removal
arjo129 marked this conversation as resolved.
Show resolved Hide resolved
/// \param[out] _needsCleanUp - Set to true if a system with a
/// PostUpdate was removed, and its thread needs to be terminated
public: void ProcessRemovedEntities(
const EntityComponentManager &_entityCompMgr,
bool &_needsCleanUp);

/// \brief Implementation for AddSystem functions that takes an SDF
/// element. This calls the AddSystemImpl that accepts an SDF Plugin.
/// \param[in] _system Generic representation of a system.
Expand Down
65 changes: 65 additions & 0 deletions src/SystemManager_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,71 @@ TEST(SystemManager, AddSystemEcm)
EXPECT_EQ(1u, systemMgr.SystemsPostUpdate().size());
}

/////////////////////////////////////////////////
TEST(SystemManager, AddAndRemoveSystemEcm)
{
auto loader = std::make_shared<SystemLoader>();

auto ecm = EntityComponentManager();
auto eventManager = EventManager();

auto paramRegistry = std::make_unique<
gz::transport::parameters::ParametersRegistry>("SystemManager_TEST");
SystemManager systemMgr(
loader, &ecm, &eventManager, std::string(), paramRegistry.get());

EXPECT_EQ(0u, systemMgr.ActiveCount());
EXPECT_EQ(0u, systemMgr.PendingCount());
EXPECT_EQ(0u, systemMgr.TotalCount());
EXPECT_EQ(0u, systemMgr.SystemsConfigure().size());
EXPECT_EQ(0u, systemMgr.SystemsPreUpdate().size());
EXPECT_EQ(0u, systemMgr.SystemsUpdate().size());
EXPECT_EQ(0u, systemMgr.SystemsPostUpdate().size());

auto configSystem = std::make_shared<SystemWithConfigure>();
systemMgr.AddSystem(configSystem, kNullEntity, nullptr);

auto entity = ecm.CreateEntity();

auto updateSystemWithChild = std::make_shared<SystemWithUpdates>();
systemMgr.AddSystem(updateSystemWithChild, entity, nullptr);

// Configure called during AddSystem
EXPECT_EQ(1, configSystem->configured);
EXPECT_EQ(1, configSystem->configuredParameters);

EXPECT_EQ(0u, systemMgr.ActiveCount());
EXPECT_EQ(2u, systemMgr.PendingCount());
EXPECT_EQ(2u, systemMgr.TotalCount());
EXPECT_EQ(0u, systemMgr.SystemsConfigure().size());
EXPECT_EQ(0u, systemMgr.SystemsPreUpdate().size());
EXPECT_EQ(0u, systemMgr.SystemsUpdate().size());
EXPECT_EQ(0u, systemMgr.SystemsPostUpdate().size());

systemMgr.ActivatePendingSystems();
EXPECT_EQ(2u, systemMgr.ActiveCount());
EXPECT_EQ(0u, systemMgr.PendingCount());
EXPECT_EQ(2u, systemMgr.TotalCount());
EXPECT_EQ(1u, systemMgr.SystemsConfigure().size());
EXPECT_EQ(1u, systemMgr.SystemsPreUpdate().size());
EXPECT_EQ(1u, systemMgr.SystemsUpdate().size());
EXPECT_EQ(1u, systemMgr.SystemsPostUpdate().size());

// Remove the entity
ecm.RequestRemoveEntity(entity);
bool needsCleanUp;
systemMgr.ProcessRemovedEntities(ecm, needsCleanUp);

EXPECT_TRUE(needsCleanUp);
EXPECT_EQ(1u, systemMgr.ActiveCount());
EXPECT_EQ(0u, systemMgr.PendingCount());
EXPECT_EQ(1u, systemMgr.TotalCount());
EXPECT_EQ(1u, systemMgr.SystemsConfigure().size());
EXPECT_EQ(0u, systemMgr.SystemsPreUpdate().size());
EXPECT_EQ(0u, systemMgr.SystemsUpdate().size());
EXPECT_EQ(0u, systemMgr.SystemsPostUpdate().size());
}

/////////////////////////////////////////////////
TEST(SystemManager, AddSystemWithInfo)
{
Expand Down
Loading