Parcourir la source

pdevs: MPI version

Eric Ramat il y a 9 ans
Parent
commit
81522c3fc5

+ 1 - 1
CMakeLists.txt

@@ -97,7 +97,7 @@ ENDIF (WIN32)
 SET(Boost_DETAILED_FAILURE_MSG FALSE)
 SET(Boost_DEBUG FALSE)
 
-FIND_PACKAGE(Boost COMPONENTS graph timer system)
+FIND_PACKAGE(Boost COMPONENTS graph mpi timer serialization system)
 IF (NOT Boost_GRAPH_FOUND)
   MESSAGE(FATAL_ERROR "The boost graph library is required")
 ENDIF (NOT Boost_GRAPH_FOUND)

+ 24 - 0
src/paradevs/common/Bag.hpp

@@ -29,6 +29,8 @@
 
 #include <paradevs/common/ExternalEvent.hpp>
 
+#include <boost/serialization/vector.hpp>
+
 #include <sstream>
 #include <string>
 #include <vector>
@@ -60,6 +62,28 @@ public:
         ss << "}";
         return ss.str();
     }
+
+private:
+    friend class boost::serialization::access;
+
+    template<class Archive>
+    void save(Archive & ar, const unsigned int version) const
+    {
+        (void) version;
+
+        ar & *dynamic_cast < const std::vector < ExternalEvent < Time > >* >(
+            this);
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int version)
+    {
+        (void) version;
+
+        ar & *dynamic_cast < std::vector < ExternalEvent < Time > >* >(this);
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
 
 } } // namespace paradevs common

+ 1 - 2
src/paradevs/common/CMakeLists.txt

@@ -7,8 +7,7 @@ INCLUDE_DIRECTORIES(
 
 LINK_DIRECTORIES(
   ${GLIBMM_LIBRARY_DIRS}
-  ${LIBXML_LIBRARY_DIR}
-  ${Boost_LIBRARY_DIRS})
+  ${LIBXML_LIBRARY_DIR})
 
 SET(COMMON_HPP Bag.hpp Coordinator.hpp ExternalEvent.hpp InternalEvent.hpp
   Links.hpp Model.hpp Node.hpp Parameters.hpp RootCoordinator.hpp Scheduler.hpp

+ 23 - 3
src/paradevs/common/ExternalEvent.hpp

@@ -30,6 +30,8 @@
 #include <paradevs/common/Model.hpp>
 #include <paradevs/common/Node.hpp>
 
+#include <boost/serialization/serialization.hpp>
+
 #include <sstream>
 #include <string>
 #include <vector>
@@ -83,12 +85,30 @@ public:
     {
         std::ostringstream ss;
 
-        ss << "( " << _port_name << " , " << (_model?_model->get_name():"<>")
-           << " , " << *(double*)_content << ")";
+        ss << "( " << _port_name << " , "
+           << (_model ? _model->get_name() : "<>")
+           << " , ";
+        if (_content) {
+            ss << *(double*)_content;
+        } else {
+            ss << "null";
+        }
+        ss << ")";
         return ss.str();
     }
 
-private :
+private:
+    friend class boost::serialization::access;
+
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int version)
+    {
+        (void) version;
+
+        ar & _port_name;
+        // ar & _model->get_name();
+    }
+
     std::string     _port_name;
     Model < Time >* _model;
     void*           _content;

+ 3 - 0
src/paradevs/common/Model.hpp

@@ -118,6 +118,9 @@ public:
 
     virtual bool is_atomic() const = 0;
 
+    virtual bool is_remote() const
+    { return false; }
+
     void set_parent(Model < Time >* parent)
     { _parent = parent; }
 

+ 2 - 1
src/paradevs/kernel/pdevs/CMakeLists.txt

@@ -13,4 +13,5 @@ SET(PDEVS_HPP Coordinator.hpp Dynamics.hpp GraphManager.hpp Simulator.hpp)
 
 INSTALL(FILES ${PDEVS_HPP} DESTINATION ${PARADEVS_INCLUDE_DIRS}/kernel/pdevs)
 
-ADD_SUBDIRECTORY(multithreading)
+ADD_SUBDIRECTORY(multithreading)
+ADD_SUBDIRECTORY(mpi)

+ 15 - 8
src/paradevs/kernel/pdevs/GraphManager.hpp

@@ -93,14 +93,8 @@ public:
                      it != result_model.second; ++it) {
                 // event on output port of coupled Model
                 if (it->second.get_model() == _coordinator) {
-                    common::Bag < Time > ymessages;
-
-                    ymessages.push_back(
-                        common::ExternalEvent <Time >(it->second,
-                                                      ymsg.get_content()));
-                    dynamic_cast < common::Coordinator < Time >* >(
-                        _coordinator->get_parent())->dispatch_events(
-                            ymessages, t);
+                    dispatch_events_to_parent(it->second, ymsg.get_content(),
+                                              t);
                 } else { // event on input port of internal model
                     it->second.get_model()->post_event(
                         t, common::ExternalEvent < Time >(
@@ -110,6 +104,19 @@ public:
         }
     }
 
+    virtual void dispatch_events_to_parent(common::Node < Time > node,
+                                           void* content,
+                                           typename Time::type t)
+    {
+        common::Bag < Time > ymessages;
+
+        ymessages.push_back(
+            common::ExternalEvent <Time >(node, content));
+        dynamic_cast < common::Coordinator < Time >* >(
+            _coordinator->get_parent())->dispatch_events(
+                ymessages, t);
+    }
+
     bool exist_link(common::Model < Time >* src_model,
                     const std::string& src_port_name,
                     common::Model < Time >* dst_model,

+ 16 - 0
src/paradevs/kernel/pdevs/mpi/CMakeLists.txt

@@ -0,0 +1,16 @@
+INCLUDE_DIRECTORIES(
+  ${PARADEVS_BINARY_DIR}/src
+  ${PARADEVS_SOURCE_DIR}/src
+  ${Boost_INCLUDE_DIRS}
+  ${GLIBMM_INCLUDE_DIRS}
+  ${LIBXML_INCLUDE_DIRS})
+
+LINK_DIRECTORIES(
+  ${GLIBMM_LIBRARY_DIRS}
+  ${LIBXML_LIBRARY_DIR})
+
+SET(PDEVS_MPI_HPP Coordinator.hpp GraphManager.hpp LogicalProcessor.hpp
+  ModelProxy.hpp)
+
+INSTALL(FILES ${PDEVS_MPI_HPP} DESTINATION
+  ${PARADEVS_INCLUDE_DIRS}/kernel/pdevs/mpi)

+ 69 - 0
src/paradevs/kernel/pdevs/mpi/Coordinator.hpp

@@ -0,0 +1,69 @@
+/**
+ * @file kernel/pdevs/mpi/Coordinator.hpp
+ * @author The PARADEVS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * PARADEVS - the multimodeling and simulation environment
+ * This file is a part of the PARADEVS environment
+ *
+ * Copyright (C) 2013-2015 ULCO http://www.univ-litoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PDEVS_MPI_COORDINATOR
+#define PDEVS_MPI_COORDINATOR 1
+
+#include <paradevs/kernel/pdevs/Coordinator.hpp>
+#include <paradevs/kernel/pdevs/mpi/LogicalProcessor.hpp>
+
+namespace paradevs { namespace pdevs { namespace mpi {
+
+template < class Time,
+           class GraphManager,
+           class Parameters = common::NoParameters,
+           class GraphParameters = common::NoParameters >
+class Coordinator : public pdevs::Coordinator < Time, GraphManager,
+                                                Parameters, GraphParameters >
+{
+    typedef pdevs::Coordinator < Time, GraphManager,
+                                 Parameters, GraphParameters > parent_type;
+    typedef Coordinator < Time, GraphManager,
+                          Parameters, GraphParameters > type;
+
+public:
+    Coordinator(const std::string& name,
+                const Parameters& parameters,
+                const GraphParameters& graph_parameters) :
+        common::Model < Time >(name),
+        pdevs::Coordinator < Time, GraphManager,
+                             Parameters, GraphParameters >(name, parameters,
+                                                           graph_parameters)
+    { }
+
+    virtual ~Coordinator()
+    { }
+
+    virtual bool is_remote() const
+    { return true; }
+
+    void set_logical_processor(LogicalProcessor < Time >* logical_processor)
+    { parent_type::_graph_manager.set_logical_processor(logical_processor); }
+};
+
+} } } // namespace paradevs pdevs mpi
+
+#endif

+ 75 - 0
src/paradevs/kernel/pdevs/mpi/GraphManager.hpp

@@ -0,0 +1,75 @@
+/**
+ * @file kernel/pdevs/GraphManager.hpp
+ * @author The PARADEVS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * PARADEVS - the multimodeling and simulation environment
+ * This file is a part of the PARADEVS environment
+ *
+ * Copyright (C) 2013-2015 ULCO http://www.univ-litoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PDEVS_MPI_GRAPH_MANANGER
+#define PDEVS_MPI_GRAPH_MANANGER 1
+
+#include <paradevs/kernel/pdevs/mpi/Coordinator.hpp>
+#include <paradevs/kernel/pdevs/mpi/LogicalProcessor.hpp>
+
+#include <sstream>
+
+namespace paradevs { namespace pdevs { namespace mpi {
+
+template < class Time,
+           class GraphParameters = common::NoParameters >
+class GraphManager : public pdevs::GraphManager < Time, GraphParameters >
+{
+public:
+    GraphManager(common::Coordinator < Time >* coordinator,
+                 const GraphParameters& parameters) :
+        pdevs::GraphManager < Time, GraphParameters >(coordinator, parameters)
+    { }
+
+    virtual ~GraphManager()
+    { }
+
+    virtual void dispatch_events_to_parent(common::Node < Time > node,
+                                           void* content,
+                                           typename Time::type t)
+    {
+/*        common::Bag < Time > ymessages;
+
+        ymessages.push_back(
+            common::ExternalEvent <Time >(node, content));
+        dynamic_cast < common::Coordinator < Time >* >(
+            _coordinator->get_parent())->dispatch_events(
+            ymessages, t); */
+
+        _logical_processor->dispatch_events_to_parent(node, content, t);
+
+    }
+
+    void set_logical_processor(LogicalProcessor < Time >* logical_processor)
+    { _logical_processor = logical_processor; }
+
+private:
+    LogicalProcessor < Time >* _logical_processor;
+};
+
+} } } // namespace paradevs pdevs mpi
+
+#endif

+ 114 - 0
src/paradevs/kernel/pdevs/mpi/LogicalProcessor.hpp

@@ -0,0 +1,114 @@
+/**
+ * @file kernel/pdevs/mpi/LogicalProcessor.hpp
+ * @author The PARADEVS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * PARADEVS - the multimodeling and simulation environment
+ * This file is a part of the PARADEVS environment
+ *
+ * Copyright (C) 2013-2015 ULCO http://www.univ-litoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PDEVS_MPI_LOGICAL_PROCESSOR
+#define PDEVS_MPI_LOGICAL_PROCESSOR 1
+
+#include <paradevs/kernel/pdevs/mpi/ModelProxy.hpp>
+
+#include <boost/mpi/communicator.hpp>
+
+namespace paradevs { namespace pdevs { namespace mpi {
+
+template < class Time >
+class LogicalProcessor
+{
+    typedef LogicalProcessor < Time > type;
+
+public:
+    LogicalProcessor(common::Model < Time >* model, int rank, int parent) :
+        _rank(rank),
+        _parent(parent),
+        _model(model)
+    { }
+
+    virtual ~LogicalProcessor()
+    { }
+
+    void dispatch_events_to_parent(common::Node < Time > node,
+                                   void* content,
+                                   typename Time::type t)
+    {
+        (void) t;
+
+        _output_bag.push_back(common::ExternalEvent <Time >(node, content));
+    }
+
+    void loop()
+    {
+        typename Time::type t;
+
+        for(;;) {
+            boost::mpi::status msg = _communicator.probe();
+
+            switch (msg.tag()) {
+            case finish_send_tag:
+                return;
+            case output_send_tag:
+                {
+                    _communicator.recv(_parent, output_send_tag, t);
+                    _model->output(t);
+                    _communicator.send(_parent, output_receive_tag,
+                                       _output_bag);
+                    _output_bag.clear();
+                    break;
+                }
+            case post_event_send_tag:
+                {
+                    common::ExternalEvent < Time > event;
+
+                    _communicator.recv(_parent, post_event_send_tag, t);
+                    _communicator.recv(_parent, post_event_send_tag, event);
+                    _model->post_event(t, event);
+                    break;
+                }
+            case start_send_tag:
+                _communicator.recv(_parent, start_send_tag, t);
+                _communicator.send(_parent, tn_receive_tag,
+                                   _model->start(t));
+                break;
+            case transition_send_tag:
+                _communicator.recv(_parent, transition_send_tag, t);
+                _communicator.send(_parent, tn_receive_tag,
+                                   _model->transition(t));
+                break;
+            default:
+                throw std::runtime_error("Invalid tag");
+            }
+        }
+    };
+
+private:
+    int _rank;
+    int _parent;
+    boost::mpi::communicator _communicator;
+    common::Model < Time >* _model;
+    common::Bag < Time > _output_bag;
+};
+
+} } } // namespace paradevs pdevs mpi
+
+#endif

+ 150 - 0
src/paradevs/kernel/pdevs/mpi/ModelProxy.hpp

@@ -0,0 +1,150 @@
+/**
+ * @file kernel/pdevs/mpi/ModelProxy.hpp
+ * @author The PARADEVS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * PARADEVS - the multimodeling and simulation environment
+ * This file is a part of the PARADEVS environment
+ *
+ * Copyright (C) 2013-2015 ULCO http://www.univ-litoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PDEVS_MPI_MODEL_PROXY
+#define PDEVS_MPI_MODEL_PROXY 1
+
+#include <paradevs/common/Model.hpp>
+
+#include <boost/mpi/communicator.hpp>
+
+namespace paradevs { namespace pdevs { namespace mpi {
+
+enum Tags
+{
+    finish_send_tag,
+    output_send_tag,
+    post_event_send_tag,
+    start_send_tag,
+    transition_send_tag,
+    output_receive_tag,
+    tn_receive_tag
+};
+
+template < class Time >
+class ModelProxy : public common::Model < Time >
+{
+    typedef common::Model < Time > parent_type;
+    typedef ModelProxy < Time > type;
+
+public:
+    ModelProxy(const std::string& name, int rank, bool atomic) :
+        common::Model < Time >(name), _atomic(atomic), _rank(rank)
+    { }
+
+    virtual ~ModelProxy()
+    { _communicator.send(_rank, finish_send_tag); }
+
+    virtual bool is_atomic() const
+    { return _atomic; }
+
+    virtual std::string to_string(int level) const
+    {
+        (void) level;
+
+        return std::string();
+    }
+
+    virtual void observation(std::ostream& file) const
+    {
+        (void) file;
+    }
+
+    virtual void output(typename Time::type t)
+    {
+        try {
+            typename common::Bag < Time > bag;
+
+            _communicator.send(_rank, output_send_tag, t);
+            _communicator.recv(_rank, output_receive_tag, bag);
+            dispatch_events(bag, t);
+        } catch (const boost::mpi::exception& e) {
+            std::cout << e.what() << std::endl;
+        }
+    }
+
+    virtual void post_event(typename Time::type t,
+                            const common::ExternalEvent < Time >& event)
+    {
+        try {
+            _communicator.send(_rank, post_event_send_tag, t);
+            _communicator.send(_rank, post_event_send_tag, event);
+        } catch (const boost::mpi::exception& e) {
+            std::cout << e.what() << std::endl;
+        }
+    }
+
+    virtual typename Time::type dispatch_events(common::Bag < Time > bag,
+                                                typename Time::type t)
+    {
+        for (auto & event : bag) {
+            event.set_model(this);
+        }
+        return dynamic_cast < common::Coordinator < Time >* >(
+            parent_type::get_parent())->dispatch_events(bag, t);
+    }
+
+    virtual typename Time::type start(typename Time::type t)
+    {
+        try {
+            _communicator.send(_rank, start_send_tag, t);
+
+            typename Time::type tn;
+
+            _communicator.recv(_rank, tn_receive_tag, tn);
+            type::_tl = t;
+            type::_tn = tn;
+        } catch (const boost::mpi::exception& e) {
+            std::cout << e.what() << std::endl;
+        }
+        return type::_tn;
+    }
+
+    virtual typename Time::type transition(typename Time::type t)
+    {
+        try {
+            _communicator.send(_rank, transition_send_tag, t);
+
+            typename Time::type tn;
+
+            _communicator.recv(_rank, tn_receive_tag, tn);
+            type::_tl = t;
+            type::_tn = tn;
+        } catch (const boost::mpi::exception& e) {
+            std::cout << e.what() << std::endl;
+        }
+        return type::_tn;
+    }
+
+private:
+    bool _atomic;
+    boost::mpi::communicator _communicator;
+    int _rank;
+};
+
+} } } // namespace paradevs pdevs mpi
+
+#endif