OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
SamplePilot.h
Go to the documentation of this file.
1//
2// Class SamplePilot
3// The sample Pilot (Master): Coordinates requests by sampler to workers.
4// Every worker thread notifies the master here if idle or not. When
5// available the master dispatches one of the pending simulations to the
6// worker who will run the specified simulation and report results back to
7// the master.
8// @see SampleWorker
9// @see Sampler
10// @tparam Opt_t type of the sampler
11// @tparam Sim_t type of the simulation
12// @tparam SolPropagationGraph_t strategy to distribute solution between
13// master islands
14// @tparam Comm_t comm splitter strategy
15//
16// Copyright (c) 2018, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
17// Yves Ineichen, ETH Zürich
18// All rights reserved
19//
20// Implemented as part of the PhD thesis
21// "Precise Simulations of Multibunches in High Intensity Cyclotrons"
22//
23// This file is part of OPAL.
24//
25// OPAL is free software: you can redistribute it and/or modify
26// it under the terms of the GNU General Public License as published by
27// the Free Software Foundation, either version 3 of the License, or
28// (at your option) any later version.
29//
30// You should have received a copy of the GNU General Public License
31// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
32//
33#ifndef __SAMPLE_PILOT_H__
34#define __SAMPLE_PILOT_H__
35
36#include "Util/AnsiColors.h"
37#include "Pilot/Pilot.h"
38#include "Sample/SampleWorker.h"
40
41template <
42 class Opt_t
43 , class Sim_t
44 , class SolPropagationGraph_t
45 , class Comm_t
46 >
47class SamplePilot : protected Pilot<Opt_t,
48 Sim_t,
49 SolPropagationGraph_t,
50 Comm_t>
51{
52
53public:
54
55 SamplePilot(CmdArguments_t args, std::shared_ptr<Comm_t> comm,
56 functionDictionary_t known_expr_funcs,
57 const DVarContainer_t &dvar,
58 const Expressions::Named_t &obj,
59 const std::map< std::string,
60 std::shared_ptr<SamplingMethod>
61 >& sampleMethods,
62 const std::vector<std::string> &storeobjstr,
63 const std::vector<std::string> &filesToKeep,
64 const std::map<std::string, std::string> &userVariables)
65 : Pilot<Opt_t,
66 Sim_t,
67 SolPropagationGraph_t,
68 Comm_t>(args,
69 comm,
70 known_expr_funcs,
71 dvar,
72 obj,
73 Expressions::Named_t(),
74 {},
75 false,
76 {})
77 , sampleMethods_m(sampleMethods)
78 {
79 if (obj.empty()) {
80 // create a dummy objective, base class requires at least 1 objective
81 this->objectives_ = {
82 {"dummy", new Expressions::Expr_t("dummy")}
83 };
84 }
85
86 this->setup(known_expr_funcs, storeobjstr, filesToKeep, userVariables);
87 }
88
89 virtual ~SamplePilot()
90 {}
91
92
93protected:
94
96 typedef std::map<size_t, Param_t > Jobs_t;
97 typedef Jobs_t::iterator JobIter_t;
100
101
102 virtual
103 void setup(functionDictionary_t known_expr_funcs,
104 const std::vector<std::string> &storeobjstr,
105 const std::vector<std::string> &filesToKeep,
106 const std::map<std::string, std::string> &userVariables)
107 {
108 this->global_rank_ = this->comm_->globalRank();
109
110 this->parseInputFile(known_expr_funcs, false);
111
112 MPI_Barrier(MPI_COMM_WORLD);
113
114 // here the control flow starts to diverge
115 if ( this->comm_->isOptimizer() ) { startSampler(); }
116 else if ( this->comm_->isWorker() ) { startWorker(storeobjstr, filesToKeep, userVariables); }
117 else if ( this->comm_->isPilot() ) { this->startPilot(); }
118 }
119
120 virtual
122
123 std::ostringstream os;
124 os << AnsiColors::BoldMagenta << " " << this->global_rank_ << " (PID: " << getpid() << ") ▶ Sampler"
125 << AnsiColors::Reset << std::endl;
126 std::cout << os.str() << std::flush;
127
128 const std::unique_ptr<Opt_t> opt(
129 new Opt_t(sampleMethods_m, this->objectives_, this->dvars_,
130 this->comm_->getBundle(), this->cmd_args_));
131 opt->initialize();
132
133 std::cout << "Stop Sampler.." << std::endl;
134 }
135
136 using Pilot<Opt_t, Sim_t, SolPropagationGraph_t, Comm_t>::startWorker;
137 void startWorker(const std::vector<std::string> &storeobjstr,
138 const std::vector<std::string> &filesToKeep,
139 const std::map<std::string, std::string> &userVariables)
140 {
141 std::ostringstream os;
142 os << AnsiColors::BoldMagenta << " " << this->global_rank_ << " (PID: " << getpid() << ") ▶ Worker"
143 << AnsiColors::Reset << std::endl;
144 std::cout << os.str() << std::flush;
145
146 size_t pos = this->input_file_.find_last_of("/");
147 std::string tmplfile = this->input_file_;
148 if (pos != std::string::npos)
149 tmplfile = this->input_file_.substr(pos+1);
150 pos = tmplfile.find(".");
151 std::string simName = tmplfile.substr(0,pos);
152
153 const std::unique_ptr< SampleWorker<Sim_t> > w(
154 new SampleWorker<Sim_t>(this->objectives_, this->constraints_, simName,
155 this->comm_->getBundle(), this->cmd_args_,
156 storeobjstr, filesToKeep, userVariables));
157
158 std::cout << "Stop Worker.." << std::endl;
159 }
160
161 virtual
162 void postPoll() {
163
164 // terminating all workers is tricky since we do not know their state.
165 // All workers are notified (to terminate) when opt has converged and
166 // all workers are idle.
167 bool all_worker_idle = true;
168
169 // in the case where new requests became available after worker
170 // delivered last results (and switched to idle state).
171 for(int i = 0; i < this->total_available_workers_; i++) {
172
173 if (i == this->my_rank_in_worker_comm_) continue;
174
175 if (this->is_worker_idle_[i] && !request_queue_.empty())
177
178 all_worker_idle = all_worker_idle && this->is_worker_idle_[i];
179 }
180
181 // when all workers have been notified we can stop polling
182 if (all_worker_idle && this->has_opt_converged_) {
183 this->continue_polling_ = false;
184 int dummy = 0;
185 for(int worker = 0; worker < this->total_available_workers_; worker++) {
186 MPI_Request req;
187 MPI_Isend(&dummy, 1, MPI_INT, worker,
188 MPI_STOP_TAG, this->worker_comm_, &req);
189 }
190 }
191 }
192
193
194 virtual
195 void sendNewJobToWorker(int worker) /*override*/ {
196
197 // no new jobs once our opt has converged
198 if (this->has_opt_converged_) return;
199
200 JobIter_t job = request_queue_.begin();
201 size_t jid = job->first;
202
203 Param_t job_params = job->second;
204 MPI_Send(&jid, 1, MPI_UNSIGNED_LONG, worker, MPI_WORK_JOBID_TAG, this->worker_comm_);
205 MPI_Send_params(job_params, worker, this->worker_comm_);
206
207 running_job_list_.insert(std::pair<size_t,
208 Param_t >(job->first, job->second));
209 request_queue_.erase(jid);
210 this->is_worker_idle_[worker] = false;
211
212 std::ostringstream dump;
213 dump << "sent job with ID " << jid << " to worker " << worker
214 << std::endl;
215 this->job_trace_->log(dump);
216
217 }
218
219
220 virtual
221 bool onMessage(MPI_Status status, size_t recv_value) /*override*/ {
222
223 MPITag_t tag = MPITag_t(status.MPI_TAG);
224 switch(tag) {
225
226 case WORKER_FINISHED_TAG: {
227
228 size_t job_id = recv_value;
229
230 size_t dummy = 1;
231 MPI_Send(&dummy, 1, MPI_UNSIGNED_LONG, status.MPI_SOURCE,
232 MPI_WORKER_FINISHED_ACK_TAG, this->worker_comm_);
233
235 MPI_Recv_reqvars(res, status.MPI_SOURCE, this->worker_comm_);
236
237 running_job_list_.erase(job_id);
238 this->is_worker_idle_[status.MPI_SOURCE] = true;
239
240 std::ostringstream dump;
241 dump << "worker finished job with ID " << job_id << std::endl;
242 this->job_trace_->log(dump);
243
244
245 // sampler already terminated, cannot accept new messages
246 if (this->has_opt_converged_) return true;
247
248 int opt_master_rank = this->comm_->getLeader();
249 MPI_Send(&job_id, 1, MPI_UNSIGNED_LONG, opt_master_rank,
251
252 MPI_Send_reqvars(res, opt_master_rank, this->opt_comm_);
253
254 // we keep worker busy _after_ results have been sent to sampler
255 if (!request_queue_.empty())
256 sendNewJobToWorker(status.MPI_SOURCE);
257
258 return true;
259 }
260
261 case OPT_NEW_JOB_TAG: {
262
263 size_t job_id = recv_value;
264 int opt_master_rank = this->comm_->getLeader();
265
266 Param_t job_params;
267 MPI_Recv_params(job_params, (size_t)opt_master_rank, this->opt_comm_);
268
269 request_queue_.insert(
270 std::pair<size_t, Param_t >(
271 job_id, job_params));
272
273 std::ostringstream dump;
274 dump << "new opt job with ID " << job_id << std::endl;
275 this->job_trace_->log(dump);
276
277 return true;
278 }
279
280 case OPT_CONVERGED_TAG: {
281 return this->stop();
282 }
283
285 this->is_worker_idle_[status.MPI_SOURCE] = true;
286 return true;
287 }
288
289 default: {
290 std::string msg = "(Pilot) Error: unexpected MPI_TAG: ";
291 msg += status.MPI_TAG;
292 throw OptPilotException("SamplePilot::onMessage", msg);
293 }
294 }
295 }
296
297private:
298 std::map< std::string,
299 std::shared_ptr<SamplingMethod>
301};
302
303#endif
std::map< std::string, client::function::type > functionDictionary_t
Definition Expression.h:51
std::map< std::string, DVar_t > DVarContainer_t
Definition Types.h:108
std::map< std::string, reqVarInfo_t > reqVarContainer_t
Definition Types.h:96
namedVariableCollection_t Param_t
Definition Types.h:52
void MPI_Send_reqvars(reqVarContainer_t reqvars, std::size_t pid, MPI_Comm comm)
void MPI_Send_params(Param_t params, std::size_t pid, MPI_Comm comm)
void MPI_Recv_reqvars(reqVarContainer_t &reqvars, std::size_t pid, MPI_Comm comm)
void MPI_Recv_params(Param_t &params, std::size_t pid, MPI_Comm comm)
std::shared_ptr< CmdArguments > CmdArguments_t
#define MPI_WORK_JOBID_TAG
unique id of the job
Definition MPIHelper.h:52
#define MPI_OPT_JOB_FINISHED_TAG
pilot tells optimizer that results are ready to collect
Definition MPIHelper.h:46
MPITag_t
Definition MPIHelper.h:71
@ WORKER_FINISHED_TAG
Definition MPIHelper.h:72
@ OPT_CONVERGED_TAG
Definition MPIHelper.h:74
@ OPT_NEW_JOB_TAG
Definition MPIHelper.h:73
@ WORKER_STATUSUPDATE_TAG
Definition MPIHelper.h:75
#define MPI_WORKER_FINISHED_ACK_TAG
pilot notifies worker that he is ready to collect the results
Definition MPIHelper.h:37
#define MPI_STOP_TAG
global stop tag to exit poll loop (
Definition MPIHelper.h:64
Representation objects and parsers for attribute expressions.
Definition Expressions.h:64
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition Expression.h:68
Expression Expr_t
type of an expression
Definition Expression.h:57
constexpr char Reset[]
Definition AnsiColors.h:5
constexpr char BoldMagenta[]
Definition AnsiColors.h:7
virtual void setup(functionDictionary_t known_expr_funcs, const std::vector< std::string > &storeobjstr, const std::vector< std::string > &filesToKeep, const std::map< std::string, std::string > &userVariables)
std::map< std::string, std::shared_ptr< SamplingMethod > > sampleMethods_m
Jobs_t running_job_list_
Definition SamplePilot.h:98
std::map< size_t, Param_t > Jobs_t
keep track of requests and running jobs
Definition SamplePilot.h:96
virtual void postPoll()
executed after handling (if any) new request
SamplePilot(CmdArguments_t args, std::shared_ptr< Comm_t > comm, functionDictionary_t known_expr_funcs, const DVarContainer_t &dvar, const Expressions::Named_t &obj, const std::map< std::string, std::shared_ptr< SamplingMethod > > &sampleMethods, const std::vector< std::string > &storeobjstr, const std::vector< std::string > &filesToKeep, const std::map< std::string, std::string > &userVariables)
Definition SamplePilot.h:55
virtual ~SamplePilot()
Definition SamplePilot.h:89
virtual void sendNewJobToWorker(int worker)
virtual bool onMessage(MPI_Status status, size_t recv_value)
Jobs_t::iterator JobIter_t
Definition SamplePilot.h:97
Jobs_t request_queue_
Definition SamplePilot.h:99
virtual void startSampler()
void startWorker(const std::vector< std::string > &storeobjstr, const std::vector< std::string > &filesToKeep, const std::map< std::string, std::string > &userVariables)
Definition Pilot.h:100
bool has_opt_converged_
Definition Pilot.h:181
int total_available_workers_
Definition Pilot.h:180
std::string input_file_
input file for simulation with embedded optimization problem
Definition Pilot.h:178
std::vector< bool > is_worker_idle_
Definition Pilot.h:191
virtual void startPilot()
Definition Pilot.h:308
int global_rank_
Definition Pilot.h:167
bool stop(bool isOpt=true)
Definition Pilot.h:570
int my_rank_in_worker_comm_
Definition Pilot.h:168
std::unique_ptr< Trace > job_trace_
Definition Pilot.h:200
Expressions::Named_t constraints_
constraints
Definition Pilot.h:185
bool continue_polling_
Definition Pilot.h:182
MPI_Comm opt_comm_
MPI communicator used for messages to/from optimizer.
Definition Pilot.h:160
Expressions::Named_t objectives_
objectives
Definition Pilot.h:184
std::shared_ptr< Comm_t > comm_
Definition Pilot.h:164
MPI_Comm worker_comm_
MPI communicator used for messages to/from worker.
Definition Pilot.h:158
DVarContainer_t dvars_
design variables
Definition Pilot.h:186
void parseInputFile(functionDictionary_t, bool isOptimizationRun)
Definition Pilot.h:235