From 0bd33fe6921edba91d6fd98e3521653695e12e29 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Jun 2012 10:56:59 +0200 Subject: [PATCH 01/52] Serialization of EO user objects. --- eo/src/CMakeLists.txt | 1 + eo/src/eo | 3 + eo/src/serial/Array.cpp | 38 ++++++++ eo/src/serial/Array.h | 149 +++++++++++++++++++++++++++++++ eo/src/serial/CMakeLists.txt | 35 ++++++++ eo/src/serial/Entity.h | 34 +++++++ eo/src/serial/Object.cpp | 40 +++++++++ eo/src/serial/Object.h | 67 ++++++++++++++ eo/src/serial/Parser.cpp | 153 ++++++++++++++++++++++++++++++++ eo/src/serial/Parser.h | 78 ++++++++++++++++ eo/src/serial/Serializable.h | 44 +++++++++ eo/src/serial/String.cpp | 11 +++ eo/src/serial/String.h | 79 +++++++++++++++++ eo/src/serial/Utils.h | 167 +++++++++++++++++++++++++++++++++++ eo/src/serial/eoSerial.h | 12 +++ eo/src/serial/json_example | 8 ++ 16 files changed, 919 insertions(+) create mode 100644 eo/src/serial/Array.cpp create mode 100644 eo/src/serial/Array.h create mode 100644 eo/src/serial/CMakeLists.txt create mode 100644 eo/src/serial/Entity.h create mode 100644 eo/src/serial/Object.cpp create mode 100644 eo/src/serial/Object.h create mode 100644 eo/src/serial/Parser.cpp create mode 100644 eo/src/serial/Parser.h create mode 100644 eo/src/serial/Serializable.h create mode 100644 eo/src/serial/String.cpp create mode 100644 eo/src/serial/String.h create mode 100644 eo/src/serial/Utils.h create mode 100644 eo/src/serial/eoSerial.h create mode 100644 eo/src/serial/json_example diff --git a/eo/src/CMakeLists.txt b/eo/src/CMakeLists.txt index c03bc509..b6a8c230 100644 --- a/eo/src/CMakeLists.txt +++ b/eo/src/CMakeLists.txt @@ -43,6 +43,7 @@ ADD_SUBDIRECTORY(ga) ADD_SUBDIRECTORY(gp) ADD_SUBDIRECTORY(other) ADD_SUBDIRECTORY(utils) +ADD_SUBDIRECTORY(serial) IF(ENABLE_PYEO) ADD_SUBDIRECTORY(pyeo) diff --git a/eo/src/eo b/eo/src/eo index 8cebd23a..23df6ee5 100644 --- a/eo/src/eo +++ b/eo/src/eo @@ -141,6 +141,9 @@ #include // includes eoRealBounds.h #include // no eoIntVectorBounds +// Serialization stuff +#include + // aliens #include #include diff --git a/eo/src/serial/Array.cpp b/eo/src/serial/Array.cpp new file mode 100644 index 00000000..f70b00e8 --- /dev/null +++ b/eo/src/serial/Array.cpp @@ -0,0 +1,38 @@ +# include "Array.h" + +namespace eoserial +{ + +std::ostream& Array::print( std::ostream& out ) const +{ + out << "["; + bool first = true; + for (ArrayChildren::const_iterator it = begin(), + end = this->end(); + it != end; + ++it) + { + if ( first ) + { + first = false; + } else { + out << ", "; + } + (*it)->print( out ); + } + out << "]\n"; + return out; +} + +Array::~Array() +{ + for (ArrayChildren::iterator it = begin(), + end = this->end(); + it != end; + ++it) + { + delete *it; + } +} + +} // namespace eoserial diff --git a/eo/src/serial/Array.h b/eo/src/serial/Array.h new file mode 100644 index 00000000..69231980 --- /dev/null +++ b/eo/src/serial/Array.h @@ -0,0 +1,149 @@ +# ifndef __EOSERIAL_ARRAY_H__ +# define __EOSERIAL_ARRAY_H__ + +# include +# include + +# include "Entity.h" +# include "Serializable.h" + +# include "Object.h" +# include "String.h" + +namespace eoserial +{ + +// Forward declaration for below declarations. +class Array; + +/* + * Declarations of functions present in Utils.h + * These are put here to avoid instead of including the file Utils.h, which would + * cause a circular inclusion. + */ +template< class T > +void unpack( const Array & array, unsigned int index, T & value ); + +void unpackObject( const Array & array, unsigned int index, Persistent & value ); + +template< class Container, template class UnpackAlgorithm > +void unpackArray( const Array & array, unsigned int index, Container & container ); + +/** + * @brief Represents a JSON array. + * + * Wrapper for an array, so as to be used as a JSON object. + */ +class Array : public eoserial::Entity, public std::vector< eoserial::Entity* > +{ +protected: + typedef std::vector< eoserial::Entity* > ArrayChildren; + +public: + /** + * @brief Adds the serializable object as a JSON object. + * @param obj Object which implemnets JsonSerializable. + */ + void push_back( const eoserial::Printable* obj ) + { + ArrayChildren::push_back( obj->pack() ); + } + + /** + * @brief Proxy for vector::push_back. + */ + void push_back( eoserial::Entity* json ) + { + ArrayChildren::push_back( json ); + } + + /** + * @brief Prints the JSON array into the given stream. + * @param out The stream + */ + virtual std::ostream& print( std::ostream& out ) const; + + /** + * @brief Dtor + */ + ~Array(); + + /* + * The following parts allows the user to automatically deserialize an eoserial::Array into a + * standard container, by giving the algorithm which will be used to deserialize contained entities. + */ + + /** + * @brief Functor which determines how to retrieve the real value contained in a eoserial::Entity at + * a given place. + * + * It will be applied for each contained variable in the array. + */ + template + struct BaseAlgorithm + { + /** + * @brief Main operator. + * + * @param array The eoserial::Array from which we're reading. + * @param i The index of the contained value. + * @param container The standard (STL) container in which we'll push back the read value. + */ + virtual void operator()( const eoserial::Array& array, unsigned int i, Container & container ) const = 0; + }; + + /** + * @brief BaseAlgorithm for retrieving primitive variables. + * + * This one should be used to retrieve primitive (and types which implement operator>>) variables, for instance + * int, double, std::string, etc... + */ + template + struct UnpackAlgorithm : public BaseAlgorithm + { + void operator()( const eoserial::Array& array, unsigned int i, C & container ) const + { + typename C::value_type t; + unpack( array, i, t ); + container.push_back( t ); + } + }; + + /** + * @brief BaseAlgorithm for retrieving eoserial::Persistent objects. + * + * This one should be used to retrieve objects which implement eoserial::Persistent. + */ + template + struct UnpackObjectAlgorithm : public BaseAlgorithm + { + void operator()( const eoserial::Array& array, unsigned int i, C & container ) const + { + typename C::value_type t; + unpackObject( array, i, t ); + container.push_back( t ); + } + }; + + /** + * @brief General algorithm for array deserialization. + * + * Applies the BaseAlgorithm to each contained variable in the eoserial::Array. + */ + template class UnpackAlgorithm> + inline void deserialize( Container & array ) + { + UnpackAlgorithm< Container > algo; + for( unsigned int i = 0, size = this->size(); + i < size; + ++i) + { + algo( *this, i, array ); + } + } +}; + +} // namespace eoserial + +# endif // __EOSERIAL_ARRAY_H__ + diff --git a/eo/src/serial/CMakeLists.txt b/eo/src/serial/CMakeLists.txt new file mode 100644 index 00000000..5358b30a --- /dev/null +++ b/eo/src/serial/CMakeLists.txt @@ -0,0 +1,35 @@ +###################################################################################### +### 1) Include the sources +###################################################################################### + +INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +###################################################################################### +### 2) Define the eoserial target +###################################################################################### + +SET(EOSERIAL_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib) +SET(LIBRARY_OUTPUT_PATH ${EOSERIAL_LIB_OUTPUT_PATH}) + +SET(EOSERIAL_SOURCES + Array.cpp + Object.cpp + Parser.cpp + String.cpp + ) + +ADD_LIBRARY(eoserial STATIC ${EOSERIAL_SOURCES}) +INSTALL(TARGETS eoserial ARCHIVE DESTINATION lib COMPONENT libraries) + +FILE(GLOB HDRS *.h) +INSTALL(FILES ${HDRS} DESTINATION include/eo/serial COMPONENT headers) + +###################################################################################### +### 3) Optionnal +###################################################################################### + +SET(EOSERIAL_VERSION ${GLOBAL_VERSION}) +SET_TARGET_PROPERTIES(eoserial PROPERTIES VERSION "${EOSERIAL_VERSION}") + +###################################################################################### diff --git a/eo/src/serial/Entity.h b/eo/src/serial/Entity.h new file mode 100644 index 00000000..df10002d --- /dev/null +++ b/eo/src/serial/Entity.h @@ -0,0 +1,34 @@ +# ifndef __EOSERIAL_ENTITY_H__ +# define __EOSERIAL_ENTITY_H__ + +# include +# include + +namespace eoserial +{ + +/** + * @brief JSON entity + * + * This class represents a JSON entity, which can be JSON objects, + * strings or arrays. It is the base class for the JSON hierarchy. + */ +class Entity +{ +public: + + /** + * Virtual dtor (base class). + */ + virtual ~Entity() { /* empty */ } + + /** + * @brief Prints the content of a JSON object into a stream. + * @param out The stream in which we're printing. + */ + virtual std::ostream& print( std::ostream& out ) const = 0; +}; + +} // namespace eoserial + +# endif // __ENTITY_H__ diff --git a/eo/src/serial/Object.cpp b/eo/src/serial/Object.cpp new file mode 100644 index 00000000..3e557a12 --- /dev/null +++ b/eo/src/serial/Object.cpp @@ -0,0 +1,40 @@ +# include "Object.h" + +using namespace eoserial; + +namespace eoserial +{ + +std::ostream& Object::print( std::ostream& out ) const +{ + out << '{'; + bool first = true; + for(JsonValues::const_iterator it = begin(), end = this->end(); + it != end; + ++it) + { + if ( first ) + { + first = false; + } else { + out << ", "; + } + + out << '"' << it->first << "\":"; // key + it->second->print( out ); // value + } + out << "}\n"; + return out; +} + +Object::~Object() +{ + for(JsonValues::iterator it = begin(), end = this->end(); + it != end; + ++it) + { + delete it->second; + } +} + +} // namespace eoserial diff --git a/eo/src/serial/Object.h b/eo/src/serial/Object.h new file mode 100644 index 00000000..36769252 --- /dev/null +++ b/eo/src/serial/Object.h @@ -0,0 +1,67 @@ +# ifndef __EOSERIAL_OBJECT_H__ +# define __EOSERIAL_OBJECT_H__ + +# include +# include +# include + +# include "Entity.h" +# include "Serializable.h" + +namespace eoserial +{ + +/** + * @brief JSON Object + * + * This class represents a JSON object, which is basically a dictionnary + * of keys (strings) and values (JSON entities). + */ +class Object : public eoserial::Entity, public std::map< std::string, eoserial::Entity* > +{ +public: + typedef std::map JsonValues; + + /** + * @brief Adds a pair into the JSON object. + * @param key The key associated with the eoserial object + * @param eoserial The JSON object as created with framework. + */ + void add( const std::string& key, eoserial::Entity* json ) + { + (*this)[ key ] = json; + } + + /** + * @brief Adds a pair into the JSON object. + * @param key The key associated with the eoserial object + * @param obj A JSON-serializable object + */ + void add( const std::string& key, const eoserial::Printable* obj ) + { + (*this)[ key ] = obj->pack(); + } + + /** + * @brief Deserializes a Serializable class instance from this JSON object. + * @param obj The object we want to rebuild. + */ + void deserialize( eoserial::Persistent & obj ) + { + obj.unpack( this ); + } + + /** + * @brief Dtor + */ + ~Object(); + + /** + * @brief Prints the content of a JSON object into a stream. + */ + virtual std::ostream& print( std::ostream& out ) const; +}; + +} // namespace eoserial +# endif // __EOSERIAL_OBJECT_H__ + diff --git a/eo/src/serial/Parser.cpp b/eo/src/serial/Parser.cpp new file mode 100644 index 00000000..c7822d29 --- /dev/null +++ b/eo/src/serial/Parser.cpp @@ -0,0 +1,153 @@ +# include +# include +# include +# include + +# include "Parser.h" + +# include "Array.h" +# include "Object.h" +# include "String.h" + +// in debug mode only +// # define DEBUG(x) std::cout << x << std::endl; +# define DEBUG(x) + +using namespace eoserial; + +namespace eoserial +{ + +/** + * @brief Parses a string contained between double quotes. + * + * Strings can contain escaped double quotes. + * @param str The string we're parsing. + * @param pos The index of current position in parsed string. + * This index will be updated so as to allow the parser to + * continue. + */ +static std::string parseString(const std::string& str, size_t & pos) +{ + // example : "hello" + // example 2 : "\"world\"" + // for hello: + // firstQuote == 0, secondQuote == 6 + // sub string should be from firstQuote+1 to secondQuote-1 + // so its size should be (secondQuote-1 -(firstQuote+1) + 1) + std::string value; + size_t firstQuote = str.find( '"', pos ); + size_t secondQuote; + + /* instead of just seeking the second quote, we need to ensure + // that there is no escaped quote before this one. + // actually this is harder than that. Using backslashes + // to escape double quotes mean that backslashes have to be + // escaped to. + // example : "text\\" to symbolize : text\ + // example : "text\\\" to symbolize : text\" + // In fact, we should find if number of backslashes is odd; in this case, + // the double quotes are escaped and we should find the next one. + */ + int backslashesCount; + do { + ++pos; + secondQuote = str.find( '"', pos ); + size_t i = secondQuote - 1; + + // Find the backslashes + backslashesCount = 0; + while ( str[ i ] == '\\' ) + { + --i; + ++backslashesCount; + } + pos = secondQuote; + } while( backslashesCount % 2 == 1 ); + + value = str.substr( firstQuote+1, secondQuote-firstQuote-1 ); + pos = secondQuote + 1; + return value; +} + +/** + * @brief Moves the given index pos to the next character which is + * neither a coma, a space nor a new line. + * + * @param str The string in which we want to ignores those characters. + * @param pos The index of current position in parsed string. + */ +static void ignoreChars(const std::string& str, size_t & pos) +{ + // ignore white spaces and comas + for (char current = str[ pos ]; + current == ',' || current == ' ' || current == '\n'; + current = str[ ++pos ]); +} + +String* Parser::parseJsonString(const std::string & str, size_t & pos) +{ + return new String( parseString( str, pos ) ); +} + +Object* Parser::parse(const std::string & str) +{ + size_t initial(0); // we begin at position 0 + return static_cast( parseRight(str, initial) ); +} + +Entity* Parser::parseRight(const std::string & str, size_t & pos) +{ + Entity* value = 0; + + if ( str[ pos ] == '{' ) + { + // next one is an object + DEBUG("We read an object.") + Object* obj = new Object; + pos += 1; + while( pos < str.size() && str[ pos ] != '}' ) + { + parseLeft( str, pos, obj ); + ignoreChars( str, pos ); + } + DEBUG("We just finished to read an object ! ") + pos += 1; // we're on the }, go to the next char + value = obj; + } + else if ( str[ pos ] == '"' ) + { + // next one is a string + DEBUG("We read a string") + value = parseJsonString( str, pos ); + } + else if ( str[ pos ] == '[' ) + { + // next one is an array + DEBUG("We read an array") + Array* array = new Array; + pos += 1; + while( pos < str.size() && str[ pos ] != ']' ) + { + Entity* child = parseRight( str, pos ); + if ( child ) + array->push_back( child ); + } + DEBUG("We've finished to read our array.") + pos += 1; // we're on the ], go to the next char + value = array; + } + ignoreChars( str, pos ); + return value; +} + +void Parser::parseLeft(const std::string & str, size_t & pos, Object* eoserial) +{ + std::string key = parseString(str, pos); + ++pos; // the colon + DEBUG("We've read the key ") + (*eoserial)[ key ] = parseRight( str, pos ); +} + +} // namespace eoserial + diff --git a/eo/src/serial/Parser.h b/eo/src/serial/Parser.h new file mode 100644 index 00000000..f0a94ee2 --- /dev/null +++ b/eo/src/serial/Parser.h @@ -0,0 +1,78 @@ +# ifndef __EOSERIAL_PARSER_H__ +# define __EOSERIAL_PARSER_H__ + +# include "Entity.h" +# include "String.h" +# include "Object.h" + +/** + * This file contains a tiny JSON parser used in DAE. This parser just handles + * a subset of JSON grammar, with the following restrictions : + * - all strings must be surrounded by double quotes. + * - everything which is not an object or an array is considered to be a string + * (even integers, booleans,...). + * - no syntax check is done. We trust the programmer and he has to ensure that + * every JSON string he produces is valid. + * + * @author Benjamin BOUVIER + */ + +namespace eoserial +{ + +/** + * @brief Parser from a JSON source. + * + * This parser does just retrieve values and does NOT check the structure of + * the input. This implies that if the input is not correct, the result is undefined + * and can result to a failure on execution. + */ +class Parser +{ + public: + + /** + * @brief Parses the given string and returns the JSON object read. + */ + static eoserial::Object* parse(const std::string & str); + + protected: + + /** + * @brief Parses the right part of a JSON object as a string. + * + * The right part of an object can be a string (for instance : + * "key":"value"), a JSON array (for instance: "key":["1"]) or + * another JSON object (for instance: "key":{"another_key":"value"}). + * + * The right parts are found after keys (which are parsed by parseLeft) + * and in arrays. + * + * @param str The string we're parsing. + * @param pos The index of the current position in the string. + * @return The JSON object matching the right part. + */ + static eoserial::Entity* parseRight(const std::string & str, size_t & pos); + + /** + * @brief Parses the left value of a key-value pair, which is the key. + * + * @param str The string we're parsing. + * @param pos The index of the current position in the string. + * @param eoserial The current JSON object for which we're adding a key-value pair. + */ + static void parseLeft(const std::string & str, size_t & pos, eoserial::Object* json); + + /** + * @brief Retrieves a string in a JSON content. + * + * @param str The string we're parsing. + * @param pos The index of the current position of parsing, + * which will be updated. + */ + static eoserial::String* parseJsonString(const std::string & str, size_t & pos); +}; + +} // namespace eoserial + +# endif // __EOSERIAL_PARSER_H__ diff --git a/eo/src/serial/Serializable.h b/eo/src/serial/Serializable.h new file mode 100644 index 00000000..482a918a --- /dev/null +++ b/eo/src/serial/Serializable.h @@ -0,0 +1,44 @@ +# ifndef __EOSERIAL_SERIALIZABLE_H__ +# define __EOSERIAL_SERIALIZABLE_H__ + +# include + +namespace eoserial +{ + +class Object; // to avoid recursive inclusion with JsonObject + +/** + * @brief Interface showing that object can be written to a eoserial type + * (currently JSON). + */ +class Printable +{ +public: + /** + * @brief Serializes the object to JSON format. + * @return A JSON object created with new. + */ + virtual eoserial::Object* pack() const = 0; +}; + +/** + * @brief Interface showing that object can be eoserialized (written and read + * from an input). + * + * Note : Persistent objects should have a default non-arguments constructor. + */ +class Persistent : public Printable +{ + public: + /** + * @brief Loads class fields from a JSON object. + * @param json A JSON object. Programmer doesn't have to delete it, it + * is automatically done. + */ + virtual void unpack(const eoserial::Object* json) = 0; +}; + +} // namespace eoserial + +# endif // __EOSERIAL_SERIALIZABLE_H__ diff --git a/eo/src/serial/String.cpp b/eo/src/serial/String.cpp new file mode 100644 index 00000000..deba05a0 --- /dev/null +++ b/eo/src/serial/String.cpp @@ -0,0 +1,11 @@ +# include "String.h" + +namespace eoserial +{ + std::ostream& String::print( std::ostream& out ) const + { + out << '"' << *this << '"'; + return out; + } +} // namespace eoserial + diff --git a/eo/src/serial/String.h b/eo/src/serial/String.h new file mode 100644 index 00000000..43a2cffa --- /dev/null +++ b/eo/src/serial/String.h @@ -0,0 +1,79 @@ +# ifndef __EOSERIAL_STRING_H__ +# define __EOSERIAL_STRING_H__ + +# include +# include + +# include "Entity.h" + +namespace eoserial +{ + +/** + * @brief JSON String + * + * Wrapper for string, so as to be used as a JSON object. + */ +class String : public eoserial::Entity, public std::string +{ + public: + + /** + * @brief Default ctor. + * @param str The string we want to wrap. + */ + String( const std::string& str ) : std::string( str ) {} + + /** + * @brief Ctor used only on parsing. + */ + String( ) {} + + /** + * @brief Prints out the string. + */ + virtual std::ostream& print( std::ostream& out ) const; + + /** + * @brief Deserializes the current String into a given primitive type value. + * @param value The value in which we're writing. + */ + template + inline void deserialize( T & value ); + + protected: + // Copy and reaffectation are forbidden + explicit String( const String& _ ); + String& operator=( const String& _ ); +}; + +/** + * @brief Casts a eoserial::String into a primitive value, or in a type which at + * least overload operator>>. + * + * @param value A reference to the variable we're writing into. + * + * It's not necessary to specify the variable type, which can be infered by compiler when + * invoking. + */ +template +inline void String::deserialize( T & value ) +{ + std::stringstream ss; + ss << *this; + ss >> value; +} + +/** + * @brief Specialization for strings, which don't need to be converted through + * a stringstream. + */ +template<> +inline void String::deserialize( std::string & value ) +{ + value = *this; +} + +} // namespace eoserial + +# endif // __EOSERIAL_STRING_H__ diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h new file mode 100644 index 00000000..70fd2f75 --- /dev/null +++ b/eo/src/serial/Utils.h @@ -0,0 +1,167 @@ +# ifndef __EOSERIAL_UTILS_H__ +# define __EOSERIAL_UTILS_H__ + +# include "Array.h" +# include "Object.h" +# include "String.h" + +namespace eoserial +{ + /***************************** + * DESERIALIZATION FUNCTIONS * + ***************************** + These functions are useful for casting eoserial::objects into simple, primitive + variables or into class instance which implement eoserial::Persistent. + + The model is always quite the same : + - the first argument is the containing object (which is a eoserial::Entity, + an object or an array) + - the second argument is the key or index, + - the last argument is the value in which we're writing. + */ + + template< class T > + inline void unpack( const Object & obj, const std::string & key, T & value ) + { + static_cast( obj.find( key )->second )->deserialize( value ); + } + + inline void unpackObject( const Object & obj, const std::string & key, Persistent & value ) + { + static_cast( obj.find( key )->second )->deserialize( value ); + } + + template< class Container, template class UnpackAlgorithm > + inline void unpackArray( const Object & obj, const std::string & key, Container & array ) + { + static_cast( obj.find( key )->second )->deserialize< Container, UnpackAlgorithm >( array ); + } + + template< class T > + inline void unpack( const Array & array, unsigned int index, T & value ) + { + static_cast( array[ index ] )->deserialize( value ); + } + + inline void unpackObject( const Array & array, unsigned int index, Persistent & value ) + { + static_cast( array[ index ] )->deserialize( value ); + } + + template< class Container, template class UnpackAlgorithm > + inline void unpackArray( const Array & array, unsigned int index, Container & container ) + { + static_cast( array[ index ] )->deserialize< Container, UnpackAlgorithm >( container ); + } + + /******************************* + *** SERIALIZATION FUNCTIONS *** + ******************************* + These functions are useful for casting classic objects and + eoserial::Persistent objects into eoserial entities which + can be manipulated by the framework. + */ + + /** + * @brief Casts a value of a stream-serializable type (i.e, which implements + * operator <<) into a JsonString. + * + * This is used when serializing the objects : all primitives types should be + * converted into strings to get more easily manipulated. + * + * @param value The value we're converting. + * @return JsonString wrapper for the value. + */ + template + String* make( const T & value ) + { + std::stringstream ss; + ss << value; + return new String( ss.str() ); + } + + /** + * @brief Specialization for strings : no need to convert as they're still + * usable as strings. + */ + template<> + inline String* make( const std::string & value ) + { + return new String( value ); + } + + /* + * These functions are useful for automatically serializing STL containers into + * eoserial arrays which could be used by the framework. + **/ + + /** + * @brief Functor which explains how to push the value into the eoserial::Array. + */ + template< class T > + struct PushAlgorithm + { + /** + * @brief Main operator. + * + * @param array The eoserial::array in which we're writing. + * @param value The variable we are writing. + */ + virtual void operator()( Array & array, const T & value ) = 0; + }; + + /** + * @brief Push algorithm for primitive variables. + * + * This one should be used when inserting primitive (and types which implement + * operator<<) variables. + */ + template< class T > + struct MakeAlgorithm : public PushAlgorithm + { + void operator()( Array & array, const T & value ) + { + array.push_back( make( value ) ); + } + }; + + /** + * @brief Push algorithm for eoserial::Persistent variables. + */ + template< class T > + struct SerializablePushAlgorithm : public PushAlgorithm + { + void operator()( Array & array, const T & obj ) + { + // obj address is not saved into array.push_back. + array.push_back( &obj ); + } + }; + + /** + * @brief Casts a STL container (vector or list, for instance) + * into a eoserial::Array. + * + * @þaram PushAlgorithm The algorithm used for inserting new element in the eoserial::Array. + * This algorithm is directly called, so it is its own charge to invoke push_back on the + * eoserial::Array. + */ + template< class Container, template class PushAlgorithm > + Array* makeArray( const Container & array ) + { + Array* returned_array = new Array; + typedef typename Container::const_iterator iterator; + typedef typename Container::value_type Type; + PushAlgorithm< Type > algo; + for ( + iterator it = array.begin(), end = array.end(); + it != end; + ++it) + { + algo( *returned_array, *it ); + } + return returned_array; + } +} // namespace eoserial + +# endif //__EOSERIAL_UTILS_H__ diff --git a/eo/src/serial/eoSerial.h b/eo/src/serial/eoSerial.h new file mode 100644 index 00000000..a10f6c01 --- /dev/null +++ b/eo/src/serial/eoSerial.h @@ -0,0 +1,12 @@ +# ifndef __EOSERIAL_HEADERS__ +# define __EOSERIAL_HEADERS__ + +# include "Object.h" +# include "Serializable.h" +# include "Array.h" +# include "Object.h" +# include "String.h" +# include "Parser.h" +# include "Utils.h" + +# endif // __EOSERIAL_HEADERS__ diff --git a/eo/src/serial/json_example b/eo/src/serial/json_example new file mode 100644 index 00000000..7ecb3edd --- /dev/null +++ b/eo/src/serial/json_example @@ -0,0 +1,8 @@ +{"a":"b", +"obj": + {"obj_a":"obj_}b","subobj_a": + {"subk":"subv"} + }, +"c":"d", +"array":["1","2",{"\"array\"_obj\"":"array_ov]"}, ["3"], "4"] +} From abc18a653df6812102fa8ffaf84dfb4bc3c50fbc Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Jun 2012 11:01:28 +0200 Subject: [PATCH 02/52] Added a gitignore for compiled files --- eo/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 eo/.gitignore diff --git a/eo/.gitignore b/eo/.gitignore new file mode 100644 index 00000000..97791071 --- /dev/null +++ b/eo/.gitignore @@ -0,0 +1,3 @@ +*.swp +debug/ +release/ From 2851cad471681833eb0d8ca392fe3e2fa5b9d4be Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Jun 2012 17:07:29 +0200 Subject: [PATCH 03/52] Configure eo-conf.cmake to enable or disable MPI use. --- eo/eo-conf.cmake | 7 +++++++ eo/src/CMakeLists.txt | 29 ++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/eo/eo-conf.cmake b/eo/eo-conf.cmake index e8f285cb..2c115cfe 100644 --- a/eo/eo-conf.cmake +++ b/eo/eo-conf.cmake @@ -5,3 +5,10 @@ SET(PROJECT_VERSION_MINOR 3) SET(PROJECT_VERSION_PATCH 0) SET(PROJECT_VERSION_MISC "-edge") +# If you plan to use MPI, precise here where are the static libraries from +# openmpi and boost::mpi. + +SET(WITH_MPI FALSE CACHE BOOL "Use mpi ?" FORCE) +SET(MPI_DIR "put root directory of openmpi here" CACHE PATH "OpenMPI directory" FORCE) +SET(BOOST_DIR "put root directory of boost here" CACHE PATH "Boost directory" FORCE) + diff --git a/eo/src/CMakeLists.txt b/eo/src/CMakeLists.txt index b6a8c230..f674da4e 100644 --- a/eo/src/CMakeLists.txt +++ b/eo/src/CMakeLists.txt @@ -5,7 +5,30 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ###################################################################################### -### 2) Define the eo target +### 2) Optionnal: add MPI and Boost MPI dependencies. +###################################################################################### + +IF(WITH_MPI) + MESSAGE("[EO] Compilation with MPI and BoostMPI.") + + SET(CMAKE_CXX_COMPILER "${MPI_DIR}/bin/mpicxx") + + # headers location + INCLUDE_DIRECTORIES(${MPI_DIR}/include) + INCLUDE_DIRECTORIES(${BOOST_DIR}/include) + + # lib location + LINK_DIRECTORIES(${MPI_DIR}/lib) + LINK_DIRECTORIES(${BOOST_DIR}/lib) + + # for conditional compilation in code + ADD_DEFINITIONS(-DWITH_MPI) + + LINK_LIBRARIES(boost_mpi boost_serialization) +ENDIF() + +###################################################################################### +### 3) Define the eo target ###################################################################################### SET(EO_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib) @@ -27,14 +50,14 @@ FILE(GLOB HDRS *.h eo) INSTALL(FILES ${HDRS} DESTINATION include/eo COMPONENT headers) ###################################################################################### -### 3) Optionnal: define your target(s)'s version: no effect for windows +### 4) Optionnal: define your target(s)'s version: no effect for windows ###################################################################################### SET(EO_VERSION ${GLOBAL_VERSION}) SET_TARGET_PROPERTIES(eo PROPERTIES VERSION "${EO_VERSION}") ###################################################################################### -### 4) Where must cmake go now ? +### 5) Where must cmake go now ? ###################################################################################### ADD_SUBDIRECTORY(do) From bc7f662b59375e7a1a5bca1edd9efabd9e3a035f Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 18 Jun 2012 14:18:22 +0200 Subject: [PATCH 04/52] Added rules to ignore CMake generated directories and Makefile --- eo/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eo/.gitignore b/eo/.gitignore index 97791071..2bfc9fc7 100644 --- a/eo/.gitignore +++ b/eo/.gitignore @@ -1,3 +1,5 @@ *.swp debug/ release/ +*CMakeFiles* +*Makefile From 04f972475cf2dffbb6c77b40efb5e60be0fb5f5d Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 18 Jun 2012 14:20:06 +0200 Subject: [PATCH 05/52] First version of generic MPI parallelization --- eo/src/eoParallelApply.h | 49 ++++++ eo/src/eompi.h | 289 +++++++++++++++++++++++++++++++ eo/test/t-eoMpiParallelApply.cpp | 59 +++++++ 3 files changed, 397 insertions(+) create mode 100644 eo/src/eoParallelApply.h create mode 100644 eo/src/eompi.h create mode 100644 eo/test/t-eoMpiParallelApply.cpp diff --git a/eo/src/eoParallelApply.h b/eo/src/eoParallelApply.h new file mode 100644 index 00000000..6a7c6eaa --- /dev/null +++ b/eo/src/eoParallelApply.h @@ -0,0 +1,49 @@ +# ifndef __EO_PARALLEL_APPLY_H__ +# define __EO_PARALLEL_APPLY_H__ + +# include "eompi.h" + +# include +# include + +template< typename EOT > +class ParallelApply : public MpiJob< EOT > +{ + public: + + ParallelApply( eoUF & _proc, std::vector& _pop ) : + MpiJob( _pop ), + func( _proc ) + { + // empty + } + + virtual void sendTask( int wrkRank, int index ) + { + MpiJob::comm.send( wrkRank, 1, MpiJob::data[ index ] ); + } + + virtual void handleResponse( int wrkRank, int index ) + { + MpiJob::comm.recv( wrkRank, 1, MpiJob::data[ index ] ); + } + + virtual void processTask( ) + { + EOT ind; + cout << "Receiving individual." << endl; + MpiJob::comm.recv( 0, 1, ind ); + cout << "Applying function." << endl; + func( ind ); + cout << "Sending result." << endl; + MpiJob::comm.send( 0, 1, ind ); + cout << "Leaving processTask" << endl; + } + + protected: + eoUF& func; +}; + +# endif // __EO_PARALLEL_APPLY_H__ + + diff --git a/eo/src/eompi.h b/eo/src/eompi.h new file mode 100644 index 00000000..82d1a585 --- /dev/null +++ b/eo/src/eompi.h @@ -0,0 +1,289 @@ +# ifndef __EO_MPI_H__ +# define __EO_MPI_H__ + +# include +# include + +# include +namespace mpi = boost::mpi; + +# include +using namespace std; +// TODO TODOB comment! + +namespace EoMpi +{ + namespace Channel + { + const int Commands = 0; + } + + namespace Message + { + const int Continue = 0; + const int Finish = 1; + } +} + +class MpiNode; + +class MpiNodeStore +{ + public: + + static void instance( MpiNode* _instance ) + { + singleton = _instance; + } + + static MpiNode* instance() + { + return singleton; + } + + protected: + + static MpiNode* singleton; +}; + +MpiNode* MpiNodeStore::singleton; + +class MpiNode +{ +protected: + mpi::environment& env; + mpi::communicator& _comm; + + int rank; + int size; + + int argc; + char** argv; + +public: + MpiNode( mpi::environment& _env, mpi::communicator& __comm ) : + env(_env), + _comm(__comm), + rank(__comm.rank()), + size(__comm.size()) + { + // empty + } + + virtual ~MpiNode() + { + // empty + } + + mpi::communicator& comm() + { + return _comm; + } +}; + +struct AssignmentAlgorithm +{ + virtual int get( ) = 0; + virtual void size( int s ) = 0; + virtual int size( ) = 0; + virtual void confirm( int wrkRank ) = 0; +}; + +struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm +{ + public: + virtual int get( ) + { + int assignee = -1; + if (! availableWrk.empty() ) + { + assignee = availableWrk.back(); + availableWrk.pop_back(); + } + return assignee; + } +; + void size( int s ) + { + for( int i = 1; i < s ; ++i ) + { + availableWrk.push_back( i ); + } + } + + int size() + { + return availableWrk.size(); + } + + void confirm( int rank ) + { + availableWrk.push_back( rank ); + } + + protected: + std::vector< int > availableWrk; +}; + +template< typename EOT > +class MpiJob +{ + public: + + MpiJob( std::vector< EOT > & _data ) : + data( _data ), + comm( MpiNodeStore::instance()->comm() ) + { + // empty + } + + // master + virtual void sendTask( int wrkRank, int index ) = 0; + virtual void handleResponse( int wrkRank, int index ) = 0; + // worker + virtual void processTask( ) = 0; + + void master( AssignmentAlgorithm & assignmentAlgorithm ) + { + for( int i = 0, size = data.size(); + i < size; + ++i) + { + cout << "Beginning loop for i = " << i << endl; + int assignee = assignmentAlgorithm.get( ); + cout << "Assignee : " << assignee << endl; + while( assignee <= 0 ) + { + cout << "Waitin' for node..." << endl; + mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); + int wrkRank = status.source(); + cout << "Node " << wrkRank << " just terminated." << endl; + handleResponse( wrkRank, assignedTasks[ wrkRank ] ); + assignmentAlgorithm.confirm( wrkRank ); + assignee = assignmentAlgorithm.get( ); + } + cout << "Assignee found : " << assignee << endl; + assignedTasks[ assignee ] = i; + comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); + sendTask( assignee, i ); + } + + // frees all the idle workers + int idle; + vector idles; + while ( ( idle = assignmentAlgorithm.get( ) ) > 0 ) + { + comm.send( idle, EoMpi::Channel::Commands, EoMpi::Message::Finish ); + idles.push_back( idle ); + } + for (int i = 0; i < idles.size(); ++i) + { + assignmentAlgorithm.confirm( idles[i] ); + } + + // wait for all responses + int wrkNb = comm.size() - 1; + while( assignmentAlgorithm.size() != wrkNb ) + { + mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); + int wrkRank = status.source(); + handleResponse( wrkRank, assignedTasks[ wrkRank ] ); + comm.send( wrkRank, EoMpi::Channel::Commands, EoMpi::Message::Finish ); + assignmentAlgorithm.confirm( wrkRank ); + } + } + + void worker( ) + { + int order; + while( true ) + { + comm.recv( 0, EoMpi::Channel::Commands, order ); + if ( order == EoMpi::Message::Finish ) + { + return; + } else + { + processTask( ); + } + } + } + +protected: + + std::vector & data; + std::map< int /* worker rank */, int /* index in vector */> assignedTasks; + + mpi::communicator& comm; +}; + +class MasterNode : public MpiNode +{ +public: + MasterNode( int _argc, char** _argv, + mpi::environment& _env, + mpi::communicator& _comm + ) : + MpiNode(_env, _comm ) + { + // empty + } + + void setAssignmentAlgorithm( AssignmentAlgorithm* assignmentAlgo ) + { + _assignmentAlgo = assignmentAlgo; + _assignmentAlgo->size( _comm.size() ); + } + + template< typename EOT > + void run( MpiJob< EOT > & job ) + { + job.master( *_assignmentAlgo ); + } + +protected: + AssignmentAlgorithm* _assignmentAlgo; +}; + +class WorkerNode : public MpiNode +{ + public: + + WorkerNode( + int _argc, char** _argv, + mpi::environment& _env, + mpi::communicator& _comm ) : + MpiNode( _env, _comm ) + { + // empty + } + + template< typename EOT > + void run( MpiJob & job ) + { + job.worker( ); + } +}; + +class MpiSingletonFactory +{ + public: + + static void init( int argc, char** argv ) + { + MpiNode* singleton; + //mpi::environment* env = new mpi::environment ( argc, argv ); + //mpi::communicator* world = new mpi::communicator; // TODO clean + static mpi::environment env( argc, argv ); + static mpi::communicator world; + if ( world.rank() == 0 ) + { + singleton = new MasterNode( argc, argv, env, world ); + } else + { + singleton = new WorkerNode( argc, argv, env, world ); + } + MpiNodeStore::instance( singleton ); + } +}; +# endif // __EO_MPI_H__ diff --git a/eo/test/t-eoMpiParallelApply.cpp b/eo/test/t-eoMpiParallelApply.cpp new file mode 100644 index 00000000..77583420 --- /dev/null +++ b/eo/test/t-eoMpiParallelApply.cpp @@ -0,0 +1,59 @@ +# include +# include +# include + +# include +using namespace std; + +struct plusOne : public eoUF< int&, void > +{ + void operator() ( int & x ) + { + ++x; + } +}; + +int main(int argc, char** argv) +{ + DynamicAssignmentAlgorithm algo; + cout << "Appel à init... " << endl; + MpiSingletonFactory::init( argc, argv ); + + cout << "Création des données... " << endl; + vector v; + + v.push_back(1); + v.push_back(3); + v.push_back(3); + v.push_back(7); + v.push_back(42); + + plusOne plusOneInstance; + + cout << "Création du job..." << endl; + ParallelApply job( plusOneInstance, v ); + + cout << "Création de l'instance..." << endl; + MpiNode* instance = MpiNodeStore::instance(); + if( dynamic_cast( instance ) != 0 ) + { + cout << "[Master] Algorithme d'assignation" << endl; + static_cast( instance )->setAssignmentAlgorithm( &algo ); + cout << "[Master] Lancement." << endl; + static_cast( instance )->run( job ); + + for (int i = 0; i < v.size(); ++i ) + { + cout << v[i] << endl; + } + } else if ( dynamic_cast( instance ) != 0 ) + { + cout << "[Worker] Lancement." << endl; + static_cast( instance )->run( job ); + } else + { + cout << "Nothing to be done;" << endl; + } + + return 0; +} From bd959cb3efa62e76b38aa3da84e4d8d107226e09 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 18 Jun 2012 15:22:47 +0200 Subject: [PATCH 06/52] First parallel evaluation with MPI. Look at t-eoMpiParallel.cpp --- eo/src/apply.h | 52 +++++++++++------ eo/test/t-eoMpiParallel.cpp | 111 ++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 16 deletions(-) create mode 100644 eo/test/t-eoMpiParallel.cpp diff --git a/eo/src/apply.h b/eo/src/apply.h index f685f8d3..39a36505 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -33,6 +33,11 @@ #include #include +# ifdef WITH_MPI +# include +# include +# endif // WITH_MPI + /** Applies a unary function to a std::vector of things. @@ -48,33 +53,48 @@ void apply(eoUF& _proc, std::vector& _pop) double t1 = 0; if ( eo::parallel.enableResults() ) - { - t1 = omp_get_wtime(); - } + { + t1 = omp_get_wtime(); + } if (!eo::parallel.isDynamic()) - { + { #pragma omp parallel for if(eo::parallel.isEnabled()) //default(none) shared(_proc, _pop, size) - for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } - } + for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } + } else - { + { #pragma omp parallel for schedule(dynamic) if(eo::parallel.isEnabled()) - //doesnot work with gcc 4.1.2 - //default(none) shared(_proc, _pop, size) - for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } - } + //doesnot work with gcc 4.1.2 + //default(none) shared(_proc, _pop, size) + for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } + } if ( eo::parallel.enableResults() ) - { - double t2 = omp_get_wtime(); - eoLogger log; - log << eo::file(eo::parallel.prefix()) << t2 - t1 << ' '; - } + { + double t2 = omp_get_wtime(); + eoLogger log; + log << eo::file(eo::parallel.prefix()) << t2 - t1 << ' '; + } #else // _OPENMP +#ifdef WITH_MPI + ParallelApply job( _proc, _pop ); + MasterNode* master = dynamic_cast( MpiNodeStore::instance() ); + if ( master ) + { + DynamicAssignmentAlgorithm algo; + master->setAssignmentAlgorithm( &algo ); + master->run( job ); + } else + { + WorkerNode* wrk = dynamic_cast( MpiNodeStore::instance() ); + wrk->run( job ); + } +#else // !_MPI for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } +#endif #endif // !_OPENMP } diff --git a/eo/test/t-eoMpiParallel.cpp b/eo/test/t-eoMpiParallel.cpp new file mode 100644 index 00000000..5529b8e2 --- /dev/null +++ b/eo/test/t-eoMpiParallel.cpp @@ -0,0 +1,111 @@ +//----------------------------------------------------------------------------- +// t-eoMpiParallel.cpp +//----------------------------------------------------------------------------- + +#include +#include +//#include +#include "real_value.h" + +#include + +//----------------------------------------------------------------------------- + +class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial::Persistent +{ + public: + + eoRealSerializable(unsigned size = 0, double value = 0.0): + eoReal(size, value) {} + + eoserial::Object* pack() const + { + eoserial::Object* obj = new eoserial::Object; + obj->add( "array", + eoserial::makeArray< vector, eoserial::MakeAlgorithm > + ( *this ) + ); + return obj; + } + + void unpack( const eoserial::Object* obj ) + { + eoserial::unpackArray< vector, eoserial::Array::UnpackAlgorithm > + ( *obj, "array", *this ); + } + + // Gives access to boost serialization + friend class boost::serialization::access; + + /** + * Serializes the decomposition in a boost archive (useful for boost::mpi) + */ + template + void save( Archive & ar, const unsigned int version ) const + { + std::stringstream ss; + printOn( ss ); + std::string asStr = ss.str(); + ar & asStr; + + (void) version; // avoid compilation warning + } + + /** + * Deserializes the decomposition from a boost archive (useful for boost:mpi) + */ + template + void load( Archive & ar, const unsigned int version ) + { + std::string asStr; + ar & asStr; + std::stringstream ss; + ss << asStr; + readFrom( ss ); + + (void) version; // avoid compilation warning + } + + // Indicates that boost save and load operations are not the same. + BOOST_SERIALIZATION_SPLIT_MEMBER() + +}; + +typedef eoRealSerializable EOT; + +int main(int ac, char** av) +{ + MpiSingletonFactory::init( ac, av ); + + eoParser parser(ac, av); + + unsigned int popSize = parser.getORcreateParam((unsigned int)100, "popSize", "Population Size", 'P', "Evolution Engine").value(); + unsigned int dimSize = parser.getORcreateParam((unsigned int)10, "dimSize", "Dimension Size", 'd', "Evolution Engine").value(); + + uint32_t seedParam = parser.getORcreateParam((uint32_t)0, "seed", "Random number seed", 0).value(); + if (seedParam == 0) { seedParam = time(0); } + + make_parallel(parser); + make_help(parser); + + rng.reseed( seedParam ); + + eoUniformGenerator< double > gen(-5, 5); + eoInitFixedLength< EOT > init( dimSize, gen ); + + eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value ); + eoEvalFuncCounter< EOT > eval( mainEval ); + + eoPop< EOT > pop( popSize, init ); + + eo::log << "Size of population : " << popSize << std::endl; + + eoPopLoopEval< EOT > popEval( eval ); + popEval( pop, pop ); + + eo::log << eo::quiet << "DONE!" << std::endl; + + return 0; +} + +//----------------------------------------------------------------------------- From fed65c4f082bc508820a3f432c573d16684af78c Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 18 Jun 2012 17:02:41 +0200 Subject: [PATCH 07/52] Added eoParallelPopEvalFunc and allow compilation of full library. --- eo/src/CMakeLists.txt | 1 + eo/src/apply.h | 15 ++++++++++----- eo/src/eoPopEvalFunc.h | 20 ++++++++++++++++++++ eo/src/eompi.cpp | 4 ++++ eo/src/eompi.h | 2 -- 5 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 eo/src/eompi.cpp diff --git a/eo/src/CMakeLists.txt b/eo/src/CMakeLists.txt index f674da4e..3d46be7a 100644 --- a/eo/src/CMakeLists.txt +++ b/eo/src/CMakeLists.txt @@ -41,6 +41,7 @@ SET(EO_SOURCES eoCtrlCContinue.cpp eoScalarFitnessAssembled.cpp eoSIGContinue.cpp + eompi.cpp ) ADD_LIBRARY(eo STATIC ${EO_SOURCES}) diff --git a/eo/src/apply.h b/eo/src/apply.h index 39a36505..c01ac574 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -79,8 +79,17 @@ void apply(eoUF& _proc, std::vector& _pop) #else // _OPENMP + for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } + +#endif // !_OPENMP +} + #ifdef WITH_MPI +template +void parallelApply(eoUF& _proc, std::vector& _pop) +{ ParallelApply job( _proc, _pop ); + MasterNode* master = dynamic_cast( MpiNodeStore::instance() ); if ( master ) { @@ -92,12 +101,8 @@ void apply(eoUF& _proc, std::vector& _pop) WorkerNode* wrk = dynamic_cast( MpiNodeStore::instance() ); wrk->run( job ); } -#else // !_MPI - for (size_t i = 0; i < size; ++i) { _proc(_pop[i]); } -#endif - -#endif // !_OPENMP } +#endif /** This is a variant of apply which is called in parallel diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index aba74d9a..cbd38b21 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -77,6 +77,26 @@ private: eoEvalFunc & eval; }; +#ifdef WITH_MPI +// TODO TODOB commenter +template +class eoParallelPopLoopEval : public eoPopEvalFunc { +public: + /** Ctor: set value of embedded eoEvalFunc */ + eoParallelPopLoopEval(eoEvalFunc & _eval) : eval(_eval) {} + + /** Do the job: simple loop over the offspring */ + void operator()(eoPop & _parents, eoPop & _offspring) + { + (void)_parents; + parallelApply(eval, _offspring); + } + +private: + eoEvalFunc & eval; +}; +#endif + ///////////////////////////////////////////////////////////// // eoTimeVaryingLoopEval ///////////////////////////////////////////////////////////// diff --git a/eo/src/eompi.cpp b/eo/src/eompi.cpp new file mode 100644 index 00000000..eff6bc39 --- /dev/null +++ b/eo/src/eompi.cpp @@ -0,0 +1,4 @@ +# include "eompi.h" + +MpiNode* MpiNodeStore::singleton; + diff --git a/eo/src/eompi.h b/eo/src/eompi.h index 82d1a585..9abcbb0f 100644 --- a/eo/src/eompi.h +++ b/eo/src/eompi.h @@ -46,8 +46,6 @@ class MpiNodeStore static MpiNode* singleton; }; -MpiNode* MpiNodeStore::singleton; - class MpiNode { protected: From 6ac423bf22c4e68014edcd6cabc1af3218321e46 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Wed, 20 Jun 2012 11:46:18 +0200 Subject: [PATCH 08/52] Adding eoEasyEA constructor allowing to precise which eoPopEvalFunc should be used --- eo/src/eoEasyEA.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/eo/src/eoEasyEA.h b/eo/src/eoEasyEA.h index 2c7c5474..4d74932f 100644 --- a/eo/src/eoEasyEA.h +++ b/eo/src/eoEasyEA.h @@ -102,6 +102,33 @@ template class eoEasyEA: public eoAlgo offspring.reserve(_offspringSize); // This line avoids an incremental resize of offsprings. } + /** + * @brief Ctor allowing to specify which pop eval function we're going to use. + * + * Ctor taking a breed and merge, an overload of ctor to define an offspring size, and + * the pop eval function used. This allows to precise if we would like to use the + * parallel evaluation, for instance. + */ + eoEasyEA( + eoContinue& _continuator, + eoEvalFunc& _eval, + eoPopEvalFunc& _pop_eval, + eoBreed& _breed, + eoReplacement& _replace, + unsigned _offspringSize + ) : continuator(_continuator), + eval (_eval), + loopEval(_eval), + popEval(_pop_eval), + selectTransform(dummySelect, dummyTransform), + breed(_breed), + mergeReduce(dummyMerge, dummyReduce), + replace(_replace), + isFirstCall(true) + { + offspring.reserve(_offspringSize); // This line avoids an incremental resize of offsprings. + } + /* eoEasyEA(eoContinue & _continuator, eoPopEvalFunc & _pop_eval, @@ -219,6 +246,8 @@ template class eoEasyEA: public eoAlgo /// Apply a few generation of evolution to the population. virtual void operator()(eoPop& _pop) { + + eo::log << "[EasyEA] Call to operator()" << std::endl; if (isFirstCall) { size_t total_capacity = _pop.capacity() + offspring.capacity(); @@ -227,22 +256,33 @@ template class eoEasyEA: public eoAlgo isFirstCall = false; } + // TODO TODOB delete all log traces + std::cout << "[EasyEA] After is first call." << std::endl; + eoPop empty_pop; + std::cout << "[EasyEA] After empty_pop." << std::endl; popEval(empty_pop, _pop); // A first eval of pop. + std::cout << "[EasyEA] After pop_eval." << std::endl; do { try { + std::cout << "[EasyEA] Beginning try." << std::endl; unsigned pSize = _pop.size(); + std::cout << "[EasyEA] psize determinated." << std::endl; offspring.clear(); // new offspring + std::cout << "[EasyEA] offspring cleared." << std::endl; breed(_pop, offspring); + std::cout << "[EasyEA] After breed, evaluating pop." << std::endl; popEval(_pop, offspring); // eval of parents + offspring if necessary + std::cout << "[EasyEA] After evaluation, replacing pop." << std::endl; replace(_pop, offspring); // after replace, the new pop. is in _pop + std::cout << "[EasyEA] After replacing, continuator." << std::endl; if (pSize > _pop.size()) throw std::runtime_error("Population shrinking!"); From fd2facb14e06440d53034766f162086831fa17f1 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 15:03:41 +0200 Subject: [PATCH 09/52] Moved mpi related files into mpi/ and compiling it as an extern library. --- eo/src/CMakeLists.txt | 5 +++-- eo/src/apply.h | 4 ++-- eo/src/mpi/CMakeLists.txt | 32 ++++++++++++++++++++++++++++++ eo/src/{ => mpi}/eoParallelApply.h | 4 ---- eo/src/{ => mpi}/eompi.cpp | 0 eo/src/{ => mpi}/eompi.h | 0 eo/test/t-eoMpiParallelApply.cpp | 4 ++-- 7 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 eo/src/mpi/CMakeLists.txt rename eo/src/{ => mpi}/eoParallelApply.h (83%) rename eo/src/{ => mpi}/eompi.cpp (100%) rename eo/src/{ => mpi}/eompi.h (100%) diff --git a/eo/src/CMakeLists.txt b/eo/src/CMakeLists.txt index 3d46be7a..caeb673a 100644 --- a/eo/src/CMakeLists.txt +++ b/eo/src/CMakeLists.txt @@ -5,7 +5,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ###################################################################################### -### 2) Optionnal: add MPI and Boost MPI dependencies. +### 2) Optional: add MPI and Boost MPI dependencies. ###################################################################################### IF(WITH_MPI) @@ -25,6 +25,8 @@ IF(WITH_MPI) ADD_DEFINITIONS(-DWITH_MPI) LINK_LIBRARIES(boost_mpi boost_serialization) + + ADD_SUBDIRECTORY(mpi) ENDIF() ###################################################################################### @@ -41,7 +43,6 @@ SET(EO_SOURCES eoCtrlCContinue.cpp eoScalarFitnessAssembled.cpp eoSIGContinue.cpp - eompi.cpp ) ADD_LIBRARY(eo STATIC ${EO_SOURCES}) diff --git a/eo/src/apply.h b/eo/src/apply.h index c01ac574..d2006fe0 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -34,8 +34,8 @@ #include # ifdef WITH_MPI -# include -# include +# include +# include # endif // WITH_MPI /** diff --git a/eo/src/mpi/CMakeLists.txt b/eo/src/mpi/CMakeLists.txt new file mode 100644 index 00000000..c770acd1 --- /dev/null +++ b/eo/src/mpi/CMakeLists.txt @@ -0,0 +1,32 @@ +###################################################################################### +### 1) Include the sources +###################################################################################### + +INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +###################################################################################### +### 2) Define the eompi target +###################################################################################### + +SET(EOMPI_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib) +SET(LIBRARY_OUTPUT_PATH ${EOMPI_LIB_OUTPUT_PATH}) + +SET(EOMPI_SOURCES + eompi.cpp + ) + +ADD_LIBRARY(eompi STATIC ${EOMPI_SOURCES}) +INSTALL(TARGETS eompi ARCHIVE DESTINATION lib COMPONENT libraries) + +FILE(GLOB HDRS *.h) +INSTALL(FILES ${HDRS} DESTINATION include/eo/mpi COMPONENT headers) + +###################################################################################### +### 3) Optionnal +###################################################################################### + +SET(EOMPI_VERSION ${GLOBAL_VERSION}) +SET_TARGET_PROPERTIES(eompi PROPERTIES VERSION "${EOMPI_VERSION}") + +###################################################################################### diff --git a/eo/src/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h similarity index 83% rename from eo/src/eoParallelApply.h rename to eo/src/mpi/eoParallelApply.h index 6a7c6eaa..528d0cb2 100644 --- a/eo/src/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -31,13 +31,9 @@ class ParallelApply : public MpiJob< EOT > virtual void processTask( ) { EOT ind; - cout << "Receiving individual." << endl; MpiJob::comm.recv( 0, 1, ind ); - cout << "Applying function." << endl; func( ind ); - cout << "Sending result." << endl; MpiJob::comm.send( 0, 1, ind ); - cout << "Leaving processTask" << endl; } protected: diff --git a/eo/src/eompi.cpp b/eo/src/mpi/eompi.cpp similarity index 100% rename from eo/src/eompi.cpp rename to eo/src/mpi/eompi.cpp diff --git a/eo/src/eompi.h b/eo/src/mpi/eompi.h similarity index 100% rename from eo/src/eompi.h rename to eo/src/mpi/eompi.h diff --git a/eo/test/t-eoMpiParallelApply.cpp b/eo/test/t-eoMpiParallelApply.cpp index 77583420..c20cc94f 100644 --- a/eo/test/t-eoMpiParallelApply.cpp +++ b/eo/test/t-eoMpiParallelApply.cpp @@ -1,5 +1,5 @@ -# include -# include +# include +# include # include # include From d0a00a5216a1028c71d4c1f3b4e71d9733177823 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 15:05:32 +0200 Subject: [PATCH 10/52] Don't force user to compile with OpenMP. --- eo/CMakeLists.txt | 10 ++++++---- eo/eo-conf.cmake | 7 +++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/eo/CMakeLists.txt b/eo/CMakeLists.txt index c10ac3c5..78cab0a5 100644 --- a/eo/CMakeLists.txt +++ b/eo/CMakeLists.txt @@ -44,10 +44,12 @@ ENABLE_LANGUAGE(C) ### 2) Include required modules / configuration files ##################################################################################### -FIND_PACKAGE(OpenMP) -IF(OPENMP_FOUND) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +IF(WITH_OMP) + FIND_PACKAGE(OpenMP) + IF(OPENMP_FOUND) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + ENDIF() ENDIF() INCLUDE(CMakeBackwardCompatibilityCXX) diff --git a/eo/eo-conf.cmake b/eo/eo-conf.cmake index 2c115cfe..1f5ee815 100644 --- a/eo/eo-conf.cmake +++ b/eo/eo-conf.cmake @@ -5,10 +5,13 @@ SET(PROJECT_VERSION_MINOR 3) SET(PROJECT_VERSION_PATCH 0) SET(PROJECT_VERSION_MISC "-edge") +# If you plan to use OpenMP, put the following boolean to true : +SET(WITH_OMP FALSE CACHE BOOL "Use OpenMP ?" FORCE) + # If you plan to use MPI, precise here where are the static libraries from # openmpi and boost::mpi. SET(WITH_MPI FALSE CACHE BOOL "Use mpi ?" FORCE) -SET(MPI_DIR "put root directory of openmpi here" CACHE PATH "OpenMPI directory" FORCE) -SET(BOOST_DIR "put root directory of boost here" CACHE PATH "Boost directory" FORCE) +SET(MPI_DIR "/mpi/directory" CACHE PATH "OpenMPI directory" FORCE) +SET(BOOST_DIR "/boost/directory" CACHE PATH "Boost directory" FORCE) From 122d0debf098b9c36cc8f4f70bcbd555153a660c Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 16:10:51 +0200 Subject: [PATCH 11/52] eoMpi API is simpler and allows to have multiple roles for a given node. --- eo/src/mpi/assignmentAlgorithm.h | 49 ++++++++ eo/src/mpi/eoParallelApply.h | 4 +- eo/src/mpi/eompi.cpp | 3 +- eo/src/mpi/eompi.h | 196 +++++++------------------------ eo/test/t-eoMpiParallelApply.cpp | 19 ++- 5 files changed, 112 insertions(+), 159 deletions(-) create mode 100644 eo/src/mpi/assignmentAlgorithm.h diff --git a/eo/src/mpi/assignmentAlgorithm.h b/eo/src/mpi/assignmentAlgorithm.h new file mode 100644 index 00000000..bd635c23 --- /dev/null +++ b/eo/src/mpi/assignmentAlgorithm.h @@ -0,0 +1,49 @@ +# ifndef __ASSIGNMENT_ALGORITHM_H__ +# define __ASSIGNMENT_ALGORITHM_H__ + +struct AssignmentAlgorithm +{ + virtual int get( ) = 0; + virtual int size( ) = 0; + virtual void confirm( int wrkRank ) = 0; +}; + +struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm +{ + public: + DynamicAssignmentAlgorithm( int offset, int size ) + { + for( int i = 0; offset + i < size; ++i) + { + availableWrk.push_back( offset + i ); + } + } + + virtual int get( ) + { + int assignee = -1; + if (! availableWrk.empty() ) + { + assignee = availableWrk.back(); + availableWrk.pop_back(); + } + return assignee; + } + + int size() + { + return availableWrk.size(); + } + + void confirm( int rank ) + { + availableWrk.push_back( rank ); + } + + protected: + std::vector< int > availableWrk; +}; + + + +# endif // __ASSIGNMENT_ALGORITHM_H__ diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 528d0cb2..80958e41 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -11,8 +11,8 @@ class ParallelApply : public MpiJob< EOT > { public: - ParallelApply( eoUF & _proc, std::vector& _pop ) : - MpiJob( _pop ), + ParallelApply( eoUF & _proc, std::vector& _pop, AssignmentAlgorithm & algo ) : + MpiJob( _pop, algo ), func( _proc ) { // empty diff --git a/eo/src/mpi/eompi.cpp b/eo/src/mpi/eompi.cpp index eff6bc39..6429a31c 100644 --- a/eo/src/mpi/eompi.cpp +++ b/eo/src/mpi/eompi.cpp @@ -1,4 +1,5 @@ # include "eompi.h" -MpiNode* MpiNodeStore::singleton; +// MpiNode* MpiNodeStore::singleton; +mpi::communicator MpiNode::_comm; diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index 9abcbb0f..3b04441d 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -7,6 +7,8 @@ # include namespace mpi = boost::mpi; +# include "assignmentAlgorithm.h" + # include using namespace std; // TODO TODOB comment! @@ -25,102 +27,22 @@ namespace EoMpi } } -class MpiNode; - -class MpiNodeStore +class MpiNode { public: - static void instance( MpiNode* _instance ) + static void init( int argc, char** argv ) { - singleton = _instance; + static mpi::environment env( argc, argv ); } - static MpiNode* instance() - { - return singleton; - } - - protected: - - static MpiNode* singleton; -}; - -class MpiNode -{ -protected: - mpi::environment& env; - mpi::communicator& _comm; - - int rank; - int size; - - int argc; - char** argv; - -public: - MpiNode( mpi::environment& _env, mpi::communicator& __comm ) : - env(_env), - _comm(__comm), - rank(__comm.rank()), - size(__comm.size()) - { - // empty - } - - virtual ~MpiNode() - { - // empty - } - - mpi::communicator& comm() + static mpi::communicator& comm() { return _comm; } -}; - -struct AssignmentAlgorithm -{ - virtual int get( ) = 0; - virtual void size( int s ) = 0; - virtual int size( ) = 0; - virtual void confirm( int wrkRank ) = 0; -}; - -struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm -{ - public: - virtual int get( ) - { - int assignee = -1; - if (! availableWrk.empty() ) - { - assignee = availableWrk.back(); - availableWrk.pop_back(); - } - return assignee; - } -; - void size( int s ) - { - for( int i = 1; i < s ; ++i ) - { - availableWrk.push_back( i ); - } - } - - int size() - { - return availableWrk.size(); - } - - void confirm( int rank ) - { - availableWrk.push_back( rank ); - } protected: - std::vector< int > availableWrk; + static mpi::communicator _comm; }; template< typename EOT > @@ -128,9 +50,10 @@ class MpiJob { public: - MpiJob( std::vector< EOT > & _data ) : + MpiJob( std::vector< EOT > & _data, AssignmentAlgorithm& algo ) : data( _data ), - comm( MpiNodeStore::instance()->comm() ) + comm( MpiNode::comm() ), + assignmentAlgo( algo ) { // empty } @@ -141,14 +64,14 @@ class MpiJob // worker virtual void processTask( ) = 0; - void master( AssignmentAlgorithm & assignmentAlgorithm ) + void master( ) { for( int i = 0, size = data.size(); i < size; ++i) { cout << "Beginning loop for i = " << i << endl; - int assignee = assignmentAlgorithm.get( ); + int assignee = assignmentAlgo.get( ); cout << "Assignee : " << assignee << endl; while( assignee <= 0 ) { @@ -157,8 +80,8 @@ class MpiJob int wrkRank = status.source(); cout << "Node " << wrkRank << " just terminated." << endl; handleResponse( wrkRank, assignedTasks[ wrkRank ] ); - assignmentAlgorithm.confirm( wrkRank ); - assignee = assignmentAlgorithm.get( ); + assignmentAlgo.confirm( wrkRank ); + assignee = assignmentAlgo.get( ); } cout << "Assignee found : " << assignee << endl; assignedTasks[ assignee ] = i; @@ -169,25 +92,25 @@ class MpiJob // frees all the idle workers int idle; vector idles; - while ( ( idle = assignmentAlgorithm.get( ) ) > 0 ) + while ( ( idle = assignmentAlgo.get( ) ) > 0 ) { comm.send( idle, EoMpi::Channel::Commands, EoMpi::Message::Finish ); idles.push_back( idle ); } for (int i = 0; i < idles.size(); ++i) { - assignmentAlgorithm.confirm( idles[i] ); + assignmentAlgo.confirm( idles[i] ); } // wait for all responses int wrkNb = comm.size() - 1; - while( assignmentAlgorithm.size() != wrkNb ) + while( assignmentAlgo.size() != wrkNb ) { mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); int wrkRank = status.source(); handleResponse( wrkRank, assignedTasks[ wrkRank ] ); comm.send( wrkRank, EoMpi::Channel::Commands, EoMpi::Message::Finish ); - assignmentAlgorithm.confirm( wrkRank ); + assignmentAlgo.confirm( wrkRank ); } } @@ -211,77 +134,44 @@ protected: std::vector & data; std::map< int /* worker rank */, int /* index in vector */> assignedTasks; - + AssignmentAlgorithm& assignmentAlgo; mpi::communicator& comm; }; -class MasterNode : public MpiNode -{ -public: - MasterNode( int _argc, char** _argv, - mpi::environment& _env, - mpi::communicator& _comm - ) : - MpiNode(_env, _comm ) - { - // empty - } - - void setAssignmentAlgorithm( AssignmentAlgorithm* assignmentAlgo ) - { - _assignmentAlgo = assignmentAlgo; - _assignmentAlgo->size( _comm.size() ); - } - - template< typename EOT > - void run( MpiJob< EOT > & job ) - { - job.master( *_assignmentAlgo ); - } - -protected: - AssignmentAlgorithm* _assignmentAlgo; -}; - -class WorkerNode : public MpiNode +template< class EOT > +class Role { public: - - WorkerNode( - int _argc, char** _argv, - mpi::environment& _env, - mpi::communicator& _comm ) : - MpiNode( _env, _comm ) + Role( MpiJob & job, bool master ) : + _job( job ), + _master( master ) { // empty } - template< typename EOT > - void run( MpiJob & job ) + bool master() { - job.worker( ); + return _master; } -}; -class MpiSingletonFactory -{ - public: - - static void init( int argc, char** argv ) - { - MpiNode* singleton; - //mpi::environment* env = new mpi::environment ( argc, argv ); - //mpi::communicator* world = new mpi::communicator; // TODO clean - static mpi::environment env( argc, argv ); - static mpi::communicator world; - if ( world.rank() == 0 ) + virtual void run( ) { - singleton = new MasterNode( argc, argv, env, world ); - } else - { - singleton = new WorkerNode( argc, argv, env, world ); + if( _master ) + { + _job.master( ); + } else + { + _job.worker( ); + } } - MpiNodeStore::instance( singleton ); - } + + virtual ~Role() + { + // empty + } + + protected: + bool _master; + MpiJob & _job; }; # endif // __EO_MPI_H__ diff --git a/eo/test/t-eoMpiParallelApply.cpp b/eo/test/t-eoMpiParallelApply.cpp index c20cc94f..ab559815 100644 --- a/eo/test/t-eoMpiParallelApply.cpp +++ b/eo/test/t-eoMpiParallelApply.cpp @@ -1,5 +1,6 @@ # include # include + # include # include @@ -15,9 +16,9 @@ struct plusOne : public eoUF< int&, void > int main(int argc, char** argv) { - DynamicAssignmentAlgorithm algo; cout << "Appel à init... " << endl; - MpiSingletonFactory::init( argc, argv ); + MpiNode::init( argc, argv ); + DynamicAssignmentAlgorithm algo( 1, MpiNode::comm().size() ); cout << "Création des données... " << endl; vector v; @@ -31,8 +32,19 @@ int main(int argc, char** argv) plusOne plusOneInstance; cout << "Création du job..." << endl; - ParallelApply job( plusOneInstance, v ); + ParallelApply job( plusOneInstance, v, algo ); + Role node( job, MpiNode::comm().rank() == 0 ); + node.run(); + if( node.master() ) + { + for(int i = 0; i < v.size(); ++i) + { + cout << v[i] << ' '; + } + cout << endl; + } + /* cout << "Création de l'instance..." << endl; MpiNode* instance = MpiNodeStore::instance(); if( dynamic_cast( instance ) != 0 ) @@ -54,6 +66,7 @@ int main(int argc, char** argv) { cout << "Nothing to be done;" << endl; } + */ return 0; } From 9275fbedad695cf716d4b1c49f77e45de65eac87 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 17:20:24 +0200 Subject: [PATCH 12/52] Making mpi tests dir --- eo/test/{t-eoMpiParallelApply.cpp => mpi/parallelApply.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename eo/test/{t-eoMpiParallelApply.cpp => mpi/parallelApply.cpp} (100%) diff --git a/eo/test/t-eoMpiParallelApply.cpp b/eo/test/mpi/parallelApply.cpp similarity index 100% rename from eo/test/t-eoMpiParallelApply.cpp rename to eo/test/mpi/parallelApply.cpp From 2aa312e43d168f6d25cde3fe3ea1a4135d4ff55a Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 17:21:13 +0200 Subject: [PATCH 13/52] Allowing more than one master. --- eo/src/mpi/assignmentAlgorithm.h | 2 +- eo/src/mpi/eoParallelApply.h | 15 ++++++----- eo/src/mpi/eompi.h | 46 +++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/eo/src/mpi/assignmentAlgorithm.h b/eo/src/mpi/assignmentAlgorithm.h index bd635c23..89b97c06 100644 --- a/eo/src/mpi/assignmentAlgorithm.h +++ b/eo/src/mpi/assignmentAlgorithm.h @@ -13,7 +13,7 @@ struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm public: DynamicAssignmentAlgorithm( int offset, int size ) { - for( int i = 0; offset + i < size; ++i) + for( int i = 0; offset + i <= size; ++i) { availableWrk.push_back( offset + i ); } diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 80958e41..990f8fad 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -10,9 +10,12 @@ template< typename EOT > class ParallelApply : public MpiJob< EOT > { public: + using MpiJob::comm; + using MpiJob::data; + using MpiJob::_masterRank; - ParallelApply( eoUF & _proc, std::vector& _pop, AssignmentAlgorithm & algo ) : - MpiJob( _pop, algo ), + ParallelApply( eoUF & _proc, std::vector& _pop, AssignmentAlgorithm & algo, int _masterRank ) : + MpiJob( _pop, algo, _masterRank ), func( _proc ) { // empty @@ -20,20 +23,20 @@ class ParallelApply : public MpiJob< EOT > virtual void sendTask( int wrkRank, int index ) { - MpiJob::comm.send( wrkRank, 1, MpiJob::data[ index ] ); + comm.send( wrkRank, 1, data[ index ] ); } virtual void handleResponse( int wrkRank, int index ) { - MpiJob::comm.recv( wrkRank, 1, MpiJob::data[ index ] ); + comm.recv( wrkRank, 1, data[ index ] ); } virtual void processTask( ) { EOT ind; - MpiJob::comm.recv( 0, 1, ind ); + comm.recv( _masterRank, 1, ind ); func( ind ); - MpiJob::comm.send( 0, 1, ind ); + comm.send( _masterRank, 1, ind ); } protected: diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index 3b04441d..df041db5 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -50,10 +50,11 @@ class MpiJob { public: - MpiJob( std::vector< EOT > & _data, AssignmentAlgorithm& algo ) : + MpiJob( std::vector< EOT > & _data, AssignmentAlgorithm& algo, int masterRank ) : data( _data ), comm( MpiNode::comm() ), - assignmentAlgo( algo ) + assignmentAlgo( algo ), + _masterRank( masterRank ) { // empty } @@ -66,29 +67,33 @@ class MpiJob void master( ) { + int totalWorkers = assignmentAlgo.size(); + cout << "[M] Have " << totalWorkers << " workers." << endl; + for( int i = 0, size = data.size(); i < size; ++i) { - cout << "Beginning loop for i = " << i << endl; + cout << "[M] Beginning loop for i = " << i << endl; int assignee = assignmentAlgo.get( ); - cout << "Assignee : " << assignee << endl; + cout << "[M] Assignee : " << assignee << endl; while( assignee <= 0 ) { - cout << "Waitin' for node..." << endl; + cout << "[M] Waitin' for node..." << endl; mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); int wrkRank = status.source(); - cout << "Node " << wrkRank << " just terminated." << endl; + cout << "[M] Node " << wrkRank << " just terminated." << endl; handleResponse( wrkRank, assignedTasks[ wrkRank ] ); assignmentAlgo.confirm( wrkRank ); assignee = assignmentAlgo.get( ); } - cout << "Assignee found : " << assignee << endl; + cout << "[M] Assignee found : " << assignee << endl; assignedTasks[ assignee ] = i; comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); sendTask( assignee, i ); } + cout << "[M] Frees all the idle." << endl; // frees all the idle workers int idle; vector idles; @@ -102,9 +107,9 @@ class MpiJob assignmentAlgo.confirm( idles[i] ); } + cout << "[M] Waits for all responses." << endl; // wait for all responses - int wrkNb = comm.size() - 1; - while( assignmentAlgo.size() != wrkNb ) + while( assignmentAlgo.size() != totalWorkers ) { mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); int wrkRank = status.source(); @@ -112,6 +117,8 @@ class MpiJob comm.send( wrkRank, EoMpi::Channel::Commands, EoMpi::Message::Finish ); assignmentAlgo.confirm( wrkRank ); } + + cout << "[M] Leaving master task." << endl; } void worker( ) @@ -119,34 +126,41 @@ class MpiJob int order; while( true ) { - comm.recv( 0, EoMpi::Channel::Commands, order ); + cout << "[W] Waiting for an order..." << std::endl; + comm.recv( _masterRank, EoMpi::Channel::Commands, order ); if ( order == EoMpi::Message::Finish ) { return; } else { + cout << "[W] Processing task..." << std::endl; processTask( ); } } } + int masterRank() + { + return _masterRank; + } + protected: std::vector & data; std::map< int /* worker rank */, int /* index in vector */> assignedTasks; AssignmentAlgorithm& assignmentAlgo; mpi::communicator& comm; + int _masterRank; }; template< class EOT > class Role { public: - Role( MpiJob & job, bool master ) : - _job( job ), - _master( master ) + Role( MpiJob & job ) : + _job( job ) { - // empty + _master = job.masterRank() == MpiNode::comm().rank(); } bool master() @@ -156,7 +170,7 @@ class Role virtual void run( ) { - if( _master ) + if( MpiNode::comm().rank() == _job.masterRank() ) { _job.master( ); } else @@ -171,7 +185,7 @@ class Role } protected: - bool _master; MpiJob & _job; + bool _master; }; # endif // __EO_MPI_H__ From 92bd4eec1b1d1d5731d88481c004289020702b53 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 17:22:28 +0200 Subject: [PATCH 14/52] Adding tests for multiple roles and updating parallel apply. --- eo/test/mpi/multipleRoles.cpp | 91 +++++++++++++++++++++++++++++++++++ eo/test/mpi/parallelApply.cpp | 6 +-- 2 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 eo/test/mpi/multipleRoles.cpp diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp new file mode 100644 index 00000000..bd91245b --- /dev/null +++ b/eo/test/mpi/multipleRoles.cpp @@ -0,0 +1,91 @@ +# include +# include + +# include + +# include + +# include +using namespace std; + +// Role map +// 0 : general master +// 1 : worker of general job, master of subjob +// 2 and more : workers of subjob + +struct plusOne : public eoUF< int&, void > +{ + void operator() ( int & x ) + { + cout << "Subjob is being applied." << endl; + ++x; + } +}; + +void subtask( vector& v ) +{ + DynamicAssignmentAlgorithm algo( 2, MpiNode::comm().size()-1 ); + plusOne plusOneInstance; + ParallelApply job( plusOneInstance, v, algo, 1 ); + Role node( job ); + node.run(); +} + +struct transmit : public eoUF< vector&, void > +{ + void operator() ( vector& v ) + { + cout << "Into the master subjob..." << endl; + subtask( v ); + } +}; + +int main(int argc, char** argv) +{ + MpiNode::init( argc, argv ); + vector v; + + v.push_back(1); + v.push_back(3); + v.push_back(3); + v.push_back(7); + v.push_back(42); + + transmit transmitInstance; + + vector< vector > metaV; + metaV.push_back( v ); + + switch( MpiNode::comm().rank() ) + { + case 0: + case 1: + { + // only one node is assigned to subjob mastering + DynamicAssignmentAlgorithm algo( 1, 1 ); + ParallelApply< vector > job( transmitInstance, metaV, algo, 0 ); + Role< vector > node( job ); + node.run(); + if( node.master() ) + { + v = metaV[0]; + cout << "Results : " << endl; + for(int i = 0; i < v.size(); ++i) + { + cout << v[i] << ' '; + } + cout << endl; + } + } + break; + + default: + { + // all the other nodes are sub workers + subtask( v ); + } + break; + } + + return 0; +} diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index ab559815..82686bf7 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -18,7 +18,7 @@ int main(int argc, char** argv) { cout << "Appel à init... " << endl; MpiNode::init( argc, argv ); - DynamicAssignmentAlgorithm algo( 1, MpiNode::comm().size() ); + DynamicAssignmentAlgorithm algo( 1, MpiNode::comm().size()-1 ); cout << "Création des données... " << endl; vector v; @@ -32,8 +32,8 @@ int main(int argc, char** argv) plusOne plusOneInstance; cout << "Création du job..." << endl; - ParallelApply job( plusOneInstance, v, algo ); - Role node( job, MpiNode::comm().rank() == 0 ); + ParallelApply job( plusOneInstance, v, algo, 0 ); + Role node( job ); node.run(); if( node.master() ) From 3c8e902155017f66366f3f58874521ab0ff9919b Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 17:23:25 +0200 Subject: [PATCH 15/52] Removing useless comments in parallelApply. --- eo/test/mpi/parallelApply.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 82686bf7..605f3911 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -44,29 +44,6 @@ int main(int argc, char** argv) } cout << endl; } - /* - cout << "Création de l'instance..." << endl; - MpiNode* instance = MpiNodeStore::instance(); - if( dynamic_cast( instance ) != 0 ) - { - cout << "[Master] Algorithme d'assignation" << endl; - static_cast( instance )->setAssignmentAlgorithm( &algo ); - cout << "[Master] Lancement." << endl; - static_cast( instance )->run( job ); - - for (int i = 0; i < v.size(); ++i ) - { - cout << v[i] << endl; - } - } else if ( dynamic_cast( instance ) != 0 ) - { - cout << "[Worker] Lancement." << endl; - static_cast( instance )->run( job ); - } else - { - cout << "Nothing to be done;" << endl; - } - */ return 0; } From 33e062d1665972eb13a94abb5c442b53ed209b52 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 17:31:07 +0200 Subject: [PATCH 16/52] Simplified master condition. --- eo/src/mpi/eompi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index df041db5..cbb66a46 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -170,7 +170,7 @@ class Role virtual void run( ) { - if( MpiNode::comm().rank() == _job.masterRank() ) + if( _master ) { _job.master( ); } else From 28ab2004ea59b1a3683c5d4bde28d4ff761862d9 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 21 Jun 2012 18:26:56 +0200 Subject: [PATCH 17/52] MpiJob now just deal with loop logic, not with handled data. Handled data is now handled by the MpiJob subclasses. Tests updated. --- eo/src/mpi/eoParallelApply.h | 49 ++++++++++++++++++++++++------ eo/src/mpi/eompi.h | 57 ++++++++++++++++++++++++++--------- eo/test/mpi/multipleRoles.cpp | 4 +-- eo/test/mpi/parallelApply.cpp | 2 +- 4 files changed, 84 insertions(+), 28 deletions(-) diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 990f8fad..86e2b04a 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -7,28 +7,53 @@ # include template< typename EOT > -class ParallelApply : public MpiJob< EOT > +struct ParallelApplyContinuator : public BaseContinuator +{ + ParallelApplyContinuator( int index, int size ) + { + _index = index; + _size = size; + } + + void index( int i ) { _index = i; } + + bool operator()() + { + return _index < _size; + } + +private: + int _index; + int _size; +}; + +template< typename EOT > +class ParallelApply : public MpiJob { public: - using MpiJob::comm; - using MpiJob::data; - using MpiJob::_masterRank; ParallelApply( eoUF & _proc, std::vector& _pop, AssignmentAlgorithm & algo, int _masterRank ) : - MpiJob( _pop, algo, _masterRank ), - func( _proc ) + MpiJob( algo, + new ParallelApplyContinuator( 0, _pop.size() ), + _masterRank ), + func( _proc ), + index( 0 ), + data( _pop ) { - // empty + pa_continuator = static_cast*>( _continuator ); } - virtual void sendTask( int wrkRank, int index ) + virtual void sendTask( int wrkRank ) { + assignedTasks[ wrkRank ] = index; comm.send( wrkRank, 1, data[ index ] ); + ++index; + pa_continuator->index( index ); } - virtual void handleResponse( int wrkRank, int index ) + virtual void handleResponse( int wrkRank ) { - comm.recv( wrkRank, 1, data[ index ] ); + comm.recv( wrkRank, 1, data[ assignedTasks[ wrkRank ] ] ); } virtual void processTask( ) @@ -40,7 +65,11 @@ class ParallelApply : public MpiJob< EOT > } protected: + vector & data; eoUF& func; + int index; + ParallelApplyContinuator * pa_continuator; + std::map< int /* worker rank */, int /* index in vector */> assignedTasks; }; # endif // __EO_PARALLEL_APPLY_H__ diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index cbb66a46..8bc25d31 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -45,23 +45,33 @@ class MpiNode static mpi::communicator _comm; }; -template< typename EOT > +struct BaseContinuator +{ + virtual bool operator()() = 0; +}; + +// template< typename EOT > class MpiJob { public: - MpiJob( std::vector< EOT > & _data, AssignmentAlgorithm& algo, int masterRank ) : - data( _data ), - comm( MpiNode::comm() ), + MpiJob( AssignmentAlgorithm& algo, BaseContinuator* c, int masterRank ) : assignmentAlgo( algo ), - _masterRank( masterRank ) + comm( MpiNode::comm() ), + _masterRank( masterRank ), + _continuator( c ) { // empty } + ~MpiJob() + { + delete _continuator; + } + // master - virtual void sendTask( int wrkRank, int index ) = 0; - virtual void handleResponse( int wrkRank, int index ) = 0; + virtual void sendTask( int wrkRank ) = 0; + virtual void handleResponse( int wrkRank ) = 0; // worker virtual void processTask( ) = 0; @@ -70,6 +80,25 @@ class MpiJob int totalWorkers = assignmentAlgo.size(); cout << "[M] Have " << totalWorkers << " workers." << endl; + while( (*_continuator)() ) + { + int assignee = assignmentAlgo.get( ); + cout << "[M] Assignee : " << assignee << endl; + while( assignee <= 0 ) + { + cout << "[M] Waitin' for node..." << endl; + mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); + int wrkRank = status.source(); + cout << "[M] Node " << wrkRank << " just terminated." << endl; + handleResponse( wrkRank ); + assignmentAlgo.confirm( wrkRank ); + assignee = assignmentAlgo.get( ); + } + comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); + sendTask( assignee ); + } + + /* for( int i = 0, size = data.size(); i < size; ++i) @@ -92,6 +121,7 @@ class MpiJob comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); sendTask( assignee, i ); } + */ cout << "[M] Frees all the idle." << endl; // frees all the idle workers @@ -102,7 +132,7 @@ class MpiJob comm.send( idle, EoMpi::Channel::Commands, EoMpi::Message::Finish ); idles.push_back( idle ); } - for (int i = 0; i < idles.size(); ++i) + for (unsigned int i = 0; i < idles.size(); ++i) { assignmentAlgo.confirm( idles[i] ); } @@ -113,7 +143,7 @@ class MpiJob { mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); int wrkRank = status.source(); - handleResponse( wrkRank, assignedTasks[ wrkRank ] ); + handleResponse( wrkRank ); comm.send( wrkRank, EoMpi::Channel::Commands, EoMpi::Message::Finish ); assignmentAlgo.confirm( wrkRank ); } @@ -145,19 +175,16 @@ class MpiJob } protected: - - std::vector & data; - std::map< int /* worker rank */, int /* index in vector */> assignedTasks; AssignmentAlgorithm& assignmentAlgo; + BaseContinuator* _continuator; mpi::communicator& comm; int _masterRank; }; -template< class EOT > class Role { public: - Role( MpiJob & job ) : + Role( MpiJob & job ) : _job( job ) { _master = job.masterRank() == MpiNode::comm().rank(); @@ -185,7 +212,7 @@ class Role } protected: - MpiJob & _job; + MpiJob & _job; bool _master; }; # endif // __EO_MPI_H__ diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index bd91245b..c300fdbb 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -27,7 +27,7 @@ void subtask( vector& v ) DynamicAssignmentAlgorithm algo( 2, MpiNode::comm().size()-1 ); plusOne plusOneInstance; ParallelApply job( plusOneInstance, v, algo, 1 ); - Role node( job ); + Role node( job ); node.run(); } @@ -64,7 +64,7 @@ int main(int argc, char** argv) // only one node is assigned to subjob mastering DynamicAssignmentAlgorithm algo( 1, 1 ); ParallelApply< vector > job( transmitInstance, metaV, algo, 0 ); - Role< vector > node( job ); + Role node( job ); node.run(); if( node.master() ) { diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 605f3911..dd11f7b3 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -33,7 +33,7 @@ int main(int argc, char** argv) cout << "Création du job..." << endl; ParallelApply job( plusOneInstance, v, algo, 0 ); - Role node( job ); + Role node( job ); node.run(); if( node.master() ) From fb871382e09377870bf7d387a3bf13c116f34327 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 12:09:19 +0200 Subject: [PATCH 18/52] Removed useless continuator functor, replaced with a virtual method into MpiJob. --- eo/src/mpi/eoParallelApply.h | 36 ++++++++--------------------- eo/src/mpi/eompi.h | 45 ++++-------------------------------- 2 files changed, 13 insertions(+), 68 deletions(-) diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 86e2b04a..cf964521 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -6,41 +6,19 @@ # include # include -template< typename EOT > -struct ParallelApplyContinuator : public BaseContinuator -{ - ParallelApplyContinuator( int index, int size ) - { - _index = index; - _size = size; - } - - void index( int i ) { _index = i; } - - bool operator()() - { - return _index < _size; - } - -private: - int _index; - int _size; -}; - template< typename EOT > class ParallelApply : public MpiJob { public: ParallelApply( eoUF & _proc, std::vector& _pop, AssignmentAlgorithm & algo, int _masterRank ) : - MpiJob( algo, - new ParallelApplyContinuator( 0, _pop.size() ), - _masterRank ), + MpiJob( algo, _masterRank ), func( _proc ), index( 0 ), + size( _pop.size() ), data( _pop ) { - pa_continuator = static_cast*>( _continuator ); + // empty } virtual void sendTask( int wrkRank ) @@ -48,7 +26,6 @@ class ParallelApply : public MpiJob assignedTasks[ wrkRank ] = index; comm.send( wrkRank, 1, data[ index ] ); ++index; - pa_continuator->index( index ); } virtual void handleResponse( int wrkRank ) @@ -64,11 +41,16 @@ class ParallelApply : public MpiJob comm.send( _masterRank, 1, ind ); } + bool isFinished() + { + return index = size; + } + protected: vector & data; eoUF& func; int index; - ParallelApplyContinuator * pa_continuator; + int size; std::map< int /* worker rank */, int /* index in vector */> assignedTasks; }; diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index 8bc25d31..f043c162 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -45,31 +45,20 @@ class MpiNode static mpi::communicator _comm; }; -struct BaseContinuator -{ - virtual bool operator()() = 0; -}; - -// template< typename EOT > class MpiJob { public: - MpiJob( AssignmentAlgorithm& algo, BaseContinuator* c, int masterRank ) : + MpiJob( AssignmentAlgorithm& algo, int masterRank ) : assignmentAlgo( algo ), comm( MpiNode::comm() ), - _masterRank( masterRank ), - _continuator( c ) + _masterRank( masterRank ) { // empty } - ~MpiJob() - { - delete _continuator; - } - // master + virtual bool isFinished() = 0; virtual void sendTask( int wrkRank ) = 0; virtual void handleResponse( int wrkRank ) = 0; // worker @@ -80,7 +69,7 @@ class MpiJob int totalWorkers = assignmentAlgo.size(); cout << "[M] Have " << totalWorkers << " workers." << endl; - while( (*_continuator)() ) + while( ! isFinished() ) { int assignee = assignmentAlgo.get( ); cout << "[M] Assignee : " << assignee << endl; @@ -98,31 +87,6 @@ class MpiJob sendTask( assignee ); } - /* - for( int i = 0, size = data.size(); - i < size; - ++i) - { - cout << "[M] Beginning loop for i = " << i << endl; - int assignee = assignmentAlgo.get( ); - cout << "[M] Assignee : " << assignee << endl; - while( assignee <= 0 ) - { - cout << "[M] Waitin' for node..." << endl; - mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); - int wrkRank = status.source(); - cout << "[M] Node " << wrkRank << " just terminated." << endl; - handleResponse( wrkRank, assignedTasks[ wrkRank ] ); - assignmentAlgo.confirm( wrkRank ); - assignee = assignmentAlgo.get( ); - } - cout << "[M] Assignee found : " << assignee << endl; - assignedTasks[ assignee ] = i; - comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); - sendTask( assignee, i ); - } - */ - cout << "[M] Frees all the idle." << endl; // frees all the idle workers int idle; @@ -176,7 +140,6 @@ class MpiJob protected: AssignmentAlgorithm& assignmentAlgo; - BaseContinuator* _continuator; mpi::communicator& comm; int _masterRank; }; From da9eb9ce7b417b737722f07fdb9dbd8cbcc9e338 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 14:24:23 +0200 Subject: [PATCH 19/52] Merged MpiJob and Role, using eoLogger instead of cout. --- eo/src/mpi/eoParallelApply.h | 8 ++-- eo/src/mpi/eompi.h | 85 ++++++++++++----------------------- eo/test/mpi/parallelApply.cpp | 10 ++--- 3 files changed, 38 insertions(+), 65 deletions(-) diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index cf964521..0c4f1e6e 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -36,18 +36,18 @@ class ParallelApply : public MpiJob virtual void processTask( ) { EOT ind; - comm.recv( _masterRank, 1, ind ); + comm.recv( masterRank, 1, ind ); func( ind ); - comm.send( _masterRank, 1, ind ); + comm.send( masterRank, 1, ind ); } bool isFinished() { - return index = size; + return index == size; } protected: - vector & data; + std::vector & data; eoUF& func; int index; int size; diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index f043c162..58ddf131 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -7,10 +7,9 @@ # include namespace mpi = boost::mpi; -# include "assignmentAlgorithm.h" +# include -# include -using namespace std; +# include "assignmentAlgorithm.h" // TODO TODOB comment! namespace EoMpi @@ -49,12 +48,12 @@ class MpiJob { public: - MpiJob( AssignmentAlgorithm& algo, int masterRank ) : - assignmentAlgo( algo ), + MpiJob( AssignmentAlgorithm& _algo, int _masterRank ) : + assignmentAlgo( _algo ), comm( MpiNode::comm() ), - _masterRank( masterRank ) + masterRank( _masterRank ) { - // empty + _isMaster = MpiNode::comm().rank() == _masterRank; } // master @@ -67,18 +66,19 @@ class MpiJob void master( ) { int totalWorkers = assignmentAlgo.size(); - cout << "[M] Have " << totalWorkers << " workers." << endl; + eo::log << eo::debug; + eo::log << "[M] Have " << totalWorkers << " workers." << std::endl; while( ! isFinished() ) { int assignee = assignmentAlgo.get( ); - cout << "[M] Assignee : " << assignee << endl; + eo::log << "[M] Assignee : " << assignee << std::endl; while( assignee <= 0 ) { - cout << "[M] Waitin' for node..." << endl; + eo::log << "[M] Waitin' for node..." << std::endl; mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); int wrkRank = status.source(); - cout << "[M] Node " << wrkRank << " just terminated." << endl; + eo::log << "[M] Node " << wrkRank << " just terminated." << std::endl; handleResponse( wrkRank ); assignmentAlgo.confirm( wrkRank ); assignee = assignmentAlgo.get( ); @@ -87,10 +87,10 @@ class MpiJob sendTask( assignee ); } - cout << "[M] Frees all the idle." << endl; + eo::log << "[M] Frees all the idle." << std::endl; // frees all the idle workers int idle; - vector idles; + std::vector idles; while ( ( idle = assignmentAlgo.get( ) ) > 0 ) { comm.send( idle, EoMpi::Channel::Commands, EoMpi::Message::Finish ); @@ -101,7 +101,7 @@ class MpiJob assignmentAlgo.confirm( idles[i] ); } - cout << "[M] Waits for all responses." << endl; + eo::log << "[M] Waits for all responses." << std::endl; // wait for all responses while( assignmentAlgo.size() != totalWorkers ) { @@ -112,70 +112,43 @@ class MpiJob assignmentAlgo.confirm( wrkRank ); } - cout << "[M] Leaving master task." << endl; + eo::log << "[M] Leaving master task." << std::endl; } void worker( ) { int order; + eo::log << eo::debug; while( true ) { - cout << "[W] Waiting for an order..." << std::endl; - comm.recv( _masterRank, EoMpi::Channel::Commands, order ); + eo::log << "[W] Waiting for an order..." << std::endl; + comm.recv( masterRank, EoMpi::Channel::Commands, order ); if ( order == EoMpi::Message::Finish ) { return; } else { - cout << "[W] Processing task..." << std::endl; + eo::log << "[W] Processing task..." << std::endl; processTask( ); } } } - int masterRank() + void run( ) { - return _masterRank; + ( _isMaster ) ? master( ) : worker( ); + } + + bool isMaster( ) + { + return _isMaster; } protected: AssignmentAlgorithm& assignmentAlgo; mpi::communicator& comm; - int _masterRank; -}; - -class Role -{ - public: - Role( MpiJob & job ) : - _job( job ) - { - _master = job.masterRank() == MpiNode::comm().rank(); - } - - bool master() - { - return _master; - } - - virtual void run( ) - { - if( _master ) - { - _job.master( ); - } else - { - _job.worker( ); - } - } - - virtual ~Role() - { - // empty - } - - protected: - MpiJob & _job; - bool _master; + int masterRank; + bool _isMaster; }; # endif // __EO_MPI_H__ + diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index dd11f7b3..0fa65f28 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -16,9 +16,10 @@ struct plusOne : public eoUF< int&, void > int main(int argc, char** argv) { + eo::log << eo::setlevel( eo::debug ); cout << "Appel à init... " << endl; MpiNode::init( argc, argv ); - DynamicAssignmentAlgorithm algo( 1, MpiNode::comm().size()-1 ); + DynamicAssignmentAlgorithm assign( 1, MpiNode::comm().size()-1 ); cout << "Création des données... " << endl; vector v; @@ -32,11 +33,10 @@ int main(int argc, char** argv) plusOne plusOneInstance; cout << "Création du job..." << endl; - ParallelApply job( plusOneInstance, v, algo, 0 ); - Role node( job ); - node.run(); + ParallelApply job( plusOneInstance, v, assign, 0 ); + job.run(); - if( node.master() ) + if( job.isMaster() ) { for(int i = 0; i < v.size(); ++i) { From cf5317f6144eb046dad4f50d6730e1545956832e Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 16:13:08 +0200 Subject: [PATCH 20/52] Static assignement algorithm --- eo/src/mpi/assignmentAlgorithm.h | 102 +++++++++++++++++++++++++++++-- eo/src/mpi/eompi.h | 23 +++---- 2 files changed, 106 insertions(+), 19 deletions(-) diff --git a/eo/src/mpi/assignmentAlgorithm.h b/eo/src/mpi/assignmentAlgorithm.h index 89b97c06..06d3ec49 100644 --- a/eo/src/mpi/assignmentAlgorithm.h +++ b/eo/src/mpi/assignmentAlgorithm.h @@ -1,21 +1,24 @@ # ifndef __ASSIGNMENT_ALGORITHM_H__ # define __ASSIGNMENT_ALGORITHM_H__ +# include + struct AssignmentAlgorithm { virtual int get( ) = 0; - virtual int size( ) = 0; + virtual int availableWorkers( ) = 0; virtual void confirm( int wrkRank ) = 0; + virtual std::vector idles( ) = 0; }; struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm { public: - DynamicAssignmentAlgorithm( int offset, int size ) + DynamicAssignmentAlgorithm( int first, int last ) { - for( int i = 0; offset + i <= size; ++i) + for( int i = first; i <= last; ++i) { - availableWrk.push_back( offset + i ); + availableWrk.push_back( i ); } } @@ -30,7 +33,7 @@ struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm return assignee; } - int size() + int availableWorkers() { return availableWrk.size(); } @@ -40,10 +43,99 @@ struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm availableWrk.push_back( rank ); } + std::vector idles( ) + { + return availableWrk; + } + protected: std::vector< int > availableWrk; }; +struct StaticAssignmentAlgorithm : public AssignmentAlgorithm +{ + public: + StaticAssignmentAlgorithm( int first, int last, int runs ) + { + unsigned int nbWorkers = last - first + 1; + freeWorkers = nbWorkers; + offset = first; + attributions.reserve( nbWorkers ); + busy.resize( nbWorkers, false ); + // Let be the euclidean division of runs by nbWorkers : + // runs == q * nbWorkers + r, 0 <= r < nbWorkers + // This one liner affects q requests to each worker + for (unsigned int i = 0; i < nbWorkers; attributions[i++] = runs / nbWorkers) ; + // The first line computes r and the one liner affects the remaining + // r requests to workers, in ascending order + unsigned int diff = runs - (runs / nbWorkers) * nbWorkers; + for (unsigned int i = 0; i < diff; ++attributions[i++]); + } + + int get( ) + { + int assignee = -1; + for( unsigned i = 0; i < busy.size(); ++i ) + { + if( !busy[i] && attributions[i] > 0 ) + { + busy[i] = true; + --freeWorkers; + assignee = realRank( i ); + break; + } + } + return assignee; + } + + int availableWorkers( ) + { + return freeWorkers; + } + + std::vector idles() + { + std::vector ret; + for(unsigned int i = 0; i < busy.size(); ++i) + { + if( !busy[i] ) + { + eo::log << "Idle : " << realRank(i) << + " / attributions : " << attributions[i] << std::endl; + ret.push_back( realRank(i) ); + } + } + afterIdle = true; + return ret; + } + + void confirm( int rank ) + { + int i = attributionsIndex( rank ); + --attributions[ i ]; + busy[ i ] = false; + ++freeWorkers; + } + + private: + int attributionsIndex( int rank ) + { + return rank - offset; + } + + int realRank( int index ) + { + return index + offset; + } + + std::vector attributions; + std::vector busy; + + bool afterIdle; + int runs; + int offset; + unsigned int freeWorkers; +}; # endif // __ASSIGNMENT_ALGORITHM_H__ diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index 58ddf131..44cdbb1a 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -65,14 +65,13 @@ class MpiJob void master( ) { - int totalWorkers = assignmentAlgo.size(); + int totalWorkers = assignmentAlgo.availableWorkers(); eo::log << eo::debug; eo::log << "[M] Have " << totalWorkers << " workers." << std::endl; while( ! isFinished() ) { int assignee = assignmentAlgo.get( ); - eo::log << "[M] Assignee : " << assignee << std::endl; while( assignee <= 0 ) { eo::log << "[M] Waitin' for node..." << std::endl; @@ -83,27 +82,22 @@ class MpiJob assignmentAlgo.confirm( wrkRank ); assignee = assignmentAlgo.get( ); } + eo::log << "[M] Assignee : " << assignee << std::endl; comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); sendTask( assignee ); } eo::log << "[M] Frees all the idle." << std::endl; // frees all the idle workers - int idle; - std::vector idles; - while ( ( idle = assignmentAlgo.get( ) ) > 0 ) + std::vector idles = assignmentAlgo.idles(); + for(unsigned int i = 0; i < idles.size(); ++i) { - comm.send( idle, EoMpi::Channel::Commands, EoMpi::Message::Finish ); - idles.push_back( idle ); - } - for (unsigned int i = 0; i < idles.size(); ++i) - { - assignmentAlgo.confirm( idles[i] ); + comm.send( idles[i], EoMpi::Channel::Commands, EoMpi::Message::Finish ); } eo::log << "[M] Waits for all responses." << std::endl; // wait for all responses - while( assignmentAlgo.size() != totalWorkers ) + while( assignmentAlgo.availableWorkers() != totalWorkers ) { mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); int wrkRank = status.source(); @@ -121,14 +115,15 @@ class MpiJob eo::log << eo::debug; while( true ) { - eo::log << "[W] Waiting for an order..." << std::endl; + eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; comm.recv( masterRank, EoMpi::Channel::Commands, order ); if ( order == EoMpi::Message::Finish ) { + eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl; return; } else { - eo::log << "[W] Processing task..." << std::endl; + eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl; processTask( ); } } From aec5236eb1069b7091e6b684113a3452f1425008 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 16:14:27 +0200 Subject: [PATCH 21/52] Updated tests: multipleRoles compiles again and parallelApply tries all kinds of assignments algorithms. --- eo/test/mpi/multipleRoles.cpp | 10 +++--- eo/test/mpi/parallelApply.cpp | 58 ++++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index c300fdbb..a45dec42 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -27,8 +27,7 @@ void subtask( vector& v ) DynamicAssignmentAlgorithm algo( 2, MpiNode::comm().size()-1 ); plusOne plusOneInstance; ParallelApply job( plusOneInstance, v, algo, 1 ); - Role node( job ); - node.run(); + job.run(); } struct transmit : public eoUF< vector&, void > @@ -37,7 +36,7 @@ struct transmit : public eoUF< vector&, void > { cout << "Into the master subjob..." << endl; subtask( v ); - } + } }; int main(int argc, char** argv) @@ -64,9 +63,8 @@ int main(int argc, char** argv) // only one node is assigned to subjob mastering DynamicAssignmentAlgorithm algo( 1, 1 ); ParallelApply< vector > job( transmitInstance, metaV, algo, 0 ); - Role node( job ); - node.run(); - if( node.master() ) + job.run(); + if( job.isMaster() ) { v = metaV[0]; cout << "Results : " << endl; diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 0fa65f28..278ffd06 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -14,16 +14,18 @@ struct plusOne : public eoUF< int&, void > } }; +struct Test +{ + AssignmentAlgorithm * assign; + string description; +}; + int main(int argc, char** argv) { - eo::log << eo::setlevel( eo::debug ); - cout << "Appel à init... " << endl; + // eo::log << eo::setlevel( eo::debug ); MpiNode::init( argc, argv ); - DynamicAssignmentAlgorithm assign( 1, MpiNode::comm().size()-1 ); - cout << "Création des données... " << endl; vector v; - v.push_back(1); v.push_back(3); v.push_back(3); @@ -32,18 +34,44 @@ int main(int argc, char** argv) plusOne plusOneInstance; - cout << "Création du job..." << endl; - ParallelApply job( plusOneInstance, v, assign, 0 ); - job.run(); + vector< Test > tests; - if( job.isMaster() ) + Test tStatic; + tStatic.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size() ); + tStatic.description = "Correct static assignment."; + tests.push_back( tStatic ); + + Test tStaticOverload; + tStaticOverload.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size()+100 ); + tStaticOverload.description = "Static assignment with too many runs."; + tests.push_back( tStaticOverload ); + + Test tDynamic; + tDynamic.assign = new DynamicAssignmentAlgorithm( 1, MpiNode::comm().size()-1 ); + tDynamic.description = "Dynamic assignment."; + tests.push_back( tDynamic ); + + for( unsigned int i = 0; i < tests.size(); ++i ) { - for(int i = 0; i < v.size(); ++i) - { - cout << v[i] << ' '; - } - cout << endl; - } + ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0 ); + if( job.isMaster() ) + { + cout << "Test : " << tests[i].description << endl; + } + + job.run(); + + if( job.isMaster() ) + { + for(int i = 0; i < v.size(); ++i) + { + cout << v[i] << ' '; + } + cout << endl; + } + + delete tests[i].assign; + } return 0; } From 5bfcf4cd2c727b583dca36375b5866a130fc9b1d Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 17:28:31 +0200 Subject: [PATCH 22/52] Moving MpiNode into MpiNode.h --- eo/src/mpi/MpiNode.h | 25 +++++++++++++++++++++++++ eo/src/mpi/eompi.h | 24 +----------------------- 2 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 eo/src/mpi/MpiNode.h diff --git a/eo/src/mpi/MpiNode.h b/eo/src/mpi/MpiNode.h new file mode 100644 index 00000000..10804ce0 --- /dev/null +++ b/eo/src/mpi/MpiNode.h @@ -0,0 +1,25 @@ +# ifndef __MPI_NODE_H__ +# define __MPI_NODE_H__ + +# include +namespace mpi = boost::mpi; + +class MpiNode +{ + public: + + static void init( int argc, char** argv ) + { + static mpi::environment env( argc, argv ); + } + + static mpi::communicator& comm() + { + return _comm; + } + + protected: + static mpi::communicator _comm; +}; + +# endif // __MPI_NODE_H__ diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h index 44cdbb1a..3b51e7a3 100644 --- a/eo/src/mpi/eompi.h +++ b/eo/src/mpi/eompi.h @@ -3,12 +3,9 @@ # include # include - -# include -namespace mpi = boost::mpi; - # include +# include "MpiNode.h" # include "assignmentAlgorithm.h" // TODO TODOB comment! @@ -25,25 +22,6 @@ namespace EoMpi const int Finish = 1; } } - -class MpiNode -{ - public: - - static void init( int argc, char** argv ) - { - static mpi::environment env( argc, argv ); - } - - static mpi::communicator& comm() - { - return _comm; - } - - protected: - static mpi::communicator _comm; -}; - class MpiJob { public: From f3cb5eec20229df974865bcccd0dd004d613961b Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 17:31:46 +0200 Subject: [PATCH 23/52] More constructors for assignment algorithms: by interval, by unique worker, by vector of ranks, or whole world. --- eo/src/mpi/assignmentAlgorithm.h | 93 ++++++++++++++++++++++++-------- eo/test/mpi/multipleRoles.cpp | 2 +- eo/test/mpi/parallelApply.cpp | 80 +++++++++++++++++++++++---- 3 files changed, 142 insertions(+), 33 deletions(-) diff --git a/eo/src/mpi/assignmentAlgorithm.h b/eo/src/mpi/assignmentAlgorithm.h index 06d3ec49..58fc09c0 100644 --- a/eo/src/mpi/assignmentAlgorithm.h +++ b/eo/src/mpi/assignmentAlgorithm.h @@ -2,7 +2,7 @@ # define __ASSIGNMENT_ALGORITHM_H__ # include - +# include "MpiNode.h" struct AssignmentAlgorithm { virtual int get( ) = 0; @@ -14,6 +14,25 @@ struct AssignmentAlgorithm struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm { public: + + DynamicAssignmentAlgorithm( ) + { + for(int i = 1; i < MpiNode::comm().size(); ++i) + { + availableWrk.push_back( i ); + } + } + + DynamicAssignmentAlgorithm( int unique ) + { + availableWrk.push_back( unique ); + } + + DynamicAssignmentAlgorithm( const std::vector & workers ) + { + availableWrk = workers; + } + DynamicAssignmentAlgorithm( int first, int last ) { for( int i = first; i <= last; ++i) @@ -55,11 +74,43 @@ struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm struct StaticAssignmentAlgorithm : public AssignmentAlgorithm { public: + StaticAssignmentAlgorithm( std::vector& workers, int runs ) + { + init( workers, runs ); + } + StaticAssignmentAlgorithm( int first, int last, int runs ) { - unsigned int nbWorkers = last - first + 1; + std::vector workers; + for(int i = first; i <= last; ++i) + { + workers.push_back( i ); + } + init( workers, runs ); + } + + StaticAssignmentAlgorithm( int runs ) + { + std::vector workers; + for(int i = 1; i < MpiNode::comm().size(); ++i) + { + workers.push_back( i ); + } + init( workers, runs ); + } + + StaticAssignmentAlgorithm( int unique, int runs ) + { + std::vector workers; + workers.push_back( unique ); + init( workers, runs ); + } + +private: + void init( std::vector & workers, int runs ) + { + unsigned int nbWorkers = workers.size(); freeWorkers = nbWorkers; - offset = first; attributions.reserve( nbWorkers ); busy.resize( nbWorkers, false ); @@ -71,8 +122,11 @@ struct StaticAssignmentAlgorithm : public AssignmentAlgorithm // r requests to workers, in ascending order unsigned int diff = runs - (runs / nbWorkers) * nbWorkers; for (unsigned int i = 0; i < diff; ++attributions[i++]); + + realRank = workers; } +public: int get( ) { int assignee = -1; @@ -82,7 +136,7 @@ struct StaticAssignmentAlgorithm : public AssignmentAlgorithm { busy[i] = true; --freeWorkers; - assignee = realRank( i ); + assignee = realRank[ i ]; break; } } @@ -101,40 +155,35 @@ struct StaticAssignmentAlgorithm : public AssignmentAlgorithm { if( !busy[i] ) { - eo::log << "Idle : " << realRank(i) << + eo::log << "Idle : " << realRank[i] << " / attributions : " << attributions[i] << std::endl; - ret.push_back( realRank(i) ); + ret.push_back( realRank[i] ); } } - afterIdle = true; return ret; } void confirm( int rank ) { - int i = attributionsIndex( rank ); + int i = -1; + for( int j = 0; j < realRank.size(); ++j ) + { + if( realRank[j] == rank ) + { + i = j; + break; + } + } + --attributions[ i ]; busy[ i ] = false; ++freeWorkers; } private: - int attributionsIndex( int rank ) - { - return rank - offset; - } - - int realRank( int index ) - { - return index + offset; - } - std::vector attributions; + std::vector realRank; std::vector busy; - - bool afterIdle; - int runs; - int offset; unsigned int freeWorkers; }; diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index a45dec42..a374def5 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -61,7 +61,7 @@ int main(int argc, char** argv) case 1: { // only one node is assigned to subjob mastering - DynamicAssignmentAlgorithm algo( 1, 1 ); + DynamicAssignmentAlgorithm algo( 1 ); ParallelApply< vector > job( transmitInstance, metaV, algo, 0 ); job.run(); if( job.isMaster() ) diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 278ffd06..3fd77dc1 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -18,8 +18,10 @@ struct Test { AssignmentAlgorithm * assign; string description; + int requiredNodesNumber; // nb : chosen nodes ranks must be sequential }; +// These tests require at least 3 processes to be launched. int main(int argc, char** argv) { // eo::log << eo::setlevel( eo::debug ); @@ -32,24 +34,71 @@ int main(int argc, char** argv) v.push_back(7); v.push_back(42); + int offset = 0; + vector originalV = v; + plusOne plusOneInstance; vector< Test > tests; + + const int ALL = MpiNode::comm().size(); - Test tStatic; - tStatic.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size() ); - tStatic.description = "Correct static assignment."; - tests.push_back( tStatic ); + Test tIntervalStatic; + tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size() ); + tIntervalStatic.description = "Correct static assignment with interval."; + tIntervalStatic.requiredNodesNumber = ALL; + tests.push_back( tIntervalStatic ); + + Test tWorldStatic; + tWorldStatic.assign = new StaticAssignmentAlgorithm( v.size() ); + tWorldStatic.description = "Correct static assignment with whole world as workers."; + tWorldStatic.requiredNodesNumber = ALL; + tests.push_back( tWorldStatic ); Test tStaticOverload; - tStaticOverload.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size()+100 ); + tStaticOverload.assign = new StaticAssignmentAlgorithm( v.size()+100 ); tStaticOverload.description = "Static assignment with too many runs."; + tStaticOverload.requiredNodesNumber = ALL; tests.push_back( tStaticOverload ); - Test tDynamic; - tDynamic.assign = new DynamicAssignmentAlgorithm( 1, MpiNode::comm().size()-1 ); - tDynamic.description = "Dynamic assignment."; - tests.push_back( tDynamic ); + Test tUniqueStatic; + tUniqueStatic.assign = new StaticAssignmentAlgorithm( 1, v.size() ); + tUniqueStatic.description = "Correct static assignment with unique worker."; + tUniqueStatic.requiredNodesNumber = 2; + tests.push_back( tUniqueStatic ); + + Test tVectorStatic; + vector workers; + workers.push_back( 1 ); + workers.push_back( 2 ); + tVectorStatic.assign = new StaticAssignmentAlgorithm( workers, v.size() ); + tVectorStatic.description = "Correct static assignment with precise workers specified."; + tVectorStatic.requiredNodesNumber = 3; + tests.push_back( tVectorStatic ); + + Test tIntervalDynamic; + tIntervalDynamic.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size() ); + tIntervalDynamic.description = "Correct static assignment with interval."; + tIntervalDynamic.requiredNodesNumber = ALL; + tests.push_back( tIntervalDynamic ); + + Test tUniqueDynamic; + tUniqueDynamic.assign = new StaticAssignmentAlgorithm( 1, v.size() ); + tUniqueDynamic.description = "Correct static assignment with unique worker."; + tUniqueDynamic.requiredNodesNumber = 2; + tests.push_back( tUniqueDynamic ); + + Test tVectorDynamic; + tVectorDynamic.assign = new StaticAssignmentAlgorithm( workers, v.size() ); + tVectorDynamic.description = "Correct static assignment with precise workers specified."; + tVectorDynamic.requiredNodesNumber = tVectorStatic.requiredNodesNumber; + tests.push_back( tVectorDynamic ); + + Test tWorldDynamic; + tWorldDynamic.assign = new StaticAssignmentAlgorithm( v.size() ); + tWorldDynamic.description = "Correct static assignment with whole world as workers."; + tWorldDynamic.requiredNodesNumber = ALL; + tests.push_back( tWorldDynamic ); for( unsigned int i = 0; i < tests.size(); ++i ) { @@ -60,17 +109,28 @@ int main(int argc, char** argv) cout << "Test : " << tests[i].description << endl; } - job.run(); + if( MpiNode::comm().rank() < tests[i].requiredNodesNumber ) + { + job.run(); + } if( job.isMaster() ) { + ++offset; for(int i = 0; i < v.size(); ++i) { cout << v[i] << ' '; + if( originalV[i] + offset != v[i] ) + { + cout << " <-- ERROR at this point." << endl; + exit( EXIT_FAILURE ); + } } cout << endl; } + MpiNode::comm().barrier(); + delete tests[i].assign; } return 0; From ac13550faa7511e874c57acd83963620b130cef6 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 17:40:00 +0200 Subject: [PATCH 24/52] REST_OF_THE_WORLD constant in assignmentAlgorithm. --- eo/src/mpi/assignmentAlgorithm.h | 17 +++++++++++++++++ eo/test/mpi/multipleRoles.cpp | 2 +- eo/test/mpi/parallelApply.cpp | 12 ++++++------ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/eo/src/mpi/assignmentAlgorithm.h b/eo/src/mpi/assignmentAlgorithm.h index 58fc09c0..a27e8289 100644 --- a/eo/src/mpi/assignmentAlgorithm.h +++ b/eo/src/mpi/assignmentAlgorithm.h @@ -3,6 +3,12 @@ # include # include "MpiNode.h" + +namespace eo +{ + const int REST_OF_THE_WORLD = -1; +} + struct AssignmentAlgorithm { virtual int get( ) = 0; @@ -35,6 +41,11 @@ struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm DynamicAssignmentAlgorithm( int first, int last ) { + if( last == eo::REST_OF_THE_WORLD ) + { + last = MpiNode::comm().size() - 1; + } + for( int i = first; i <= last; ++i) { availableWrk.push_back( i ); @@ -82,6 +93,12 @@ struct StaticAssignmentAlgorithm : public AssignmentAlgorithm StaticAssignmentAlgorithm( int first, int last, int runs ) { std::vector workers; + + if( last == eo::REST_OF_THE_WORLD ) + { + last = MpiNode::comm().size() - 1; + } + for(int i = first; i <= last; ++i) { workers.push_back( i ); diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index a374def5..6fa930d1 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -24,7 +24,7 @@ struct plusOne : public eoUF< int&, void > void subtask( vector& v ) { - DynamicAssignmentAlgorithm algo( 2, MpiNode::comm().size()-1 ); + DynamicAssignmentAlgorithm algo( 2, eo::REST_OF_THE_WORLD ); plusOne plusOneInstance; ParallelApply job( plusOneInstance, v, algo, 1 ); job.run(); diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 3fd77dc1..5a6b64f2 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -44,7 +44,7 @@ int main(int argc, char** argv) const int ALL = MpiNode::comm().size(); Test tIntervalStatic; - tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size() ); + tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD, v.size() ); tIntervalStatic.description = "Correct static assignment with interval."; tIntervalStatic.requiredNodesNumber = ALL; tests.push_back( tIntervalStatic ); @@ -77,26 +77,26 @@ int main(int argc, char** argv) tests.push_back( tVectorStatic ); Test tIntervalDynamic; - tIntervalDynamic.assign = new StaticAssignmentAlgorithm( 1, MpiNode::comm().size()-1, v.size() ); - tIntervalDynamic.description = "Correct static assignment with interval."; + tIntervalDynamic.assign = new StaticAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD, v.size() ); + tIntervalDynamic.description = "Dynamic assignment with interval."; tIntervalDynamic.requiredNodesNumber = ALL; tests.push_back( tIntervalDynamic ); Test tUniqueDynamic; tUniqueDynamic.assign = new StaticAssignmentAlgorithm( 1, v.size() ); - tUniqueDynamic.description = "Correct static assignment with unique worker."; + tUniqueDynamic.description = "Dynamic assignment with unique worker."; tUniqueDynamic.requiredNodesNumber = 2; tests.push_back( tUniqueDynamic ); Test tVectorDynamic; tVectorDynamic.assign = new StaticAssignmentAlgorithm( workers, v.size() ); - tVectorDynamic.description = "Correct static assignment with precise workers specified."; + tVectorDynamic.description = "Dynamic assignment with precise workers specified."; tVectorDynamic.requiredNodesNumber = tVectorStatic.requiredNodesNumber; tests.push_back( tVectorDynamic ); Test tWorldDynamic; tWorldDynamic.assign = new StaticAssignmentAlgorithm( v.size() ); - tWorldDynamic.description = "Correct static assignment with whole world as workers."; + tWorldDynamic.description = "Dynamic assignment with whole world as workers."; tWorldDynamic.requiredNodesNumber = ALL; tests.push_back( tWorldDynamic ); From 5bf03dec2b090abb25fbeb78faad469570e5c2f3 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Jun 2012 17:56:08 +0200 Subject: [PATCH 25/52] Multiple roles demo has now 2 sub masters. Needs to be launched with at least 7 nodes. --- eo/test/mpi/multipleRoles.cpp | 44 +++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index 6fa930d1..d855c998 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -13,34 +13,42 @@ using namespace std; // 1 : worker of general job, master of subjob // 2 and more : workers of subjob -struct plusOne : public eoUF< int&, void > +struct SubWork: public eoUF< int&, void > { void operator() ( int & x ) { - cout << "Subjob is being applied." << endl; + cout << "Subwork phase." << endl; ++x; } }; -void subtask( vector& v ) +void subtask( vector& v, int rank ) { - DynamicAssignmentAlgorithm algo( 2, eo::REST_OF_THE_WORLD ); - plusOne plusOneInstance; - ParallelApply job( plusOneInstance, v, algo, 1 ); + vector workers; + workers.push_back( rank + 2 ); + workers.push_back( rank + 4 ); + DynamicAssignmentAlgorithm algo( workers ); + SubWork sw; + ParallelApply job( sw, v, algo, rank ); job.run(); } -struct transmit : public eoUF< vector&, void > +struct Work: public eoUF< vector&, void > { void operator() ( vector& v ) { - cout << "Into the master subjob..." << endl; - subtask( v ); + cout << "Work phase..." << endl; + subtask( v, MpiNode::comm().rank() ); + for( int i = 0; i < v.size(); ++i ) + { + v[i] *= 2; + } } }; int main(int argc, char** argv) { + // eo::log << eo::setlevel( eo::debug ); MpiNode::init( argc, argv ); vector v; @@ -50,19 +58,19 @@ int main(int argc, char** argv) v.push_back(7); v.push_back(42); - transmit transmitInstance; - vector< vector > metaV; metaV.push_back( v ); + metaV.push_back( v ); switch( MpiNode::comm().rank() ) { case 0: case 1: + case 2: { - // only one node is assigned to subjob mastering - DynamicAssignmentAlgorithm algo( 1 ); - ParallelApply< vector > job( transmitInstance, metaV, algo, 0 ); + Work w; + DynamicAssignmentAlgorithm algo( 1, 2 ); + ParallelApply< vector > job( w, metaV, algo, 0 ); job.run(); if( job.isMaster() ) { @@ -80,7 +88,13 @@ int main(int argc, char** argv) default: { // all the other nodes are sub workers - subtask( v ); + int rank = MpiNode::comm().rank(); + if ( rank == 3 or rank == 5 ) + { + subtask( v, 1 ); + } else { + subtask( v, 2 ); + } } break; } From 66c7b1f12d49cf123b1c60cbc0f977c387a44d7a Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 11:44:14 +0200 Subject: [PATCH 26/52] Using real dynamic assignments for tests. --- eo/test/mpi/parallelApply.cpp | 94 ++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 5a6b64f2..d9577121 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -24,7 +24,8 @@ struct Test // These tests require at least 3 processes to be launched. int main(int argc, char** argv) { - // eo::log << eo::setlevel( eo::debug ); + eo::log << eo::setlevel( eo::debug ); + bool launchOnlyOne = true; MpiNode::init( argc, argv ); vector v; @@ -49,60 +50,63 @@ int main(int argc, char** argv) tIntervalStatic.requiredNodesNumber = ALL; tests.push_back( tIntervalStatic ); - Test tWorldStatic; - tWorldStatic.assign = new StaticAssignmentAlgorithm( v.size() ); - tWorldStatic.description = "Correct static assignment with whole world as workers."; - tWorldStatic.requiredNodesNumber = ALL; - tests.push_back( tWorldStatic ); + if( !launchOnlyOne ) + { + Test tWorldStatic; + tWorldStatic.assign = new StaticAssignmentAlgorithm( v.size() ); + tWorldStatic.description = "Correct static assignment with whole world as workers."; + tWorldStatic.requiredNodesNumber = ALL; + tests.push_back( tWorldStatic ); - Test tStaticOverload; - tStaticOverload.assign = new StaticAssignmentAlgorithm( v.size()+100 ); - tStaticOverload.description = "Static assignment with too many runs."; - tStaticOverload.requiredNodesNumber = ALL; - tests.push_back( tStaticOverload ); + Test tStaticOverload; + tStaticOverload.assign = new StaticAssignmentAlgorithm( v.size()+100 ); + tStaticOverload.description = "Static assignment with too many runs."; + tStaticOverload.requiredNodesNumber = ALL; + tests.push_back( tStaticOverload ); - Test tUniqueStatic; - tUniqueStatic.assign = new StaticAssignmentAlgorithm( 1, v.size() ); - tUniqueStatic.description = "Correct static assignment with unique worker."; - tUniqueStatic.requiredNodesNumber = 2; - tests.push_back( tUniqueStatic ); + Test tUniqueStatic; + tUniqueStatic.assign = new StaticAssignmentAlgorithm( 1, v.size() ); + tUniqueStatic.description = "Correct static assignment with unique worker."; + tUniqueStatic.requiredNodesNumber = 2; + tests.push_back( tUniqueStatic ); - Test tVectorStatic; - vector workers; - workers.push_back( 1 ); - workers.push_back( 2 ); - tVectorStatic.assign = new StaticAssignmentAlgorithm( workers, v.size() ); - tVectorStatic.description = "Correct static assignment with precise workers specified."; - tVectorStatic.requiredNodesNumber = 3; - tests.push_back( tVectorStatic ); + Test tVectorStatic; + vector workers; + workers.push_back( 1 ); + workers.push_back( 2 ); + tVectorStatic.assign = new StaticAssignmentAlgorithm( workers, v.size() ); + tVectorStatic.description = "Correct static assignment with precise workers specified."; + tVectorStatic.requiredNodesNumber = 3; + tests.push_back( tVectorStatic ); - Test tIntervalDynamic; - tIntervalDynamic.assign = new StaticAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD, v.size() ); - tIntervalDynamic.description = "Dynamic assignment with interval."; - tIntervalDynamic.requiredNodesNumber = ALL; - tests.push_back( tIntervalDynamic ); + Test tIntervalDynamic; + tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD ); + tIntervalDynamic.description = "Dynamic assignment with interval."; + tIntervalDynamic.requiredNodesNumber = ALL; + tests.push_back( tIntervalDynamic ); - Test tUniqueDynamic; - tUniqueDynamic.assign = new StaticAssignmentAlgorithm( 1, v.size() ); - tUniqueDynamic.description = "Dynamic assignment with unique worker."; - tUniqueDynamic.requiredNodesNumber = 2; - tests.push_back( tUniqueDynamic ); + Test tUniqueDynamic; + tUniqueDynamic.assign = new DynamicAssignmentAlgorithm( 1 ); + tUniqueDynamic.description = "Dynamic assignment with unique worker."; + tUniqueDynamic.requiredNodesNumber = 2; + tests.push_back( tUniqueDynamic ); - Test tVectorDynamic; - tVectorDynamic.assign = new StaticAssignmentAlgorithm( workers, v.size() ); - tVectorDynamic.description = "Dynamic assignment with precise workers specified."; - tVectorDynamic.requiredNodesNumber = tVectorStatic.requiredNodesNumber; - tests.push_back( tVectorDynamic ); + Test tVectorDynamic; + tVectorDynamic.assign = new DynamicAssignmentAlgorithm( workers ); + tVectorDynamic.description = "Dynamic assignment with precise workers specified."; + tVectorDynamic.requiredNodesNumber = tVectorStatic.requiredNodesNumber; + tests.push_back( tVectorDynamic ); - Test tWorldDynamic; - tWorldDynamic.assign = new StaticAssignmentAlgorithm( v.size() ); - tWorldDynamic.description = "Dynamic assignment with whole world as workers."; - tWorldDynamic.requiredNodesNumber = ALL; - tests.push_back( tWorldDynamic ); + Test tWorldDynamic; + tWorldDynamic.assign = new DynamicAssignmentAlgorithm; + tWorldDynamic.description = "Dynamic assignment with whole world as workers."; + tWorldDynamic.requiredNodesNumber = ALL; + tests.push_back( tWorldDynamic ); + } for( unsigned int i = 0; i < tests.size(); ++i ) { - ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0 ); + ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, 3 ); if( job.isMaster() ) { From f4d8b43f7d15e923acdc59eb7e64590757e2a421 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 13:41:48 +0200 Subject: [PATCH 27/52] ParallelApply can now handle many data at a time. --- eo/src/mpi/eoParallelApply.h | 64 ++++++++++++++++++++++++++++------- eo/test/mpi/multipleRoles.cpp | 4 +-- eo/test/mpi/parallelApply.cpp | 5 +-- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 0c4f1e6e..e401fda6 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -6,39 +6,76 @@ # include # include + template< typename EOT > class ParallelApply : public MpiJob { + private: + struct ParallelApplyAssignment + { + int index; + int size; + }; public: - ParallelApply( eoUF & _proc, std::vector& _pop, AssignmentAlgorithm & algo, int _masterRank ) : + ParallelApply( + eoUF & _proc, + std::vector& _pop, + AssignmentAlgorithm & algo, + int _masterRank, + int _packetSize = 1 + ) : MpiJob( algo, _masterRank ), func( _proc ), index( 0 ), size( _pop.size() ), - data( _pop ) + data( _pop ), + packetSize( _packetSize ) { - // empty + tempArray = new EOT[ packetSize ]; + } + + ~ParallelApply() + { + delete [] tempArray; } virtual void sendTask( int wrkRank ) { - assignedTasks[ wrkRank ] = index; - comm.send( wrkRank, 1, data[ index ] ); - ++index; + int futureIndex; + + if( index + packetSize < size ) + { + futureIndex = index + packetSize; + } else { + futureIndex = size; + } + + int sentSize = futureIndex - index ; + comm.send( wrkRank, 1, sentSize ); + + assignedTasks[ wrkRank ].index = index; + assignedTasks[ wrkRank ].size = sentSize; + + comm.send( wrkRank, 1, &data[ index ] , sentSize ); + index = futureIndex; } virtual void handleResponse( int wrkRank ) { - comm.recv( wrkRank, 1, data[ assignedTasks[ wrkRank ] ] ); + comm.recv( wrkRank, 1, &data[ assignedTasks[wrkRank].index ], assignedTasks[wrkRank].size ); } virtual void processTask( ) { - EOT ind; - comm.recv( masterRank, 1, ind ); - func( ind ); - comm.send( masterRank, 1, ind ); + int recvSize; + comm.recv( masterRank, 1, recvSize ); + comm.recv( masterRank, 1, tempArray, recvSize ); + for( int i = 0; i < recvSize ; ++i ) + { + func( tempArray[ i ] ); + } + comm.send( masterRank, 1, tempArray, recvSize ); } bool isFinished() @@ -51,7 +88,10 @@ class ParallelApply : public MpiJob eoUF& func; int index; int size; - std::map< int /* worker rank */, int /* index in vector */> assignedTasks; + std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks; + + int packetSize; + EOT* tempArray; }; # endif // __EO_PARALLEL_APPLY_H__ diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index d855c998..ab802073 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -10,8 +10,8 @@ using namespace std; // Role map // 0 : general master -// 1 : worker of general job, master of subjob -// 2 and more : workers of subjob +// 1, 2 : worker of general job, master of subjob +// 3 to 7 : workers of subjob struct SubWork: public eoUF< int&, void > { diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index d9577121..69b01e48 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -24,8 +24,9 @@ struct Test // These tests require at least 3 processes to be launched. int main(int argc, char** argv) { - eo::log << eo::setlevel( eo::debug ); - bool launchOnlyOne = true; + // eo::log << eo::setlevel( eo::debug ); + bool launchOnlyOne = false; // Set this to true if you wanna launch only the first test. + MpiNode::init( argc, argv ); vector v; From 2cc112c33ba46c6f2976337532087143ece5c3a7 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 13:50:22 +0200 Subject: [PATCH 28/52] Throwing exception when packet size is negative. --- eo/src/mpi/eoParallelApply.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index e401fda6..064396da 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -6,7 +6,6 @@ # include # include - template< typename EOT > class ParallelApply : public MpiJob { @@ -32,6 +31,10 @@ class ParallelApply : public MpiJob data( _pop ), packetSize( _packetSize ) { + if ( _packetSize <= 0 ) + { + throw std::runtime_error("Packet size should not be negative."); + } tempArray = new EOT[ packetSize ]; } From d9c7ef0300903898b09c1b8f873dc6bba1c532dc Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 13:51:49 +0200 Subject: [PATCH 29/52] Parallel apply test is done on a big table. --- eo/test/mpi/parallelApply.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 69b01e48..143e7350 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -30,12 +30,11 @@ int main(int argc, char** argv) MpiNode::init( argc, argv ); vector v; - v.push_back(1); - v.push_back(3); - v.push_back(3); - v.push_back(7); - v.push_back(42); - + for( int i = 0; i < 1000; ++i ) + { + v.push_back( rand() ); + } + int offset = 0; vector originalV = v; @@ -140,3 +139,4 @@ int main(int argc, char** argv) } return 0; } + From b9a2246f82c00f91d8af5d2ff0d0f80c09b1eca6 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 13:53:34 +0200 Subject: [PATCH 30/52] Generating time based seed for random generator --- eo/test/mpi/parallelApply.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 143e7350..46130b80 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -29,6 +29,7 @@ int main(int argc, char** argv) MpiNode::init( argc, argv ); + srand( time(0) ); vector v; for( int i = 0; i < 1000; ++i ) { From b291e56e03c60dd04d16808fbbf513cd4c9916af Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 14:11:44 +0200 Subject: [PATCH 31/52] Putting everything in namespace eo::mpi --- eo/src/mpi/CMakeLists.txt | 2 +- eo/src/mpi/MpiNode.h | 25 ---- eo/src/mpi/assignmentAlgorithm.h | 207 -------------------------- eo/src/mpi/eoMpi.cpp | 11 ++ eo/src/mpi/eoMpi.h | 132 ++++++++++++++++ eo/src/mpi/eoMpiAssignmentAlgorithm.h | 207 ++++++++++++++++++++++++++ eo/src/mpi/eoMpiNode.h | 31 ++++ eo/src/mpi/eoParallelApply.h | 183 ++++++++++++----------- eo/src/mpi/eompi.cpp | 5 - eo/src/mpi/eompi.h | 127 ---------------- eo/test/mpi/multipleRoles.cpp | 12 +- eo/test/mpi/parallelApply.cpp | 16 +- 12 files changed, 492 insertions(+), 466 deletions(-) delete mode 100644 eo/src/mpi/MpiNode.h delete mode 100644 eo/src/mpi/assignmentAlgorithm.h create mode 100644 eo/src/mpi/eoMpi.cpp create mode 100644 eo/src/mpi/eoMpi.h create mode 100644 eo/src/mpi/eoMpiAssignmentAlgorithm.h create mode 100644 eo/src/mpi/eoMpiNode.h delete mode 100644 eo/src/mpi/eompi.cpp delete mode 100644 eo/src/mpi/eompi.h diff --git a/eo/src/mpi/CMakeLists.txt b/eo/src/mpi/CMakeLists.txt index c770acd1..0e22e47e 100644 --- a/eo/src/mpi/CMakeLists.txt +++ b/eo/src/mpi/CMakeLists.txt @@ -13,7 +13,7 @@ SET(EOMPI_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib) SET(LIBRARY_OUTPUT_PATH ${EOMPI_LIB_OUTPUT_PATH}) SET(EOMPI_SOURCES - eompi.cpp + eoMpi.cpp ) ADD_LIBRARY(eompi STATIC ${EOMPI_SOURCES}) diff --git a/eo/src/mpi/MpiNode.h b/eo/src/mpi/MpiNode.h deleted file mode 100644 index 10804ce0..00000000 --- a/eo/src/mpi/MpiNode.h +++ /dev/null @@ -1,25 +0,0 @@ -# ifndef __MPI_NODE_H__ -# define __MPI_NODE_H__ - -# include -namespace mpi = boost::mpi; - -class MpiNode -{ - public: - - static void init( int argc, char** argv ) - { - static mpi::environment env( argc, argv ); - } - - static mpi::communicator& comm() - { - return _comm; - } - - protected: - static mpi::communicator _comm; -}; - -# endif // __MPI_NODE_H__ diff --git a/eo/src/mpi/assignmentAlgorithm.h b/eo/src/mpi/assignmentAlgorithm.h deleted file mode 100644 index a27e8289..00000000 --- a/eo/src/mpi/assignmentAlgorithm.h +++ /dev/null @@ -1,207 +0,0 @@ -# ifndef __ASSIGNMENT_ALGORITHM_H__ -# define __ASSIGNMENT_ALGORITHM_H__ - -# include -# include "MpiNode.h" - -namespace eo -{ - const int REST_OF_THE_WORLD = -1; -} - -struct AssignmentAlgorithm -{ - virtual int get( ) = 0; - virtual int availableWorkers( ) = 0; - virtual void confirm( int wrkRank ) = 0; - virtual std::vector idles( ) = 0; -}; - -struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm -{ - public: - - DynamicAssignmentAlgorithm( ) - { - for(int i = 1; i < MpiNode::comm().size(); ++i) - { - availableWrk.push_back( i ); - } - } - - DynamicAssignmentAlgorithm( int unique ) - { - availableWrk.push_back( unique ); - } - - DynamicAssignmentAlgorithm( const std::vector & workers ) - { - availableWrk = workers; - } - - DynamicAssignmentAlgorithm( int first, int last ) - { - if( last == eo::REST_OF_THE_WORLD ) - { - last = MpiNode::comm().size() - 1; - } - - for( int i = first; i <= last; ++i) - { - availableWrk.push_back( i ); - } - } - - virtual int get( ) - { - int assignee = -1; - if (! availableWrk.empty() ) - { - assignee = availableWrk.back(); - availableWrk.pop_back(); - } - return assignee; - } - - int availableWorkers() - { - return availableWrk.size(); - } - - void confirm( int rank ) - { - availableWrk.push_back( rank ); - } - - std::vector idles( ) - { - return availableWrk; - } - - protected: - std::vector< int > availableWrk; -}; - -struct StaticAssignmentAlgorithm : public AssignmentAlgorithm -{ - public: - StaticAssignmentAlgorithm( std::vector& workers, int runs ) - { - init( workers, runs ); - } - - StaticAssignmentAlgorithm( int first, int last, int runs ) - { - std::vector workers; - - if( last == eo::REST_OF_THE_WORLD ) - { - last = MpiNode::comm().size() - 1; - } - - for(int i = first; i <= last; ++i) - { - workers.push_back( i ); - } - init( workers, runs ); - } - - StaticAssignmentAlgorithm( int runs ) - { - std::vector workers; - for(int i = 1; i < MpiNode::comm().size(); ++i) - { - workers.push_back( i ); - } - init( workers, runs ); - } - - StaticAssignmentAlgorithm( int unique, int runs ) - { - std::vector workers; - workers.push_back( unique ); - init( workers, runs ); - } - -private: - void init( std::vector & workers, int runs ) - { - unsigned int nbWorkers = workers.size(); - freeWorkers = nbWorkers; - attributions.reserve( nbWorkers ); - busy.resize( nbWorkers, false ); - - // Let be the euclidean division of runs by nbWorkers : - // runs == q * nbWorkers + r, 0 <= r < nbWorkers - // This one liner affects q requests to each worker - for (unsigned int i = 0; i < nbWorkers; attributions[i++] = runs / nbWorkers) ; - // The first line computes r and the one liner affects the remaining - // r requests to workers, in ascending order - unsigned int diff = runs - (runs / nbWorkers) * nbWorkers; - for (unsigned int i = 0; i < diff; ++attributions[i++]); - - realRank = workers; - } - -public: - int get( ) - { - int assignee = -1; - for( unsigned i = 0; i < busy.size(); ++i ) - { - if( !busy[i] && attributions[i] > 0 ) - { - busy[i] = true; - --freeWorkers; - assignee = realRank[ i ]; - break; - } - } - return assignee; - } - - int availableWorkers( ) - { - return freeWorkers; - } - - std::vector idles() - { - std::vector ret; - for(unsigned int i = 0; i < busy.size(); ++i) - { - if( !busy[i] ) - { - eo::log << "Idle : " << realRank[i] << - " / attributions : " << attributions[i] << std::endl; - ret.push_back( realRank[i] ); - } - } - return ret; - } - - void confirm( int rank ) - { - int i = -1; - for( int j = 0; j < realRank.size(); ++j ) - { - if( realRank[j] == rank ) - { - i = j; - break; - } - } - - --attributions[ i ]; - busy[ i ] = false; - ++freeWorkers; - } - - private: - std::vector attributions; - std::vector realRank; - std::vector busy; - unsigned int freeWorkers; -}; - -# endif // __ASSIGNMENT_ALGORITHM_H__ diff --git a/eo/src/mpi/eoMpi.cpp b/eo/src/mpi/eoMpi.cpp new file mode 100644 index 00000000..f6e3b3c5 --- /dev/null +++ b/eo/src/mpi/eoMpi.cpp @@ -0,0 +1,11 @@ +# include "eoMpi.h" + +// MpiNode* MpiNodeStore::singleton; +namespace eo +{ + namespace mpi + { + bmpi::communicator Node::_comm; + } +} + diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h new file mode 100644 index 00000000..86ad55ab --- /dev/null +++ b/eo/src/mpi/eoMpi.h @@ -0,0 +1,132 @@ +# ifndef __EO_MPI_H__ +# define __EO_MPI_H__ + +# include +# include +# include + +# include "eoMpiNode.h" +# include "eoMpiAssignmentAlgorithm.h" +// TODO TODOB comment! + +namespace eo +{ + namespace mpi + { + namespace Channel + { + const int Commands = 0; + } + + namespace Message + { + const int Continue = 0; + const int Finish = 1; + } + + class Job + { + public: + + Job( AssignmentAlgorithm& _algo, int _masterRank ) : + assignmentAlgo( _algo ), + comm( Node::comm() ), + masterRank( _masterRank ) + { + _isMaster = Node::comm().rank() == _masterRank; + } + + // master + virtual bool isFinished() = 0; + virtual void sendTask( int wrkRank ) = 0; + virtual void handleResponse( int wrkRank ) = 0; + // worker + virtual void processTask( ) = 0; + + void master( ) + { + int totalWorkers = assignmentAlgo.availableWorkers(); + eo::log << eo::debug; + eo::log << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl; + + while( ! isFinished() ) + { + int assignee = assignmentAlgo.get( ); + while( assignee <= 0 ) + { + eo::log << "[M" << comm.rank() << "] Waitin' for node..." << std::endl; + bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); + int wrkRank = status.source(); + eo::log << "[M" << comm.rank() << "] Node " << wrkRank << " just terminated." << std::endl; + handleResponse( wrkRank ); + assignmentAlgo.confirm( wrkRank ); + assignee = assignmentAlgo.get( ); + } + eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; + comm.send( assignee, Channel::Commands, Message::Continue ); + sendTask( assignee ); + } + + eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; + // frees all the idle workers + std::vector idles = assignmentAlgo.idles(); + for(unsigned int i = 0; i < idles.size(); ++i) + { + comm.send( idles[i], Channel::Commands, Message::Finish ); + } + + eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl; + // wait for all responses + while( assignmentAlgo.availableWorkers() != totalWorkers ) + { + bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); + int wrkRank = status.source(); + handleResponse( wrkRank ); + comm.send( wrkRank, Channel::Commands, Message::Finish ); + assignmentAlgo.confirm( wrkRank ); + } + + eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; + } + + void worker( ) + { + int order; + eo::log << eo::debug; + while( true ) + { + eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; + comm.recv( masterRank, Channel::Commands, order ); + if ( order == Message::Finish ) + { + eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl; + return; + } else + { + eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl; + processTask( ); + } + } + } + + void run( ) + { + ( _isMaster ) ? master( ) : worker( ); + } + + bool isMaster( ) + { + return _isMaster; + } + + protected: + AssignmentAlgorithm& assignmentAlgo; + bmpi::communicator& comm; + int masterRank; + bool _isMaster; + }; + } +} + +# endif // __EO_MPI_H__ + diff --git a/eo/src/mpi/eoMpiAssignmentAlgorithm.h b/eo/src/mpi/eoMpiAssignmentAlgorithm.h new file mode 100644 index 00000000..aa162d95 --- /dev/null +++ b/eo/src/mpi/eoMpiAssignmentAlgorithm.h @@ -0,0 +1,207 @@ +# ifndef __MPI_ASSIGNMENT_ALGORITHM_H__ +# define __MPI_ASSIGNMENT_ALGORITHM_H__ + +# include +# include "eoMpiNode.h" + +namespace eo +{ + namespace mpi + { + const int REST_OF_THE_WORLD = -1; + + struct AssignmentAlgorithm + { + virtual int get( ) = 0; + virtual int availableWorkers( ) = 0; + virtual void confirm( int wrkRank ) = 0; + virtual std::vector idles( ) = 0; + }; + + struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm + { + public: + + DynamicAssignmentAlgorithm( ) + { + for(int i = 1; i < Node::comm().size(); ++i) + { + availableWrk.push_back( i ); + } + } + + DynamicAssignmentAlgorithm( int unique ) + { + availableWrk.push_back( unique ); + } + + DynamicAssignmentAlgorithm( const std::vector & workers ) + { + availableWrk = workers; + } + + DynamicAssignmentAlgorithm( int first, int last ) + { + if( last == REST_OF_THE_WORLD ) + { + last = Node::comm().size() - 1; + } + + for( int i = first; i <= last; ++i) + { + availableWrk.push_back( i ); + } + } + + virtual int get( ) + { + int assignee = -1; + if (! availableWrk.empty() ) + { + assignee = availableWrk.back(); + availableWrk.pop_back(); + } + return assignee; + } + + int availableWorkers() + { + return availableWrk.size(); + } + + void confirm( int rank ) + { + availableWrk.push_back( rank ); + } + + std::vector idles( ) + { + return availableWrk; + } + + protected: + std::vector< int > availableWrk; + }; + + struct StaticAssignmentAlgorithm : public AssignmentAlgorithm + { + public: + StaticAssignmentAlgorithm( std::vector& workers, int runs ) + { + init( workers, runs ); + } + + StaticAssignmentAlgorithm( int first, int last, int runs ) + { + std::vector workers; + + if( last == REST_OF_THE_WORLD ) + { + last = Node::comm().size() - 1; + } + + for(int i = first; i <= last; ++i) + { + workers.push_back( i ); + } + init( workers, runs ); + } + + StaticAssignmentAlgorithm( int runs ) + { + std::vector workers; + for(int i = 1; i < Node::comm().size(); ++i) + { + workers.push_back( i ); + } + init( workers, runs ); + } + + StaticAssignmentAlgorithm( int unique, int runs ) + { + std::vector workers; + workers.push_back( unique ); + init( workers, runs ); + } + + private: + void init( std::vector & workers, int runs ) + { + unsigned int nbWorkers = workers.size(); + freeWorkers = nbWorkers; + attributions.reserve( nbWorkers ); + busy.resize( nbWorkers, false ); + + // Let be the euclidean division of runs by nbWorkers : + // runs == q * nbWorkers + r, 0 <= r < nbWorkers + // This one liner affects q requests to each worker + for (unsigned int i = 0; i < nbWorkers; attributions[i++] = runs / nbWorkers) ; + // The first line computes r and the one liner affects the remaining + // r requests to workers, in ascending order + unsigned int diff = runs - (runs / nbWorkers) * nbWorkers; + for (unsigned int i = 0; i < diff; ++attributions[i++]); + + realRank = workers; + } + + public: + int get( ) + { + int assignee = -1; + for( unsigned i = 0; i < busy.size(); ++i ) + { + if( !busy[i] && attributions[i] > 0 ) + { + busy[i] = true; + --freeWorkers; + assignee = realRank[ i ]; + break; + } + } + return assignee; + } + + int availableWorkers( ) + { + return freeWorkers; + } + + std::vector idles() + { + std::vector ret; + for(unsigned int i = 0; i < busy.size(); ++i) + { + if( !busy[i] ) + { + ret.push_back( realRank[i] ); + } + } + return ret; + } + + void confirm( int rank ) + { + int i = -1; + for( unsigned int j = 0; j < realRank.size(); ++j ) + { + if( realRank[j] == rank ) + { + i = j; + break; + } + } + + --attributions[ i ]; + busy[ i ] = false; + ++freeWorkers; + } + + private: + std::vector attributions; + std::vector realRank; + std::vector busy; + unsigned int freeWorkers; + }; + } +} +# endif // __MPI_ASSIGNMENT_ALGORITHM_H__ diff --git a/eo/src/mpi/eoMpiNode.h b/eo/src/mpi/eoMpiNode.h new file mode 100644 index 00000000..9f1ea7b5 --- /dev/null +++ b/eo/src/mpi/eoMpiNode.h @@ -0,0 +1,31 @@ +# ifndef __MPI_NODE_H__ +# define __MPI_NODE_H__ + +# include +namespace bmpi = boost::mpi; + +namespace eo +{ + namespace mpi + { + class Node + { + public: + + static void init( int argc, char** argv ) + { + static bmpi::environment env( argc, argv ); + } + + static bmpi::communicator& comm() + { + return _comm; + } + + protected: + static bmpi::communicator _comm; + }; + } +} +# endif // __MPI_NODE_H__ + diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 064396da..1e9d4c1d 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -1,102 +1,107 @@ # ifndef __EO_PARALLEL_APPLY_H__ # define __EO_PARALLEL_APPLY_H__ -# include "eompi.h" +# include "eoMpi.h" # include # include -template< typename EOT > -class ParallelApply : public MpiJob +namespace eo { - private: - struct ParallelApplyAssignment + namespace mpi + { + template< typename EOT > + class ParallelApply : public Job { - int index; - int size; + private: + struct ParallelApplyAssignment + { + int index; + int size; + }; + public: + + ParallelApply( + eoUF & _proc, + std::vector& _pop, + AssignmentAlgorithm & algo, + int _masterRank, + int _packetSize = 1 + ) : + Job( algo, _masterRank ), + func( _proc ), + index( 0 ), + size( _pop.size() ), + data( _pop ), + packetSize( _packetSize ) + { + if ( _packetSize <= 0 ) + { + throw std::runtime_error("Packet size should not be negative."); + } + tempArray = new EOT[ packetSize ]; + } + + ~ParallelApply() + { + delete [] tempArray; + } + + virtual void sendTask( int wrkRank ) + { + int futureIndex; + + if( index + packetSize < size ) + { + futureIndex = index + packetSize; + } else { + futureIndex = size; + } + + int sentSize = futureIndex - index ; + comm.send( wrkRank, 1, sentSize ); + + assignedTasks[ wrkRank ].index = index; + assignedTasks[ wrkRank ].size = sentSize; + + comm.send( wrkRank, 1, &data[ index ] , sentSize ); + index = futureIndex; + } + + virtual void handleResponse( int wrkRank ) + { + comm.recv( wrkRank, 1, &data[ assignedTasks[wrkRank].index ], assignedTasks[wrkRank].size ); + } + + virtual void processTask( ) + { + int recvSize; + comm.recv( masterRank, 1, recvSize ); + comm.recv( masterRank, 1, tempArray, recvSize ); + for( int i = 0; i < recvSize ; ++i ) + { + func( tempArray[ i ] ); + } + comm.send( masterRank, 1, tempArray, recvSize ); + } + + bool isFinished() + { + return index == size; + } + + protected: + std::vector & data; + eoUF& func; + int index; + int size; + std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks; + + int packetSize; + EOT* tempArray; }; - public: - - ParallelApply( - eoUF & _proc, - std::vector& _pop, - AssignmentAlgorithm & algo, - int _masterRank, - int _packetSize = 1 - ) : - MpiJob( algo, _masterRank ), - func( _proc ), - index( 0 ), - size( _pop.size() ), - data( _pop ), - packetSize( _packetSize ) - { - if ( _packetSize <= 0 ) - { - throw std::runtime_error("Packet size should not be negative."); - } - tempArray = new EOT[ packetSize ]; - } - - ~ParallelApply() - { - delete [] tempArray; - } - - virtual void sendTask( int wrkRank ) - { - int futureIndex; - - if( index + packetSize < size ) - { - futureIndex = index + packetSize; - } else { - futureIndex = size; - } - - int sentSize = futureIndex - index ; - comm.send( wrkRank, 1, sentSize ); - - assignedTasks[ wrkRank ].index = index; - assignedTasks[ wrkRank ].size = sentSize; - - comm.send( wrkRank, 1, &data[ index ] , sentSize ); - index = futureIndex; - } - - virtual void handleResponse( int wrkRank ) - { - comm.recv( wrkRank, 1, &data[ assignedTasks[wrkRank].index ], assignedTasks[wrkRank].size ); - } - - virtual void processTask( ) - { - int recvSize; - comm.recv( masterRank, 1, recvSize ); - comm.recv( masterRank, 1, tempArray, recvSize ); - for( int i = 0; i < recvSize ; ++i ) - { - func( tempArray[ i ] ); - } - comm.send( masterRank, 1, tempArray, recvSize ); - } - - bool isFinished() - { - return index == size; - } - - protected: - std::vector & data; - eoUF& func; - int index; - int size; - std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks; - - int packetSize; - EOT* tempArray; -}; - + } +} # endif // __EO_PARALLEL_APPLY_H__ diff --git a/eo/src/mpi/eompi.cpp b/eo/src/mpi/eompi.cpp deleted file mode 100644 index 6429a31c..00000000 --- a/eo/src/mpi/eompi.cpp +++ /dev/null @@ -1,5 +0,0 @@ -# include "eompi.h" - -// MpiNode* MpiNodeStore::singleton; -mpi::communicator MpiNode::_comm; - diff --git a/eo/src/mpi/eompi.h b/eo/src/mpi/eompi.h deleted file mode 100644 index 3b51e7a3..00000000 --- a/eo/src/mpi/eompi.h +++ /dev/null @@ -1,127 +0,0 @@ -# ifndef __EO_MPI_H__ -# define __EO_MPI_H__ - -# include -# include -# include - -# include "MpiNode.h" -# include "assignmentAlgorithm.h" -// TODO TODOB comment! - -namespace EoMpi -{ - namespace Channel - { - const int Commands = 0; - } - - namespace Message - { - const int Continue = 0; - const int Finish = 1; - } -} -class MpiJob -{ - public: - - MpiJob( AssignmentAlgorithm& _algo, int _masterRank ) : - assignmentAlgo( _algo ), - comm( MpiNode::comm() ), - masterRank( _masterRank ) - { - _isMaster = MpiNode::comm().rank() == _masterRank; - } - - // master - virtual bool isFinished() = 0; - virtual void sendTask( int wrkRank ) = 0; - virtual void handleResponse( int wrkRank ) = 0; - // worker - virtual void processTask( ) = 0; - - void master( ) - { - int totalWorkers = assignmentAlgo.availableWorkers(); - eo::log << eo::debug; - eo::log << "[M] Have " << totalWorkers << " workers." << std::endl; - - while( ! isFinished() ) - { - int assignee = assignmentAlgo.get( ); - while( assignee <= 0 ) - { - eo::log << "[M] Waitin' for node..." << std::endl; - mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); - int wrkRank = status.source(); - eo::log << "[M] Node " << wrkRank << " just terminated." << std::endl; - handleResponse( wrkRank ); - assignmentAlgo.confirm( wrkRank ); - assignee = assignmentAlgo.get( ); - } - eo::log << "[M] Assignee : " << assignee << std::endl; - comm.send( assignee, EoMpi::Channel::Commands, EoMpi::Message::Continue ); - sendTask( assignee ); - } - - eo::log << "[M] Frees all the idle." << std::endl; - // frees all the idle workers - std::vector idles = assignmentAlgo.idles(); - for(unsigned int i = 0; i < idles.size(); ++i) - { - comm.send( idles[i], EoMpi::Channel::Commands, EoMpi::Message::Finish ); - } - - eo::log << "[M] Waits for all responses." << std::endl; - // wait for all responses - while( assignmentAlgo.availableWorkers() != totalWorkers ) - { - mpi::status status = comm.probe( mpi::any_source, mpi::any_tag ); - int wrkRank = status.source(); - handleResponse( wrkRank ); - comm.send( wrkRank, EoMpi::Channel::Commands, EoMpi::Message::Finish ); - assignmentAlgo.confirm( wrkRank ); - } - - eo::log << "[M] Leaving master task." << std::endl; - } - - void worker( ) - { - int order; - eo::log << eo::debug; - while( true ) - { - eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; - comm.recv( masterRank, EoMpi::Channel::Commands, order ); - if ( order == EoMpi::Message::Finish ) - { - eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl; - return; - } else - { - eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl; - processTask( ); - } - } - } - - void run( ) - { - ( _isMaster ) ? master( ) : worker( ); - } - - bool isMaster( ) - { - return _isMaster; - } - -protected: - AssignmentAlgorithm& assignmentAlgo; - mpi::communicator& comm; - int masterRank; - bool _isMaster; -}; -# endif // __EO_MPI_H__ - diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index ab802073..5b829c89 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -1,4 +1,4 @@ -# include +# include # include # include @@ -8,6 +8,8 @@ # include using namespace std; +using namespace eo::mpi; + // Role map // 0 : general master // 1, 2 : worker of general job, master of subjob @@ -38,7 +40,7 @@ struct Work: public eoUF< vector&, void > void operator() ( vector& v ) { cout << "Work phase..." << endl; - subtask( v, MpiNode::comm().rank() ); + subtask( v, Node::comm().rank() ); for( int i = 0; i < v.size(); ++i ) { v[i] *= 2; @@ -49,7 +51,7 @@ struct Work: public eoUF< vector&, void > int main(int argc, char** argv) { // eo::log << eo::setlevel( eo::debug ); - MpiNode::init( argc, argv ); + Node::init( argc, argv ); vector v; v.push_back(1); @@ -62,7 +64,7 @@ int main(int argc, char** argv) metaV.push_back( v ); metaV.push_back( v ); - switch( MpiNode::comm().rank() ) + switch( Node::comm().rank() ) { case 0: case 1: @@ -88,7 +90,7 @@ int main(int argc, char** argv) default: { // all the other nodes are sub workers - int rank = MpiNode::comm().rank(); + int rank = Node::comm().rank(); if ( rank == 3 or rank == 5 ) { subtask( v, 1 ); diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 46130b80..82f4e0e7 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -1,4 +1,4 @@ -# include +# include # include # include @@ -6,6 +6,8 @@ # include using namespace std; +using namespace eo::mpi; + struct plusOne : public eoUF< int&, void > { void operator() ( int & x ) @@ -27,7 +29,7 @@ int main(int argc, char** argv) // eo::log << eo::setlevel( eo::debug ); bool launchOnlyOne = false; // Set this to true if you wanna launch only the first test. - MpiNode::init( argc, argv ); + Node::init( argc, argv ); srand( time(0) ); vector v; @@ -43,10 +45,10 @@ int main(int argc, char** argv) vector< Test > tests; - const int ALL = MpiNode::comm().size(); + const int ALL = Node::comm().size(); Test tIntervalStatic; - tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD, v.size() ); + tIntervalStatic.assign = new StaticAssignmentAlgorithm( 1, REST_OF_THE_WORLD, v.size() ); tIntervalStatic.description = "Correct static assignment with interval."; tIntervalStatic.requiredNodesNumber = ALL; tests.push_back( tIntervalStatic ); @@ -81,7 +83,7 @@ int main(int argc, char** argv) tests.push_back( tVectorStatic ); Test tIntervalDynamic; - tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, eo::REST_OF_THE_WORLD ); + tIntervalDynamic.assign = new DynamicAssignmentAlgorithm( 1, REST_OF_THE_WORLD ); tIntervalDynamic.description = "Dynamic assignment with interval."; tIntervalDynamic.requiredNodesNumber = ALL; tests.push_back( tIntervalDynamic ); @@ -114,7 +116,7 @@ int main(int argc, char** argv) cout << "Test : " << tests[i].description << endl; } - if( MpiNode::comm().rank() < tests[i].requiredNodesNumber ) + if( Node::comm().rank() < tests[i].requiredNodesNumber ) { job.run(); } @@ -134,7 +136,7 @@ int main(int argc, char** argv) cout << endl; } - MpiNode::comm().barrier(); + Node::comm().barrier(); delete tests[i].assign; } From de2df9de810a71b918ca57ad8335a85a951ed1db Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 14:18:04 +0200 Subject: [PATCH 32/52] Preprocessor conditions for debug print --- eo/src/mpi/eoMpi.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 86ad55ab..b12233c5 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -46,28 +46,38 @@ namespace eo void master( ) { int totalWorkers = assignmentAlgo.availableWorkers(); +# ifndef NDEBUG eo::log << eo::debug; eo::log << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl; +# endif while( ! isFinished() ) { int assignee = assignmentAlgo.get( ); while( assignee <= 0 ) { +# ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Waitin' for node..." << std::endl; +# endif bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); int wrkRank = status.source(); +# ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Node " << wrkRank << " just terminated." << std::endl; +# endif handleResponse( wrkRank ); assignmentAlgo.confirm( wrkRank ); assignee = assignmentAlgo.get( ); } +# ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; +# endif comm.send( assignee, Channel::Commands, Message::Continue ); sendTask( assignee ); } +# ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; +# endif // frees all the idle workers std::vector idles = assignmentAlgo.idles(); for(unsigned int i = 0; i < idles.size(); ++i) @@ -75,7 +85,9 @@ namespace eo comm.send( idles[i], Channel::Commands, Message::Finish ); } +# ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl; +# endif // wait for all responses while( assignmentAlgo.availableWorkers() != totalWorkers ) { @@ -86,24 +98,34 @@ namespace eo assignmentAlgo.confirm( wrkRank ); } +# ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; +# endif } void worker( ) { int order; +# ifndef NDEBUG eo::log << eo::debug; +# endif while( true ) { +# ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; +# endif comm.recv( masterRank, Channel::Commands, order ); if ( order == Message::Finish ) { +# ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl; +# endif return; } else { +# ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl; +# endif processTask( ); } } From fc68c3b81ef59944a8f2fd94db083f2cab0ca543 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 25 Jun 2012 14:55:15 +0200 Subject: [PATCH 33/52] eoPopEvalFunc updated for parallel evaluation. --- eo/src/apply.h | 24 +++++++------------ eo/src/eoPopEvalFunc.h | 20 ++++++++++++++-- eo/test/{t-eoMpiParallel.cpp => mpi/eval.cpp} | 18 ++++++++++---- 3 files changed, 41 insertions(+), 21 deletions(-) rename eo/test/{t-eoMpiParallel.cpp => mpi/eval.cpp} (90%) diff --git a/eo/src/apply.h b/eo/src/apply.h index d2006fe0..c3c0365c 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -34,7 +34,7 @@ #include # ifdef WITH_MPI -# include +# include # include # endif // WITH_MPI @@ -86,21 +86,15 @@ void apply(eoUF& _proc, std::vector& _pop) #ifdef WITH_MPI template -void parallelApply(eoUF& _proc, std::vector& _pop) +void parallelApply( + eoUF& _proc, + std::vector& _pop, + eo::mpi::AssignmentAlgorithm& _algo, + int _masterRank, + int _packetSize) { - ParallelApply job( _proc, _pop ); - - MasterNode* master = dynamic_cast( MpiNodeStore::instance() ); - if ( master ) - { - DynamicAssignmentAlgorithm algo; - master->setAssignmentAlgorithm( &algo ); - master->run( job ); - } else - { - WorkerNode* wrk = dynamic_cast( MpiNodeStore::instance() ); - wrk->run( job ); - } + eo::mpi::ParallelApply job( _proc, _pop, _algo, _masterRank, _packetSize ); + job.run(); } #endif diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index cbd38b21..8885ef11 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -83,17 +83,33 @@ template class eoParallelPopLoopEval : public eoPopEvalFunc { public: /** Ctor: set value of embedded eoEvalFunc */ - eoParallelPopLoopEval(eoEvalFunc & _eval) : eval(_eval) {} + eoParallelPopLoopEval( + eoEvalFunc & _eval, + eo::mpi::AssignmentAlgorithm& _assignAlgo, + int _masterRank, + int _packetSize = 1 + ) : + eval(_eval), + assignAlgo( _assignAlgo ), + masterRank( _masterRank ), + packetSize( _packetSize ) + { + // empty + } /** Do the job: simple loop over the offspring */ void operator()(eoPop & _parents, eoPop & _offspring) { (void)_parents; - parallelApply(eval, _offspring); + parallelApply(eval, _offspring, assignAlgo, masterRank, packetSize); } private: eoEvalFunc & eval; + + eo::mpi::AssignmentAlgorithm & assignAlgo; + int masterRank; + int packetSize; }; #endif diff --git a/eo/test/t-eoMpiParallel.cpp b/eo/test/mpi/eval.cpp similarity index 90% rename from eo/test/t-eoMpiParallel.cpp rename to eo/test/mpi/eval.cpp index 5529b8e2..7e15ac6f 100644 --- a/eo/test/t-eoMpiParallel.cpp +++ b/eo/test/mpi/eval.cpp @@ -3,12 +3,19 @@ //----------------------------------------------------------------------------- #include +#include + #include -//#include -#include "real_value.h" +// #include +#include "../real_value.h" + +#include #include +#include +using namespace std; + //----------------------------------------------------------------------------- class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial::Persistent @@ -75,7 +82,7 @@ typedef eoRealSerializable EOT; int main(int ac, char** av) { - MpiSingletonFactory::init( ac, av ); + eo::mpi::Node::init( ac, av ); eoParser parser(ac, av); @@ -100,7 +107,10 @@ int main(int ac, char** av) eo::log << "Size of population : " << popSize << std::endl; - eoPopLoopEval< EOT > popEval( eval ); + eo::log << eo::setlevel( eo::debug ); + + eo::mpi::DynamicAssignmentAlgorithm assign; + eoParallelPopLoopEval< EOT > popEval( eval, assign, 0, 3 ); popEval( pop, pop ); eo::log << eo::quiet << "DONE!" << std::endl; From 7b399aa1ddfe72566c89bb5276f29705c6c2b9b7 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 26 Jun 2012 17:53:32 +0200 Subject: [PATCH 34/52] Putting time conditions into eo::mpi::Job and MultiParallelApply, which doesn't prefigure about number of workers evaluations. --- eo/src/apply.h | 7 ++--- eo/src/eoPopEvalFunc.h | 9 ++++--- eo/src/mpi/eoMpi.h | 34 ++++++++++++++++++++--- eo/src/mpi/eoMultiParallelApply.h | 45 +++++++++++++++++++++++++++++++ eo/src/mpi/eoParallelApply.h | 12 ++++++--- eo/src/mpi/eoTerminateJob.h | 42 +++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 eo/src/mpi/eoMultiParallelApply.h create mode 100644 eo/src/mpi/eoTerminateJob.h diff --git a/eo/src/apply.h b/eo/src/apply.h index c3c0365c..7e59c21b 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -35,7 +35,7 @@ # ifdef WITH_MPI # include -# include +# include # endif // WITH_MPI /** @@ -91,9 +91,10 @@ void parallelApply( std::vector& _pop, eo::mpi::AssignmentAlgorithm& _algo, int _masterRank, - int _packetSize) + int _packetSize, + int _maxTime) { - eo::mpi::ParallelApply job( _proc, _pop, _algo, _masterRank, _packetSize ); + eo::mpi::MultiParallelApply job( _proc, _pop, _algo, _masterRank, _packetSize, _maxTime ); job.run(); } #endif diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index 8885ef11..77473eb1 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -87,12 +87,14 @@ public: eoEvalFunc & _eval, eo::mpi::AssignmentAlgorithm& _assignAlgo, int _masterRank, - int _packetSize = 1 + int _packetSize = 1, + int _maxTime = 0 ) : eval(_eval), assignAlgo( _assignAlgo ), masterRank( _masterRank ), - packetSize( _packetSize ) + packetSize( _packetSize ), + maxTime( _maxTime ) { // empty } @@ -101,7 +103,7 @@ public: void operator()(eoPop & _parents, eoPop & _offspring) { (void)_parents; - parallelApply(eval, _offspring, assignAlgo, masterRank, packetSize); + parallelApply(eval, _offspring, assignAlgo, masterRank, packetSize, maxTime); } private: @@ -110,6 +112,7 @@ private: eo::mpi::AssignmentAlgorithm & assignAlgo; int masterRank; int packetSize; + int maxTime; }; #endif diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index b12233c5..480bfbcb 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -3,10 +3,15 @@ # include # include +# include +# include + # include +# include # include "eoMpiNode.h" # include "eoMpiAssignmentAlgorithm.h" + // TODO TODOB comment! namespace eo @@ -28,10 +33,11 @@ namespace eo { public: - Job( AssignmentAlgorithm& _algo, int _masterRank ) : + Job( AssignmentAlgorithm& _algo, int _masterRank, long maxTime = 0 ) : assignmentAlgo( _algo ), comm( Node::comm() ), - masterRank( _masterRank ) + masterRank( _masterRank ), + _maxTime( maxTime ) { _isMaster = Node::comm().rank() == _masterRank; } @@ -43,6 +49,8 @@ namespace eo // worker virtual void processTask( ) = 0; + protected: + void master( ) { int totalWorkers = assignmentAlgo.availableWorkers(); @@ -50,9 +58,18 @@ namespace eo eo::log << eo::debug; eo::log << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl; # endif - + bool timeStopped = false; while( ! isFinished() ) { + // Time restrictions + getrusage( RUSAGE_SELF , &_usage ); + _current = _usage.ru_utime.tv_sec + _usage.ru_stime.tv_sec; + if( _maxTime > 0 && _current > _maxTime ) + { + timeStopped = true; + break; + } + int assignee = assignmentAlgo.get( ); while( assignee <= 0 ) { @@ -71,6 +88,7 @@ namespace eo # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; # endif + comm.send( assignee, Channel::Commands, Message::Continue ); sendTask( assignee ); } @@ -101,6 +119,10 @@ namespace eo # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; # endif + if( timeStopped ) + { + throw eoMaxTimeException( _current ); + } } void worker( ) @@ -131,6 +153,8 @@ namespace eo } } + public: + void run( ) { ( _isMaster ) ? master( ) : worker( ); @@ -146,6 +170,10 @@ namespace eo bmpi::communicator& comm; int masterRank; bool _isMaster; + + struct rusage _usage; + long _current; + const long _maxTime; }; } } diff --git a/eo/src/mpi/eoMultiParallelApply.h b/eo/src/mpi/eoMultiParallelApply.h new file mode 100644 index 00000000..f3df801d --- /dev/null +++ b/eo/src/mpi/eoMultiParallelApply.h @@ -0,0 +1,45 @@ + +# ifndef __EO_MULTI_PARALLEL_APPLY_H__ +# define __EO_MULTI_PARALLEL_APPLY_H__ + +# include "eoParallelApply.h" + +namespace eo +{ + namespace mpi + { + template< typename EOT > + class MultiParallelApply : public ParallelApply + { + public: + + // using ParallelApply::comm; + using ParallelApply::masterRank; + + MultiParallelApply( + eoUF & _proc, + std::vector& _pop, + AssignmentAlgorithm & algo, + int _masterRank, + int _packetSize = 1, + long _maxTime = 0 + ) : + ParallelApply( _proc, _pop, algo, _masterRank, _packetSize, _maxTime ) + { + // empty + } + + virtual void processTask( ) + { + int order = Message::Continue; + while( order != Message::Finish ) + { + ParallelApply::processTask( ); + ParallelApply::comm.recv( masterRank, Channel::Commands, order ); + } + } + }; + } +} +# endif // __EO_PARALLEL_APPLY_H__ + diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 1e9d4c1d..af0666cc 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -26,9 +26,10 @@ namespace eo std::vector& _pop, AssignmentAlgorithm & algo, int _masterRank, - int _packetSize = 1 + int _packetSize = 1, + long _maxTime = 0 ) : - Job( algo, _masterRank ), + Job( algo, _masterRank, _maxTime ), func( _proc ), index( 0 ), size( _pop.size() ), @@ -42,7 +43,7 @@ namespace eo tempArray = new EOT[ packetSize ]; } - ~ParallelApply() + virtual ~ParallelApply() { delete [] tempArray; } @@ -59,8 +60,11 @@ namespace eo } int sentSize = futureIndex - index ; + comm.send( wrkRank, 1, sentSize ); + eo::log << eo::progress << "Evaluating individual " << index << std::endl; + assignedTasks[ wrkRank ].index = index; assignedTasks[ wrkRank ].size = sentSize; @@ -85,7 +89,7 @@ namespace eo comm.send( masterRank, 1, tempArray, recvSize ); } - bool isFinished() + virtual bool isFinished() { return index == size; } diff --git a/eo/src/mpi/eoTerminateJob.h b/eo/src/mpi/eoTerminateJob.h new file mode 100644 index 00000000..4cb18225 --- /dev/null +++ b/eo/src/mpi/eoTerminateJob.h @@ -0,0 +1,42 @@ +# ifndef __EO_TERMINATE_H__ +# define __EO_TERMINATE_H__ + +# include "eoMpi.h" + +namespace eo +{ + namespace mpi + { + class TerminateJob : public Job + { + public: + TerminateJob( AssignmentAlgorithm& algo, int _ ) + : Job( algo, _ ) + { + // empty + } + + void sendTask( int wrkRank ) + { + // empty + } + + void handleResponse( int wrkRank ) + { + // empty + } + + void processTask( ) + { + // empty + } + + bool isFinished() + { + return true; + } + }; + } +} + +# endif // __EO_TERMINATE_H__ From 2861fc98de4f4fd6d2bbd508f62ac96594fa5d8e Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Wed, 27 Jun 2012 15:09:12 +0200 Subject: [PATCH 35/52] Mesuring time with eoTimer. --- eo/src/mpi/eoMpi.cpp | 1 + eo/src/mpi/eoMpi.h | 13 ++++ eo/src/mpi/eoParallelApply.h | 2 + eo/src/utils/eoTimer.h | 145 +++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 eo/src/utils/eoTimer.h diff --git a/eo/src/mpi/eoMpi.cpp b/eo/src/mpi/eoMpi.cpp index f6e3b3c5..9ffc84bd 100644 --- a/eo/src/mpi/eoMpi.cpp +++ b/eo/src/mpi/eoMpi.cpp @@ -6,6 +6,7 @@ namespace eo namespace mpi { bmpi::communicator Node::_comm; + eoTimerStat timerStat; } } diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 480bfbcb..a516b442 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -7,6 +7,7 @@ # include # include +# include # include # include "eoMpiNode.h" @@ -18,6 +19,8 @@ namespace eo { namespace mpi { + extern eoTimerStat timerStat; + namespace Channel { const int Commands = 0; @@ -70,6 +73,7 @@ namespace eo break; } + timerStat.start("master_wait_for_assignee"); int assignee = assignmentAlgo.get( ); while( assignee <= 0 ) { @@ -85,28 +89,34 @@ namespace eo assignmentAlgo.confirm( wrkRank ); assignee = assignmentAlgo.get( ); } + timerStat.stop("master_wait_for_assignee"); # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; # endif + timerStat.start("master_wait_for_send"); comm.send( assignee, Channel::Commands, Message::Continue ); sendTask( assignee ); + timerStat.stop("master_wait_for_send"); } # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; # endif // frees all the idle workers + timerStat.start("master_wait_for_idles"); std::vector idles = assignmentAlgo.idles(); for(unsigned int i = 0; i < idles.size(); ++i) { comm.send( idles[i], Channel::Commands, Message::Finish ); } + timerStat.stop("master_wait_for_idles"); # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl; # endif // wait for all responses + timerStat.start("master_wait_for_all_responses"); while( assignmentAlgo.availableWorkers() != totalWorkers ) { bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); @@ -115,6 +125,7 @@ namespace eo comm.send( wrkRank, Channel::Commands, Message::Finish ); assignmentAlgo.confirm( wrkRank ); } + timerStat.stop("master_wait_for_all_responses"); # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; @@ -136,7 +147,9 @@ namespace eo # ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; # endif + timerStat.start("worker_wait_for_order"); comm.recv( masterRank, Channel::Commands, order ); + timerStat.stop("worker_wait_for_order"); if ( order == Message::Finish ) { # ifndef NDEBUG diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index af0666cc..b89da73e 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -82,10 +82,12 @@ namespace eo int recvSize; comm.recv( masterRank, 1, recvSize ); comm.recv( masterRank, 1, tempArray, recvSize ); + timerStat.start("worker_processes"); for( int i = 0; i < recvSize ; ++i ) { func( tempArray[ i ] ); } + timerStat.stop("worker_processes"); comm.send( masterRank, 1, tempArray, recvSize ); } diff --git a/eo/src/utils/eoTimer.h b/eo/src/utils/eoTimer.h new file mode 100644 index 00000000..c97ab5d3 --- /dev/null +++ b/eo/src/utils/eoTimer.h @@ -0,0 +1,145 @@ +# ifndef __TIMER_H__ +# define __TIMER_H__ + +# include +# include + +# include +# include + +# ifdef WITH_MPI +# include +# include +# include +# endif + +// TODO TODOB commenter +class eoTimer +{ + public: + + eoTimer() + { + restart(); + } + + void restart() + { + uuremainder = 0; + usremainder = 0; + wc_start = time(NULL); + getrusage( RUSAGE_SELF, &_start ); + } + + long int usertime() + { + struct rusage _now; + getrusage( RUSAGE_SELF, &_now ); + long int result = _now.ru_utime.tv_sec - _start.ru_utime.tv_sec; + if( _now.ru_utime.tv_sec == _start.ru_utime.tv_sec ) + { + uuremainder += _now.ru_utime.tv_usec - _start.ru_utime.tv_usec; + if( uuremainder > 1000000) + { + ++result; + uuremainder = 0; + } + } + return result; + } + + long int systime() + { + struct rusage _now; + getrusage( RUSAGE_SELF, &_now ); + long int result = _now.ru_stime.tv_sec - _start.ru_stime.tv_sec; + if( _now.ru_stime.tv_sec == _start.ru_stime.tv_sec ) + { + usremainder += _now.ru_stime.tv_usec - _start.ru_stime.tv_usec; + if( usremainder > 1000000) + { + ++result; + usremainder = 0; + } + } + return result; + } + + double wallclock() + { + return std::difftime( std::time(NULL) , wc_start ); + } + + protected: + struct rusage _start; + long int uuremainder; + long int usremainder; + time_t wc_start; +}; + +class eoTimerStat +{ + public: + + struct Stat + { + std::vector utime; + std::vector stime; + std::vector wtime; +#ifdef WITH_MPI + // Gives access to boost serialization + friend class boost::serialization::access; + + /** + * Serializes the statistique in a boost archive (useful for boost::mpi) + */ + template + void serialize( Archive & ar, const unsigned int version ) + { + ar & utime & stime & wtime; + (void) version; // avoid compilation warning + } +# endif + }; + +#ifdef WITH_MPI + // Gives access to boost serialization + friend class boost::serialization::access; + + /** + * Serializes the map of statistics in a boost archive (useful for boost::mpi) + */ + template + void serialize( Archive & ar, const unsigned int version ) + { + ar & _stats; + (void) version; // avoid compilation warning + } +# endif + + void start( const std::string & key ) + { + _timers[ key ].restart(); + } + + void stop( const std::string& key ) + { + Stat & s = _stats[ key ]; + eoTimer & t = _timers[ key ]; + s.utime.push_back( t.usertime() ); + s.stime.push_back( t.systime() ); + s.wtime.push_back( t.wallclock() ); + } + + std::map< std::string, Stat > stats() + { + return _stats; + } + + protected: + std::map< std::string, Stat > _stats; + std::map< std::string, eoTimer > _timers; +}; + +# endif // __TIMER_H__ + From 4675abaa24becca1c6f5d2bdecf2dbf9a72f8b20 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 29 Jun 2012 18:19:55 +0200 Subject: [PATCH 36/52] Implementation test of functional configurable job --- eo/src/mpi/eoMpi.h | 67 ++++++++- eo/src/mpi/eoParallelApply.h | 262 ++++++++++++++++++++++++----------- 2 files changed, 245 insertions(+), 84 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index a516b442..6d22a1bf 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -8,6 +8,7 @@ # include # include +# include # include # include "eoMpiNode.h" @@ -32,28 +33,84 @@ namespace eo const int Finish = 1; } + template + struct SharedDataFunction + { + void data( Data & _d ) { d = _d; } + + protected: + Data d; + }; + + template + struct SendTaskFunction : public eoUF, public SharedDataFunction + { + virtual ~SendTaskFunction() {} + }; + + template + struct HandleResponseFunction : public eoUF, public SharedDataFunction + { + virtual ~HandleResponseFunction() {} + }; + + template + struct ProcessTaskFunction : public eoF, public SharedDataFunction + { + virtual ~ProcessTaskFunction() {} + }; + + template + struct IsFinishedFunction : public eoF, public SharedDataFunction + { + virtual ~IsFinishedFunction() {} + }; + + template + struct JobStore + { + virtual SendTaskFunction & sendTask() = 0; + virtual HandleResponseFunction & handleResponse() = 0; + virtual ProcessTaskFunction & processTask() = 0; + virtual IsFinishedFunction & isFinished() = 0; + }; + + template class Job { public: - Job( AssignmentAlgorithm& _algo, int _masterRank, long maxTime = 0 ) : + Job( AssignmentAlgorithm& _algo, int _masterRank, JobStore store ) : + // Job( AssignmentAlgorithm& _algo, int _masterRank, long maxTime = 0 ) : assignmentAlgo( _algo ), comm( Node::comm() ), + // _maxTime( maxTime ), masterRank( _masterRank ), - _maxTime( maxTime ) + // Functors + sendTask( store.sendTask() ), + handleResponse( store.handleResponse() ), + processTask( store.processTask() ), + isFinished( store.isFinished() ) { _isMaster = Node::comm().rank() == _masterRank; } + /* // master virtual bool isFinished() = 0; virtual void sendTask( int wrkRank ) = 0; virtual void handleResponse( int wrkRank ) = 0; // worker virtual void processTask( ) = 0; + */ protected: + SendTaskFunction & sendTask; + HandleResponseFunction & handleResponse; + ProcessTaskFunction & processTask; + IsFinishedFunction & isFinished; + void master( ) { int totalWorkers = assignmentAlgo.availableWorkers(); @@ -65,6 +122,7 @@ namespace eo while( ! isFinished() ) { // Time restrictions + /* getrusage( RUSAGE_SELF , &_usage ); _current = _usage.ru_utime.tv_sec + _usage.ru_stime.tv_sec; if( _maxTime > 0 && _current > _maxTime ) @@ -72,6 +130,7 @@ namespace eo timeStopped = true; break; } + */ timerStat.start("master_wait_for_assignee"); int assignee = assignmentAlgo.get( ); @@ -130,10 +189,12 @@ namespace eo # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; # endif + /* if( timeStopped ) { throw eoMaxTimeException( _current ); } + */ } void worker( ) @@ -186,7 +247,7 @@ namespace eo struct rusage _usage; long _current; - const long _maxTime; + // const long _maxTime; }; } } diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index b89da73e..6ec78c80 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -10,15 +10,177 @@ namespace eo { namespace mpi { - template< typename EOT > - class ParallelApply : public Job + struct ParallelApplyAssignment { - private: - struct ParallelApplyAssignment + int index; + int size; + }; + + template + struct ParallelApplyData + { + ParallelApplyData() {} + + ParallelApplyData( + eoUF & _proc, + std::vector& _pop, + int _masterRank, + int _packetSize + ) : + func( _proc ), + data( _pop ), + index( 0 ), + size( _pop.size() ), + packetSize( _packetSize ), + // job + masterRank( _masterRank ), + comm( Node::comm() ) + { + tempArray = new EOT[ _packetSize ]; + } + + ~ParallelApplyData() + { + delete [] tempArray; + } + + std::vector & data; + eoUF & func; + int index; + int size; + std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks; + + int packetSize; + EOT* tempArray; + + int masterRank; + bmpi::communicator& comm; + }; + + template + struct SendTaskParallelApply : public SendTaskFunction< Data > + { + SendTaskParallelApply( Data & _d ) + { + data( _d ); + } + + using SharedDataFunction< Data >::d; + + // futureIndex, index, packetSize, size, comm, assignedTasks, data + void operator()(int wrkRank) + { + int futureIndex; + + if( d.index + d.packetSize < d.size ) { - int index; - int size; - }; + futureIndex = d.index + d.packetSize; + } else { + futureIndex = d.size; + } + + int sentSize = futureIndex - d.index ; + + d.comm.send( wrkRank, 1, sentSize ); + + eo::log << eo::progress << "Evaluating individual " << d.index << std::endl; + + d.assignedTasks[ wrkRank ].index = d.index; + d.assignedTasks[ wrkRank ].size = sentSize; + + d.comm.send( wrkRank, 1, & (d.data[ index ]) , sentSize ); + d.index = futureIndex; + } + }; + + template + struct HandleResponseParallelApply : public HandleResponseFunction< Data > + { + HandleResponseParallelApply( Data & _d ) + { + data( _d ); + } + + using SharedDataFunction< Data >::d; + void operator()(int wrkRank) + { + d.comm.recv( wrkRank, 1, & (d.data[ d.assignedTasks[wrkRank].index ] ), d.assignedTasks[wrkRank].size ); + } + }; + + template + struct ProcessTaskParallelApply : public ProcessTaskFunction< Data > + { + ProcessTaskParallelApply( Data & _d ) + { + data( _d ); + } + + using SharedDataFunction< Data >::d; + void operator()() + { + int recvSize; + d.comm.recv( d.masterRank, 1, recvSize ); + d.comm.recv( d.masterRank, 1, d.tempArray, recvSize ); + timerStat.start("worker_processes"); + for( int i = 0; i < recvSize ; ++i ) + { + d.func( d.tempArray[ i ] ); + } + timerStat.stop("worker_processes"); + d.comm.send( d.masterRank, 1, d.tempArray, recvSize ); + } + }; + + template + struct IsFinishedParallelApply : public IsFinishedFunction< Data > + { + IsFinishedParallelApply( Data & _d ) + { + data( _d ); + } + + using SharedDataFunction< Data >::d; + bool operator()() + { + return d.index == d.size; + } + }; + + template< typename Data > + struct ParallelApplyStore : public JobStore< Data > + { + ParallelApplyStore( Data & data ) + { + stpa = new SendTaskParallelApply< Data >( data ); + hrpa = new HandleResponseParallelApply< Data >( data ); + ptpa = new ProcessTaskParallelApply< Data >( data ); + ispa = new IsFinishedParallelApply< Data >( data ); + } + + ~ParallelApplyStore() + { + delete stpa; + delete hrpa; + delete ptpa; + delete ispa; + } + + SendTaskFunction< Data > & sendTask() { return *stpa; } + HandleResponseFunction< Data > & handleResponse() { return *hrpa; } + ProcessTaskFunction< Data > & processTask() { return *ptpa; } + IsFinishedFunction< Data > & isFinished() { return *ispa; } + + protected: + SendTaskParallelApply< Data >* stpa; + HandleResponseParallelApply< Data >* hrpa; + ProcessTaskParallelApply< Data >* ptpa; + IsFinishedParallelApply< Data >* ispa; + }; + + template< typename EOT > + class ParallelApply : public Job< ParallelApplyData > + { public: ParallelApply( @@ -26,85 +188,23 @@ namespace eo std::vector& _pop, AssignmentAlgorithm & algo, int _masterRank, - int _packetSize = 1, - long _maxTime = 0 + // long _maxTime = 0, + int _packetSize = 1 ) : - Job( algo, _masterRank, _maxTime ), - func( _proc ), - index( 0 ), - size( _pop.size() ), - data( _pop ), - packetSize( _packetSize ) + + Job< ParallelApplyData >( algo, _masterRank, ParallelApplyStore< ParallelApplyData >( sharedData ) ), + // Job( algo, _masterRank, _maxTime ), + sharedData( _proc, _pop, _masterRank, _packetSize ) + + { + if ( _packetSize <= 0 ) { - if ( _packetSize <= 0 ) - { - throw std::runtime_error("Packet size should not be negative."); - } - tempArray = new EOT[ packetSize ]; - } - - virtual ~ParallelApply() - { - delete [] tempArray; - } - - virtual void sendTask( int wrkRank ) - { - int futureIndex; - - if( index + packetSize < size ) - { - futureIndex = index + packetSize; - } else { - futureIndex = size; - } - - int sentSize = futureIndex - index ; - - comm.send( wrkRank, 1, sentSize ); - - eo::log << eo::progress << "Evaluating individual " << index << std::endl; - - assignedTasks[ wrkRank ].index = index; - assignedTasks[ wrkRank ].size = sentSize; - - comm.send( wrkRank, 1, &data[ index ] , sentSize ); - index = futureIndex; - } - - virtual void handleResponse( int wrkRank ) - { - comm.recv( wrkRank, 1, &data[ assignedTasks[wrkRank].index ], assignedTasks[wrkRank].size ); - } - - virtual void processTask( ) - { - int recvSize; - comm.recv( masterRank, 1, recvSize ); - comm.recv( masterRank, 1, tempArray, recvSize ); - timerStat.start("worker_processes"); - for( int i = 0; i < recvSize ; ++i ) - { - func( tempArray[ i ] ); - } - timerStat.stop("worker_processes"); - comm.send( masterRank, 1, tempArray, recvSize ); - } - - virtual bool isFinished() - { - return index == size; + throw std::runtime_error("Packet size should not be negative."); } + } protected: - std::vector & data; - eoUF& func; - int index; - int size; - std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks; - - int packetSize; - EOT* tempArray; + ParallelApplyData sharedData; }; } } From d05cbfd60dc2cbe104434168c7ed9730ed50c028 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 2 Jul 2012 11:56:41 +0200 Subject: [PATCH 37/52] First version of functional job --- eo/src/mpi/eoMpi.h | 46 +++---- eo/src/mpi/eoParallelApply.h | 232 +++++++++++++++++----------------- eo/test/mpi/parallelApply.cpp | 7 +- 3 files changed, 140 insertions(+), 145 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 6d22a1bf..433e4c27 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -33,54 +33,42 @@ namespace eo const int Finish = 1; } - template - struct SharedDataFunction - { - void data( Data & _d ) { d = _d; } - - protected: - Data d; - }; - - template - struct SendTaskFunction : public eoUF, public SharedDataFunction + class SendTaskFunction : public eoUF { + public: virtual ~SendTaskFunction() {} }; - template - struct HandleResponseFunction : public eoUF, public SharedDataFunction + class HandleResponseFunction : public eoUF { + public: virtual ~HandleResponseFunction() {} }; - template - struct ProcessTaskFunction : public eoF, public SharedDataFunction + class ProcessTaskFunction : public eoF { + public: virtual ~ProcessTaskFunction() {} }; - template - struct IsFinishedFunction : public eoF, public SharedDataFunction + class IsFinishedFunction : public eoF { + public: virtual ~IsFinishedFunction() {} }; - template struct JobStore { - virtual SendTaskFunction & sendTask() = 0; - virtual HandleResponseFunction & handleResponse() = 0; - virtual ProcessTaskFunction & processTask() = 0; - virtual IsFinishedFunction & isFinished() = 0; + virtual SendTaskFunction & sendTask() const = 0; + virtual HandleResponseFunction & handleResponse() const = 0; + virtual ProcessTaskFunction & processTask() const = 0; + virtual IsFinishedFunction & isFinished() const = 0; }; - template class Job { public: - - Job( AssignmentAlgorithm& _algo, int _masterRank, JobStore store ) : + Job( AssignmentAlgorithm& _algo, int _masterRank, const JobStore & store ) : // Job( AssignmentAlgorithm& _algo, int _masterRank, long maxTime = 0 ) : assignmentAlgo( _algo ), comm( Node::comm() ), @@ -106,10 +94,10 @@ namespace eo protected: - SendTaskFunction & sendTask; - HandleResponseFunction & handleResponse; - ProcessTaskFunction & processTask; - IsFinishedFunction & isFinished; + SendTaskFunction & sendTask; + HandleResponseFunction & handleResponse; + ProcessTaskFunction & processTask; + IsFinishedFunction & isFinished; void master( ) { diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 6ec78c80..9cc7bb5f 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -17,145 +17,178 @@ namespace eo }; template - struct ParallelApplyData - { - ParallelApplyData() {} + class SendTaskParallelApply; - ParallelApplyData( - eoUF & _proc, - std::vector& _pop, - int _masterRank, - int _packetSize - ) : - func( _proc ), - data( _pop ), - index( 0 ), - size( _pop.size() ), - packetSize( _packetSize ), - // job - masterRank( _masterRank ), - comm( Node::comm() ) + template + class HandleResponseParallelApply; + + template + class ProcessTaskParallelApply; + + template + class IsFinishedParallelApply; + + template + class ParallelApply; + + template< class EOT > + class BaseParallelApply + { + public: + void owner(ParallelApply * job) { - tempArray = new EOT[ _packetSize ]; + j = job; } - ~ParallelApplyData() - { - delete [] tempArray; - } + protected: + ParallelApply * j; + }; + + template< typename EOT > + class ParallelApply : public Job + { + friend class SendTaskParallelApply; + friend class HandleResponseParallelApply; + friend class ProcessTaskParallelApply; + friend class IsFinishedParallelApply; + + public: + + ParallelApply( + eoUF & _proc, + std::vector& _pop, + AssignmentAlgorithm & algo, + int _masterRank, + const JobStore& store, + // long _maxTime = 0, + int _packetSize = 1 + ) : + Job( algo, _masterRank, store ), + // Job( algo, _masterRank, _maxTime ), + func( _proc ), + data( _pop ), + packetSize( _packetSize ), + index( 0 ), + size( _pop.size() ) + { + if ( _packetSize <= 0 ) + { + throw std::runtime_error("Packet size should not be negative."); + } + tempArray = new EOT [ _packetSize ]; + + dynamic_cast< BaseParallelApply& >( sendTask ).owner( this ); + dynamic_cast< BaseParallelApply& >( handleResponse ).owner( this ); + dynamic_cast< BaseParallelApply& >( processTask ).owner( this ); + dynamic_cast< BaseParallelApply& >( isFinished ).owner( this ); + } + + ~ParallelApply() + { + delete [] tempArray; + } + + protected: std::vector & data; eoUF & func; int index; int size; std::map< int /* worker rank */, ParallelApplyAssignment /* min indexes in vector */> assignedTasks; - int packetSize; EOT* tempArray; - int masterRank; - bmpi::communicator& comm; + // bmpi::communicator& comm; }; - template - struct SendTaskParallelApply : public SendTaskFunction< Data > + template< class EOT > + class SendTaskParallelApply : public SendTaskFunction, public BaseParallelApply { - SendTaskParallelApply( Data & _d ) - { - data( _d ); - } - - using SharedDataFunction< Data >::d; + public: + using BaseParallelApply::j; // futureIndex, index, packetSize, size, comm, assignedTasks, data void operator()(int wrkRank) { int futureIndex; - if( d.index + d.packetSize < d.size ) + if( j->index + j->packetSize < j->size ) { - futureIndex = d.index + d.packetSize; + futureIndex = j->index + j->packetSize; } else { - futureIndex = d.size; + futureIndex = j->size; } - int sentSize = futureIndex - d.index ; + int sentSize = futureIndex - j->index ; - d.comm.send( wrkRank, 1, sentSize ); + j->comm.send( wrkRank, 1, sentSize ); - eo::log << eo::progress << "Evaluating individual " << d.index << std::endl; + eo::log << eo::progress << "Evaluating individual " << j->index << std::endl; - d.assignedTasks[ wrkRank ].index = d.index; - d.assignedTasks[ wrkRank ].size = sentSize; + j->assignedTasks[ wrkRank ].index = j->index; + j->assignedTasks[ wrkRank ].size = sentSize; - d.comm.send( wrkRank, 1, & (d.data[ index ]) , sentSize ); - d.index = futureIndex; + j->comm.send( wrkRank, 1, & ( (j->data)[ j->index ] ) , sentSize ); + j->index = futureIndex; } }; - template - struct HandleResponseParallelApply : public HandleResponseFunction< Data > + template< class EOT > + class HandleResponseParallelApply : public HandleResponseFunction, public BaseParallelApply { - HandleResponseParallelApply( Data & _d ) - { - data( _d ); - } + public: + using BaseParallelApply::j; - using SharedDataFunction< Data >::d; void operator()(int wrkRank) { - d.comm.recv( wrkRank, 1, & (d.data[ d.assignedTasks[wrkRank].index ] ), d.assignedTasks[wrkRank].size ); + j->comm.recv( wrkRank, 1, & (j->data[ j->assignedTasks[wrkRank].index ] ), j->assignedTasks[wrkRank].size ); } }; - template - struct ProcessTaskParallelApply : public ProcessTaskFunction< Data > + template< class EOT > + class ProcessTaskParallelApply : public ProcessTaskFunction, public BaseParallelApply { - ProcessTaskParallelApply( Data & _d ) - { - data( _d ); - } + public: + using BaseParallelApply::j; - using SharedDataFunction< Data >::d; void operator()() { int recvSize; - d.comm.recv( d.masterRank, 1, recvSize ); - d.comm.recv( d.masterRank, 1, d.tempArray, recvSize ); + + j->comm.recv( j->masterRank, 1, recvSize ); + j->comm.recv( j->masterRank, 1, j->tempArray, recvSize ); timerStat.start("worker_processes"); for( int i = 0; i < recvSize ; ++i ) { - d.func( d.tempArray[ i ] ); + j->func( j->tempArray[ i ] ); } timerStat.stop("worker_processes"); - d.comm.send( d.masterRank, 1, d.tempArray, recvSize ); + j->comm.send( j->masterRank, 1, j->tempArray, recvSize ); } }; - template - struct IsFinishedParallelApply : public IsFinishedFunction< Data > + template< class EOT > + class IsFinishedParallelApply : public IsFinishedFunction, public BaseParallelApply { - IsFinishedParallelApply( Data & _d ) - { - data( _d ); - } + public: + + using BaseParallelApply::j; - using SharedDataFunction< Data >::d; bool operator()() { - return d.index == d.size; + return j->index == j->size; } }; - template< typename Data > - struct ParallelApplyStore : public JobStore< Data > + template< class EOT > + struct ParallelApplyStore : public JobStore { - ParallelApplyStore( Data & data ) + ParallelApplyStore() { - stpa = new SendTaskParallelApply< Data >( data ); - hrpa = new HandleResponseParallelApply< Data >( data ); - ptpa = new ProcessTaskParallelApply< Data >( data ); - ispa = new IsFinishedParallelApply< Data >( data ); + stpa = new SendTaskParallelApply; + hrpa = new HandleResponseParallelApply; + ptpa = new ProcessTaskParallelApply; + ispa = new IsFinishedParallelApply; } ~ParallelApplyStore() @@ -166,45 +199,16 @@ namespace eo delete ispa; } - SendTaskFunction< Data > & sendTask() { return *stpa; } - HandleResponseFunction< Data > & handleResponse() { return *hrpa; } - ProcessTaskFunction< Data > & processTask() { return *ptpa; } - IsFinishedFunction< Data > & isFinished() { return *ispa; } + SendTaskFunction& sendTask() const { return *stpa; } + HandleResponseFunction& handleResponse() const { return *hrpa; } + ProcessTaskFunction& processTask() const { return *ptpa; } + IsFinishedFunction& isFinished() const { return *ispa; } protected: - SendTaskParallelApply< Data >* stpa; - HandleResponseParallelApply< Data >* hrpa; - ProcessTaskParallelApply< Data >* ptpa; - IsFinishedParallelApply< Data >* ispa; - }; - - template< typename EOT > - class ParallelApply : public Job< ParallelApplyData > - { - public: - - ParallelApply( - eoUF & _proc, - std::vector& _pop, - AssignmentAlgorithm & algo, - int _masterRank, - // long _maxTime = 0, - int _packetSize = 1 - ) : - - Job< ParallelApplyData >( algo, _masterRank, ParallelApplyStore< ParallelApplyData >( sharedData ) ), - // Job( algo, _masterRank, _maxTime ), - sharedData( _proc, _pop, _masterRank, _packetSize ) - - { - if ( _packetSize <= 0 ) - { - throw std::runtime_error("Packet size should not be negative."); - } - } - - protected: - ParallelApplyData sharedData; + SendTaskParallelApply* stpa; + HandleResponseParallelApply* hrpa; + ProcessTaskParallelApply* ptpa; + IsFinishedParallelApply* ispa; }; } } diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 82f4e0e7..18aadd54 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -27,7 +27,8 @@ struct Test int main(int argc, char** argv) { // eo::log << eo::setlevel( eo::debug ); - bool launchOnlyOne = false; // Set this to true if you wanna launch only the first test. + eo::log << eo::setlevel( eo::quiet ); + bool launchOnlyOne = false ; // Set this to true if you wanna launch only the first test. Node::init( argc, argv ); @@ -44,6 +45,8 @@ int main(int argc, char** argv) plusOne plusOneInstance; vector< Test > tests; + + ParallelApplyStore store; const int ALL = Node::comm().size(); @@ -109,7 +112,7 @@ int main(int argc, char** argv) for( unsigned int i = 0; i < tests.size(); ++i ) { - ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, 3 ); + ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, store, 3 ); if( job.isMaster() ) { From ff61676fb7ac5e17e625202732bde8773173ba48 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 2 Jul 2012 17:53:02 +0200 Subject: [PATCH 38/52] Cleaner version of functional parallel job. --- eo/src/mpi/eoMpi.h | 80 +++++++++++++--- eo/src/mpi/eoParallelApply.h | 173 ++++++++++++++++------------------ eo/test/mpi/parallelApply.cpp | 8 +- 3 files changed, 154 insertions(+), 107 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 433e4c27..9ad2bd7b 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -33,42 +33,91 @@ namespace eo const int Finish = 1; } - class SendTaskFunction : public eoUF + template< typename JobData, typename Wrapped > + struct SharedDataFunction + { + SharedDataFunction( Wrapped * w ) + { + wrapped = w; + } + + void data( JobData* _d ) + { + d = _d; + } + + protected: + JobData* d; + Wrapped* wrapped; + }; + + template< typename JobData > + struct SendTaskFunction : public eoUF, public SharedDataFunction< JobData, SendTaskFunction > { public: + + SendTaskFunction( SendTaskFunction* w = 0 ) : SharedDataFunction >( w ) + { + // empty + } + virtual ~SendTaskFunction() {} }; - class HandleResponseFunction : public eoUF + template< typename JobData > + struct HandleResponseFunction : public eoUF, public SharedDataFunction< JobData, HandleResponseFunction > { public: + + HandleResponseFunction( HandleResponseFunction* w = 0 ) : SharedDataFunction >( w ) + { + // empty + } + virtual ~HandleResponseFunction() {} }; - class ProcessTaskFunction : public eoF + template< typename JobData > + struct ProcessTaskFunction : public eoF, public SharedDataFunction< JobData, ProcessTaskFunction > { public: + + ProcessTaskFunction( ProcessTaskFunction* w = 0 ) : SharedDataFunction >( w ) + { + // empty + } + virtual ~ProcessTaskFunction() {} }; - class IsFinishedFunction : public eoF + template< typename JobData > + struct IsFinishedFunction : public eoF, public SharedDataFunction< JobData, IsFinishedFunction > { public: + + IsFinishedFunction( IsFinishedFunction* w = 0 ) : SharedDataFunction >( w ) + { + // empty + } + virtual ~IsFinishedFunction() {} }; + template< typename JobData > struct JobStore { - virtual SendTaskFunction & sendTask() const = 0; - virtual HandleResponseFunction & handleResponse() const = 0; - virtual ProcessTaskFunction & processTask() const = 0; - virtual IsFinishedFunction & isFinished() const = 0; + virtual SendTaskFunction & sendTask() const = 0; + virtual HandleResponseFunction & handleResponse() const = 0; + virtual ProcessTaskFunction & processTask() const = 0; + virtual IsFinishedFunction & isFinished() const = 0; + virtual JobData* data() = 0; }; + template< class JobData > class Job { public: - Job( AssignmentAlgorithm& _algo, int _masterRank, const JobStore & store ) : + Job( AssignmentAlgorithm& _algo, int _masterRank, JobStore & store ) : // Job( AssignmentAlgorithm& _algo, int _masterRank, long maxTime = 0 ) : assignmentAlgo( _algo ), comm( Node::comm() ), @@ -81,6 +130,11 @@ namespace eo isFinished( store.isFinished() ) { _isMaster = Node::comm().rank() == _masterRank; + + sendTask.data( store.data() ); + handleResponse.data( store.data() ); + processTask.data( store.data() ); + isFinished.data( store.data() ); } /* @@ -94,10 +148,10 @@ namespace eo protected: - SendTaskFunction & sendTask; - HandleResponseFunction & handleResponse; - ProcessTaskFunction & processTask; - IsFinishedFunction & isFinished; + SendTaskFunction & sendTask; + HandleResponseFunction & handleResponse; + ProcessTaskFunction & processTask; + IsFinishedFunction & isFinished; void master( ) { diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 9cc7bb5f..bc85d438 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -17,79 +17,29 @@ namespace eo }; template - class SendTaskParallelApply; - - template - class HandleResponseParallelApply; - - template - class ProcessTaskParallelApply; - - template - class IsFinishedParallelApply; - - template - class ParallelApply; - - template< class EOT > - class BaseParallelApply + struct JobData { - public: - void owner(ParallelApply * job) - { - j = job; - } - - protected: - ParallelApply * j; - }; - - template< typename EOT > - class ParallelApply : public Job - { - friend class SendTaskParallelApply; - friend class HandleResponseParallelApply; - friend class ProcessTaskParallelApply; - friend class IsFinishedParallelApply; - - public: - - ParallelApply( + JobData( eoUF & _proc, std::vector& _pop, - AssignmentAlgorithm & algo, int _masterRank, - const JobStore& store, // long _maxTime = 0, - int _packetSize = 1 - ) : - Job( algo, _masterRank, store ), - // Job( algo, _masterRank, _maxTime ), - func( _proc ), - data( _pop ), - packetSize( _packetSize ), - index( 0 ), - size( _pop.size() ) + int _packetSize + ) : + data( _pop ), func( _proc ), index( 0 ), size( _pop.size() ), packetSize( _packetSize ), masterRank( _masterRank ), comm( Node::comm() ) { if ( _packetSize <= 0 ) { throw std::runtime_error("Packet size should not be negative."); } - tempArray = new EOT [ _packetSize ]; - - dynamic_cast< BaseParallelApply& >( sendTask ).owner( this ); - dynamic_cast< BaseParallelApply& >( handleResponse ).owner( this ); - dynamic_cast< BaseParallelApply& >( processTask ).owner( this ); - dynamic_cast< BaseParallelApply& >( isFinished ).owner( this ); + tempArray = new EOT[ _packetSize ]; } - ~ParallelApply() + ~JobData() { delete [] tempArray; } - protected: - std::vector & data; eoUF & func; int index; @@ -98,92 +48,131 @@ namespace eo int packetSize; EOT* tempArray; - // bmpi::communicator& comm; + int masterRank; + bmpi::communicator& comm; }; - template< class EOT > - class SendTaskParallelApply : public SendTaskFunction, public BaseParallelApply + /* + template< typename EOT > + class ParallelApply : public Job< JobData > { public: - using BaseParallelApply::j; + + ParallelApply( + // eoUF & _proc, + // std::vector& _pop, + AssignmentAlgorithm & algo, + int _masterRank, + const JobStore< JobData >& store + // long _maxTime = 0, + // int _packetSize = 1 + ) : + Job( algo, _masterRank, store ) + // Job( algo, _masterRank, _maxTime ), + func( _proc ), + data( _pop ), + packetSize( _packetSize ), + index( 0 ), + size( _pop.size() ) + { + // empty + } + + protected: + + // bmpi::communicator& comm; + }; + */ + + template< class EOT > + class SendTaskParallelApply : public SendTaskFunction< JobData > + { + public: + using SendTaskFunction< JobData >::d; // futureIndex, index, packetSize, size, comm, assignedTasks, data void operator()(int wrkRank) { int futureIndex; - if( j->index + j->packetSize < j->size ) + if( d->index + d->packetSize < d->size ) { - futureIndex = j->index + j->packetSize; + futureIndex = d->index + d->packetSize; } else { - futureIndex = j->size; + futureIndex = d->size; } - int sentSize = futureIndex - j->index ; + int sentSize = futureIndex - d->index ; - j->comm.send( wrkRank, 1, sentSize ); + d->comm.send( wrkRank, 1, sentSize ); - eo::log << eo::progress << "Evaluating individual " << j->index << std::endl; + eo::log << eo::progress << "Evaluating individual " << d->index << std::endl; - j->assignedTasks[ wrkRank ].index = j->index; - j->assignedTasks[ wrkRank ].size = sentSize; + d->assignedTasks[ wrkRank ].index = d->index; + d->assignedTasks[ wrkRank ].size = sentSize; - j->comm.send( wrkRank, 1, & ( (j->data)[ j->index ] ) , sentSize ); - j->index = futureIndex; + d->comm.send( wrkRank, 1, & ( (d->data)[ d->index ] ) , sentSize ); + d->index = futureIndex; } }; template< class EOT > - class HandleResponseParallelApply : public HandleResponseFunction, public BaseParallelApply + class HandleResponseParallelApply : public HandleResponseFunction< JobData > { public: - using BaseParallelApply::j; + using HandleResponseFunction< JobData >::d; void operator()(int wrkRank) { - j->comm.recv( wrkRank, 1, & (j->data[ j->assignedTasks[wrkRank].index ] ), j->assignedTasks[wrkRank].size ); + d->comm.recv( wrkRank, 1, & (d->data[ d->assignedTasks[wrkRank].index ] ), d->assignedTasks[wrkRank].size ); } }; template< class EOT > - class ProcessTaskParallelApply : public ProcessTaskFunction, public BaseParallelApply + class ProcessTaskParallelApply : public ProcessTaskFunction< JobData > { public: - using BaseParallelApply::j; + using ProcessTaskFunction< JobData >::d; void operator()() { int recvSize; - j->comm.recv( j->masterRank, 1, recvSize ); - j->comm.recv( j->masterRank, 1, j->tempArray, recvSize ); + d->comm.recv( d->masterRank, 1, recvSize ); + d->comm.recv( d->masterRank, 1, d->tempArray, recvSize ); timerStat.start("worker_processes"); for( int i = 0; i < recvSize ; ++i ) { - j->func( j->tempArray[ i ] ); + d->func( d->tempArray[ i ] ); } timerStat.stop("worker_processes"); - j->comm.send( j->masterRank, 1, j->tempArray, recvSize ); + d->comm.send( d->masterRank, 1, d->tempArray, recvSize ); } }; template< class EOT > - class IsFinishedParallelApply : public IsFinishedFunction, public BaseParallelApply + class IsFinishedParallelApply : public IsFinishedFunction< JobData > { public: - - using BaseParallelApply::j; + using IsFinishedFunction< JobData >::d; bool operator()() { - return j->index == j->size; + return d->index == d->size; } }; template< class EOT > - struct ParallelApplyStore : public JobStore + struct ParallelApplyStore : public JobStore< JobData > { - ParallelApplyStore() + ParallelApplyStore( + eoUF & _proc, + std::vector& _pop, + int _masterRank, + // long _maxTime = 0, + int _packetSize = 1 + ) + : j( _proc, _pop, _masterRank, _packetSize ) { stpa = new SendTaskParallelApply; hrpa = new HandleResponseParallelApply; @@ -199,16 +188,20 @@ namespace eo delete ispa; } - SendTaskFunction& sendTask() const { return *stpa; } - HandleResponseFunction& handleResponse() const { return *hrpa; } - ProcessTaskFunction& processTask() const { return *ptpa; } - IsFinishedFunction& isFinished() const { return *ispa; } + SendTaskFunction< JobData >& sendTask() const { return *stpa; } + HandleResponseFunction< JobData >& handleResponse() const { return *hrpa; } + ProcessTaskFunction< JobData >& processTask() const { return *ptpa; } + IsFinishedFunction< JobData >& isFinished() const { return *ispa; } + + JobData* data() { return &j; } protected: SendTaskParallelApply* stpa; HandleResponseParallelApply* hrpa; ProcessTaskParallelApply* ptpa; IsFinishedParallelApply* ispa; + + JobData j; }; } } diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 18aadd54..4e331334 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -38,7 +38,7 @@ int main(int argc, char** argv) { v.push_back( rand() ); } - + int offset = 0; vector originalV = v; @@ -46,8 +46,6 @@ int main(int argc, char** argv) vector< Test > tests; - ParallelApplyStore store; - const int ALL = Node::comm().size(); Test tIntervalStatic; @@ -112,7 +110,9 @@ int main(int argc, char** argv) for( unsigned int i = 0; i < tests.size(); ++i ) { - ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, store, 3 ); + // ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, store, 3 ); + ParallelApplyStore< int > store( plusOneInstance, v, 0, 3 ); + Job< JobData > job( *(tests[i].assign), 0, store ); if( job.isMaster() ) { From 6bb2ccfbd6be0bbb1e2c736dd116d757f767e82d Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 3 Jul 2012 13:57:20 +0200 Subject: [PATCH 39/52] Steps of MpiJob are now functors which can be wrapped (using decorator pattern). --- eo/src/mpi/eoMpi.h | 4 ++ eo/src/mpi/eoParallelApply.h | 112 +++++++++++++++++++--------------- eo/test/mpi/parallelApply.cpp | 3 +- eo/test/mpi/wrapper.cpp | 89 +++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 50 deletions(-) create mode 100644 eo/test/mpi/wrapper.cpp diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 9ad2bd7b..940f4129 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -44,6 +44,10 @@ namespace eo void data( JobData* _d ) { d = _d; + if( wrapped ) + { + wrapped->data( _d ); + } } protected: diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index bc85d438..94549fc3 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -17,14 +17,14 @@ namespace eo }; template - struct JobData + struct ParallelApplyData { - JobData( + ParallelApplyData( eoUF & _proc, std::vector& _pop, int _masterRank, // long _maxTime = 0, - int _packetSize + int _packetSize // FIXME = 1 ? ) : data( _pop ), func( _proc ), index( 0 ), size( _pop.size() ), packetSize( _packetSize ), masterRank( _masterRank ), comm( Node::comm() ) { @@ -35,7 +35,7 @@ namespace eo tempArray = new EOT[ _packetSize ]; } - ~JobData() + ~ParallelApplyData() { delete [] tempArray; } @@ -52,43 +52,16 @@ namespace eo bmpi::communicator& comm; }; - /* - template< typename EOT > - class ParallelApply : public Job< JobData > + template< class EOT > + class SendTaskParallelApply : public SendTaskFunction< ParallelApplyData > { public: + using SendTaskFunction< ParallelApplyData >::d; - ParallelApply( - // eoUF & _proc, - // std::vector& _pop, - AssignmentAlgorithm & algo, - int _masterRank, - const JobStore< JobData >& store - // long _maxTime = 0, - // int _packetSize = 1 - ) : - Job( algo, _masterRank, store ) - // Job( algo, _masterRank, _maxTime ), - func( _proc ), - data( _pop ), - packetSize( _packetSize ), - index( 0 ), - size( _pop.size() ) + SendTaskParallelApply( SendTaskParallelApply * w = 0 ) : SendTaskFunction< ParallelApplyData >( w ) { // empty } - - protected: - - // bmpi::communicator& comm; - }; - */ - - template< class EOT > - class SendTaskParallelApply : public SendTaskFunction< JobData > - { - public: - using SendTaskFunction< JobData >::d; // futureIndex, index, packetSize, size, comm, assignedTasks, data void operator()(int wrkRank) @@ -117,10 +90,15 @@ namespace eo }; template< class EOT > - class HandleResponseParallelApply : public HandleResponseFunction< JobData > + class HandleResponseParallelApply : public HandleResponseFunction< ParallelApplyData > { public: - using HandleResponseFunction< JobData >::d; + using HandleResponseFunction< ParallelApplyData >::d; + + HandleResponseParallelApply( HandleResponseParallelApply * w = 0 ) : HandleResponseFunction< ParallelApplyData >( w ) + { + // empty + } void operator()(int wrkRank) { @@ -129,10 +107,15 @@ namespace eo }; template< class EOT > - class ProcessTaskParallelApply : public ProcessTaskFunction< JobData > + class ProcessTaskParallelApply : public ProcessTaskFunction< ParallelApplyData > { public: - using ProcessTaskFunction< JobData >::d; + using ProcessTaskFunction< ParallelApplyData >::d; + + ProcessTaskParallelApply( ProcessTaskParallelApply * w = 0 ) : ProcessTaskFunction< ParallelApplyData >( w ) + { + // empty + } void operator()() { @@ -151,10 +134,15 @@ namespace eo }; template< class EOT > - class IsFinishedParallelApply : public IsFinishedFunction< JobData > + class IsFinishedParallelApply : public IsFinishedFunction< ParallelApplyData > { public: - using IsFinishedFunction< JobData >::d; + using IsFinishedFunction< ParallelApplyData >::d; + + IsFinishedParallelApply( IsFinishedParallelApply * w = 0 ) : IsFinishedFunction< ParallelApplyData >( w ) + { + // empty + } bool operator()() { @@ -163,7 +151,7 @@ namespace eo }; template< class EOT > - struct ParallelApplyStore : public JobStore< JobData > + struct ParallelApplyStore : public JobStore< ParallelApplyData > { ParallelApplyStore( eoUF & _proc, @@ -172,7 +160,7 @@ namespace eo // long _maxTime = 0, int _packetSize = 1 ) - : j( _proc, _pop, _masterRank, _packetSize ) + : _data( _proc, _pop, _masterRank, _packetSize ) { stpa = new SendTaskParallelApply; hrpa = new HandleResponseParallelApply; @@ -188,20 +176,46 @@ namespace eo delete ispa; } - SendTaskFunction< JobData >& sendTask() const { return *stpa; } - HandleResponseFunction< JobData >& handleResponse() const { return *hrpa; } - ProcessTaskFunction< JobData >& processTask() const { return *ptpa; } - IsFinishedFunction< JobData >& isFinished() const { return *ispa; } + SendTaskParallelApply< EOT >& sendTask() const { return *stpa; } + HandleResponseParallelApply< EOT >& handleResponse() const { return *hrpa; } + ProcessTaskParallelApply< EOT > & processTask() const { return *ptpa; } + IsFinishedParallelApply< EOT >& isFinished() const { return *ispa; } - JobData* data() { return &j; } + void sendTask( SendTaskParallelApply< EOT >* _stpa ) { stpa = _stpa; } + void handleResponse( HandleResponseParallelApply< EOT >* _hrpa ) { hrpa = _hrpa; } + void processTask( ProcessTaskParallelApply< EOT >* _ptpa ) { ptpa = _ptpa; } + void isFinished( IsFinishedParallelApply< EOT >* _ispa ) { ispa = _ispa; } + + ParallelApplyData* data() { return &_data; } protected: + // TODO commenter : Utiliser des pointeurs pour éviter d'écraser les fonctions wrappées SendTaskParallelApply* stpa; HandleResponseParallelApply* hrpa; ProcessTaskParallelApply* ptpa; IsFinishedParallelApply* ispa; - JobData j; + ParallelApplyData _data; + }; + + template< typename EOT > + class ParallelApply : public Job< ParallelApplyData > + { + public: + + ParallelApply( + AssignmentAlgorithm & algo, + int _masterRank, + ParallelApplyStore & store + ) : + Job< ParallelApplyData >( algo, _masterRank, store ) + { + // empty + } + + protected: + + // bmpi::communicator& comm; }; } } diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 4e331334..75b515e9 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -112,7 +112,8 @@ int main(int argc, char** argv) { // ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, store, 3 ); ParallelApplyStore< int > store( plusOneInstance, v, 0, 3 ); - Job< JobData > job( *(tests[i].assign), 0, store ); + // Job< JobData > job( *(tests[i].assign), 0, store ); + ParallelApply< int > job( *(tests[i].assign), 0, store ); if( job.isMaster() ) { diff --git a/eo/test/mpi/wrapper.cpp b/eo/test/mpi/wrapper.cpp new file mode 100644 index 00000000..c653d5f8 --- /dev/null +++ b/eo/test/mpi/wrapper.cpp @@ -0,0 +1,89 @@ +# include +# include + +# include + +# include +using namespace std; + +using namespace eo::mpi; + +struct plusOne : public eoUF< int&, void > +{ + void operator() ( int & x ) + { + ++x; + } +}; + +template< class EOT > +struct ShowWrappedResult : public IsFinishedParallelApply +{ + using IsFinishedParallelApply::wrapped; + + ShowWrappedResult ( IsFinishedParallelApply * w ) : IsFinishedParallelApply( w ), times( 0 ) + { + // empty + } + + bool operator()() + { + bool wrappedValue = wrapped->operator()(); // (*wrapped)(); + cout << times << ") Wrapped function would say that it is " << ( wrappedValue ? "":"not ") << "finished" << std::endl; + ++times; + return wrappedValue; + } + + private: + int times; +}; + +// These tests require at least 3 processes to be launched. +int main(int argc, char** argv) +{ + // eo::log << eo::setlevel( eo::debug ); + eo::log << eo::setlevel( eo::quiet ); + + Node::init( argc, argv ); + + srand( time(0) ); + vector v; + for( int i = 0; i < 1000; ++i ) + { + v.push_back( rand() ); + } + + int offset = 0; + vector originalV = v; + + plusOne plusOneInstance; + + StaticAssignmentAlgorithm assign( v.size() ); + + ParallelApplyStore< int > store( plusOneInstance, v, 0, 1 ); + IsFinishedParallelApply< int >& wrapped = store.isFinished(); + ShowWrappedResult< int >* wrapper = new ShowWrappedResult( &wrapped ); + store.isFinished( wrapper ); + + // Job< ParallelApplyData > job( assign, 0, store ); + ParallelApply job( assign, 0, store ); + job.run(); + + if( job.isMaster() ) + { + ++offset; + for(int i = 0; i < v.size(); ++i) + { + cout << v[i] << ' '; + if( originalV[i] + offset != v[i] ) + { + cout << " <-- ERROR at this point." << endl; + exit( EXIT_FAILURE ); + } + } + cout << endl; + } + + return 0; +} + From 63f12c4e1ce3bfc325527013fbee9eaae751a504 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 3 Jul 2012 14:48:47 +0200 Subject: [PATCH 40/52] JobStore has now getters, setters and wrappers methods. --- eo/src/mpi/eoMpi.h | 101 ++++++++++++++++++++++++++++------- eo/src/mpi/eoParallelApply.h | 51 +++++++----------- eo/test/mpi/wrapper.cpp | 13 +++-- 3 files changed, 108 insertions(+), 57 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 940f4129..7dafe128 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -25,6 +25,7 @@ namespace eo namespace Channel { const int Commands = 0; + const int Messages = 1; } namespace Message @@ -33,26 +34,32 @@ namespace eo const int Finish = 1; } + template< typename JobData, typename Wrapped > struct SharedDataFunction { - SharedDataFunction( Wrapped * w ) + SharedDataFunction( Wrapped * w = 0 ) : _wrapped( w ) { - wrapped = w; + // empty + } + + void wrapped( Wrapped * w ) + { + _wrapped = w; } void data( JobData* _d ) { d = _d; - if( wrapped ) + if( _wrapped ) { - wrapped->data( _d ); + _wrapped->data( _d ); } } protected: JobData* d; - Wrapped* wrapped; + Wrapped* _wrapped; }; template< typename JobData > @@ -110,11 +117,78 @@ namespace eo template< typename JobData > struct JobStore { - virtual SendTaskFunction & sendTask() const = 0; - virtual HandleResponseFunction & handleResponse() const = 0; - virtual ProcessTaskFunction & processTask() const = 0; - virtual IsFinishedFunction & isFinished() const = 0; + JobStore( + SendTaskFunction* stf, + HandleResponseFunction* hrf, + ProcessTaskFunction* ptf, + IsFinishedFunction* iff + ) : + _stf( stf ), _hrf( hrf ), _ptf( ptf ), _iff( iff ) + { + // empty + } + + JobStore() + { + // empty + } + + SendTaskFunction & sendTask() { return *_stf; } + HandleResponseFunction & handleResponse() { return *_hrf; } + ProcessTaskFunction & processTask() { return *_ptf; } + IsFinishedFunction & isFinished() { return *_iff; } + + void sendTask( SendTaskFunction* stf ) { _stf = stf; } + void handleResponse( HandleResponseFunction* hrf ) { _hrf = hrf; } + void processTask( ProcessTaskFunction* ptf ) { _ptf = ptf; } + void isFinished( IsFinishedFunction* iff ) { _iff = iff; } + + void wrapSendTask( SendTaskFunction* stf ) + { + if( stf ) + { + stf->wrapped( _stf ); + _stf = stf; + } + } + + void wrapHandleResponse( HandleResponseFunction* hrf ) + { + if( hrf ) + { + hrf->wrapped( _hrf ); + _hrf = hrf; + } + } + + void wrapProcessTask( ProcessTaskFunction* ptf ) + { + if( ptf ) + { + ptf->wrapped( _ptf ); + _ptf = ptf; + } + } + + void wrapIsFinished( IsFinishedFunction* iff ) + { + if( iff ) + { + iff->wrapped( _iff ); + _iff = iff; + } + } + + // TODO commenter : laissé à la couche d'en dessous car impossible d'initialiser une donnée membre d'une classe mère depuis une classe fille. virtual JobData* data() = 0; + + protected: + + // TODO commenter : Utiliser des pointeurs pour éviter d'écraser les fonctions wrappées + SendTaskFunction< JobData >* _stf; + HandleResponseFunction< JobData >* _hrf; + ProcessTaskFunction< JobData >* _ptf; + IsFinishedFunction< JobData >* _iff; }; template< class JobData > @@ -141,15 +215,6 @@ namespace eo isFinished.data( store.data() ); } - /* - // master - virtual bool isFinished() = 0; - virtual void sendTask( int wrkRank ) = 0; - virtual void handleResponse( int wrkRank ) = 0; - // worker - virtual void processTask( ) = 0; - */ - protected: SendTaskFunction & sendTask; diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 94549fc3..1487da9f 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -153,6 +153,11 @@ namespace eo template< class EOT > struct ParallelApplyStore : public JobStore< ParallelApplyData > { + using JobStore< ParallelApplyData >::_stf; + using JobStore< ParallelApplyData >::_hrf; + using JobStore< ParallelApplyData >::_ptf; + using JobStore< ParallelApplyData >::_iff; + ParallelApplyStore( eoUF & _proc, std::vector& _pop, @@ -162,42 +167,28 @@ namespace eo ) : _data( _proc, _pop, _masterRank, _packetSize ) { - stpa = new SendTaskParallelApply; - hrpa = new HandleResponseParallelApply; - ptpa = new ProcessTaskParallelApply; - ispa = new IsFinishedParallelApply; + _stf = new SendTaskParallelApply; + _hrf = new HandleResponseParallelApply; + _ptf = new ProcessTaskParallelApply; + _iff = new IsFinishedParallelApply; } - ~ParallelApplyStore() - { - delete stpa; - delete hrpa; - delete ptpa; - delete ispa; - } - - SendTaskParallelApply< EOT >& sendTask() const { return *stpa; } - HandleResponseParallelApply< EOT >& handleResponse() const { return *hrpa; } - ProcessTaskParallelApply< EOT > & processTask() const { return *ptpa; } - IsFinishedParallelApply< EOT >& isFinished() const { return *ispa; } - - void sendTask( SendTaskParallelApply< EOT >* _stpa ) { stpa = _stpa; } - void handleResponse( HandleResponseParallelApply< EOT >* _hrpa ) { hrpa = _hrpa; } - void processTask( ProcessTaskParallelApply< EOT >* _ptpa ) { ptpa = _ptpa; } - void isFinished( IsFinishedParallelApply< EOT >* _ispa ) { ispa = _ispa; } - ParallelApplyData* data() { return &_data; } - protected: - // TODO commenter : Utiliser des pointeurs pour éviter d'écraser les fonctions wrappées - SendTaskParallelApply* stpa; - HandleResponseParallelApply* hrpa; - ProcessTaskParallelApply* ptpa; - IsFinishedParallelApply* ispa; + ~ParallelApplyStore() + { + delete _stf; + delete _hrf; + delete _ptf; + delete _iff; + } + protected: ParallelApplyData _data; }; + // TODO commentaire : impossible de faire un typedef sur un template sans passer + // par un traits => complique la tâche de l'utilisateur pour rien. template< typename EOT > class ParallelApply : public Job< ParallelApplyData > { @@ -212,10 +203,6 @@ namespace eo { // empty } - - protected: - - // bmpi::communicator& comm; }; } } diff --git a/eo/test/mpi/wrapper.cpp b/eo/test/mpi/wrapper.cpp index c653d5f8..e2bf25d6 100644 --- a/eo/test/mpi/wrapper.cpp +++ b/eo/test/mpi/wrapper.cpp @@ -19,16 +19,16 @@ struct plusOne : public eoUF< int&, void > template< class EOT > struct ShowWrappedResult : public IsFinishedParallelApply { - using IsFinishedParallelApply::wrapped; + using IsFinishedParallelApply::_wrapped; - ShowWrappedResult ( IsFinishedParallelApply * w ) : IsFinishedParallelApply( w ), times( 0 ) + ShowWrappedResult ( IsFinishedParallelApply * w = 0 ) : IsFinishedParallelApply( w ), times( 0 ) { // empty } bool operator()() { - bool wrappedValue = wrapped->operator()(); // (*wrapped)(); + bool wrappedValue = _wrapped->operator()(); // (*_wrapped)(); cout << times << ") Wrapped function would say that it is " << ( wrappedValue ? "":"not ") << "finished" << std::endl; ++times; return wrappedValue; @@ -61,12 +61,11 @@ int main(int argc, char** argv) StaticAssignmentAlgorithm assign( v.size() ); ParallelApplyStore< int > store( plusOneInstance, v, 0, 1 ); - IsFinishedParallelApply< int >& wrapped = store.isFinished(); - ShowWrappedResult< int >* wrapper = new ShowWrappedResult( &wrapped ); - store.isFinished( wrapper ); + store.wrapIsFinished( new ShowWrappedResult ); - // Job< ParallelApplyData > job( assign, 0, store ); ParallelApply job( assign, 0, store ); + // Equivalent to: + // Job< ParallelApplyData > job( assign, 0, store ); job.run(); if( job.isMaster() ) From 564cc3bccdd57f5af2487c575c0c4809a208e62f Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 3 Jul 2012 14:51:34 +0200 Subject: [PATCH 41/52] Using eo::mpi::DEFAULT_MASTER instead of raw constants. --- eo/src/mpi/eoMpi.h | 1 + eo/test/mpi/parallelApply.cpp | 6 +++--- eo/test/mpi/wrapper.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 7dafe128..8a4e86b6 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -34,6 +34,7 @@ namespace eo const int Finish = 1; } + const int DEFAULT_MASTER = 0; template< typename JobData, typename Wrapped > struct SharedDataFunction diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 75b515e9..7ccbf3d9 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -111,9 +111,9 @@ int main(int argc, char** argv) for( unsigned int i = 0; i < tests.size(); ++i ) { // ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, store, 3 ); - ParallelApplyStore< int > store( plusOneInstance, v, 0, 3 ); - // Job< JobData > job( *(tests[i].assign), 0, store ); - ParallelApply< int > job( *(tests[i].assign), 0, store ); + ParallelApplyStore< int > store( plusOneInstance, v, eo::mpi::DEFAULT_MASTER, 3 ); + // Job< JobData > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store ); + ParallelApply< int > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store ); if( job.isMaster() ) { diff --git a/eo/test/mpi/wrapper.cpp b/eo/test/mpi/wrapper.cpp index e2bf25d6..d8b72c98 100644 --- a/eo/test/mpi/wrapper.cpp +++ b/eo/test/mpi/wrapper.cpp @@ -60,10 +60,10 @@ int main(int argc, char** argv) StaticAssignmentAlgorithm assign( v.size() ); - ParallelApplyStore< int > store( plusOneInstance, v, 0, 1 ); + ParallelApplyStore< int > store( plusOneInstance, v, eo::mpi::DEFAULT_MASTER, 1 ); store.wrapIsFinished( new ShowWrappedResult ); - ParallelApply job( assign, 0, store ); + ParallelApply job( assign, eo::mpi::DEFAULT_MASTER, store ); // Equivalent to: // Job< ParallelApplyData > job( assign, 0, store ); job.run(); From 1d3790a0e466c193d8c74ac46af76f68671dc1c0 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 3 Jul 2012 15:07:27 +0200 Subject: [PATCH 42/52] Updating multiple roles test. --- eo/test/mpi/multipleRoles.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/eo/test/mpi/multipleRoles.cpp b/eo/test/mpi/multipleRoles.cpp index 5b829c89..ce10f621 100644 --- a/eo/test/mpi/multipleRoles.cpp +++ b/eo/test/mpi/multipleRoles.cpp @@ -31,7 +31,9 @@ void subtask( vector& v, int rank ) workers.push_back( rank + 4 ); DynamicAssignmentAlgorithm algo( workers ); SubWork sw; - ParallelApply job( sw, v, algo, rank ); + + ParallelApplyStore store( sw, v, rank ); + ParallelApply job( algo, rank, store ); job.run(); } @@ -72,7 +74,8 @@ int main(int argc, char** argv) { Work w; DynamicAssignmentAlgorithm algo( 1, 2 ); - ParallelApply< vector > job( w, metaV, algo, 0 ); + ParallelApplyStore< vector > store( w, metaV, 0 ); + ParallelApply< vector > job( algo, 0, store ); job.run(); if( job.isMaster() ) { From 24c29db6f3f8caeabbda8cf5c893e3788738b93e Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 3 Jul 2012 15:53:19 +0200 Subject: [PATCH 43/52] Using again parallel apply into eoPopEvalFunc::eoParallelPopEvalFunc. --- eo/src/apply.h | 4 +- eo/src/eoPopEvalFunc.h | 9 ++++ eo/src/mpi/eoMultiParallelApply.h | 52 ++++++++++++----------- eo/src/mpi/eoParallelApply.h | 21 ++++++---- eo/src/mpi/eoTerminateJob.h | 68 +++++++++++++++++++++++++++++++ eo/test/mpi/eval.cpp | 5 ++- eo/test/mpi/parallelApply.cpp | 1 - 7 files changed, 125 insertions(+), 35 deletions(-) diff --git a/eo/src/apply.h b/eo/src/apply.h index 7e59c21b..86fc8927 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -36,6 +36,7 @@ # ifdef WITH_MPI # include # include +# include # endif // WITH_MPI /** @@ -94,7 +95,8 @@ void parallelApply( int _packetSize, int _maxTime) { - eo::mpi::MultiParallelApply job( _proc, _pop, _algo, _masterRank, _packetSize, _maxTime ); + eo::mpi::ParallelEvalStore store( _proc, _pop, _masterRank, _packetSize ); + eo::mpi::ParallelApply job( _algo, _masterRank, store ); job.run(); } #endif diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index 77473eb1..1b7b447f 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -99,6 +99,15 @@ public: // empty } + ~eoParallelPopLoopEval() + { + if( eo::mpi::Node::comm().rank() == masterRank ) + { + eo::mpi::EmptyJob job( assignAlgo, masterRank ); + job.run(); + } + } + /** Do the job: simple loop over the offspring */ void operator()(eoPop & _parents, eoPop & _offspring) { diff --git a/eo/src/mpi/eoMultiParallelApply.h b/eo/src/mpi/eoMultiParallelApply.h index f3df801d..121e0b74 100644 --- a/eo/src/mpi/eoMultiParallelApply.h +++ b/eo/src/mpi/eoMultiParallelApply.h @@ -1,4 +1,3 @@ - # ifndef __EO_MULTI_PARALLEL_APPLY_H__ # define __EO_MULTI_PARALLEL_APPLY_H__ @@ -8,36 +7,41 @@ namespace eo { namespace mpi { - template< typename EOT > - class MultiParallelApply : public ParallelApply + template< class EOT > + class ProcessTaskParallelEval : public ProcessTaskParallelApply { public: - // using ParallelApply::comm; - using ParallelApply::masterRank; + using ProcessTaskParallelApply::_wrapped; + using ProcessTaskParallelApply::d; - MultiParallelApply( - eoUF & _proc, - std::vector& _pop, - AssignmentAlgorithm & algo, - int _masterRank, - int _packetSize = 1, - long _maxTime = 0 - ) : - ParallelApply( _proc, _pop, algo, _masterRank, _packetSize, _maxTime ) + void operator()() + { + int order = Message::Continue; + while( order != Message::Finish ) { - // empty + _wrapped->operator()(); + d->comm.recv( d->masterRank, Channel::Commands, order ); } + } + }; - virtual void processTask( ) - { - int order = Message::Continue; - while( order != Message::Finish ) - { - ParallelApply::processTask( ); - ParallelApply::comm.recv( masterRank, Channel::Commands, order ); - } - } + template< class EOT > + struct ParallelEvalStore : public ParallelApplyStore< EOT > + { + using ParallelApplyStore::wrapProcessTask; + + ParallelEvalStore( + eoUF & _proc, + std::vector& _pop, + int _masterRank, + // long _maxTime = 0, + int _packetSize = 1 + ) : + ParallelApplyStore< EOT >( _proc, _pop, _masterRank, _packetSize ) + { + wrapProcessTask( new ProcessTaskParallelEval ); + } }; } } diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index 1487da9f..f195965a 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -24,7 +24,7 @@ namespace eo std::vector& _pop, int _masterRank, // long _maxTime = 0, - int _packetSize // FIXME = 1 ? + int _packetSize ) : data( _pop ), func( _proc ), index( 0 ), size( _pop.size() ), packetSize( _packetSize ), masterRank( _masterRank ), comm( Node::comm() ) { @@ -163,14 +163,19 @@ namespace eo std::vector& _pop, int _masterRank, // long _maxTime = 0, - int _packetSize = 1 - ) - : _data( _proc, _pop, _masterRank, _packetSize ) + int _packetSize = 1, + // JobStore functors + SendTaskParallelApply * stpa = new SendTaskParallelApply, + HandleResponseParallelApply* hrpa = new HandleResponseParallelApply, + ProcessTaskParallelApply* ptpa = new ProcessTaskParallelApply, + IsFinishedParallelApply* ifpa = new IsFinishedParallelApply + ) : + _data( _proc, _pop, _masterRank, _packetSize ) { - _stf = new SendTaskParallelApply; - _hrf = new HandleResponseParallelApply; - _ptf = new ProcessTaskParallelApply; - _iff = new IsFinishedParallelApply; + _stf = stpa; + _hrf = hrpa; + _ptf = ptpa; + _iff = ifpa; } ParallelApplyData* data() { return &_data; } diff --git a/eo/src/mpi/eoTerminateJob.h b/eo/src/mpi/eoTerminateJob.h index 4cb18225..6c63cb69 100644 --- a/eo/src/mpi/eoTerminateJob.h +++ b/eo/src/mpi/eoTerminateJob.h @@ -7,6 +7,73 @@ namespace eo { namespace mpi { + struct DummySendTaskFunction : public SendTaskFunction + { + void operator()( int _ ) + { + } + }; + + struct DummyHandleResponseFunction : public HandleResponseFunction + { + void operator()( int _ ) + { + } + }; + + struct DummyProcessTaskFunction : public ProcessTaskFunction + { + void operator()() + { + // nothing! + } + }; + + struct DummyIsFinishedFunction : public IsFinishedFunction + { + bool operator()() + { + return true; + } + }; + + struct DummyJobStore : public JobStore + { + using JobStore::_stf; + using JobStore::_hrf; + using JobStore::_ptf; + using JobStore::_iff; + + DummyJobStore() + { + _stf = new DummySendTaskFunction; + _hrf = new DummyHandleResponseFunction; + _ptf = new DummyProcessTaskFunction; + _iff = new DummyIsFinishedFunction; + } + + ~DummyJobStore() + { + delete _stf; + delete _hrf; + delete _ptf; + delete _iff; + } + + void* data() { return 0; } + }; + + struct EmptyJob : public Job + { + EmptyJob( AssignmentAlgorithm& algo, int masterRank ) : + Job( algo, masterRank, *(new DummyJobStore) ) + // FIXME memory leak => will be corrected by using const correctness + { + // empty + } + }; + + /* class TerminateJob : public Job { public: @@ -36,6 +103,7 @@ namespace eo return true; } }; + */ } } diff --git a/eo/test/mpi/eval.cpp b/eo/test/mpi/eval.cpp index 7e15ac6f..7d8666cb 100644 --- a/eo/test/mpi/eval.cpp +++ b/eo/test/mpi/eval.cpp @@ -11,6 +11,8 @@ #include +#include + #include #include @@ -83,6 +85,7 @@ typedef eoRealSerializable EOT; int main(int ac, char** av) { eo::mpi::Node::init( ac, av ); + eo::log << eo::setlevel( eo::debug ); eoParser parser(ac, av); @@ -110,7 +113,7 @@ int main(int ac, char** av) eo::log << eo::setlevel( eo::debug ); eo::mpi::DynamicAssignmentAlgorithm assign; - eoParallelPopLoopEval< EOT > popEval( eval, assign, 0, 3 ); + eoParallelPopLoopEval< EOT > popEval( eval, assign, eo::mpi::DEFAULT_MASTER, 3 ); popEval( pop, pop ); eo::log << eo::quiet << "DONE!" << std::endl; diff --git a/eo/test/mpi/parallelApply.cpp b/eo/test/mpi/parallelApply.cpp index 7ccbf3d9..d562ef0e 100644 --- a/eo/test/mpi/parallelApply.cpp +++ b/eo/test/mpi/parallelApply.cpp @@ -110,7 +110,6 @@ int main(int argc, char** argv) for( unsigned int i = 0; i < tests.size(); ++i ) { - // ParallelApply job( plusOneInstance, v, *(tests[i].assign), 0, store, 3 ); ParallelApplyStore< int > store( plusOneInstance, v, eo::mpi::DEFAULT_MASTER, 3 ); // Job< JobData > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store ); ParallelApply< int > job( *(tests[i].assign), eo::mpi::DEFAULT_MASTER, store ); From 603268b053dafbe0c545486f2354b1970d683a79 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Wed, 4 Jul 2012 10:53:57 +0200 Subject: [PATCH 44/52] Added store management to eoPopEvalFunc. --- eo/src/apply.h | 8 +-- eo/src/eoPopEvalFunc.h | 100 ++++++++++++++++++------------ eo/src/mpi/eoMultiParallelApply.h | 14 ++++- eo/src/mpi/eoParallelApply.h | 12 +++- eo/test/mpi/eval.cpp | 66 +++++++++++++++++--- 5 files changed, 143 insertions(+), 57 deletions(-) diff --git a/eo/src/apply.h b/eo/src/apply.h index 86fc8927..df3c43e1 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -88,15 +88,13 @@ void apply(eoUF& _proc, std::vector& _pop) #ifdef WITH_MPI template void parallelApply( - eoUF& _proc, std::vector& _pop, eo::mpi::AssignmentAlgorithm& _algo, int _masterRank, - int _packetSize, - int _maxTime) + eo::mpi::ParallelEvalStore & _store ) { - eo::mpi::ParallelEvalStore store( _proc, _pop, _masterRank, _packetSize ); - eo::mpi::ParallelApply job( _algo, _masterRank, store ); + _store.data( _pop ); + eo::mpi::ParallelApply job( _algo, _masterRank, _store ); job.run(); } #endif diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index 1b7b447f..ce4dc5cf 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -80,48 +80,72 @@ private: #ifdef WITH_MPI // TODO TODOB commenter template -class eoParallelPopLoopEval : public eoPopEvalFunc { -public: - /** Ctor: set value of embedded eoEvalFunc */ - eoParallelPopLoopEval( - eoEvalFunc & _eval, - eo::mpi::AssignmentAlgorithm& _assignAlgo, - int _masterRank, - int _packetSize = 1, - int _maxTime = 0 - ) : - eval(_eval), - assignAlgo( _assignAlgo ), - masterRank( _masterRank ), - packetSize( _packetSize ), - maxTime( _maxTime ) - { - // empty - } +class eoParallelPopLoopEval : public eoPopEvalFunc +{ + public: + /** Ctor: set value of embedded eoEvalFunc */ + eoParallelPopLoopEval( + eoEvalFunc & _eval, + eo::mpi::AssignmentAlgorithm& _assignAlgo, + int _masterRank, + int _packetSize = 1 + ) : + eval(_eval), + assignAlgo( _assignAlgo ), + masterRank( _masterRank ), + packetSize( _packetSize ), + needToDeleteStore( true ) + { + store = new eo::mpi::ParallelEvalStore( _eval, _masterRank, _packetSize ); + } - ~eoParallelPopLoopEval() - { - if( eo::mpi::Node::comm().rank() == masterRank ) - { - eo::mpi::EmptyJob job( assignAlgo, masterRank ); - job.run(); - } - } + eoParallelPopLoopEval( + eoEvalFunc & _eval, + eo::mpi::AssignmentAlgorithm& _assignAlgo, + eo::mpi::ParallelEvalStore* _store, + int _masterRank, + int _packetSize = 1 + ) : + eval(_eval), + assignAlgo( _assignAlgo ), + masterRank( _masterRank ), + packetSize( _packetSize ), + needToDeleteStore( false ), + store( _store ) + { + // empty + } - /** Do the job: simple loop over the offspring */ - void operator()(eoPop & _parents, eoPop & _offspring) - { - (void)_parents; - parallelApply(eval, _offspring, assignAlgo, masterRank, packetSize, maxTime); - } + ~eoParallelPopLoopEval() + { + if( eo::mpi::Node::comm().rank() == masterRank ) + { + eo::mpi::EmptyJob job( assignAlgo, masterRank ); + job.run(); + } -private: - eoEvalFunc & eval; + if( needToDeleteStore ) + { + delete store; + } + } - eo::mpi::AssignmentAlgorithm & assignAlgo; - int masterRank; - int packetSize; - int maxTime; + /** Do the job: simple loop over the offspring */ + void operator()(eoPop & _parents, eoPop & _offspring) + { + (void)_parents; + parallelApply(_offspring, assignAlgo, masterRank, *store); + } + + private: + eoEvalFunc & eval; + + eo::mpi::AssignmentAlgorithm & assignAlgo; + eo::mpi::ParallelEvalStore* store; + int masterRank; + int packetSize; + + bool needToDeleteStore; }; #endif diff --git a/eo/src/mpi/eoMultiParallelApply.h b/eo/src/mpi/eoMultiParallelApply.h index 121e0b74..85b1689e 100644 --- a/eo/src/mpi/eoMultiParallelApply.h +++ b/eo/src/mpi/eoMultiParallelApply.h @@ -24,6 +24,11 @@ namespace eo d->comm.recv( d->masterRank, Channel::Commands, order ); } } + + ~ProcessTaskParallelEval() + { + delete _wrapped; + } }; template< class EOT > @@ -33,15 +38,20 @@ namespace eo ParallelEvalStore( eoUF & _proc, - std::vector& _pop, int _masterRank, // long _maxTime = 0, int _packetSize = 1 ) : - ParallelApplyStore< EOT >( _proc, _pop, _masterRank, _packetSize ) + ParallelApplyStore< EOT >( _proc, *( new std::vector ), _masterRank, _packetSize ) + // FIXME memory leak because of vector ==> use const correctness { wrapProcessTask( new ProcessTaskParallelEval ); } + + void data( std::vector& _pop ) + { + ParallelApplyStore::_data.init( _pop ); + } }; } } diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index f195965a..faedc7b3 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -21,7 +21,7 @@ namespace eo { ParallelApplyData( eoUF & _proc, - std::vector& _pop, + std::vector & _pop, int _masterRank, // long _maxTime = 0, int _packetSize @@ -35,6 +35,14 @@ namespace eo tempArray = new EOT[ _packetSize ]; } + void init( std::vector& _pop ) + { + index = 0; + size = _pop.size(); + data = _pop; + assignedTasks.clear(); + } + ~ParallelApplyData() { delete [] tempArray; @@ -180,7 +188,7 @@ namespace eo ParallelApplyData* data() { return &_data; } - ~ParallelApplyStore() + virtual ~ParallelApplyStore() { delete _stf; delete _hrf; diff --git a/eo/test/mpi/eval.cpp b/eo/test/mpi/eval.cpp index 7d8666cb..06fa8ad3 100644 --- a/eo/test/mpi/eval.cpp +++ b/eo/test/mpi/eval.cpp @@ -82,10 +82,40 @@ class eoRealSerializable : public eoReal< eoMinimizingFitness >, public eoserial typedef eoRealSerializable EOT; +struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply +{ + CatBestAnswers() + { + best.fitness( 1000000000. ); + } + + using eo::mpi::HandleResponseParallelApply::_wrapped; + using eo::mpi::HandleResponseParallelApply::d; + + void operator()(int wrkRank) + { + int index = d->assignedTasks[wrkRank].index; + int size = d->assignedTasks[wrkRank].size; + (*_wrapped)( wrkRank ); + for(int i = index; i < index+size; ++i) + { + if( best.fitness() < d->data[ i ].fitness() ) + { + eo::log << eo::quiet << "Better solution found:" << d->data[i].fitness() << std::endl; + best = d->data[ i ]; + } + } + } + + protected: + + EOT best; +}; + int main(int ac, char** av) { eo::mpi::Node::init( ac, av ); - eo::log << eo::setlevel( eo::debug ); + eo::log << eo::setlevel( eo::quiet ); eoParser parser(ac, av); @@ -106,17 +136,33 @@ int main(int ac, char** av) eoEvalFuncPtr< EOT, double, const std::vector< double >& > mainEval( real_value ); eoEvalFuncCounter< EOT > eval( mainEval ); - eoPop< EOT > pop( popSize, init ); - - eo::log << "Size of population : " << popSize << std::endl; - - eo::log << eo::setlevel( eo::debug ); - + int rank = eo::mpi::Node::comm().rank(); eo::mpi::DynamicAssignmentAlgorithm assign; - eoParallelPopLoopEval< EOT > popEval( eval, assign, eo::mpi::DEFAULT_MASTER, 3 ); - popEval( pop, pop ); + if( rank == eo::mpi::DEFAULT_MASTER ) + { + eoPop< EOT > pop( popSize, init ); - eo::log << eo::quiet << "DONE!" << std::endl; + eo::log << "Size of population : " << popSize << std::endl; + + eo::mpi::ParallelEvalStore< EOT > store( eval, eo::mpi::DEFAULT_MASTER ); + store.wrapHandleResponse( new CatBestAnswers ); + + eoParallelPopLoopEval< EOT > popEval( eval, assign, &store, eo::mpi::DEFAULT_MASTER, 3 ); + eo::log << eo::quiet << "Before first evaluation." << std::endl; + popEval( pop, pop ); + eo::log << eo::quiet << "After first evaluation." << std::endl; + + pop = eoPop< EOT >( popSize, init ); + popEval( pop, pop ); + eo::log << eo::quiet << "After second evaluation." << std::endl; + + eo::log << eo::quiet << "DONE!" << std::endl; + } else + { + eoPop< EOT > pop( popSize, init ); + eoParallelPopLoopEval< EOT > popEval( eval, assign, eo::mpi::DEFAULT_MASTER, 3 ); + popEval( pop, pop ); + } return 0; } From 581b24af186c12ed9e4c46062d81c1028f3e6e5c Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Wed, 4 Jul 2012 13:24:10 +0200 Subject: [PATCH 45/52] Bugfix: a reference can't be reinitialized. Different vectors weren't recopied after evaluation. --- eo/src/mpi/eoParallelApply.h | 16 ++++++++++------ eo/test/mpi/eval.cpp | 6 +++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index faedc7b3..a0225471 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -26,7 +26,7 @@ namespace eo // long _maxTime = 0, int _packetSize ) : - data( _pop ), func( _proc ), index( 0 ), size( _pop.size() ), packetSize( _packetSize ), masterRank( _masterRank ), comm( Node::comm() ) + _data( &_pop ), func( _proc ), index( 0 ), size( _pop.size() ), packetSize( _packetSize ), masterRank( _masterRank ), comm( Node::comm() ) { if ( _packetSize <= 0 ) { @@ -39,7 +39,7 @@ namespace eo { index = 0; size = _pop.size(); - data = _pop; + _data = &_pop; assignedTasks.clear(); } @@ -48,7 +48,12 @@ namespace eo delete [] tempArray; } - std::vector & data; + std::vector& data() + { + return *_data; + } + + std::vector * _data; eoUF & func; int index; int size; @@ -71,7 +76,6 @@ namespace eo // empty } - // futureIndex, index, packetSize, size, comm, assignedTasks, data void operator()(int wrkRank) { int futureIndex; @@ -92,7 +96,7 @@ namespace eo d->assignedTasks[ wrkRank ].index = d->index; d->assignedTasks[ wrkRank ].size = sentSize; - d->comm.send( wrkRank, 1, & ( (d->data)[ d->index ] ) , sentSize ); + d->comm.send( wrkRank, 1, & ( (d->data())[ d->index ] ) , sentSize ); d->index = futureIndex; } }; @@ -110,7 +114,7 @@ namespace eo void operator()(int wrkRank) { - d->comm.recv( wrkRank, 1, & (d->data[ d->assignedTasks[wrkRank].index ] ), d->assignedTasks[wrkRank].size ); + d->comm.recv( wrkRank, 1, & (d->data()[ d->assignedTasks[wrkRank].index ] ), d->assignedTasks[wrkRank].size ); } }; diff --git a/eo/test/mpi/eval.cpp b/eo/test/mpi/eval.cpp index 06fa8ad3..312c9d65 100644 --- a/eo/test/mpi/eval.cpp +++ b/eo/test/mpi/eval.cpp @@ -99,10 +99,10 @@ struct CatBestAnswers : public eo::mpi::HandleResponseParallelApply (*_wrapped)( wrkRank ); for(int i = index; i < index+size; ++i) { - if( best.fitness() < d->data[ i ].fitness() ) + if( best.fitness() < d->data()[ i ].fitness() ) { - eo::log << eo::quiet << "Better solution found:" << d->data[i].fitness() << std::endl; - best = d->data[ i ]; + eo::log << eo::quiet << "Better solution found:" << d->data()[i].fitness() << std::endl; + best = d->data()[ i ]; } } } From 8753787725c603fa7de939e794a351617f2b7ae6 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 5 Jul 2012 18:16:49 +0200 Subject: [PATCH 46/52] Cleaning code (useless comments, suppressing warnings, etc...) --- eo/src/mpi/eoMpi.h | 21 --------------------- eo/src/mpi/eoTerminateJob.h | 2 ++ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 8a4e86b6..5f430be2 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -197,10 +197,8 @@ namespace eo { public: Job( AssignmentAlgorithm& _algo, int _masterRank, JobStore & store ) : - // Job( AssignmentAlgorithm& _algo, int _masterRank, long maxTime = 0 ) : assignmentAlgo( _algo ), comm( Node::comm() ), - // _maxTime( maxTime ), masterRank( _masterRank ), // Functors sendTask( store.sendTask() ), @@ -230,20 +228,8 @@ namespace eo eo::log << eo::debug; eo::log << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl; # endif - bool timeStopped = false; while( ! isFinished() ) { - // Time restrictions - /* - getrusage( RUSAGE_SELF , &_usage ); - _current = _usage.ru_utime.tv_sec + _usage.ru_stime.tv_sec; - if( _maxTime > 0 && _current > _maxTime ) - { - timeStopped = true; - break; - } - */ - timerStat.start("master_wait_for_assignee"); int assignee = assignmentAlgo.get( ); while( assignee <= 0 ) @@ -301,12 +287,6 @@ namespace eo # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; # endif - /* - if( timeStopped ) - { - throw eoMaxTimeException( _current ); - } - */ } void worker( ) @@ -359,7 +339,6 @@ namespace eo struct rusage _usage; long _current; - // const long _maxTime; }; } } diff --git a/eo/src/mpi/eoTerminateJob.h b/eo/src/mpi/eoTerminateJob.h index 6c63cb69..25e63eb7 100644 --- a/eo/src/mpi/eoTerminateJob.h +++ b/eo/src/mpi/eoTerminateJob.h @@ -11,6 +11,7 @@ namespace eo { void operator()( int _ ) { + ++_; } }; @@ -18,6 +19,7 @@ namespace eo { void operator()( int _ ) { + ++_; } }; From 23acd1a6331d5b3e46cdca1634a13cbed821f346 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 6 Jul 2012 10:06:34 +0200 Subject: [PATCH 47/52] Catching exceptions and sending them back in eoMpi loop. --- eo/src/mpi/eoMpi.h | 135 ++++++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 50 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 5f430be2..a2dcebf7 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -221,6 +221,63 @@ namespace eo ProcessTaskFunction & processTask; IsFinishedFunction & isFinished; + struct FinallyBlock + { + FinallyBlock( + int _totalWorkers, + AssignmentAlgorithm& _algo, + Job< JobData > & _that + ) : + totalWorkers( _totalWorkers ), + assignmentAlgo( _algo ), + comm( Node::comm() ), + that( _that ) + { + // empty + } + + ~FinallyBlock() + { +# ifndef NDEBUG + eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; +# endif + // frees all the idle workers + timerStat.start("master_wait_for_idles"); + std::vector idles = assignmentAlgo.idles(); + for(unsigned int i = 0; i < idles.size(); ++i) + { + comm.send( idles[i], Channel::Commands, Message::Finish ); + } + timerStat.stop("master_wait_for_idles"); + +# ifndef NDEBUG + eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl; +# endif + // wait for all responses + timerStat.start("master_wait_for_all_responses"); + while( assignmentAlgo.availableWorkers() != totalWorkers ) + { + bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); + int wrkRank = status.source(); + that.handleResponse( wrkRank ); + comm.send( wrkRank, Channel::Commands, Message::Finish ); + assignmentAlgo.confirm( wrkRank ); + } + timerStat.stop("master_wait_for_all_responses"); + +# ifndef NDEBUG + eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; +# endif + } + + protected: + + int totalWorkers; + bmpi::communicator & comm; + Job< JobData > & that; + AssignmentAlgorithm& assignmentAlgo; + }; + void master( ) { int totalWorkers = assignmentAlgo.availableWorkers(); @@ -228,65 +285,43 @@ namespace eo eo::log << eo::debug; eo::log << "[M" << comm.rank() << "] Have " << totalWorkers << " workers." << std::endl; # endif - while( ! isFinished() ) - { - timerStat.start("master_wait_for_assignee"); - int assignee = assignmentAlgo.get( ); - while( assignee <= 0 ) + try { + FinallyBlock finally( totalWorkers, assignmentAlgo, *this ); + while( ! isFinished() ) { + timerStat.start("master_wait_for_assignee"); + int assignee = assignmentAlgo.get( ); + while( assignee <= 0 ) + { # ifndef NDEBUG - eo::log << "[M" << comm.rank() << "] Waitin' for node..." << std::endl; + eo::log << "[M" << comm.rank() << "] Waitin' for node..." << std::endl; # endif - bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); - int wrkRank = status.source(); + bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); + int wrkRank = status.source(); # ifndef NDEBUG - eo::log << "[M" << comm.rank() << "] Node " << wrkRank << " just terminated." << std::endl; + eo::log << "[M" << comm.rank() << "] Node " << wrkRank << " just terminated." << std::endl; # endif - handleResponse( wrkRank ); - assignmentAlgo.confirm( wrkRank ); - assignee = assignmentAlgo.get( ); + handleResponse( wrkRank ); + assignmentAlgo.confirm( wrkRank ); + assignee = assignmentAlgo.get( ); + } + timerStat.stop("master_wait_for_assignee"); +# ifndef NDEBUG + eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; +# endif + + timerStat.start("master_wait_for_send"); + comm.send( assignee, Channel::Commands, Message::Continue ); + sendTask( assignee ); + timerStat.stop("master_wait_for_send"); } - timerStat.stop("master_wait_for_assignee"); -# ifndef NDEBUG - eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; -# endif - - timerStat.start("master_wait_for_send"); - comm.send( assignee, Channel::Commands, Message::Continue ); - sendTask( assignee ); - timerStat.stop("master_wait_for_send"); - } - -# ifndef NDEBUG - eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; -# endif - // frees all the idle workers - timerStat.start("master_wait_for_idles"); - std::vector idles = assignmentAlgo.idles(); - for(unsigned int i = 0; i < idles.size(); ++i) + } catch( const std::exception & e ) { - comm.send( idles[i], Channel::Commands, Message::Finish ); + std::string s = e.what(); + s.append( " in eoMpi loop"); + throw std::runtime_error( s ); } - timerStat.stop("master_wait_for_idles"); -# ifndef NDEBUG - eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl; -# endif - // wait for all responses - timerStat.start("master_wait_for_all_responses"); - while( assignmentAlgo.availableWorkers() != totalWorkers ) - { - bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); - int wrkRank = status.source(); - handleResponse( wrkRank ); - comm.send( wrkRank, Channel::Commands, Message::Finish ); - assignmentAlgo.confirm( wrkRank ); - } - timerStat.stop("master_wait_for_all_responses"); - -# ifndef NDEBUG - eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; -# endif } void worker( ) From 79c7a263a355f906cfd87a247e0d973475c72bca Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 6 Jul 2012 16:44:06 +0200 Subject: [PATCH 48/52] Static assignment algorithm works with parallel eval now. --- eo/src/apply.h | 1 + eo/src/mpi/eoMpiAssignmentAlgorithm.h | 14 +++++++++++++- eo/src/mpi/eoTerminateJob.h | 9 +++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/eo/src/apply.h b/eo/src/apply.h index df3c43e1..7845c14e 100644 --- a/eo/src/apply.h +++ b/eo/src/apply.h @@ -94,6 +94,7 @@ void parallelApply( eo::mpi::ParallelEvalStore & _store ) { _store.data( _pop ); + _algo.reinit( _pop.size() ); eo::mpi::ParallelApply job( _algo, _masterRank, _store ); job.run(); } diff --git a/eo/src/mpi/eoMpiAssignmentAlgorithm.h b/eo/src/mpi/eoMpiAssignmentAlgorithm.h index aa162d95..c3d24a19 100644 --- a/eo/src/mpi/eoMpiAssignmentAlgorithm.h +++ b/eo/src/mpi/eoMpiAssignmentAlgorithm.h @@ -16,6 +16,7 @@ namespace eo virtual int availableWorkers( ) = 0; virtual void confirm( int wrkRank ) = 0; virtual std::vector idles( ) = 0; + virtual void reinit( int runs ) = 0; }; struct DynamicAssignmentAlgorithm : public AssignmentAlgorithm @@ -79,6 +80,12 @@ namespace eo return availableWrk; } + void reinit( int _ ) + { + ++_; + // nothing to do + } + protected: std::vector< int > availableWrk; }; @@ -181,7 +188,7 @@ namespace eo void confirm( int rank ) { - int i = -1; + int i = -1; // i is the real index in table for( unsigned int j = 0; j < realRank.size(); ++j ) { if( realRank[j] == rank ) @@ -196,6 +203,11 @@ namespace eo ++freeWorkers; } + void reinit( int runs ) + { + init( realRank, runs ); + } + private: std::vector attributions; std::vector realRank; diff --git a/eo/src/mpi/eoTerminateJob.h b/eo/src/mpi/eoTerminateJob.h index 25e63eb7..d85aeeb0 100644 --- a/eo/src/mpi/eoTerminateJob.h +++ b/eo/src/mpi/eoTerminateJob.h @@ -73,6 +73,15 @@ namespace eo { // empty } + + ~EmptyJob() + { + std::vector< int > idles = assignmentAlgo.idles(); + for(unsigned i = 0, size = idles.size(); i < size; ++i) + { + comm.send( idles[i], Channel::Commands, Message::Kill ); + } + } }; /* From ad89e280f929200188911a87f18a364775217f88 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 10 Jul 2012 14:46:12 +0200 Subject: [PATCH 49/52] Serialization: using maximum precision when converting double to string. --- eo/src/serial/String.h | 2 ++ eo/src/serial/Utils.h | 1 + 2 files changed, 3 insertions(+) diff --git a/eo/src/serial/String.h b/eo/src/serial/String.h index 43a2cffa..6d81937f 100644 --- a/eo/src/serial/String.h +++ b/eo/src/serial/String.h @@ -3,6 +3,7 @@ # include # include +# include # include "Entity.h" @@ -60,6 +61,7 @@ template inline void String::deserialize( T & value ) { std::stringstream ss; + ss.precision(std::numeric_limits::digits10 + 1); ss << *this; ss >> value; } diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h index 70fd2f75..f40c08d9 100644 --- a/eo/src/serial/Utils.h +++ b/eo/src/serial/Utils.h @@ -76,6 +76,7 @@ namespace eoserial String* make( const T & value ) { std::stringstream ss; + ss.precision(std::numeric_limits::digits10 + 1); ss << value; return new String( ss.str() ); } From 606eef08d8eb19e6d78f98d02c127d2e72cd0fb8 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 10 Jul 2012 14:48:46 +0200 Subject: [PATCH 50/52] Difference between termination messages Kill (stops the worker) and Terminate (waits for another task). --- eo/src/mpi/eoMpi.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index a2dcebf7..0281c9d5 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -31,7 +31,8 @@ namespace eo namespace Message { const int Continue = 0; - const int Finish = 1; + const int Finish = 1; // TODO commentaire : différence entre finir une tâche et arrêter le worker à expliciter. + const int Kill = 2; } const int DEFAULT_MASTER = 0; @@ -239,6 +240,7 @@ namespace eo ~FinallyBlock() { # ifndef NDEBUG + eo::log << eo::debug; eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; # endif // frees all the idle workers @@ -264,7 +266,6 @@ namespace eo assignmentAlgo.confirm( wrkRank ); } timerStat.stop("master_wait_for_all_responses"); - # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; # endif @@ -321,7 +322,6 @@ namespace eo s.append( " in eoMpi loop"); throw std::runtime_error( s ); } - } void worker( ) @@ -330,27 +330,32 @@ namespace eo # ifndef NDEBUG eo::log << eo::debug; # endif + timerStat.start("worker_wait_for_order"); + comm.recv( masterRank, Channel::Commands, order ); + timerStat.stop("worker_wait_for_order"); + while( true ) { # ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; # endif - timerStat.start("worker_wait_for_order"); - comm.recv( masterRank, Channel::Commands, order ); - timerStat.stop("worker_wait_for_order"); - if ( order == Message::Finish ) + if ( order == Message::Kill ) { # ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Leaving worker task." << std::endl; # endif return; - } else + } else if( order == Message::Continue ) { # ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Processing task..." << std::endl; # endif processTask( ); } + + timerStat.start("worker_wait_for_order"); + comm.recv( masterRank, Channel::Commands, order ); + timerStat.stop("worker_wait_for_order"); } } From 76c4f19829096b0f3f7985980952357df9158493 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 10 Jul 2012 15:38:36 +0200 Subject: [PATCH 51/52] Separating parameters of store's default constructor of job parameters in eoParallelPopEval. --- eo/src/eoPopEvalFunc.h | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index ce4dc5cf..a728baa8 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -85,31 +85,28 @@ class eoParallelPopLoopEval : public eoPopEvalFunc public: /** Ctor: set value of embedded eoEvalFunc */ eoParallelPopLoopEval( - eoEvalFunc & _eval, + // Job parameters eo::mpi::AssignmentAlgorithm& _assignAlgo, int _masterRank, + // Default parameters for store + eoEvalFunc & _eval, int _packetSize = 1 ) : - eval(_eval), assignAlgo( _assignAlgo ), masterRank( _masterRank ), - packetSize( _packetSize ), needToDeleteStore( true ) { store = new eo::mpi::ParallelEvalStore( _eval, _masterRank, _packetSize ); } eoParallelPopLoopEval( - eoEvalFunc & _eval, + // Job parameters eo::mpi::AssignmentAlgorithm& _assignAlgo, - eo::mpi::ParallelEvalStore* _store, int _masterRank, - int _packetSize = 1 + eo::mpi::ParallelEvalStore* _store ) : - eval(_eval), assignAlgo( _assignAlgo ), masterRank( _masterRank ), - packetSize( _packetSize ), needToDeleteStore( false ), store( _store ) { @@ -131,20 +128,17 @@ class eoParallelPopLoopEval : public eoPopEvalFunc } /** Do the job: simple loop over the offspring */ - void operator()(eoPop & _parents, eoPop & _offspring) + void operator()( eoPop & _parents, eoPop & _offspring ) { (void)_parents; parallelApply(_offspring, assignAlgo, masterRank, *store); } private: - eoEvalFunc & eval; - eo::mpi::AssignmentAlgorithm & assignAlgo; - eo::mpi::ParallelEvalStore* store; int masterRank; - int packetSize; + eo::mpi::ParallelEvalStore* store; bool needToDeleteStore; }; #endif From 6600f1db51388626e52dc73fd37a18adc083ecf5 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 10 Jul 2012 16:08:35 +0200 Subject: [PATCH 52/52] Suppressed some warnings at compilation. --- eo/src/eoPopEvalFunc.h | 4 ++-- eo/src/mpi/eoMpi.h | 38 +++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/eo/src/eoPopEvalFunc.h b/eo/src/eoPopEvalFunc.h index a728baa8..d37eebaf 100644 --- a/eo/src/eoPopEvalFunc.h +++ b/eo/src/eoPopEvalFunc.h @@ -107,8 +107,8 @@ class eoParallelPopLoopEval : public eoPopEvalFunc ) : assignAlgo( _assignAlgo ), masterRank( _masterRank ), - needToDeleteStore( false ), - store( _store ) + store( _store ), + needToDeleteStore( false ) { // empty } diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 0281c9d5..0ef80c12 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -197,10 +197,13 @@ namespace eo class Job { public: - Job( AssignmentAlgorithm& _algo, int _masterRank, JobStore & store ) : + Job( AssignmentAlgorithm& _algo, + int _masterRank, + JobStore & store + ) : assignmentAlgo( _algo ), - comm( Node::comm() ), masterRank( _masterRank ), + comm( Node::comm() ), // Functors sendTask( store.sendTask() ), handleResponse( store.handleResponse() ), @@ -217,11 +220,6 @@ namespace eo protected: - SendTaskFunction & sendTask; - HandleResponseFunction & handleResponse; - ProcessTaskFunction & processTask; - IsFinishedFunction & isFinished; - struct FinallyBlock { FinallyBlock( @@ -231,8 +229,9 @@ namespace eo ) : totalWorkers( _totalWorkers ), assignmentAlgo( _algo ), - comm( Node::comm() ), - that( _that ) + that( _that ), + // global field + comm( Node::comm() ) { // empty } @@ -274,9 +273,10 @@ namespace eo protected: int totalWorkers; - bmpi::communicator & comm; - Job< JobData > & that; AssignmentAlgorithm& assignmentAlgo; + Job< JobData > & that; + + bmpi::communicator & comm; }; void master( ) @@ -372,13 +372,17 @@ namespace eo } protected: - AssignmentAlgorithm& assignmentAlgo; - bmpi::communicator& comm; - int masterRank; - bool _isMaster; - struct rusage _usage; - long _current; + AssignmentAlgorithm& assignmentAlgo; + int masterRank; + bmpi::communicator& comm; + + SendTaskFunction & sendTask; + HandleResponseFunction & handleResponse; + ProcessTaskFunction & processTask; + IsFinishedFunction & isFinished; + + bool _isMaster; }; } }