1 /* _______________________________________________________________________
2
3 DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
4 Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
5 This software is distributed under the GNU Lesser General Public License.
6 For more information, see the README file in the top Dakota directory.
7 _______________________________________________________________________ */
8
9 //- Class: ProcessHandleApplicInterface
10 //- Description: Derived class for the case when analysis code simulators use
11 //- fork\exec\wait to provide the function evaluations
12 //- Owner: Mike Eldred
13 //- Version: $Id: ProcessHandleApplicInterface.hpp 6492 2009-12-19 00:04:28Z briadam $
14
15 #ifndef PROCESS_HANDLE_APPLIC_INTERFACE_H
16 #define PROCESS_HANDLE_APPLIC_INTERFACE_H
17
18 #include "ProcessApplicInterface.hpp"
19 #include <boost/shared_array.hpp>
20
21 namespace Dakota {
22
23 /// Derived application interface class that spawns a simulation code
24 /// using a separate process, receives a process identifier, and
25 /// communicates with the spawned process through files.
26
27 /** ProcessHandleApplicInterface is subclassed for fork/execvp/waitpid
28 (Unix) and spawnvp (Windows). */
29
30
31 class ProcessHandleApplicInterface: public ProcessApplicInterface
32 {
33 public:
34
35 //
36 //- Heading: Constructors and destructor
37 //
38
39 /// constructor
40 ProcessHandleApplicInterface(const ProblemDescDB& problem_db);
41 /// destructor
42 ~ProcessHandleApplicInterface();
43
44 protected:
45
46 //
47 //- Heading: Virtual function redefinitions
48 //
49
50 int synchronous_local_analysis(int analysis_id);
51
52 void init_communicators_checks(int max_eval_concurrency);
53 void set_communicators_checks(int max_eval_concurrency);
54
55 void map_bookkeeping(pid_t pid, int fn_eval_id);
56
57 pid_t create_evaluation_process(bool block_flag);
58
59 //
60 //- Heading: New virtual functions
61 //
62
63 /// spawn a child process for an analysis component within an evaluation
64 virtual pid_t create_analysis_process(bool block_flag, bool new_group) = 0;
65
66 /// wait for asynchronous analyses on the local processor, completing
67 /// at least one job
68 virtual size_t wait_local_analyses() = 0;
69
70 /// test for asynchronous analysis completions on the local processor
71 /// and return results for any completions by sending messages
72 virtual size_t test_local_analyses_send(int analysis_id) = 0;
73
74 /// create (if new_group) and join the process group for asynch evaluations
75 virtual void join_evaluation_process_group(bool new_group);
76 /// create (if new_group) and join the process group for asynch analyses
77 virtual void join_analysis_process_group(bool new_group);
78
79 /// set evalProcGroupId
80 virtual void evaluation_process_group_id(pid_t pgid);
81 /// return evalProcGroupId
82 virtual pid_t evaluation_process_group_id() const;
83 /// set analysisProcGroupId
84 virtual void analysis_process_group_id(pid_t pgid);
85 /// return analysisProcGroupId
86 virtual pid_t analysis_process_group_id() const;
87
88 //
89 //- Heading: Methods
90 //
91
92 /// Common processing code used by {wait,test}_local_evaluations
93 void process_local_evaluation(PRPQueue& prp_queue, const pid_t pid);
94
95 //void clear_bookkeeping(); // virtual fn redefinition: clear processIdMap
96
97 /// check the exit status of a forked process and abort if an error code
98 /// was returned
99 void check_wait(pid_t pid, int status);
100
101 /// execute analyses asynchronously on the local processor
102 void asynchronous_local_analyses(int start, int end, int step);
103
104 /// serve the analysis scheduler and execute analysis jobs asynchronously
105 void serve_analyses_asynch();
106
107 /// set argList for execution of the input filter
108 void ifilter_argument_list();
109 /// set argList for execution of the output filter
110 void ofilter_argument_list();
111 /// set argList for execution of the specified analysis driver
112 void driver_argument_list(int analysis_id);
113
114 /// parse argList into argument array av suitable for passing to
115 /// execvp, appending parameters and results filenames if requested
116 /// by commandLineArgs
117 void create_command_arguments(boost::shared_array<const char*>& av,
118 StringArray& driver_and_args);
119
120
121 //
122 //- Heading: Data
123 //
124
125 /// map of fork process id's to function evaluation id's for asynchronous
126 /// evaluations
127 std::map<pid_t, int> evalProcessIdMap;
128 /// map of fork process id's to analysis job id's for asynchronous analyses
129 std::map<pid_t, int> analysisProcessIdMap;
130
131 /// an array of strings for use with execvp(const char *, char * const *).
132 /// These are converted to an array of const char*'s in fork_program().
133 std::vector<std::string> argList;
134
135 private:
136
137 //
138 //- Heading: Data
139 //
140
141 // Used for substitution of parameter input files and result output files
142 // for analysis drivers.
143 };
144
145
146 /** argList sized 3 for [driver name, input file, output file] */
147 inline ProcessHandleApplicInterface::
ProcessHandleApplicInterface(const ProblemDescDB & problem_db)148 ProcessHandleApplicInterface(const ProblemDescDB& problem_db):
149 ProcessApplicInterface(problem_db), argList(3)
150 { }
151
152
~ProcessHandleApplicInterface()153 inline ProcessHandleApplicInterface::~ProcessHandleApplicInterface()
154 { }
155
156
157 /** This code provides the derived function used by ApplicationInterface::
158 serve_analyses_synch() as well as a convenience function for
159 ProcessHandleApplicInterface::synchronous_local_analyses() below. */
160 inline int ProcessHandleApplicInterface::
synchronous_local_analysis(int analysis_id)161 synchronous_local_analysis(int analysis_id)
162 {
163 #ifdef MPI_DEBUG
164 Cout << "Blocking fork to analysis " << analysis_id << std::endl; // flush buf
165 #endif // MPI_DEBUG
166 driver_argument_list(analysis_id);
167 create_analysis_process(BLOCK, false);
168 return 0; // used for failure codes in DirectFn case
169 }
170
171
172 /** No derived interface plug-ins, so perform construct-time checks.
173 However, process init issues as warnings since some contexts (e.g.,
174 HierarchSurrModel) initialize more configurations than will be used. */
175 inline void ProcessHandleApplicInterface::
init_communicators_checks(int max_eval_concurrency)176 init_communicators_checks(int max_eval_concurrency)
177 {
178 bool warn = true;
179 check_multiprocessor_analysis(warn);
180 check_multiprocessor_asynchronous(warn, max_eval_concurrency);
181 }
182
183
184 /** Process run-time issues as hard errors. */
185 inline void ProcessHandleApplicInterface::
set_communicators_checks(int max_eval_concurrency)186 set_communicators_checks(int max_eval_concurrency)
187 {
188 bool warn = false, mp1 = check_multiprocessor_analysis(warn),
189 mp2 = check_multiprocessor_asynchronous(warn, max_eval_concurrency);
190 if (mp1 || mp2)
191 abort_handler(-1);
192 }
193
194
195 //inline void ProcessHandleApplicInterface::clear_bookkeeping()
196 //{ evalProcessIdMap.clear(); }
197
198
ifilter_argument_list()199 inline void ProcessHandleApplicInterface::ifilter_argument_list()
200 {
201 argList[0] = iFilterName;
202 argList[1] = paramsFileName;
203 argList[2] = resultsFileName;
204 }
205
206
ofilter_argument_list()207 inline void ProcessHandleApplicInterface::ofilter_argument_list()
208 {
209 argList[0] = oFilterName;
210 argList[1] = paramsFileName;
211 argList[2] = resultsFileName;
212 }
213
214
driver_argument_list(int analysis_id)215 inline void ProcessHandleApplicInterface::driver_argument_list(int analysis_id)
216 {
217 std::string tag_str = "." + std::to_string(analysis_id);
218 argList[0] = programNames[analysis_id-1];
219 argList[1] = (multipleParamsFiles) ? paramsFileName+tag_str : paramsFileName;
220 argList[2] = (programNames.size() > 1) ? resultsFileName+tag_str :
221 resultsFileName;
222
223 #ifdef DEBUG
224 Cout << "argList: " << argList[0] << ' ' << argList[1] << ' ' << argList[2]
225 << std::endl;
226 #endif
227 }
228
229 } // namespace Dakota
230
231 #endif
232