This commit is contained in:
Benjamin BOUVIER 2012-10-05 15:14:38 -07:00
commit 33a465e9b9
7 changed files with 683 additions and 39 deletions

View file

@ -118,12 +118,14 @@ Entity* Parser::parseRight(const std::string & str, size_t & pos)
{
Entity* value = 0;
ignoreChars( str, pos );
if ( str[ pos ] == '{' )
{
// next one is an object
DEBUG("We read an object.")
Object* obj = new Object;
pos += 1;
ignoreChars( str, pos );
while( pos < str.size() && str[ pos ] != '}' )
{
parseLeft( str, pos, obj );
@ -145,11 +147,13 @@ Entity* Parser::parseRight(const std::string & str, size_t & pos)
DEBUG("We read an array")
Array* array = new Array;
pos += 1;
ignoreChars( str, pos );
while( pos < str.size() && str[ pos ] != ']' )
{
Entity* child = parseRight( str, pos );
if ( child )
array->push_back( child );
ignoreChars( str, pos );
}
DEBUG("We've finished to read our array.")
pos += 1; // we're on the ], go to the next char

View file

@ -245,6 +245,18 @@ public :
double normal(double mean, double stdev)
{ return mean + normal(stdev); }
/**
* @brief Forgets the last cached value of normal(), so as to be able to perform some repeatable calls to normal().
*
* As normal() stores a cached value for performance purposes, sequences of pseudo random numbers can't be repeated
* when reseeding, since the cached value can be yield before a number is generated. To avoid that, this method
* allows one to clean the cache and force to regenerate a new pseudo random number.
*/
void clearCache()
{
cached = false;
}
/** Random numbers using a negative exponential distribution
@param mean Mean value of distribution

View file

@ -22,7 +22,7 @@ Authors:
# ifndef __EO_TIMER_H__
# define __EO_TIMER_H__
# include <sys/time.h> // time()
# include <sys/time.h> // gettimeofday()
# include <sys/resource.h> // rusage()
# include <vector> // std::vector
@ -61,7 +61,7 @@ class eoTimer
*/
void restart()
{
wc_start = time(NULL);
gettimeofday( &wc_start, NULL );
getrusage( RUSAGE_SELF, &_start );
}
@ -138,7 +138,9 @@ class eoTimer
*/
double wallclock()
{
return std::difftime( std::time(NULL) , wc_start );
struct timeval wc_end;
gettimeofday( &wc_end, NULL );
return ( wc_end.tv_sec - wc_start.tv_sec ) + ( wc_end.tv_usec - wc_start.tv_usec ) / 1000000.;
}
protected:
@ -149,7 +151,7 @@ class eoTimer
// Remainder (in milliseconds) for system time.
long int usremainder;
// Structure used to measure wallclock time.
time_t wc_start;
struct timeval wc_start;
};
/**
@ -203,6 +205,14 @@ class eoTimerStat
{
public:
/**
* @brief Initializes a timer stat object.
*/
eoTimerStat() : _forceDoMeasure(false)
{
// empty
}
/**
* @brief Statistic related to a key (name).
*
@ -272,6 +282,14 @@ class eoTimerStat
}
# endif
/**
* @brief Forces the measures to be retrieved.
*/
void forceDoMeasure()
{
_forceDoMeasure = true;
}
/**
* @brief Starts a new measure for the given key.
*
@ -282,7 +300,7 @@ class eoTimerStat
*/
void start( const std::string & key )
{
if( eo::parallel.doMeasure() )
if( eo::parallel.doMeasure() or _forceDoMeasure )
{
_timers[ key ].restart();
}
@ -300,7 +318,7 @@ class eoTimerStat
*/
void stop( const std::string& key )
{
if( eo::parallel.doMeasure() )
if( eo::parallel.doMeasure() or _forceDoMeasure )
{
Stat & s = _stats[ key ];
eoTimer & t = _timers[ key ];
@ -318,11 +336,21 @@ class eoTimerStat
return _stats;
}
/**
* @brief Empties the statistics map.
*/
void clear()
{
_stats.clear();
}
protected:
// Statistics map: links a key (string) to a statistic.
std::map< std::string, Stat > _stats;
// Timers map: links a key to its timer.
std::map< std::string, eoTimer > _timers;
// boolean to force the retrieval of statistics
bool _forceDoMeasure;
};
# endif // __TIMER_H__

View file

@ -0,0 +1,21 @@
README
------
To launch a set of experiments with t-mpi-distrib-exp:
1) Generate the experiments, thanks to the script gen-xp.py
This script will guide you and ask you for all experiments. The prefix is used in the results filenames.
You may want to modify the name of the experiments file (default value: "experiments.json") or
the pattern of the results files. However, you have to ensure that the pattern is an one-to-one
function of the parameters, otherwise some results could be lost.
2) Launch the t-mpi-distrib-exp program with mpirun:
For 4 cores (= 1 master + 3 workers)
mpirun -np 4 ./t-mpi-distrib-exp --use-experiment-file=1 --experiment-file=/home/eodev/eo/test/mpi/experiments.json
For 16 cores (= 1 master + 15 workers)
mpirun -np 5 ./t-mpi-distrib-exp --use-experiment-file=1 --experiment-file=/home/eodev/eo/test/mpi/experiments.json
3) The program will generate the results of the experiments, as txt files. There is one result file for each run of each
experiment.

View file

@ -0,0 +1,6 @@
{
"experiments":[
{"size":"10", "packet_size":"1", "seed":"1337", "distribution":{"name":"normal", "mean":"500", "stddev":"100"}, "worker_print_waiting_time":"1", "filename":""}
{"size":"10", "packet_size":"1", "seed":"1337", "distribution":{"name":"normal", "mean":"100", "stddev":"20"}, "worker_print_waiting_time":"1", "filename":"exp2.result.txt"}
]
}

152
eo/test/mpi/gen-xp.py Normal file
View file

@ -0,0 +1,152 @@
# -*- coding:utf-8 -*-
"""
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Authors:
Benjamin Bouvier <benjamin.bouvier@gmail.com>
"""
import json
# Where will be saved the experiments?
EXPERIMENTS_FILENAME = "experiments.json"
# What will be the pattern for experiments filenames?
FILENAME_PATTERN = "%(prefix)s_%(distrib_name)s_%(size)s_%(packet_size)s_%(run)s.txt"
def input_number_at_least( min ):
n = min - 1
while n < min:
try:
n = int(raw_input("Enter a number greater or equal to %s: "% min))
except Exception:
print "Please enter an integer."
return n
def input_number_between( min, max ):
n = min - 1
while n < min or n > max:
try:
n = int(raw_input("Enter a number between %s and %s: " % (min,max)))
except Exception:
print "Please enter a number."
return n
def choose_continue():
print """Do you want to continue?
0. No
1. Yes"""
return bool( input_number_between(0,1) )
def choose_distribution_uniform():
distribution = {}
distribution["name"] = "uniform"
print "Enter the minimum value (in milliseconds): "
min = input_number_at_least( 0 )
distribution["min"] = str(min)
print "Enter the maximum value (in milliseconds): "
distribution["max"] = str(input_number_at_least( min ))
return distribution
def choose_distribution_normal():
distribution = {}
distribution["name"] = "normal"
print "Enter the mean (in milliseconds): "
distribution["mean"] = str(input_number_at_least( 0 ))
print "Enter the standard deviation (in milliseconds): "
distribution["stddev"] = str(input_number_at_least( 0 ))
return distribution
def choose_distribution_power():
distribution = {}
distribution["name"] = "exponential"
print "Enter the mean (in milliseconds): "
distribution["mean"] = str(input_number_at_least( 0 ))
return distribution
def choose_distribution():
print """Choose your distribution:
0. Uniform
1. Normal
2. Exponential"""
choice = input_number_between( 0, 2 )
choose_distrib_functions = [ choose_distribution_uniform, choose_distribution_normal, choose_distribution_power ]
return choose_distrib_functions[ choice ]()
def choose_packet_size():
print "Enter the size of a packet (group of elements):"
return str(input_number_at_least( 0 ))
def choose_size():
print "Enter the total size (size of population):"
return str(input_number_at_least( 0 ))
def choose_worker_print():
print """Should the workers print the time they sleep on stdout?
0. No
1. Yes"""
return str(input_number_between( 0, 1 ))
def choose_nb_runs():
print """How many runs should be launched for this configuration? Seeds will be automatically affected to the number
of run+1 (for instance, the first run has a seed of 1, the second has a seed of 2, etc.)."""
return input_number_at_least( 1 )
def choose_prefix():
print """What is the name of the experiment? It will be used as the prefix of file names."""
return raw_input("Enter the prefix name: ")
def main():
prefix = choose_prefix()
exps = []
while True:
exp = {}
exp["distribution"] = choose_distribution()
exp["size"] = choose_size()
exp["packet_size"] = choose_packet_size()
exp["worker_print_waiting_time"] = choose_worker_print()
runs = choose_nb_runs()
for i in range( runs ):
exp["seed"] = str(i+1)
filename_map = exp.copy()
filename_map["run"] = exp["seed"]
filename_map["distrib_name"] = exp["distribution"]["name"]
filename_map["prefix"] = prefix
filename = FILENAME_PATTERN % filename_map
exp["filename"] = filename
copy = exp.copy()
exps.append( copy )
if not choose_continue():
break
# Write the experiments in a file
f = file( EXPERIMENTS_FILENAME , 'wb')
f.write("""{"experiments":[""")
i = 0
for exp in exps:
if i > 0:
f.write(",\n")
i += 1
f.write( json.dumps(exp) )
f.write("]}")
f.close()
if __name__ == "__main__":
main()

View file

@ -1,29 +1,80 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Authors:
* Benjamin Bouvier <benjamin.bouvier@gmail.com>
*/
/**
* @file t-mpi-distrib-exp.cpp
* @brief File for parallel experimentations.
*
* When using parallel evaluation, the individuals to evaluate are sent by packets (group),
* so as to avoid that communication time be more important than worker's execution time.
* However, the ideal size of packet depends on the problem and the time needed to carry out
* the atomic operation on each individual. This experiment tries to find a relation between
* the total number of elements to process (size), the execution time and the size of packet.
* This could lead to an heuristic allowing to optimize the size of packet according to the
* processing times.
*/
# include <unistd.h> // usleep
# include <iostream>
# include <iomanip>
# include <string>
# include <sstream>
# include <vector>
# include <eo>
# include <mpi/eoParallelApply.h>
# include "../test/mpi/t-mpi-common.h"
# include "t-mpi-common.h"
using namespace eo::mpi;
// Serializable int
typedef SerializableBase<int> type;
/*
* The task is the following: the worker receives a number of milliseconds to wait, which
* simulates the process of one individual. This way, the sequences of processing times are
* generated only by the master and are more easily reproductible.
*/
struct Wait : public eoUF< type &, void >
{
Wait( bool print ) : _print( print )
{
// empty
}
void operator()( type & milliseconds )
{
std::cout << "Sleeping for " << milliseconds << "ms..." << std::endl;
if( _print )
std::cout << "Sleeping for " << milliseconds << "ms..." << std::endl;
// usleep takes an input in microseconds
usleep( milliseconds * 1000 );
}
} wait;
class Distribution : public std::vector< type >
private:
bool _print;
};
/**
* @brief Represents a distribution of processing times.
*/
class Distribution : public std::vector< type >, public eoserial::Persistent
{
public:
@ -34,7 +85,9 @@ class Distribution : public std::vector< type >
{
for( unsigned i = 0; i < size; ++i )
{
push_back( next_element() );
int next = next_element();
if( next < 0 ) next = 0;
push_back( next );
}
}
@ -42,13 +95,15 @@ class Distribution : public std::vector< type >
* @brief Returns the next element of the distribution to put in the
* vector.
*
* @returns Number of milliseconds to wait
* @returns Number of milliseconds to wait. Can be negative ; in this case,
* the number will be truncated to 0ms.
*/
virtual int next_element() = 0;
// Idea for function name: enlarge_your_parser
/**
* @brief Creates params and retrieves values from parser
*
* Parser's params should take milliseconds as inputs.
*/
virtual void make_parser( eoParser & parser ) = 0;
@ -56,21 +111,39 @@ class Distribution : public std::vector< type >
* @brief Returns true if this distribution has been activated by the
* command line.
*
* Serves to main program to check if at least one distribution has been
* Used by the main program so as to check if at least one distribution has been
* activated.
*/
bool isActive() { return _active; }
/**
* @brief Prints the name and the parameters of the distribution
*/
virtual std::string toString() const = 0;
protected:
bool _active;
};
/**
* @brief Uniform distribution.
*
* This is an uniform distribution, defined by a minimum value and a maximum value.
* In the uniform distribution, every number from min to max has the same probability
* to appear.
*
* The 3 parameters activable from a parser are the following:
* - uniform=1 : if we want to use the uniform distribution
* - uniform-min=x : use x milliseconds as the minimum value of waiting time.
* - uniform-max=y : use y milliseconds as the maximum value of waiting time.
* Ensure that x < y, or the results are unpredictable.
*/
class UniformDistribution : public Distribution
{
public:
UniformDistribution() : _rng(0)
UniformDistribution()
{
// empty
}
@ -78,57 +151,405 @@ class UniformDistribution : public Distribution
void make_parser( eoParser & parser )
{
_active = parser.createParam( false, "uniform", "Uniform distribution", '\0', "Uniform").value();
_min = parser.createParam( 0.0, "uniform-min", "Minimum for uniform distribution", '\0', "Uniform").value();
_max = parser.createParam( 1.0, "uniform-max", "Maximum for uniform distribution", '\0', "Uniform").value();
_min = parser.createParam( 0.0, "uniform-min", "Minimum for uniform distribution, in ms.", '\0', "Uniform").value();
_max = parser.createParam( 1.0, "uniform-max", "Maximum for uniform distribution, in ms.", '\0', "Uniform").value();
}
int next_element()
{
return std::floor( 1000. * _rng.uniform( _min, _max ) );
return std::floor( eo::rng.uniform( _min, _max ) );
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "name", eoserial::make( "uniform" ) );
obj->add( "min", eoserial::make( _min ) );
obj->add( "max", eoserial::make( _max ) );
return obj;
}
void unpack( const eoserial::Object* obj )
{
eoserial::unpack( *obj, "min", _min );
eoserial::unpack( *obj, "max", _max );
}
std::string toString() const
{
std::stringstream ss;
ss << "uniform" << '\n'
<< "min: " << _min << '\n'
<< "max: " << _max << '\n';
return ss.str();
}
protected:
eoRng _rng;
double _min;
double _max;
} uniformDistribution;
/**
* @brief Normal (gaussian) distribution of times.
*
* A normal distribution is defined by a mean and a standard deviation.
* The 3 parameters activable from the parser are the following:
* - normal=1: activates the gaussian distribution.
* - normal-mean=50: use 50ms as the mean of the distribution.
* - normal-stddev=10: use 10ms as the standard deviation of the distribution.
*/
class NormalDistribution : public Distribution
{
public:
NormalDistribution()
{
// empty
}
void make_parser( eoParser & parser )
{
_active = parser.createParam( false, "normal", "Normal distribution", '\0', "Normal").value();
_mean = parser.createParam( 0.0, "normal-mean", "Mean for the normal distribution (0 by default), in ms.", '\0', "Normal").value();
_stddev = parser.createParam( 1.0, "normal-stddev", "Standard deviation for the normal distribution (1ms by default), 0 isn't acceptable.", '\0', "Normal").value();
}
int next_element()
{
return std::floor( eo::rng.normal( _mean, _stddev ) );
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "name", eoserial::make( "normal" ) );
obj->add( "mean", eoserial::make( _mean ) );
obj->add( "stddev", eoserial::make( _stddev ) );
return obj;
}
void unpack( const eoserial::Object* obj )
{
eoserial::unpack( *obj, "mean", _mean );
eoserial::unpack( *obj, "stddev", _stddev );
}
std::string toString() const
{
std::stringstream ss;
ss << "normal" << '\n'
<< "mean: " << _mean << '\n'
<< "stddev: " << _stddev << '\n';
return ss.str();
}
protected:
double _mean;
double _stddev;
} normalDistribution;
/**
* @brief Exponential distribution.
*
* This distribution belongs to the category of the decreasing power laws and are affected by long trails
* phenomenons.
* An exponential distribution is only defined by its mean.
*
* The 2 parameters activable from the parser are the following:
* - exponential=1: to activate the exponential distribution.
* - exponential-mean=50: indicates that the mean must be 50ms.
*/
class ExponentialDistribution : public Distribution
{
public:
ExponentialDistribution()
{
// empty
}
void make_parser( eoParser & parser )
{
_active = parser.createParam( false, "exponential", "Exponential distribution", '\0', "Exponential").value();
_mean = parser.createParam( 0.0, "exponential-mean", "Mean for the exponential distribution (0 by default), in ms.", '\0', "Exponential").value();
}
int next_element()
{
return std::floor( eo::rng.negexp( _mean ) );
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "name", eoserial::make( "exponential" ) );
obj->add( "mean", eoserial::make( _mean ) );
return obj;
}
void unpack( const eoserial::Object* obj )
{
eoserial::unpack( *obj, "mean", _mean );
}
std::string toString() const
{
std::stringstream ss;
ss << "exponential" << '\n'
<< "mean: " << _mean << '\n';
return ss.str();
}
protected:
double _mean;
} exponentialDistribution;
/**
* @brief Serializable experiment.
*
* Allows an experiment to be saved and loaded via a file, using eoserial.
*
* Construct the experiment with the good parameters from the command line or load experiments from a file. Then call run() to launch the parallel job.
*
* If a filename is given to the constructor (or during the loading), the results of the experiments (time series) will
* be redirected to the file with the given file name. Otherwise (filename == ""), the output will just be shown on the
* standard output.
*/
class Experiment : public eoserial::Persistent
{
public:
Experiment() : _distribution(0), _worker_print_waiting_time( false ), _fileName("")
{
// empty
}
Experiment( Distribution* distrib, unsigned size, unsigned packet_size, bool print_waiting_time, unsigned seed, const std::string& fileName = "" ) :
_distribution( distrib ),
_size( size ),
_packet_size( packet_size ),
_worker_print_waiting_time( print_waiting_time ),
_seed( seed ),
_fileName( fileName )
{
// empty
}
eoserial::Object* pack( void ) const
{
eoserial::Object* obj = new eoserial::Object;
obj->add( "size", eoserial::make( _size ) );
obj->add( "packet_size", eoserial::make( _packet_size ) );
obj->add( "worker_print_waiting_time", eoserial::make( _worker_print_waiting_time ) );
obj->add( "seed", eoserial::make( _seed ) );
if( _distribution )
{
obj->add( "distribution", _distribution );
}
obj->add( "filename", eoserial::make( _fileName ) );
return obj;
}
void unpack( const eoserial::Object* obj )
{
eoserial::unpack( *obj, "size", _size );
eoserial::unpack( *obj, "packet_size", _packet_size );
eoserial::unpack( *obj, "worker_print_waiting_time", _worker_print_waiting_time );
eoserial::unpack( *obj, "seed", _seed );
eoserial::unpack( *obj, "filename", _fileName );
eoserial::Object* distribObject = static_cast<eoserial::Object*>( obj->find("distribution")->second );
std::string distribName = *static_cast<eoserial::String*>( distribObject->find("name")->second );
// TODO find a better design...
if( distribName == "normal" ) {
_distribution = & normalDistribution;
} else if( distribName == "uniform" ) {
_distribution = & uniformDistribution;
} else if( distribName == "exponential" ) {
_distribution = & exponentialDistribution;
} else {
throw std::runtime_error("When unpacking experience, no distribution found.");
}
eoserial::unpackObject( *obj, "distribution", *_distribution );
}
void run()
{
mpi::communicator& comm = eo::mpi::Node::comm();
// reinits every objects
eo::rng.reseed( _seed );
eo::rng.clearCache(); // trick for repeatable sequences of normal numbers, cf eo::rng
_distribution->clear();
_distribution->fill( _size );
timerStat.start("run");
Wait wait( _worker_print_waiting_time );
ParallelApplyStore< type > store( wait, DEFAULT_MASTER, _packet_size );
store.data( *_distribution );
DynamicAssignmentAlgorithm scheduling;
ParallelApply< type > job( scheduling, DEFAULT_MASTER, store );
job.run();
timerStat.stop("run");
if( job.isMaster() )
{
EmptyJob( scheduling, DEFAULT_MASTER ); // to terminate parallel apply
// Receive statistics
typedef std::map< std::string, eoTimerStat::Stat > typeStats;
std::ostream* pout;
std::ofstream file;
bool fileSaveActivated = false;
if( _fileName == "" ) {
pout = & std::cout;
} else {
pout = & file;
file.open( _fileName.c_str() );
fileSaveActivated = true;
}
std::ostream& out = *pout;
// Reminder of the parameters
out << "size: " << _size << '\n'
<< "packet_size: " << _packet_size << '\n'
<< "distribution: " << _distribution->toString()
<< "seed: " << _seed << '\n' << std::endl;
// Results
out << std::fixed << std::setprecision( 5 );
for( int i = 1, s = comm.size(); i < s; ++i )
{
eoTimerStat timerStat;
comm.recv( i, eo::mpi::Channel::Commands, timerStat );
typeStats stats = timerStat.stats();
for( typeStats::iterator it = stats.begin(),
end = stats.end();
it != end;
++it )
{
out << i << " " << it->first << std::endl;
for( int j = 0, t = it->second.wtime.size(); j < t; ++j )
{
out << it->second.wtime[j] << " ";
}
out << std::endl;
}
out << std::endl;
}
if( fileSaveActivated ) {
file.close();
}
} else
{
// Send statistics
comm.send( DEFAULT_MASTER, eo::mpi::Channel::Commands, eo::mpi::timerStat );
}
timerStat.clear();
}
private:
Distribution* _distribution;
unsigned _size;
unsigned _packet_size;
bool _worker_print_waiting_time;
unsigned _seed;
std::string _fileName;
};
int main( int argc, char** argv )
{
Node::init( argc, argv );
eoParser parser( argc, argv );
// TODO for each available distribution, check if activated.
// If no distribution is activated, show an error message
// If two distributions or more are activated, show an error message
// Otherwise, use the activated distribution as distrib
Distribution & distrib = uniformDistribution;
// Make parser of distribution here
distrib.make_parser( parser );
// forces the statistics to be retrieved
eo::mpi::timerStat.forceDoMeasure();
// General parameters for the experimentation
unsigned size = parser.createParam( 10U, "size", "Number of elements to distribute.", 's', "Distribution").value();
unsigned packet_size = parser.createParam( 1U, "packet_size", "Number of elements to distribute at each time for a single worker.", 'p', "Parallelization").value();
unsigned packet_size = parser.createParam( 1U, "packet-size", "Number of elements to distribute at each time for a single worker.", 'p', "Parallelization").value();
bool worker_print_waiting_time = parser.createParam( false, "print-waiting-time", "Do the workers need to print the time they wait?", '\0', "Parallelization").value();
unsigned seed = parser.createParam( 0U, "seed", "Seed of random generator", '\0', "General").value();
std::string fileName = parser.createParam( std::string(""), "filename", "File name to which redirect the results (for a single experiment)", '\0', "General").value();
make_parallel( parser );
make_help( parser );
bool useExperimentFile = parser.createParam( false, "use-experiment-file", "Put to true if you want to launch experiments from a file formatted in JSON (see experiment-file).", '\0', "General").value();
std::string experimentFile = parser.createParam( std::string("experiments.json"), "experiment-file", "File name of experiments to provide, in format JSON.", '\0', "General").value();
ParallelApplyStore< type> store( wait, DEFAULT_MASTER, packet_size );
// Fill distribution
distrib.fill( size );
store.data( distrib );
DynamicAssignmentAlgorithm scheduling;
ParallelApply< type > job( scheduling, DEFAULT_MASTER, store );
job.run();
if( job.isMaster() )
if( !useExperimentFile )
{
EmptyJob( scheduling, DEFAULT_MASTER ); // to terminate parallel apply
std::vector<Distribution*> distribs;
distribs.push_back( &uniformDistribution );
distribs.push_back( &normalDistribution );
distribs.push_back( &exponentialDistribution );
// for each available distribution, check if activated.
// If no distribution is activated, show an error message
// If two distributions or more are activated, show an error message
// Otherwise, use the activated distribution as distrib
bool isChosenDistrib = false;
Distribution* pdistrib = 0;
for( int i = 0, s = distribs.size(); i < s; ++i )
{
distribs[i]->make_parser( parser );
if( distribs[i]->isActive() )
{
if( isChosenDistrib )
{
throw std::runtime_error("Only one distribution can be chosen during a launch!");
} else
{
isChosenDistrib = true;
pdistrib = distribs[i];
}
}
}
make_parallel( parser );
make_help( parser );
if( !isChosenDistrib )
{
throw std::runtime_error("No distribution chosen. One distribution should be chosen.");
}
Experiment e( pdistrib, size, packet_size, worker_print_waiting_time, seed, fileName );
e.run();
}
else // use experiments file
{
// read content of file
std::ifstream file( experimentFile.c_str() );
std::string fileContent;
while( file )
{
char temp[4096];
file.getline( temp, 4096, '\n' );
fileContent += temp;
fileContent += '\n';
}
file.close();
// transform content into array of experiments
eoserial::Object* wrapper = eoserial::Parser::parse( fileContent );
eoserial::Array& experiments = *static_cast< eoserial::Array* >( wrapper->find("experiments")->second );
for( unsigned i = 0, s = experiments.size(); i < s; ++i )
{
std::cout << "Launching experiment " << (i+1) << "..." << std::endl;
eoserial::Object* expObj = static_cast< eoserial::Object* >( experiments[i] );
Experiment exp;
exp.unpack( expObj );
exp.run();
}
delete wrapper;
}
return 0;