Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
bee98a6fd284ba3fdb0690442e0deea33d93d756
[simgrid.git] / src / mc / mc_api.cpp
1 #include "mc_api.hpp"
2
3 #include "src/kernel/activity/MailboxImpl.hpp"
4 #include "src/mc/Session.hpp"
5 #include "src/mc/mc_comm_pattern.hpp"
6 #include "src/mc/mc_private.hpp"
7 #include "src/mc/mc_record.hpp"
8 #include "src/mc/mc_smx.hpp"
9 #include "src/mc/remote/RemoteSimulation.hpp"
10 #include "src/mc/mc_pattern.hpp"
11
12 #include <xbt/asserts.h>
13 #include <xbt/log.h>
14
15 #if HAVE_SMPI
16 #include "src/smpi/include/smpi_request.hpp"
17 #endif
18
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_api, mc, "Logging specific to MC Fasade APIs ");
20
21 using Simcall = simgrid::simix::Simcall;
22
23 namespace simgrid {
24 namespace mc {
25
26 /* Search an enabled transition for the given process.
27  *
28  * This can be seen as an iterator returning the next transition of the process.
29  *
30  * We only consider the processes that are both
31  *  - marked "to be interleaved" in their ActorState (controlled by the checker algorithm).
32  *  - which simcall can currently be executed (like a comm where the other partner is already known)
33  * Once we returned the last enabled transition of a process, it is marked done.
34  *
35  * Things can get muddled with the WAITANY and TESTANY simcalls, that are rewritten on the fly to a bunch of WAIT
36  * (resp TEST) transitions using the transition.argument field to remember what was the last returned sub-transition.
37  */
38 static inline smx_simcall_t MC_state_choose_request_for_process(simgrid::mc::State* state, smx_actor_t actor)
39 {
40   /* reset the outgoing transition */
41   simgrid::mc::ActorState* procstate = &state->actor_states_[actor->get_pid()];
42   state->transition_.pid_            = -1;
43   state->transition_.argument_       = -1;
44   state->executed_req_.call_         =  Simcall::NONE;
45
46   if (not simgrid::mc::actor_is_enabled(actor))
47     return nullptr; // Not executable in the application
48
49   smx_simcall_t req = nullptr;
50   switch (actor->simcall_.call_) {
51     case Simcall::COMM_WAITANY:
52       state->transition_.argument_ = -1;
53       while (procstate->times_considered < simcall_comm_waitany__get__count(&actor->simcall_)) {
54         if (simgrid::mc::request_is_enabled_by_idx(&actor->simcall_, procstate->times_considered)) {
55           state->transition_.argument_ = procstate->times_considered;
56           ++procstate->times_considered;
57           break;
58         }
59         ++procstate->times_considered;
60       }
61
62       if (procstate->times_considered >= simcall_comm_waitany__get__count(&actor->simcall_))
63         procstate->set_done();
64       if (state->transition_.argument_ != -1)
65         req = &actor->simcall_;
66       break;
67
68     case Simcall::COMM_TESTANY: {
69       unsigned start_count         = procstate->times_considered;
70       state->transition_.argument_ = -1;
71       while (procstate->times_considered < simcall_comm_testany__get__count(&actor->simcall_)) {
72         if (simgrid::mc::request_is_enabled_by_idx(&actor->simcall_, procstate->times_considered)) {
73           state->transition_.argument_ = procstate->times_considered;
74           ++procstate->times_considered;
75           break;
76         }
77         ++procstate->times_considered;
78       }
79
80       if (procstate->times_considered >= simcall_comm_testany__get__count(&actor->simcall_))
81         procstate->set_done();
82
83       if (state->transition_.argument_ != -1 || start_count == 0)
84         req = &actor->simcall_;
85
86       break;
87     }
88
89     case Simcall::COMM_WAIT: {
90       simgrid::mc::RemotePtr<simgrid::kernel::activity::CommImpl> remote_act =
91           remote(simcall_comm_wait__getraw__comm(&actor->simcall_));
92       simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_act;
93       mc_model_checker->get_remote_simulation().read(temp_act, remote_act);
94       const simgrid::kernel::activity::CommImpl* act = temp_act.get_buffer();
95       if (act->src_actor_.get() && act->dst_actor_.get())
96         state->transition_.argument_ = 0; // OK
97       else if (act->src_actor_.get() == nullptr && act->type_ == simgrid::kernel::activity::CommImpl::Type::READY &&
98                act->detached())
99         state->transition_.argument_ = 0; // OK
100       else
101         state->transition_.argument_ = -1; // timeout
102       procstate->set_done();
103       req = &actor->simcall_;
104       break;
105     }
106
107     case Simcall::MC_RANDOM: {
108       int min_value                = simcall_mc_random__get__min(&actor->simcall_);
109       state->transition_.argument_ = procstate->times_considered + min_value;
110       procstate->times_considered++;
111       if (state->transition_.argument_ == simcall_mc_random__get__max(&actor->simcall_))
112         procstate->set_done();
113       req = &actor->simcall_;
114       break;
115     }
116
117     default:
118       procstate->set_done();
119       state->transition_.argument_ = 0;
120       req                          = &actor->simcall_;
121       break;
122   }
123   if (not req)
124     return nullptr;
125
126   state->transition_.pid_ = actor->get_pid();
127   state->executed_req_    = *req;
128   // Fetch the data of the request and translate it:
129   state->internal_req_ = *req;
130
131   /* The waitany and testany request are transformed into a wait or test request over the corresponding communication
132    * action so it can be treated later by the dependence function. */
133   switch (req->call_) {
134     case Simcall::COMM_WAITANY: {
135       state->internal_req_.call_ = Simcall::COMM_WAIT;
136       simgrid::kernel::activity::CommImpl* remote_comm;
137       remote_comm = mc_model_checker->get_remote_simulation().read(
138           remote(simcall_comm_waitany__get__comms(req) + state->transition_.argument_));
139       mc_model_checker->get_remote_simulation().read(state->internal_comm_, remote(remote_comm));
140       simcall_comm_wait__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
141       simcall_comm_wait__set__timeout(&state->internal_req_, 0);
142       break;
143     }
144
145     case Simcall::COMM_TESTANY:
146       state->internal_req_.call_ = Simcall::COMM_TEST;
147
148       if (state->transition_.argument_ > 0) {
149         simgrid::kernel::activity::CommImpl* remote_comm = mc_model_checker->get_remote_simulation().read(
150             remote(simcall_comm_testany__get__comms(req) + state->transition_.argument_));
151         mc_model_checker->get_remote_simulation().read(state->internal_comm_, remote(remote_comm));
152       }
153
154       simcall_comm_test__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
155       simcall_comm_test__set__result(&state->internal_req_, state->transition_.argument_);
156       break;
157
158     case Simcall::COMM_WAIT:
159       mc_model_checker->get_remote_simulation().read_bytes(&state->internal_comm_, sizeof(state->internal_comm_),
160                                                            remote(simcall_comm_wait__getraw__comm(req)));
161       simcall_comm_wait__set__comm(&state->executed_req_, state->internal_comm_.get_buffer());
162       simcall_comm_wait__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
163       break;
164
165     case Simcall::COMM_TEST:
166       mc_model_checker->get_remote_simulation().read_bytes(&state->internal_comm_, sizeof(state->internal_comm_),
167                                                            remote(simcall_comm_test__getraw__comm(req)));
168       simcall_comm_test__set__comm(&state->executed_req_, state->internal_comm_.get_buffer());
169       simcall_comm_test__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
170       break;
171
172     default:
173       /* No translation needed */
174       break;
175   }
176
177   return req;
178 }
179
180 void mc_api::initialize(char** argv)
181 {
182   simgrid::mc::session = new simgrid::mc::Session([argv] {
183     int i = 1;
184     while (argv[i] != nullptr && argv[i][0] == '-')
185       i++;
186     xbt_assert(argv[i] != nullptr,
187                "Unable to find a binary to exec on the command line. Did you only pass config flags?");
188     execvp(argv[i], argv + i);
189     xbt_die("The model-checked process failed to exec(): %s", strerror(errno));
190   });
191 }
192
193 std::vector<simgrid::mc::ActorInformation>& mc_api::get_actors() const
194 {
195   return mc_model_checker->get_remote_simulation().actors();
196 }
197
198 bool mc_api::actor_is_enabled(aid_t pid) const
199 {
200   return session->actor_is_enabled(pid);
201 }
202
203 unsigned long mc_api::get_maxpid() const
204 {
205   return MC_smx_get_maxpid();
206 }
207
208 int mc_api::get_actors_size() const
209 {
210   return mc_model_checker->get_remote_simulation().actors().size();
211 }
212
213 void mc_api::copy_incomplete_comm_pattern(const simgrid::mc::State* state) const
214 {
215   MC_state_copy_incomplete_communications_pattern((simgrid::mc::State*)state);
216 }
217
218 void mc_api::copy_index_comm_pattern(const simgrid::mc::State* state) const
219 {
220   MC_state_copy_index_communications_pattern((simgrid::mc::State*)state);
221 }
222
223 kernel::activity::CommImpl* mc_api::get_pattern_comm_addr(smx_simcall_t request) const
224 {
225   auto comm_addr = simcall_comm_isend__getraw__result(request);
226   return static_cast<kernel::activity::CommImpl*>(comm_addr);
227 }
228
229 std::string mc_api::get_pattern_comm_rdv(void* addr) const
230 {
231   Remote<kernel::activity::CommImpl> temp_synchro;
232   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
233   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
234
235   char* remote_name = mc_model_checker->get_remote_simulation().read<char*>(RemotePtr<char*>(
236       (uint64_t)(synchro->get_mailbox() ? &synchro->get_mailbox()->get_name() : &synchro->mbox_cpy->get_name())));
237   auto rdv = mc_model_checker->get_remote_simulation().read_string(RemotePtr<char>(remote_name));
238   return rdv;
239 }
240
241 unsigned long mc_api::get_pattern_comm_src_proc(void* addr) const
242 {
243   Remote<kernel::activity::CommImpl> temp_synchro;
244   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
245   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
246   auto src_proc = mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(synchro->src_actor_.get()))->get_pid();
247   return src_proc;
248 }
249
250 unsigned long mc_api::get_pattern_comm_dst_proc(void* addr) const
251 {
252   Remote<kernel::activity::CommImpl> temp_synchro;
253   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
254   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
255   auto src_proc = mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(synchro->dst_actor_.get()))->get_pid();
256   return src_proc;
257 }
258
259 std::vector<char> mc_api::get_pattern_comm_data(void* addr) const
260 {
261   Remote<kernel::activity::CommImpl> temp_synchro;
262   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
263   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
264
265   std::vector<char> buffer {};
266   if (synchro->src_buff_ != nullptr) {
267     buffer.resize(synchro->src_buff_size_);
268     mc_model_checker->get_remote_simulation().read_bytes(buffer.data(), buffer.size(),
269                                                          remote(synchro->src_buff_));
270   }
271   return buffer;
272 }
273
274 std::vector<char> mc_api::get_pattern_comm_data(mc::RemotePtr<kernel::activity::CommImpl> const& comm_addr) const
275 {
276   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
277   mc_model_checker->get_remote_simulation().read(temp_comm, comm_addr);
278   const simgrid::kernel::activity::CommImpl* comm = temp_comm.get_buffer();
279   
280   std::vector<char> buffer {};
281   if (comm->src_buff_ != nullptr) {
282     buffer.resize(comm->src_buff_size_);
283     mc_model_checker->get_remote_simulation().read_bytes(buffer.data(), buffer.size(),
284                                                          remote(comm->src_buff_));
285   }
286   return buffer;
287 }
288
289 const char* mc_api::get_actor_host_name(smx_actor_t actor) const
290 {
291   const char* host_name = MC_smx_actor_get_host_name(actor);
292   return host_name;
293 }
294
295 bool mc_api::check_send_request_detached(smx_simcall_t const& simcall) const
296 {
297   simgrid::smpi::Request mpi_request;
298   mc_model_checker->get_remote_simulation().read(
299       &mpi_request, remote(static_cast<smpi::Request*>(simcall_comm_isend__get__data(simcall))));
300   return mpi_request.detached();
301 }
302
303 smx_actor_t mc_api::get_src_actor(mc::RemotePtr<kernel::activity::CommImpl> const& comm_addr) const
304 {
305   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
306   mc_model_checker->get_remote_simulation().read(temp_comm, comm_addr);
307   const simgrid::kernel::activity::CommImpl* comm = temp_comm.get_buffer();
308
309   auto src_proc = mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(comm->src_actor_.get()));
310   return src_proc;
311 }
312
313 smx_actor_t mc_api::get_dst_actor(mc::RemotePtr<kernel::activity::CommImpl> const& comm_addr) const
314 {
315   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
316   mc_model_checker->get_remote_simulation().read(temp_comm, comm_addr);
317   const simgrid::kernel::activity::CommImpl* comm = temp_comm.get_buffer();
318
319   auto dst_proc = mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(comm->dst_actor_.get()));
320   return dst_proc;
321 }
322
323 std::size_t mc_api::get_remote_heap_bytes() const
324 {
325   RemoteSimulation& process = mc_model_checker->get_remote_simulation();
326   auto heap_bytes_used      = mmalloc_get_bytes_used_remote(process.get_heap()->heaplimit, process.get_malloc_info());
327   return heap_bytes_used;
328 }
329
330 void mc_api::s_initialize() const
331 {
332   session->initialize();
333 }
334
335 ModelChecker* mc_api::get_model_checker() const
336 {
337   return mc_model_checker;
338 }
339
340 void mc_api::mc_inc_visited_states() const
341 {
342   mc_model_checker->visited_states++;
343 }
344
345 void mc_api::mc_inc_executed_trans() const
346 {
347   mc_model_checker->executed_transitions++;
348 }
349
350 unsigned long mc_api::mc_get_visited_states() const
351 {
352   return mc_model_checker->visited_states;
353 }
354
355 unsigned long mc_api::mc_get_executed_trans() const
356 {
357   return mc_model_checker->executed_transitions;
358 }
359
360 bool mc_api::mc_check_deadlock() const
361 {
362   return mc_model_checker->checkDeadlock();
363 }
364
365 void mc_api::mc_show_deadlock() const
366 {
367   MC_show_deadlock();
368 }
369
370 smx_actor_t mc_api::mc_smx_simcall_get_issuer(s_smx_simcall const* req) const
371 {
372   return MC_smx_simcall_get_issuer(req);
373 }
374
375 bool mc_api::mc_is_null() const
376 {
377   auto is_null = (mc_model_checker == nullptr) ? true : false;
378   return is_null;
379 }
380
381 Checker* mc_api::mc_get_checker() const
382 {
383   return mc_model_checker->getChecker();
384 }
385
386 RemoteSimulation& mc_api::mc_get_remote_simulation() const
387 {
388   return mc_model_checker->get_remote_simulation();
389 }
390
391 void mc_api::handle_simcall(Transition const& transition) const
392 {
393   mc_model_checker->handle_simcall(transition);
394 }
395
396 void mc_api::mc_wait_for_requests() const
397 {
398   mc_model_checker->wait_for_requests();
399 }
400
401 void mc_api::mc_exit(int status) const
402 {
403   mc_model_checker->exit(status);
404 }
405
406 std::string const& mc_api::mc_get_host_name(std::string const& hostname) const
407 {
408   return mc_model_checker->get_host_name(hostname);
409 }
410
411 void mc_api::mc_dump_record_path() const
412 {
413   simgrid::mc::dumpRecordPath();
414 }
415
416 smx_simcall_t mc_api::mc_state_choose_request(simgrid::mc::State* state) const
417 {
418   for (auto& actor : mc_model_checker->get_remote_simulation().actors()) {
419     /* Only consider the actors that were marked as interleaving by the checker algorithm */
420     if (not state->actor_states_[actor.copy.get_buffer()->get_pid()].is_todo())
421       continue;
422
423     smx_simcall_t res = MC_state_choose_request_for_process(state, actor.copy.get_buffer());
424     if (res)
425       return res;
426   }
427   return nullptr;
428 }
429
430 bool mc_api::request_depend(smx_simcall_t req1, smx_simcall_t req2) const
431 {
432   return simgrid::mc::request_depend(req1, req2);
433 }
434
435 std::string mc_api::request_to_string(smx_simcall_t req, int value, RequestType request_type) const
436 {
437   return simgrid::mc::request_to_string(req, value, request_type).c_str();
438 }
439
440 std::string mc_api::request_get_dot_output(smx_simcall_t req, int value) const
441 {
442   return simgrid::mc::request_get_dot_output(req, value);
443 }
444
445 const char* mc_api::simix_simcall_name(simgrid::simix::Simcall kind) const
446 {
447   return SIMIX_simcall_name(kind);
448 }
449
450 #if HAVE_SMPI
451 int mc_api::get_smpi_request_tag(smx_simcall_t const& simcall, simgrid::simix::Simcall type) const
452 {
453   simgrid::smpi::Request mpi_request;
454   void* simcall_data = nullptr;
455   if (type == Simcall::COMM_ISEND)
456     simcall_data = simcall_comm_isend__get__data(simcall);
457   else if (type == Simcall::COMM_IRECV)
458     simcall_data = simcall_comm_irecv__get__data(simcall);
459   mc_model_checker->get_remote_simulation().read(&mpi_request, remote(static_cast<smpi::Request*>(simcall_data)));
460   return mpi_request.tag();
461 }
462 #endif
463
464 void mc_api::restore_state(std::shared_ptr<simgrid::mc::Snapshot> system_state) const
465 {
466   system_state->restore(&mc_model_checker->get_remote_simulation());
467 }
468
469 bool mc_api::snapshot_equal(const Snapshot* s1, const Snapshot* s2) const
470 {
471   return simgrid::mc::snapshot_equal(s1, s2);
472 }
473
474 simgrid::mc::Snapshot* mc_api::take_snapshot(int num_state) const
475 {
476   auto snapshot = new simgrid::mc::Snapshot(num_state);
477   return snapshot;
478 }
479
480 void mc_api::s_close() const
481 {
482   session->close();
483 }
484
485 void mc_api::s_restore_initial_state() const
486 {
487   session->restore_initial_state();
488 }
489
490 void mc_api::execute(Transition const& transition)
491 {
492   session->execute(transition);
493 }
494
495 void mc_api::log_state() const
496 {
497   session->log_state();
498 }
499
500 } // namespace mc
501 } // namespace simgrid