From d481c724a3f014cce39f982210db66b0da16cd83 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 4 Mar 2019 17:09:23 +0100
Subject: [PATCH] Add SynchronizerManager repository

This singleton stores Synchronizer's associated to a given Connectivity. This
allows a lazy built of synchronization info.

Stored Synchronizer's are deleted when Connectivity's destructor is called
---
 src/main.cpp                     |  6 ++++
 src/mesh/CMakeLists.txt          |  3 +-
 src/mesh/Connectivity.hpp        |  5 ++-
 src/mesh/ItemValueUtils.hpp      |  5 ++-
 src/mesh/Synchronizer.hpp        |  2 --
 src/mesh/SynchronizerManager.cpp | 53 ++++++++++++++++++++++++++++++++
 src/mesh/SynchronizerManager.hpp | 37 ++++++++++++++++++++++
 7 files changed, 106 insertions(+), 5 deletions(-)
 create mode 100644 src/mesh/SynchronizerManager.cpp
 create mode 100644 src/mesh/SynchronizerManager.hpp

diff --git a/src/main.cpp b/src/main.cpp
index 466806afb..fe8b4eb48 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,6 +22,8 @@
 
 #include <GmshReader.hpp>
 
+#include <SynchronizerManager.hpp>
+
 #include <limits>
 #include <map>
 
@@ -30,6 +32,8 @@ int main(int argc, char *argv[])
   std::string filename = initialize(argc, argv);
   std::map<std::string, double> method_cost_map;
 
+  SynchronizerManager::create();
+
   if (filename != "") {
     pout() << "Reading (gmsh) " << rang::style::underline << filename << rang::style::reset << " ...\n";
     Timer gmsh_timer;
@@ -373,6 +377,8 @@ int main(int argc, char *argv[])
     std::exit(0);
   }
 
+  SynchronizerManager::destroy();
+
   finalize();
 
   std::string::size_type size=0;
diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt
index e9f66aa5c..3569306a4 100644
--- a/src/mesh/CMakeLists.txt
+++ b/src/mesh/CMakeLists.txt
@@ -7,7 +7,8 @@ add_library(
   PastisMesh
   Connectivity.cpp
   ConnectivityComputer.cpp
-  GmshReader.cpp)
+  GmshReader.cpp
+  SynchronizerManager.cpp)
 
 include_directories(${PASTIS_BINARY_DIR}/src/utils)
 
diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index bebb67e01..e07a26a27 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -31,6 +31,8 @@
 #include <RefNodeList.hpp>
 #include <RefFaceList.hpp>
 
+#include <SynchronizerManager.hpp>
+
 #include <tuple>
 #include <algorithm>
 #include <set>
@@ -635,7 +637,8 @@ class Connectivity final
  public:
   ~Connectivity()
   {
-    ;
+    auto& manager = SynchronizerManager::instance();
+    manager.deleteConnectivitySynchronizer(this);
   }
 };
 
diff --git a/src/mesh/ItemValueUtils.hpp b/src/mesh/ItemValueUtils.hpp
index d6f60ebcb..6c45be4c2 100644
--- a/src/mesh/ItemValueUtils.hpp
+++ b/src/mesh/ItemValueUtils.hpp
@@ -6,6 +6,7 @@
 
 #include <Connectivity.hpp>
 
+#include <SynchronizerManager.hpp>
 #include <Synchronizer.hpp>
 
 template <typename DataType,
@@ -300,7 +301,9 @@ void synchronize(ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
 {
   static_assert(not std::is_const_v<DataType>, "cannot synchronize ItemValue of const data");
   if (parallel::size() > 1) {
-    static Synchronizer synchronizer;
+    auto& manager = SynchronizerManager::instance();
+    const IConnectivity* connectivity = item_value.connectivity_ptr().get();
+    Synchronizer& synchronizer = manager.getConnectivitySynchronizer(connectivity);
     synchronizer.synchronize(item_value);
   }
 }
diff --git a/src/mesh/Synchronizer.hpp b/src/mesh/Synchronizer.hpp
index 8f82e3a33..a44a17ed3 100644
--- a/src/mesh/Synchronizer.hpp
+++ b/src/mesh/Synchronizer.hpp
@@ -61,8 +61,6 @@ class Synchronizer
     using ItemId = ItemIdT<item_type>;
 
     auto& requested_item_info = this->_getRequestedItemInfo<item_type>();
-
-    pout() << "... building synchronization info\n";
     requested_item_info
         = [&] () {
             std::vector<std::vector<ItemId>> requested_item_vector_info(parallel::size());
diff --git a/src/mesh/SynchronizerManager.cpp b/src/mesh/SynchronizerManager.cpp
new file mode 100644
index 000000000..1db720e39
--- /dev/null
+++ b/src/mesh/SynchronizerManager.cpp
@@ -0,0 +1,53 @@
+#include <SynchronizerManager.hpp>
+#include <PastisAssert.hpp>
+
+#include <Messenger.hpp>
+#include <Synchronizer.hpp>
+
+SynchronizerManager*
+SynchronizerManager::m_instance{nullptr};
+
+SynchronizerManager::
+~SynchronizerManager()
+{
+  if (m_connectivity_synchronizer_map.size() > 0)
+  {
+    perr() << __FILE__ << ':' << __LINE__
+           << ": warning: some connectivities are still registered\n";;
+  }
+}
+
+void SynchronizerManager::create()
+{
+  Assert(m_instance == nullptr, "SynchronizerManager is already created");
+  m_instance = new SynchronizerManager;
+}
+
+void SynchronizerManager::destroy()
+{
+  Assert(m_instance != nullptr, "SynchronizerManager was not created!");
+  delete m_instance;
+  m_instance = nullptr;
+}
+
+
+void
+SynchronizerManager::
+deleteConnectivitySynchronizer(const IConnectivity* connectivity)
+{
+  m_connectivity_synchronizer_map.erase(connectivity);
+}
+
+Synchronizer&
+SynchronizerManager::
+getConnectivitySynchronizer(const IConnectivity* connectivity)
+{
+  if (auto connectivity_synchronizer = m_connectivity_synchronizer_map.find(connectivity);
+      connectivity_synchronizer != m_connectivity_synchronizer_map.end()) {
+    return (*connectivity_synchronizer->second);
+  } else {
+    std::shared_ptr synchronizer = std::make_shared<Synchronizer>();
+    m_connectivity_synchronizer_map[connectivity] = synchronizer;
+    return *synchronizer;
+  }
+}
diff --git a/src/mesh/SynchronizerManager.hpp b/src/mesh/SynchronizerManager.hpp
new file mode 100644
index 000000000..3fdf57d9b
--- /dev/null
+++ b/src/mesh/SynchronizerManager.hpp
@@ -0,0 +1,37 @@
+#ifndef SYNCHRONIZER_MANAGER_HPP
+#define SYNCHRONIZER_MANAGER_HPP
+
+#include <PastisMacros.hpp>
+#include <PastisAssert.hpp>
+
+#include <memory>
+#include <map>
+
+class IConnectivity;
+class Synchronizer;
+
+class SynchronizerManager
+{
+ private:
+  std::map<const IConnectivity*, std::shared_ptr<Synchronizer>> m_connectivity_synchronizer_map;
+
+  static SynchronizerManager* m_instance;
+  SynchronizerManager() = default;
+  ~SynchronizerManager();
+
+ public:
+  static void create();
+  static void destroy();
+
+  PASTIS_INLINE
+  static SynchronizerManager& instance()
+  {
+    Assert(m_instance != nullptr, "SynchronizerManager was not created!");
+    return *m_instance;
+  }
+
+  void deleteConnectivitySynchronizer(const IConnectivity*);
+  Synchronizer& getConnectivitySynchronizer(const IConnectivity*);
+};
+
+#endif // SYNCHRONIZER_MANAGER_HPP
-- 
GitLab