From 972b44f726b597d8c016aff41c2cf2da40876c53 Mon Sep 17 00:00:00 2001 From: joanvallve <jvallve@iri.upc.edu> Date: Fri, 29 May 2020 16:37:33 +0200 Subject: [PATCH] working on removal order --- src/capture/capture_base.cpp | 10 +++---- src/factor/factor_base.cpp | 10 +++---- src/feature/feature_base.cpp | 10 +++---- src/frame/frame_base.cpp | 10 +++---- src/landmark/landmark_base.cpp | 9 +++---- src/solver/solver_manager.cpp | 4 +-- test/gtest_solver_manager.cpp | 48 +++++++++++++++++++++++++++++----- 7 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/capture/capture_base.cpp b/src/capture/capture_base.cpp index 9facee2ec..db50a89fa 100644 --- a/src/capture/capture_base.cpp +++ b/src/capture/capture_base.cpp @@ -63,14 +63,14 @@ CaptureBase::~CaptureBase() void CaptureBase::remove(bool viral_remove_empty_parent) { - /* Important to ensure that lower nodes are removed first. - * Factors should be removed first, and afterwards the rest of nodes containing state blocks. - * Then, REMOVE notifications are sent to the problem in the correct order. - * In case multi-threading solver interrupts notifications, in the solver - * there won't be factors (not yet notified to remove) with already removed state blocks. + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) */ if (!is_removing_) { + WOLF_INFO("CaptureBase::remove"); is_removing_ = true; CaptureBasePtr this_C = shared_from_this(); // keep this alive while removing it diff --git a/src/factor/factor_base.cpp b/src/factor/factor_base.cpp index b3b54c5a4..bc54b2f1a 100644 --- a/src/factor/factor_base.cpp +++ b/src/factor/factor_base.cpp @@ -67,14 +67,14 @@ FactorBase::FactorBase(const std::string& _tp, void FactorBase::remove(bool viral_remove_empty_parent) { - /* Important to ensure that lower nodes are removed first. - * Factors should be removed first, and afterwards the rest of nodes containing state blocks. - * Then, REMOVE notifications are sent to the problem in the correct order. - * In case multi-threading solver interrupts notifications, in the solver - * there won't be factors (not yet notified to remove) with already removed state blocks. + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) */ if (!is_removing_) { + WOLF_INFO("FactorBase::remove"); is_removing_ = true; FactorBasePtr this_fac = shared_from_this(); // keep this alive while removing it diff --git a/src/feature/feature_base.cpp b/src/feature/feature_base.cpp index 9f01a18c3..8f91944fe 100644 --- a/src/feature/feature_base.cpp +++ b/src/feature/feature_base.cpp @@ -39,14 +39,14 @@ FeatureBase::~FeatureBase() void FeatureBase::remove(bool viral_remove_empty_parent) { - /* Important to ensure that lower nodes are removed first. - * Factors should be removed first, and afterwards the rest of nodes containing state blocks. - * Then, REMOVE notifications are sent to the problem in the correct order. - * In case multi-threading solver interrupts notifications, in the solver - * there won't be factors (not yet notified to remove) with already removed state blocks. + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) */ if (!is_removing_) { + WOLF_INFO("FeatureBase::remove"); is_removing_ = true; FeatureBasePtr this_f = shared_from_this(); // keep this alive while removing it diff --git a/src/frame/frame_base.cpp b/src/frame/frame_base.cpp index 8c670de81..47fb6fae2 100644 --- a/src/frame/frame_base.cpp +++ b/src/frame/frame_base.cpp @@ -117,14 +117,14 @@ FrameBase::~FrameBase() void FrameBase::remove(bool viral_remove_empty_parent) { - /* Important to ensure that lower nodes are removed first. - * Factors should be removed first, and afterwards the rest of nodes containing state blocks. - * Then, REMOVE notifications are sent to the problem in the correct order. - * In case multi-threading solver interrupts notifications, in the solver - * there won't be factors (not yet notified to remove) with already removed state blocks. + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) */ if (!is_removing_) { + WOLF_INFO("FrameBase::remove"); is_removing_ = true; FrameBasePtr this_F = shared_from_this(); // keep this alive while removing it diff --git a/src/landmark/landmark_base.cpp b/src/landmark/landmark_base.cpp index 6510fc671..42877a8e3 100644 --- a/src/landmark/landmark_base.cpp +++ b/src/landmark/landmark_base.cpp @@ -37,11 +37,10 @@ LandmarkBase::~LandmarkBase() void LandmarkBase::remove(bool viral_remove_empty_parent) { - /* Important to ensure that lower nodes are removed first. - * Factors should be removed first, and afterwards the rest of nodes containing state blocks. - * Then, REMOVE notifications are sent to the problem in the correct order. - * In case multi-threading solver interrupts notifications, in the solver - * there won't be factors (not yet notified to remove) with already removed state blocks. + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) */ if (!is_removing_) { diff --git a/src/solver/solver_manager.cpp b/src/solver/solver_manager.cpp index 00c9c4454..1c3bcc60a 100644 --- a/src/solver/solver_manager.cpp +++ b/src/solver/solver_manager.cpp @@ -131,7 +131,7 @@ void SolverManager::addFactor(const FactorBasePtr& fac_ptr) for (const auto& st : fac_ptr->getStateBlockPtrVector()) if (state_blocks_.count(st) == 0) { - WOLF_WARN("\n************\n************\nSolverManager::addFactor(): Factor ", fac_ptr->id(), " is notified to ADD but the involved state block ", st, " is not. Skipping, will be added later."); + WOLF_WARN("SolverManager::addFactor(): Factor ", fac_ptr->id(), " is notified to ADD but the involved state block ", st, " is not. Skipping, will be added later."); // put back notification in problem (will be added next update() call) and do nothing wolf_problem_->notifyFactor(fac_ptr, ADD); return; @@ -234,7 +234,7 @@ void SolverManager::removeStateBlock(const StateBlockPtr& state_ptr) */ if (!state_blocks_2_factors_.at(state_ptr).empty()) { - WOLF_WARN("\n************\n************\nSolverManager::addFactor(): StateBlock ", state_ptr, " is notified to REMOVE but ", state_blocks_2_factors_.at(state_ptr).size(), " involved factors still not removed. Skipping, will be removed later."); + WOLF_WARN("SolverManager::removeStateBlock(): StateBlock ", state_ptr, " is notified to REMOVE but ", state_blocks_2_factors_.at(state_ptr).size(), " involved factors still not removed. Skipping, will be removed later."); // put back notification in problem (will be removed next update() call) and do nothing wolf_problem_->notifyStateBlock(state_ptr, REMOVE); return; diff --git a/test/gtest_solver_manager.cpp b/test/gtest_solver_manager.cpp index d4ad57425..646f43d12 100644 --- a/test/gtest_solver_manager.cpp +++ b/test/gtest_solver_manager.cpp @@ -18,6 +18,7 @@ #include "dummy/solver_manager_dummy.h" #include <iostream> +#include <thread> using namespace wolf; using namespace Eigen; @@ -433,7 +434,7 @@ TEST(SolverManager, AddFactor) FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // notification Notification notif; @@ -460,7 +461,7 @@ TEST(SolverManager, RemoveFactor) FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // update solver solver_manager_ptr->update(); @@ -494,7 +495,7 @@ TEST(SolverManager, AddRemoveFactor) auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // notification Notification notif; @@ -524,12 +525,12 @@ TEST(SolverManager, DoubleRemoveFactor) Vector2d state; state << 1, 2; StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); - // Create (and add) factor point 2d + // Create (and add) factor pose 2d FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // update solver solver_manager_ptr->update(); @@ -550,9 +551,44 @@ TEST(SolverManager, DoubleRemoveFactor) ASSERT_FALSE(solver_manager_ptr->isFactorRegistered(c)); } +TEST(SolverManager, MultiThreadingTruncatedNotifications) +{ + double Dt = 5.0; + ProblemPtr P = Problem::create("PO", 2); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); + + // loop updating (without sleep) + std::thread t([&](){ + auto start_t = std::chrono::high_resolution_clock::now(); + while (true) + { + solver_manager_ptr->update(); + if (std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start_t).count() > Dt) + break; + }}); + + // loop emplacing and removing frames (window of 10 KF) + auto start = std::chrono::high_resolution_clock::now(); + while (true) + { + // Emplace Frame, Capture, feature and factor pose 2d + FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); + auto f = FeatureBase::emplace<FeatureBase>(C, "FeaturePose2d", Vector3d::Zero(), Matrix3d::Identity()); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + + if (P->getTrajectory()->getFrameList().size() > 10) + P->getTrajectory()->getFrameList().front()->remove(); + + if (std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start).count() > Dt) + break; + } + + t.join(); +} + int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - -- GitLab