Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Session instance removed from Checker class
[simgrid.git] / src / mc / mc_api.cpp
1 #include "mc_api.hpp"
2
3 #include "src/kernel/activity/MailboxImpl.hpp"
4 #include "src/kernel/activity/MutexImpl.hpp"
5 #include "src/mc/Session.hpp"
6 #include "src/mc/mc_comm_pattern.hpp"
7 #include "src/mc/mc_private.hpp"
8 #include "src/mc/mc_record.hpp"
9 #include "src/mc/mc_smx.hpp"
10 #include "src/mc/remote/RemoteSimulation.hpp"
11 #include "src/mc/mc_pattern.hpp"
12 #include "src/mc/checker/SimcallInspector.hpp"
13 #include <xbt/asserts.h>
14 #include <xbt/log.h>
15 // #include <xbt/dynar.h>
16
17 #if HAVE_SMPI
18 #include "src/smpi/include/smpi_request.hpp"
19 #endif
20
21 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_api, mc, "Logging specific to MC Fasade APIs ");
22
23 using Simcall = simgrid::simix::Simcall;
24
25 namespace simgrid {
26 namespace mc {
27
28 static inline const char* get_color(int id)
29 {
30   static constexpr std::array<const char*, 13> colors{{"blue", "red", "green3", "goldenrod", "brown", "purple",
31                                                        "magenta", "turquoise4", "gray25", "forestgreen", "hotpink",
32                                                        "lightblue", "tan"}};
33   return colors[id % colors.size()];
34 }
35
36 static char *pointer_to_string(void *pointer)
37 {
38   if (XBT_LOG_ISENABLED(mc_api, xbt_log_priority_verbose))
39     return bprintf("%p", pointer);
40
41   return xbt_strdup("(verbose only)");
42 }
43
44 static char *buff_size_to_string(size_t buff_size)
45 {
46   if (XBT_LOG_ISENABLED(mc_api, xbt_log_priority_verbose))
47     return bprintf("%zu", buff_size);
48
49   return xbt_strdup("(verbose only)");
50 }
51
52 /* Search an enabled transition for the given process.
53  *
54  * This can be seen as an iterator returning the next transition of the process.
55  *
56  * We only consider the processes that are both
57  *  - marked "to be interleaved" in their ActorState (controlled by the checker algorithm).
58  *  - which simcall can currently be executed (like a comm where the other partner is already known)
59  * Once we returned the last enabled transition of a process, it is marked done.
60  *
61  * Things can get muddled with the WAITANY and TESTANY simcalls, that are rewritten on the fly to a bunch of WAIT
62  * (resp TEST) transitions using the transition.argument field to remember what was the last returned sub-transition.
63  */
64 static inline smx_simcall_t MC_state_choose_request_for_process(simgrid::mc::State* state, smx_actor_t actor)
65 {
66   /* reset the outgoing transition */
67   simgrid::mc::ActorState* procstate = &state->actor_states_[actor->get_pid()];
68   state->transition_.pid_            = -1;
69   state->transition_.argument_       = -1;
70   state->executed_req_.call_         =  Simcall::NONE;
71
72   if (not simgrid::mc::actor_is_enabled(actor))
73     return nullptr; // Not executable in the application
74
75   smx_simcall_t req = nullptr;
76   switch (actor->simcall_.call_) {
77     case Simcall::COMM_WAITANY:
78       state->transition_.argument_ = -1;
79       while (procstate->times_considered < simcall_comm_waitany__get__count(&actor->simcall_)) {
80         if (simgrid::mc::request_is_enabled_by_idx(&actor->simcall_, procstate->times_considered)) {
81           state->transition_.argument_ = procstate->times_considered;
82           ++procstate->times_considered;
83           break;
84         }
85         ++procstate->times_considered;
86       }
87
88       if (procstate->times_considered >= simcall_comm_waitany__get__count(&actor->simcall_))
89         procstate->set_done();
90       if (state->transition_.argument_ != -1)
91         req = &actor->simcall_;
92       break;
93
94     case Simcall::COMM_TESTANY: {
95       unsigned start_count         = procstate->times_considered;
96       state->transition_.argument_ = -1;
97       while (procstate->times_considered < simcall_comm_testany__get__count(&actor->simcall_)) {
98         if (simgrid::mc::request_is_enabled_by_idx(&actor->simcall_, procstate->times_considered)) {
99           state->transition_.argument_ = procstate->times_considered;
100           ++procstate->times_considered;
101           break;
102         }
103         ++procstate->times_considered;
104       }
105
106       if (procstate->times_considered >= simcall_comm_testany__get__count(&actor->simcall_))
107         procstate->set_done();
108
109       if (state->transition_.argument_ != -1 || start_count == 0)
110         req = &actor->simcall_;
111
112       break;
113     }
114
115     case Simcall::COMM_WAIT: {
116       simgrid::mc::RemotePtr<simgrid::kernel::activity::CommImpl> remote_act =
117           remote(simcall_comm_wait__getraw__comm(&actor->simcall_));
118       simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_act;
119       mc_model_checker->get_remote_simulation().read(temp_act, remote_act);
120       const simgrid::kernel::activity::CommImpl* act = temp_act.get_buffer();
121       if (act->src_actor_.get() && act->dst_actor_.get())
122         state->transition_.argument_ = 0; // OK
123       else if (act->src_actor_.get() == nullptr && act->type_ == simgrid::kernel::activity::CommImpl::Type::READY &&
124                act->detached())
125         state->transition_.argument_ = 0; // OK
126       else
127         state->transition_.argument_ = -1; // timeout
128       procstate->set_done();
129       req = &actor->simcall_;
130       break;
131     }
132
133     case Simcall::MC_RANDOM: {
134       int min_value                = simcall_mc_random__get__min(&actor->simcall_);
135       state->transition_.argument_ = procstate->times_considered + min_value;
136       procstate->times_considered++;
137       if (state->transition_.argument_ == simcall_mc_random__get__max(&actor->simcall_))
138         procstate->set_done();
139       req = &actor->simcall_;
140       break;
141     }
142
143     default:
144       procstate->set_done();
145       state->transition_.argument_ = 0;
146       req                          = &actor->simcall_;
147       break;
148   }
149   if (not req)
150     return nullptr;
151
152   state->transition_.pid_ = actor->get_pid();
153   state->executed_req_    = *req;
154   // Fetch the data of the request and translate it:
155   state->internal_req_ = *req;
156
157   /* The waitany and testany request are transformed into a wait or test request over the corresponding communication
158    * action so it can be treated later by the dependence function. */
159   switch (req->call_) {
160     case Simcall::COMM_WAITANY: {
161       state->internal_req_.call_ = Simcall::COMM_WAIT;
162       simgrid::kernel::activity::CommImpl* remote_comm;
163       remote_comm = mc_model_checker->get_remote_simulation().read(
164           remote(simcall_comm_waitany__get__comms(req) + state->transition_.argument_));
165       mc_model_checker->get_remote_simulation().read(state->internal_comm_, remote(remote_comm));
166       simcall_comm_wait__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
167       simcall_comm_wait__set__timeout(&state->internal_req_, 0);
168       break;
169     }
170
171     case Simcall::COMM_TESTANY:
172       state->internal_req_.call_ = Simcall::COMM_TEST;
173
174       if (state->transition_.argument_ > 0) {
175         simgrid::kernel::activity::CommImpl* remote_comm = mc_model_checker->get_remote_simulation().read(
176             remote(simcall_comm_testany__get__comms(req) + state->transition_.argument_));
177         mc_model_checker->get_remote_simulation().read(state->internal_comm_, remote(remote_comm));
178       }
179
180       simcall_comm_test__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
181       simcall_comm_test__set__result(&state->internal_req_, state->transition_.argument_);
182       break;
183
184     case Simcall::COMM_WAIT:
185       mc_model_checker->get_remote_simulation().read_bytes(&state->internal_comm_, sizeof(state->internal_comm_),
186                                                            remote(simcall_comm_wait__getraw__comm(req)));
187       simcall_comm_wait__set__comm(&state->executed_req_, state->internal_comm_.get_buffer());
188       simcall_comm_wait__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
189       break;
190
191     case Simcall::COMM_TEST:
192       mc_model_checker->get_remote_simulation().read_bytes(&state->internal_comm_, sizeof(state->internal_comm_),
193                                                            remote(simcall_comm_test__getraw__comm(req)));
194       simcall_comm_test__set__comm(&state->executed_req_, state->internal_comm_.get_buffer());
195       simcall_comm_test__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
196       break;
197
198     default:
199       /* No translation needed */
200       break;
201   }
202
203   return req;
204 }
205
206 void mc_api::initialize(char** argv)
207 {
208   simgrid::mc::session = new simgrid::mc::Session([argv] {
209     int i = 1;
210     while (argv[i] != nullptr && argv[i][0] == '-')
211       i++;
212     xbt_assert(argv[i] != nullptr,
213                "Unable to find a binary to exec on the command line. Did you only pass config flags?");
214     execvp(argv[i], argv + i);
215     xbt_die("The model-checked process failed to exec(): %s", strerror(errno));
216   });
217 }
218
219 std::vector<simgrid::mc::ActorInformation>& mc_api::get_actors() const
220 {
221   return mc_model_checker->get_remote_simulation().actors();
222 }
223
224 bool mc_api::actor_is_enabled(aid_t pid) const
225 {
226   return session->actor_is_enabled(pid);
227 }
228
229 unsigned long mc_api::get_maxpid() const
230 {
231   return MC_smx_get_maxpid();
232 }
233
234 int mc_api::get_actors_size() const
235 {
236   return mc_model_checker->get_remote_simulation().actors().size();
237 }
238
239 bool mc_api::comm_addr_equal(const kernel::activity::CommImpl* comm_addr1, const kernel::activity::CommImpl* comm_addr2) const
240 {
241   return remote(comm_addr1) == remote(comm_addr2);
242 }
243
244 kernel::activity::CommImpl* mc_api::get_comm_isend_raw_addr(smx_simcall_t request) const
245 {
246   auto comm_addr = simcall_comm_isend__getraw__result(request);
247   return static_cast<kernel::activity::CommImpl*>(comm_addr);
248 }
249
250 kernel::activity::CommImpl* mc_api::get_comm_wait_raw_addr(smx_simcall_t request) const
251 {
252   return simcall_comm_wait__getraw__comm(request);
253 }
254
255 kernel::activity::CommImpl* mc_api::get_comm_waitany_raw_addr(smx_simcall_t request, int value) const
256 {
257   auto addr = mc_model_checker->get_remote_simulation().read(remote(simcall_comm_waitany__getraw__comms(request) + value));
258   return static_cast<simgrid::kernel::activity::CommImpl*>(addr);
259 }
260
261 std::string mc_api::get_pattern_comm_rdv(void* addr) const
262 {
263   Remote<kernel::activity::CommImpl> temp_synchro;
264   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
265   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
266
267   char* remote_name = mc_model_checker->get_remote_simulation().read<char*>(RemotePtr<char*>(
268       (uint64_t)(synchro->get_mailbox() ? &synchro->get_mailbox()->get_name() : &synchro->mbox_cpy->get_name())));
269   auto rdv = mc_model_checker->get_remote_simulation().read_string(RemotePtr<char>(remote_name));
270   return rdv;
271 }
272
273 unsigned long mc_api::get_pattern_comm_src_proc(void* addr) const
274 {
275   Remote<kernel::activity::CommImpl> temp_synchro;
276   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
277   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
278   auto src_proc = mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(synchro->src_actor_.get()))->get_pid();
279   return src_proc;
280 }
281
282 unsigned long mc_api::get_pattern_comm_dst_proc(void* addr) const
283 {
284   Remote<kernel::activity::CommImpl> temp_synchro;
285   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
286   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
287   auto src_proc = mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(synchro->dst_actor_.get()))->get_pid();
288   return src_proc;
289 }
290
291 std::vector<char> mc_api::get_pattern_comm_data(void* addr) const
292 {
293   Remote<kernel::activity::CommImpl> temp_synchro;
294   mc_model_checker->get_remote_simulation().read(temp_synchro, remote((simgrid::kernel::activity::CommImpl*)addr));
295   const kernel::activity::CommImpl* synchro = temp_synchro.get_buffer();
296
297   std::vector<char> buffer {};
298   if (synchro->src_buff_ != nullptr) {
299     buffer.resize(synchro->src_buff_size_);
300     mc_model_checker->get_remote_simulation().read_bytes(buffer.data(), buffer.size(),
301                                                          remote(synchro->src_buff_));
302   }
303   return buffer;
304 }
305
306 std::vector<char> mc_api::get_pattern_comm_data(const kernel::activity::CommImpl* comm_addr) const
307 {
308   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
309   mc_model_checker->get_remote_simulation().read(temp_comm, remote((kernel::activity::CommImpl*)comm_addr));
310   const simgrid::kernel::activity::CommImpl* comm = temp_comm.get_buffer();
311   
312   std::vector<char> buffer {};
313   if (comm->src_buff_ != nullptr) {
314     buffer.resize(comm->src_buff_size_);
315     mc_model_checker->get_remote_simulation().read_bytes(buffer.data(), buffer.size(),
316                                                          remote(comm->src_buff_));
317   }
318   return buffer;
319 }
320
321 const char* mc_api::get_actor_host_name(smx_actor_t actor) const
322 {
323   const char* host_name = MC_smx_actor_get_host_name(actor);
324   return host_name;
325 }
326
327 #if HAVE_SMPI
328 bool mc_api::check_send_request_detached(smx_simcall_t const& simcall) const
329 {
330   simgrid::smpi::Request mpi_request;
331   mc_model_checker->get_remote_simulation().read(
332       &mpi_request, remote(static_cast<smpi::Request*>(simcall_comm_isend__get__data(simcall))));
333   return mpi_request.detached();
334 }
335 #endif
336
337 smx_actor_t mc_api::get_src_actor(const kernel::activity::CommImpl* comm_addr) const
338 {
339   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
340   mc_model_checker->get_remote_simulation().read(temp_comm, remote((kernel::activity::CommImpl*)comm_addr));
341   const simgrid::kernel::activity::CommImpl* comm = temp_comm.get_buffer();
342
343   auto src_proc = mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(comm->src_actor_.get()));
344   return src_proc;
345 }
346
347 smx_actor_t mc_api::get_dst_actor(const kernel::activity::CommImpl* comm_addr) const
348 {
349   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
350   mc_model_checker->get_remote_simulation().read(temp_comm, remote((kernel::activity::CommImpl*)comm_addr));
351   const simgrid::kernel::activity::CommImpl* comm = temp_comm.get_buffer();
352
353   auto dst_proc = mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(comm->dst_actor_.get()));
354   return dst_proc;
355 }
356
357 std::size_t mc_api::get_remote_heap_bytes() const
358 {
359   RemoteSimulation& process = mc_model_checker->get_remote_simulation();
360   auto heap_bytes_used      = mmalloc_get_bytes_used_remote(process.get_heap()->heaplimit, process.get_malloc_info());
361   return heap_bytes_used;
362 }
363
364 void mc_api::session_initialize() const
365 {
366   session->initialize();
367 }
368
369 ModelChecker* mc_api::get_model_checker() const
370 {
371   return mc_model_checker;
372 }
373
374 void mc_api::mc_inc_visited_states() const
375 {
376   mc_model_checker->visited_states++;
377 }
378
379 void mc_api::mc_inc_executed_trans() const
380 {
381   mc_model_checker->executed_transitions++;
382 }
383
384 unsigned long mc_api::mc_get_visited_states() const
385 {
386   return mc_model_checker->visited_states;
387 }
388
389 unsigned long mc_api::mc_get_executed_trans() const
390 {
391   return mc_model_checker->executed_transitions;
392 }
393
394 bool mc_api::mc_check_deadlock() const
395 {
396   return mc_model_checker->checkDeadlock();
397 }
398
399 void mc_api::mc_show_deadlock() const
400 {
401   MC_show_deadlock();
402 }
403
404 smx_actor_t mc_api::simcall_get_issuer(s_smx_simcall const* req) const
405 {
406   return MC_smx_simcall_get_issuer(req);
407 }
408
409 bool mc_api::mc_is_null() const
410 {
411   auto is_null = (mc_model_checker == nullptr) ? true : false;
412   return is_null;
413 }
414
415 Checker* mc_api::mc_get_checker() const
416 {
417   return mc_model_checker->getChecker();
418 }
419
420 RemoteSimulation& mc_api::mc_get_remote_simulation() const
421 {
422   return mc_model_checker->get_remote_simulation();
423 }
424
425 void mc_api::handle_simcall(Transition const& transition) const
426 {
427   mc_model_checker->handle_simcall(transition);
428 }
429
430 void mc_api::mc_wait_for_requests() const
431 {
432   mc_model_checker->wait_for_requests();
433 }
434
435 void mc_api::mc_exit(int status) const
436 {
437   mc_model_checker->exit(status);
438 }
439
440 std::string const& mc_api::mc_get_host_name(std::string const& hostname) const
441 {
442   return mc_model_checker->get_host_name(hostname);
443 }
444
445 void mc_api::dump_record_path() const
446 {
447   simgrid::mc::dumpRecordPath();
448 }
449
450 smx_simcall_t mc_api::mc_state_choose_request(simgrid::mc::State* state) const
451 {
452   for (auto& actor : mc_model_checker->get_remote_simulation().actors()) {
453     /* Only consider the actors that were marked as interleaving by the checker algorithm */
454     if (not state->actor_states_[actor.copy.get_buffer()->get_pid()].is_todo())
455       continue;
456
457     smx_simcall_t res = MC_state_choose_request_for_process(state, actor.copy.get_buffer());
458     if (res)
459       return res;
460   }
461   return nullptr;
462 }
463
464 bool mc_api::request_depend(smx_simcall_t req1, smx_simcall_t req2) const
465 {
466   return simgrid::mc::request_depend(req1, req2);
467 }
468
469 std::string mc_api::request_to_string(smx_simcall_t req, int value, RequestType request_type) const
470 {
471   xbt_assert(mc_model_checker != nullptr, "Must be called from MCer");
472
473   if (req->inspector_ != nullptr)
474     return req->inspector_->to_string();
475
476   bool use_remote_comm = true;
477   switch(request_type) {
478   case simgrid::mc::RequestType::simix:
479     use_remote_comm = true;
480     break;
481   case simgrid::mc::RequestType::executed:
482   case simgrid::mc::RequestType::internal:
483     use_remote_comm = false;
484     break;
485   default:
486     THROW_IMPOSSIBLE;
487   }
488
489   const char* type = nullptr;
490   char *args = nullptr;
491
492   smx_actor_t issuer = MC_smx_simcall_get_issuer(req);
493
494   switch (req->call_) {
495     case Simcall::COMM_ISEND: {
496       type     = "iSend";
497       char* p  = pointer_to_string(simcall_comm_isend__get__src_buff(req));
498       char* bs = buff_size_to_string(simcall_comm_isend__get__src_buff_size(req));
499       if (issuer->get_host())
500         args = bprintf("src=(%ld)%s (%s), buff=%s, size=%s", issuer->get_pid(), MC_smx_actor_get_host_name(issuer),
501                        MC_smx_actor_get_name(issuer), p, bs);
502       else
503         args = bprintf("src=(%ld)%s, buff=%s, size=%s", issuer->get_pid(), MC_smx_actor_get_name(issuer), p, bs);
504       xbt_free(bs);
505       xbt_free(p);
506       break;
507     }
508
509     case Simcall::COMM_IRECV: {
510       size_t* remote_size = simcall_comm_irecv__get__dst_buff_size(req);
511       size_t size         = 0;
512       if (remote_size)
513         mc_model_checker->get_remote_simulation().read_bytes(&size, sizeof(size), remote(remote_size));
514
515       type     = "iRecv";
516       char* p  = pointer_to_string(simcall_comm_irecv__get__dst_buff(req));
517       char* bs = buff_size_to_string(size);
518       if (issuer->get_host())
519         args = bprintf("dst=(%ld)%s (%s), buff=%s, size=%s", issuer->get_pid(), MC_smx_actor_get_host_name(issuer),
520                        MC_smx_actor_get_name(issuer), p, bs);
521       else
522         args = bprintf("dst=(%ld)%s, buff=%s, size=%s", issuer->get_pid(), MC_smx_actor_get_name(issuer), p, bs);
523       xbt_free(bs);
524       xbt_free(p);
525       break;
526     }
527
528     case Simcall::COMM_WAIT: {
529       simgrid::kernel::activity::CommImpl* remote_act = simcall_comm_wait__getraw__comm(req);
530       char* p;
531       if (value == -1) {
532         type = "WaitTimeout";
533         p    = pointer_to_string(remote_act);
534         args = bprintf("comm=%s", p);
535       } else {
536         type = "Wait";
537         p    = pointer_to_string(remote_act);
538
539         simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_synchro;
540         const simgrid::kernel::activity::CommImpl* act;
541         if (use_remote_comm) {
542           mc_model_checker->get_remote_simulation().read(temp_synchro, remote(remote_act));
543           act = temp_synchro.get_buffer();
544         } else
545           act = remote_act;
546
547         smx_actor_t src_proc =
548             mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(act->src_actor_.get()));
549         smx_actor_t dst_proc =
550             mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(act->dst_actor_.get()));
551         args                 = bprintf("comm=%s [(%ld)%s (%s)-> (%ld)%s (%s)]", p, src_proc ? src_proc->get_pid() : 0,
552                        src_proc ? MC_smx_actor_get_host_name(src_proc) : "",
553                        src_proc ? MC_smx_actor_get_name(src_proc) : "", dst_proc ? dst_proc->get_pid() : 0,
554                        dst_proc ? MC_smx_actor_get_host_name(dst_proc) : "",
555                        dst_proc ? MC_smx_actor_get_name(dst_proc) : "");
556       }
557       xbt_free(p);
558       break;
559     }
560
561     case Simcall::COMM_TEST: {
562       simgrid::kernel::activity::CommImpl* remote_act = simcall_comm_test__getraw__comm(req);
563       simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_synchro;
564       const simgrid::kernel::activity::CommImpl* act;
565       if (use_remote_comm) {
566         mc_model_checker->get_remote_simulation().read(temp_synchro, remote(remote_act));
567         act = temp_synchro.get_buffer();
568       } else
569         act = remote_act;
570
571       char* p;
572       if (act->src_actor_.get() == nullptr || act->dst_actor_.get() == nullptr) {
573         type = "Test FALSE";
574         p    = pointer_to_string(remote_act);
575         args = bprintf("comm=%s", p);
576       } else {
577         type = "Test TRUE";
578         p    = pointer_to_string(remote_act);
579
580         smx_actor_t src_proc =
581             mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(act->src_actor_.get()));
582         smx_actor_t dst_proc =
583             mc_model_checker->get_remote_simulation().resolve_actor(simgrid::mc::remote(act->dst_actor_.get()));
584         args                 = bprintf("comm=%s [(%ld)%s (%s) -> (%ld)%s (%s)]", p, src_proc->get_pid(),
585                        MC_smx_actor_get_name(src_proc), MC_smx_actor_get_host_name(src_proc), dst_proc->get_pid(),
586                        MC_smx_actor_get_name(dst_proc), MC_smx_actor_get_host_name(dst_proc));
587       }
588       xbt_free(p);
589       break;
590     }
591
592     case Simcall::COMM_WAITANY: {
593       type         = "WaitAny";
594       size_t count = simcall_comm_waitany__get__count(req);
595       if (count > 0) {
596         simgrid::kernel::activity::CommImpl* remote_sync;
597         remote_sync =
598             mc_model_checker->get_remote_simulation().read(remote(simcall_comm_waitany__get__comms(req) + value));
599         char* p     = pointer_to_string(remote_sync);
600         args        = bprintf("comm=%s (%d of %zu)", p, value + 1, count);
601         xbt_free(p);
602       } else
603         args = bprintf("comm at idx %d", value);
604       break;
605     }
606
607     case Simcall::COMM_TESTANY:
608       if (value == -1) {
609         type = "TestAny FALSE";
610         args = xbt_strdup("-");
611       } else {
612         type = "TestAny";
613         args = bprintf("(%d of %zu)", value + 1, simcall_comm_testany__get__count(req));
614       }
615       break;
616
617     case Simcall::MUTEX_TRYLOCK:
618     case Simcall::MUTEX_LOCK: {
619       if (req->call_ == Simcall::MUTEX_LOCK)
620         type = "Mutex LOCK";
621       else
622         type = "Mutex TRYLOCK";
623
624       simgrid::mc::Remote<simgrid::kernel::activity::MutexImpl> mutex;
625       mc_model_checker->get_remote_simulation().read_bytes(mutex.get_buffer(), sizeof(mutex),
626                                                            remote(req->call_ == Simcall::MUTEX_LOCK
627                                                                       ? simcall_mutex_lock__get__mutex(req)
628                                                                       : simcall_mutex_trylock__get__mutex(req)));
629       args = bprintf("locked = %d, owner = %d, sleeping = n/a", mutex.get_buffer()->is_locked(),
630                      mutex.get_buffer()->get_owner() != nullptr
631                          ? (int)mc_model_checker->get_remote_simulation()
632                                .resolve_actor(simgrid::mc::remote(mutex.get_buffer()->get_owner()))
633                                ->get_pid()
634                          : -1);
635       break;
636     }
637
638     case Simcall::MC_RANDOM:
639       type = "MC_RANDOM";
640       args = bprintf("%d", value);
641       break;
642
643     default:
644       type = SIMIX_simcall_name(req->call_);
645       args = bprintf("??");
646       break;
647   }
648
649   std::string str;
650   if (args != nullptr)
651     str = simgrid::xbt::string_printf("[(%ld)%s (%s)] %s(%s)", issuer->get_pid(), MC_smx_actor_get_host_name(issuer),
652                                       MC_smx_actor_get_name(issuer), type, args);
653   else
654     str = simgrid::xbt::string_printf("[(%ld)%s (%s)] %s ", issuer->get_pid(), MC_smx_actor_get_host_name(issuer),
655                                       MC_smx_actor_get_name(issuer), type);
656   xbt_free(args);
657   return str;  
658 }
659
660 std::string mc_api::request_get_dot_output(smx_simcall_t req, int value) const
661 {
662   const smx_actor_t issuer = MC_smx_simcall_get_issuer(req);
663   const char* color        = get_color(issuer->get_pid() - 1);
664
665   if (req->inspector_ != nullptr)
666     return simgrid::xbt::string_printf("label = \"%s\", color = %s, fontcolor = %s",
667                                        req->inspector_->dot_label().c_str(), color, color);
668
669   std::string label;
670
671   switch (req->call_) {
672     case Simcall::COMM_ISEND:
673       if (issuer->get_host())
674         label = xbt::string_printf("[(%ld)%s] iSend", issuer->get_pid(), MC_smx_actor_get_host_name(issuer));
675       else
676         label = bprintf("[(%ld)] iSend", issuer->get_pid());
677       break;
678
679     case Simcall::COMM_IRECV:
680       if (issuer->get_host())
681         label = xbt::string_printf("[(%ld)%s] iRecv", issuer->get_pid(), MC_smx_actor_get_host_name(issuer));
682       else
683         label = xbt::string_printf("[(%ld)] iRecv", issuer->get_pid());
684       break;
685
686     case Simcall::COMM_WAIT:
687       if (value == -1) {
688         if (issuer->get_host())
689           label = xbt::string_printf("[(%ld)%s] WaitTimeout", issuer->get_pid(), MC_smx_actor_get_host_name(issuer));
690         else
691           label = xbt::string_printf("[(%ld)] WaitTimeout", issuer->get_pid());
692       } else {
693         kernel::activity::ActivityImpl* remote_act = simcall_comm_wait__getraw__comm(req);
694         Remote<kernel::activity::CommImpl> temp_comm;
695         mc_model_checker->get_remote_simulation().read(temp_comm,
696                                                        remote(static_cast<kernel::activity::CommImpl*>(remote_act)));
697         const kernel::activity::CommImpl* comm = temp_comm.get_buffer();
698
699         const kernel::actor::ActorImpl* src_proc =
700             mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(comm->src_actor_.get()));
701         const kernel::actor::ActorImpl* dst_proc =
702             mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(comm->dst_actor_.get()));
703         if (issuer->get_host())
704           label =
705               xbt::string_printf("[(%ld)%s] Wait [(%ld)->(%ld)]", issuer->get_pid(), MC_smx_actor_get_host_name(issuer),
706                                  src_proc ? src_proc->get_pid() : 0, dst_proc ? dst_proc->get_pid() : 0);
707         else
708           label = xbt::string_printf("[(%ld)] Wait [(%ld)->(%ld)]", issuer->get_pid(),
709                                      src_proc ? src_proc->get_pid() : 0, dst_proc ? dst_proc->get_pid() : 0);
710       }
711       break;
712
713     case Simcall::COMM_TEST: {
714       kernel::activity::ActivityImpl* remote_act = simcall_comm_test__getraw__comm(req);
715       Remote<simgrid::kernel::activity::CommImpl> temp_comm;
716       mc_model_checker->get_remote_simulation().read(temp_comm,
717                                                      remote(static_cast<kernel::activity::CommImpl*>(remote_act)));
718       const kernel::activity::CommImpl* comm = temp_comm.get_buffer();
719       if (comm->src_actor_.get() == nullptr || comm->dst_actor_.get() == nullptr) {
720         if (issuer->get_host())
721           label = xbt::string_printf("[(%ld)%s] Test FALSE", issuer->get_pid(), MC_smx_actor_get_host_name(issuer));
722         else
723           label = bprintf("[(%ld)] Test FALSE", issuer->get_pid());
724       } else {
725         if (issuer->get_host())
726           label = xbt::string_printf("[(%ld)%s] Test TRUE", issuer->get_pid(), MC_smx_actor_get_host_name(issuer));
727         else
728           label = xbt::string_printf("[(%ld)] Test TRUE", issuer->get_pid());
729       }
730       break;
731     }
732
733     case Simcall::COMM_WAITANY: {
734       size_t comms_size = simcall_comm_waitany__get__count(req);
735       if (issuer->get_host())
736         label = xbt::string_printf("[(%ld)%s] WaitAny [%d of %zu]", issuer->get_pid(),
737                                    MC_smx_actor_get_host_name(issuer), value + 1, comms_size);
738       else
739         label = xbt::string_printf("[(%ld)] WaitAny [%d of %zu]", issuer->get_pid(), value + 1, comms_size);
740       break;
741     }
742
743     case Simcall::COMM_TESTANY:
744       if (value == -1) {
745         if (issuer->get_host())
746           label = xbt::string_printf("[(%ld)%s] TestAny FALSE", issuer->get_pid(), MC_smx_actor_get_host_name(issuer));
747         else
748           label = xbt::string_printf("[(%ld)] TestAny FALSE", issuer->get_pid());
749       } else {
750         if (issuer->get_host())
751           label =
752               xbt::string_printf("[(%ld)%s] TestAny TRUE [%d of %lu]", issuer->get_pid(),
753                                  MC_smx_actor_get_host_name(issuer), value + 1, simcall_comm_testany__get__count(req));
754         else
755           label = xbt::string_printf("[(%ld)] TestAny TRUE [%d of %lu]", issuer->get_pid(), value + 1,
756                                      simcall_comm_testany__get__count(req));
757       }
758       break;
759
760     case Simcall::MUTEX_TRYLOCK:
761       label = xbt::string_printf("[(%ld)] Mutex TRYLOCK", issuer->get_pid());
762       break;
763
764     case Simcall::MUTEX_LOCK:
765       label = xbt::string_printf("[(%ld)] Mutex LOCK", issuer->get_pid());
766       break;
767
768     case Simcall::MC_RANDOM:
769       if (issuer->get_host())
770         label = xbt::string_printf("[(%ld)%s] MC_RANDOM (%d)", issuer->get_pid(), MC_smx_actor_get_host_name(issuer),
771                                    value);
772       else
773         label = xbt::string_printf("[(%ld)] MC_RANDOM (%d)", issuer->get_pid(), value);
774       break;
775
776     default:
777       THROW_UNIMPLEMENTED;
778   }
779
780   return xbt::string_printf("label = \"%s\", color = %s, fontcolor = %s", label.c_str(), color, color);  
781 }
782
783 const char* mc_api::simcall_get_name(simgrid::simix::Simcall kind) const
784 {
785   return SIMIX_simcall_name(kind);
786 }
787
788 #if HAVE_SMPI
789 int mc_api::get_smpi_request_tag(smx_simcall_t const& simcall, simgrid::simix::Simcall type) const
790 {
791   simgrid::smpi::Request mpi_request;
792   void* simcall_data = nullptr;
793   if (type == Simcall::COMM_ISEND)
794     simcall_data = simcall_comm_isend__get__data(simcall);
795   else if (type == Simcall::COMM_IRECV)
796     simcall_data = simcall_comm_irecv__get__data(simcall);
797   mc_model_checker->get_remote_simulation().read(&mpi_request, remote(static_cast<smpi::Request*>(simcall_data)));
798   return mpi_request.tag();
799 }
800 #endif
801
802 void mc_api::restore_state(std::shared_ptr<simgrid::mc::Snapshot> system_state) const
803 {
804   system_state->restore(&mc_model_checker->get_remote_simulation());
805 }
806
807 void mc_api::log_state() const
808 {
809   session->log_state();
810 }
811
812 bool mc_api::snapshot_equal(const Snapshot* s1, const Snapshot* s2) const
813 {
814   return simgrid::mc::snapshot_equal(s1, s2);
815 }
816
817 simgrid::mc::Snapshot* mc_api::take_snapshot(int num_state) const
818 {
819   auto snapshot = new simgrid::mc::Snapshot(num_state);
820   return snapshot;
821 }
822
823 void mc_api::s_close() const
824 {
825   session->close();
826 }
827
828 void mc_api::restore_initial_state() const
829 {
830   session->restore_initial_state();
831 }
832
833 void mc_api::execute(Transition const& transition) const
834 {
835   session->execute(transition);
836 }
837
838 #if SIMGRID_HAVE_MC
839 void mc_api::automaton_load(const char *file) const
840
841   MC_automaton_load(file); 
842 }
843 #endif
844
845 std::vector<int> mc_api::automaton_propositional_symbol_evaluate() const  
846 {
847   unsigned int cursor = 0;
848   std::vector<int> values;    
849   xbt_automaton_propositional_symbol_t ps = nullptr;
850   xbt_dynar_foreach (mc::property_automaton->propositional_symbols, cursor, ps)
851     values.push_back(xbt_automaton_propositional_symbol_evaluate(ps));
852   return values;
853 }
854
855 std::vector<xbt_automaton_state_t> mc_api::get_automaton_state() const
856 {
857   std::vector<xbt_automaton_state_t> automaton_stack;
858   unsigned int cursor = 0;
859   xbt_automaton_state_t automaton_state;
860   xbt_dynar_foreach (mc::property_automaton->states, cursor, automaton_state)
861     if (automaton_state->type == -1)
862       automaton_stack.push_back(automaton_state);
863   return automaton_stack;
864 }
865
866 int mc_api::compare_automaton_exp_lable(const xbt_automaton_exp_label* l, std::vector<int> const& values) const
867 {
868   unsigned int cursor = 0;
869   xbt_automaton_propositional_symbol_t p = nullptr;
870   xbt_dynar_foreach (simgrid::mc::property_automaton->propositional_symbols, cursor, p) {
871     if (std::strcmp(xbt_automaton_propositional_symbol_get_name(p), l->u.predicat) == 0)
872       return cursor;
873   }
874   return -1;
875 }
876
877 void mc_api::set_property_automaton(xbt_automaton_state_t const& automaton_state) const
878 {
879   mc::property_automaton->current_state = automaton_state;
880 }
881
882 xbt_automaton_exp_label_t mc_api::get_automaton_transition_label(xbt_dynar_t const& dynar, int index) const
883 {
884   const xbt_automaton_transition* transition =
885       xbt_dynar_get_as(dynar, index, xbt_automaton_transition_t);
886   return transition->label;
887 }
888
889 xbt_automaton_state_t mc_api::get_automaton_transition_dst(xbt_dynar_t const& dynar, int index) const
890 {
891   const xbt_automaton_transition* transition =
892       xbt_dynar_get_as(dynar, index, xbt_automaton_transition_t);
893   return transition->dst;
894 }
895
896 } // namespace mc
897 } // namespace simgrid