Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Implement I/O as asynchronous activities
[simgrid.git] / src / mc / checker / CommunicationDeterminismChecker.cpp
1 /* Copyright (c) 2008-2018. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "src/mc/checker/CommunicationDeterminismChecker.hpp"
7 #include "src/kernel/activity/MailboxImpl.hpp"
8 #include "src/mc/VisitedState.hpp"
9 #include "src/mc/mc_exit.hpp"
10 #include "src/mc/mc_private.hpp"
11 #include "src/mc/mc_record.hpp"
12 #include "src/mc/mc_request.hpp"
13 #include "src/mc/mc_smx.hpp"
14 #include "src/mc/mc_state.hpp"
15 #include "src/mc/remote/Client.hpp"
16
17 #include "smpi_request.hpp"
18
19 #include <cstdint>
20
21 using simgrid::mc::remote;
22
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_determinism, mc, "Logging specific to MC communication determinism detection");
24
25 /********** Global variables **********/
26
27 xbt_dynar_t initial_communications_pattern;
28 xbt_dynar_t incomplete_communications_pattern;
29
30 /********** Static functions ***********/
31
32 static e_mc_comm_pattern_difference_t compare_comm_pattern(simgrid::mc::PatternCommunication* comm1,
33                                                            simgrid::mc::PatternCommunication* comm2)
34 {
35   if(comm1->type != comm2->type)
36     return TYPE_DIFF;
37   if (comm1->rdv != comm2->rdv)
38     return RDV_DIFF;
39   if (comm1->src_proc != comm2->src_proc)
40     return SRC_PROC_DIFF;
41   if (comm1->dst_proc != comm2->dst_proc)
42     return DST_PROC_DIFF;
43   if (comm1->tag != comm2->tag)
44     return TAG_DIFF;
45   if (comm1->data.size() != comm2->data.size())
46     return DATA_SIZE_DIFF;
47   if (comm1->data != comm2->data)
48     return DATA_DIFF;
49   return NONE_DIFF;
50 }
51
52 static char* print_determinism_result(e_mc_comm_pattern_difference_t diff, int process,
53                                       simgrid::mc::PatternCommunication* comm, unsigned int cursor)
54 {
55   char* type;
56   char* res;
57
58   if (comm->type == simgrid::mc::PatternCommunicationType::send)
59     type = bprintf("The send communications pattern of the process %d is different!", process - 1);
60   else
61     type = bprintf("The recv communications pattern of the process %d is different!", process - 1);
62
63   switch(diff) {
64   case TYPE_DIFF:
65     res = bprintf("%s Different type for communication #%u", type, cursor);
66     break;
67   case RDV_DIFF:
68     res = bprintf("%s Different rdv for communication #%u", type, cursor);
69     break;
70   case TAG_DIFF:
71     res = bprintf("%s Different tag for communication #%u", type, cursor);
72     break;
73   case SRC_PROC_DIFF:
74     res = bprintf("%s Different source for communication #%u", type, cursor);
75     break;
76   case DST_PROC_DIFF:
77     res = bprintf("%s Different destination for communication #%u", type, cursor);
78     break;
79   case DATA_SIZE_DIFF:
80     res = bprintf("%s\n Different data size for communication #%u", type, cursor);
81     break;
82   case DATA_DIFF:
83     res = bprintf("%s\n Different data for communication #%u", type, cursor);
84     break;
85   default:
86     res = nullptr;
87     break;
88   }
89
90   return res;
91 }
92
93 static void update_comm_pattern(simgrid::mc::PatternCommunication* comm_pattern,
94                                 simgrid::mc::RemotePtr<simgrid::kernel::activity::CommImpl> comm_addr)
95 {
96   // HACK, type punning
97   simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
98   mc_model_checker->process().read(temp_comm, comm_addr);
99   simgrid::kernel::activity::CommImpl* comm = temp_comm.getBuffer();
100
101   smx_actor_t src_proc   = mc_model_checker->process().resolveActor(simgrid::mc::remote(comm->src_proc));
102   smx_actor_t dst_proc   = mc_model_checker->process().resolveActor(simgrid::mc::remote(comm->dst_proc));
103   comm_pattern->src_proc = src_proc->pid_;
104   comm_pattern->dst_proc = dst_proc->pid_;
105   comm_pattern->src_host = MC_smx_actor_get_host_name(src_proc);
106   comm_pattern->dst_host = MC_smx_actor_get_host_name(dst_proc);
107   if (comm_pattern->data.size() == 0 && comm->src_buff != nullptr) {
108     size_t buff_size;
109     mc_model_checker->process().read(&buff_size, remote(comm->dst_buff_size));
110     comm_pattern->data.resize(buff_size);
111     mc_model_checker->process().read_bytes(comm_pattern->data.data(), comm_pattern->data.size(),
112                                            remote(comm->src_buff));
113   }
114 }
115
116 namespace simgrid {
117 namespace mc {
118
119 void CommunicationDeterminismChecker::deterministic_comm_pattern(int process, simgrid::mc::PatternCommunication* comm,
120                                                                  int backtracking)
121 {
122   simgrid::mc::PatternCommunicationList* list =
123     xbt_dynar_get_as(initial_communications_pattern, process, simgrid::mc::PatternCommunicationList*);
124
125   if (not backtracking) {
126     e_mc_comm_pattern_difference_t diff = compare_comm_pattern(list->list[list->index_comm].get(), comm);
127
128     if (diff != NONE_DIFF) {
129       if (comm->type == simgrid::mc::PatternCommunicationType::send) {
130         this->send_deterministic = 0;
131         if (this->send_diff != nullptr)
132           xbt_free(this->send_diff);
133         this->send_diff = print_determinism_result(diff, process, comm, list->index_comm + 1);
134       } else {
135         this->recv_deterministic = 0;
136         if (this->recv_diff != nullptr)
137           xbt_free(this->recv_diff);
138         this->recv_diff = print_determinism_result(diff, process, comm, list->index_comm + 1);
139       }
140       if (_sg_mc_send_determinism && not this->send_deterministic) {
141         XBT_INFO("*********************************************************");
142         XBT_INFO("***** Non-send-deterministic communications pattern *****");
143         XBT_INFO("*********************************************************");
144         XBT_INFO("%s", this->send_diff);
145         xbt_free(this->send_diff);
146         this->send_diff = nullptr;
147         simgrid::mc::session->logState();
148         mc_model_checker->exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
149       } else if (_sg_mc_comms_determinism && (not this->send_deterministic && not this->recv_deterministic)) {
150         XBT_INFO("****************************************************");
151         XBT_INFO("***** Non-deterministic communications pattern *****");
152         XBT_INFO("****************************************************");
153         XBT_INFO("%s", this->send_diff);
154         XBT_INFO("%s", this->recv_diff);
155         xbt_free(this->send_diff);
156         this->send_diff = nullptr;
157         xbt_free(this->recv_diff);
158         this->recv_diff = nullptr;
159         simgrid::mc::session->logState();
160         mc_model_checker->exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
161       }
162     }
163   }
164 }
165
166 /********** Non Static functions ***********/
167
168 void CommunicationDeterminismChecker::get_comm_pattern(xbt_dynar_t list, smx_simcall_t request,
169                                                        e_mc_call_type_t call_type, int backtracking)
170 {
171   const smx_actor_t issuer = MC_smx_simcall_get_issuer(request);
172   simgrid::mc::PatternCommunicationList* initial_pattern =
173       xbt_dynar_get_as(initial_communications_pattern, issuer->pid_, simgrid::mc::PatternCommunicationList*);
174   xbt_dynar_t incomplete_pattern = xbt_dynar_get_as(incomplete_communications_pattern, issuer->pid_, xbt_dynar_t);
175
176   std::unique_ptr<simgrid::mc::PatternCommunication> pattern =
177       std::unique_ptr<simgrid::mc::PatternCommunication>(new simgrid::mc::PatternCommunication());
178   pattern->index = initial_pattern->index_comm + xbt_dynar_length(incomplete_pattern);
179
180   if (call_type == MC_CALL_TYPE_SEND) {
181     /* Create comm pattern */
182     pattern->type = simgrid::mc::PatternCommunicationType::send;
183     pattern->comm_addr = static_cast<simgrid::kernel::activity::CommImpl*>(simcall_comm_isend__getraw__result(request));
184
185     simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_synchro;
186     mc_model_checker->process().read(temp_synchro,
187                                      remote(static_cast<simgrid::kernel::activity::CommImpl*>(pattern->comm_addr)));
188     simgrid::kernel::activity::CommImpl* synchro =
189         static_cast<simgrid::kernel::activity::CommImpl*>(temp_synchro.getBuffer());
190
191     char* remote_name = mc_model_checker->process().read<char*>(
192         RemotePtr<char*>((uint64_t)(synchro->mbox ? &synchro->mbox->name_ : &synchro->mbox_cpy->name_)));
193     pattern->rdv      = mc_model_checker->process().read_string(RemotePtr<char>(remote_name));
194     pattern->src_proc = mc_model_checker->process().resolveActor(simgrid::mc::remote(synchro->src_proc))->pid_;
195     pattern->src_host = MC_smx_actor_get_host_name(issuer);
196
197     simgrid::smpi::Request mpi_request = mc_model_checker->process().read<simgrid::smpi::Request>(
198         RemotePtr<simgrid::smpi::Request>((std::uint64_t)simcall_comm_isend__get__data(request)));
199     pattern->tag = mpi_request.tag();
200
201     if (synchro->src_buff != nullptr) {
202       pattern->data.resize(synchro->src_buff_size);
203       mc_model_checker->process().read_bytes(pattern->data.data(), pattern->data.size(), remote(synchro->src_buff));
204     }
205     if(mpi_request.detached()){
206       if (not this->initial_communications_pattern_done) {
207         /* Store comm pattern */
208         simgrid::mc::PatternCommunicationList* list =
209             xbt_dynar_get_as(initial_communications_pattern, pattern->src_proc, simgrid::mc::PatternCommunicationList*);
210         list->list.push_back(std::move(pattern));
211       } else {
212         /* Evaluate comm determinism */
213         this->deterministic_comm_pattern(pattern->src_proc, pattern.get(), backtracking);
214         xbt_dynar_get_as(initial_communications_pattern, pattern->src_proc, simgrid::mc::PatternCommunicationList*)
215             ->index_comm++;
216       }
217       return;
218     }
219   } else if (call_type == MC_CALL_TYPE_RECV) {
220     pattern->type = simgrid::mc::PatternCommunicationType::receive;
221     pattern->comm_addr = static_cast<simgrid::kernel::activity::CommImpl*>(simcall_comm_irecv__getraw__result(request));
222
223     simgrid::smpi::Request mpi_request;
224     mc_model_checker->process().read(&mpi_request,
225                                      remote((simgrid::smpi::Request*)simcall_comm_irecv__get__data(request)));
226     pattern->tag = mpi_request.tag();
227
228     simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_comm;
229     mc_model_checker->process().read(temp_comm,
230                                      remote(static_cast<simgrid::kernel::activity::CommImpl*>(pattern->comm_addr)));
231     simgrid::kernel::activity::CommImpl* comm = temp_comm.getBuffer();
232
233     char* remote_name;
234     mc_model_checker->process().read(
235         &remote_name, remote(comm->mbox ? &simgrid::xbt::string::to_string_data(comm->mbox->name_).data
236                                         : &simgrid::xbt::string::to_string_data(comm->mbox_cpy->name_).data));
237     pattern->rdv      = mc_model_checker->process().read_string(RemotePtr<char>(remote_name));
238     pattern->dst_proc = mc_model_checker->process().resolveActor(simgrid::mc::remote(comm->dst_proc))->pid_;
239     pattern->dst_host = MC_smx_actor_get_host_name(issuer);
240   } else
241     xbt_die("Unexpected call_type %i", (int) call_type);
242
243   XBT_DEBUG("Insert incomplete comm pattern %p for process %ld", pattern.get(), issuer->pid_);
244   xbt_dynar_t dynar = xbt_dynar_get_as(incomplete_communications_pattern, issuer->pid_, xbt_dynar_t);
245   simgrid::mc::PatternCommunication* pattern2 = pattern.release();
246   xbt_dynar_push(dynar, &pattern2);
247 }
248
249 void CommunicationDeterminismChecker::complete_comm_pattern(
250     xbt_dynar_t list, simgrid::mc::RemotePtr<simgrid::kernel::activity::CommImpl> comm_addr, unsigned int issuer,
251     int backtracking)
252 {
253   simgrid::mc::PatternCommunication* current_comm_pattern;
254   unsigned int cursor = 0;
255   std::unique_ptr<simgrid::mc::PatternCommunication> comm_pattern;
256   int completed = 0;
257
258   /* Complete comm pattern */
259   xbt_dynar_foreach(xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t), cursor, current_comm_pattern)
260     if (remote(current_comm_pattern->comm_addr) == comm_addr) {
261       update_comm_pattern(current_comm_pattern, comm_addr);
262       completed = 1;
263       simgrid::mc::PatternCommunication* temp;
264       xbt_dynar_remove_at(xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t), cursor, &temp);
265       comm_pattern = std::unique_ptr<simgrid::mc::PatternCommunication>(temp);
266       XBT_DEBUG("Remove incomplete comm pattern for process %u at cursor %u", issuer, cursor);
267       break;
268     }
269
270   if (not completed)
271     xbt_die("Corresponding communication not found!");
272
273   simgrid::mc::PatternCommunicationList* pattern =
274       xbt_dynar_get_as(initial_communications_pattern, issuer, simgrid::mc::PatternCommunicationList*);
275
276   if (not this->initial_communications_pattern_done)
277     /* Store comm pattern */
278     pattern->list.push_back(std::move(comm_pattern));
279   else {
280     /* Evaluate comm determinism */
281     this->deterministic_comm_pattern(issuer, comm_pattern.get(), backtracking);
282     pattern->index_comm++;
283   }
284 }
285
286 CommunicationDeterminismChecker::CommunicationDeterminismChecker(Session& session) : Checker(session)
287 {
288 }
289
290 CommunicationDeterminismChecker::~CommunicationDeterminismChecker() = default;
291
292 RecordTrace CommunicationDeterminismChecker::getRecordTrace() // override
293 {
294   RecordTrace res;
295   for (auto const& state : stack_)
296     res.push_back(state->getTransition());
297   return res;
298 }
299
300 std::vector<std::string> CommunicationDeterminismChecker::getTextualTrace() // override
301 {
302   std::vector<std::string> trace;
303   for (auto const& state : stack_) {
304     smx_simcall_t req = &state->executed_req;
305     if (req)
306       trace.push_back(
307           simgrid::mc::request_to_string(req, state->transition.argument, simgrid::mc::RequestType::executed));
308   }
309   return trace;
310 }
311
312 void CommunicationDeterminismChecker::logState() // override
313 {
314   if (_sg_mc_comms_determinism && not this->recv_deterministic && this->send_deterministic) {
315     XBT_INFO("******************************************************");
316     XBT_INFO("**** Only-send-deterministic communication pattern ****");
317     XBT_INFO("******************************************************");
318     XBT_INFO("%s", this->recv_diff);
319   } else if (_sg_mc_comms_determinism && not this->send_deterministic && this->recv_deterministic) {
320     XBT_INFO("******************************************************");
321     XBT_INFO("**** Only-recv-deterministic communication pattern ****");
322     XBT_INFO("******************************************************");
323     XBT_INFO("%s", this->send_diff);
324   }
325   XBT_INFO("Expanded states = %lu", expandedStatesCount_);
326   XBT_INFO("Visited states = %lu", mc_model_checker->visited_states);
327   XBT_INFO("Executed transitions = %lu", mc_model_checker->executed_transitions);
328   XBT_INFO("Send-deterministic : %s", not this->send_deterministic ? "No" : "Yes");
329   if (_sg_mc_comms_determinism)
330     XBT_INFO("Recv-deterministic : %s", not this->recv_deterministic ? "No" : "Yes");
331 }
332
333 void CommunicationDeterminismChecker::prepare()
334 {
335   const int maxpid = MC_smx_get_maxpid();
336
337   // Create initial_communications_pattern elements:
338   initial_communications_pattern = simgrid::xbt::newDeleteDynar<simgrid::mc::PatternCommunicationList*>();
339   for (int i = 0; i < maxpid; i++) {
340     simgrid::mc::PatternCommunicationList* process_list_pattern = new simgrid::mc::PatternCommunicationList();
341     xbt_dynar_insert_at(initial_communications_pattern, i, &process_list_pattern);
342   }
343
344   // Create incomplete_communications_pattern elements:
345   incomplete_communications_pattern = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
346   for (int i = 0; i < maxpid; i++) {
347     xbt_dynar_t process_pattern = xbt_dynar_new(sizeof(simgrid::mc::PatternCommunication*), nullptr);
348     xbt_dynar_insert_at(incomplete_communications_pattern, i, &process_pattern);
349   }
350
351   std::unique_ptr<simgrid::mc::State> initial_state =
352       std::unique_ptr<simgrid::mc::State>(new simgrid::mc::State(++expandedStatesCount_));
353
354   XBT_DEBUG("********* Start communication determinism verification *********");
355
356   /* Get an enabled actor and insert it in the interleave set of the initial state */
357   for (auto& actor : mc_model_checker->process().actors())
358     if (simgrid::mc::actor_is_enabled(actor.copy.getBuffer()))
359       initial_state->addInterleavingSet(actor.copy.getBuffer());
360
361   stack_.push_back(std::move(initial_state));
362 }
363
364 static inline bool all_communications_are_finished()
365 {
366   for (size_t current_actor = 1; current_actor < MC_smx_get_maxpid(); current_actor++) {
367     xbt_dynar_t pattern = xbt_dynar_get_as(incomplete_communications_pattern, current_actor, xbt_dynar_t);
368     if (not xbt_dynar_is_empty(pattern)) {
369       XBT_DEBUG("Some communications are not finished, cannot stop the exploration! State not visited.");
370       return false;
371     }
372   }
373   return true;
374 }
375
376 void CommunicationDeterminismChecker::restoreState()
377 {
378   /* Intermediate backtracking */
379   simgrid::mc::State* state = stack_.back().get();
380   if (state->system_state) {
381     simgrid::mc::restore_snapshot(state->system_state);
382     MC_restore_communications_pattern(state);
383     return;
384   }
385
386   /* Restore the initial state */
387   simgrid::mc::session->restoreInitialState();
388
389   unsigned n = MC_smx_get_maxpid();
390   assert(n == xbt_dynar_length(incomplete_communications_pattern));
391   assert(n == xbt_dynar_length(initial_communications_pattern));
392   for (unsigned j=0; j < n ; j++) {
393     xbt_dynar_reset((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, j, xbt_dynar_t));
394     xbt_dynar_get_as(initial_communications_pattern, j, simgrid::mc::PatternCommunicationList*)->index_comm = 0;
395   }
396
397   /* Traverse the stack from the state at position start and re-execute the transitions */
398   for (std::unique_ptr<simgrid::mc::State> const& state : stack_) {
399     if (state == stack_.back())
400       break;
401
402     int req_num = state->transition.argument;
403     smx_simcall_t saved_req = &state->executed_req;
404     xbt_assert(saved_req);
405
406     /* because we got a copy of the executed request, we have to fetch the
407        real one, pointed by the request field of the issuer process */
408
409     const smx_actor_t issuer = MC_smx_simcall_get_issuer(saved_req);
410     smx_simcall_t req = &issuer->simcall;
411
412     /* TODO : handle test and testany simcalls */
413     e_mc_call_type_t call = MC_get_call_type(req);
414     mc_model_checker->handle_simcall(state->transition);
415     MC_handle_comm_pattern(call, req, req_num, nullptr, 1);
416     mc_model_checker->wait_for_requests();
417
418     /* Update statistics */
419     mc_model_checker->visited_states++;
420     mc_model_checker->executed_transitions++;
421   }
422 }
423
424 void CommunicationDeterminismChecker::main()
425 {
426   std::unique_ptr<simgrid::mc::VisitedState> visited_state = nullptr;
427   smx_simcall_t req = nullptr;
428
429   while (not stack_.empty()) {
430     /* Get current state */
431     simgrid::mc::State* state = stack_.back().get();
432
433     XBT_DEBUG("**************************************************");
434     XBT_DEBUG("Exploration depth = %zu (state = %d, interleaved processes = %zu)", stack_.size(), state->num,
435               state->interleaveSize());
436
437     /* Update statistics */
438     mc_model_checker->visited_states++;
439
440     if (stack_.size() <= (std::size_t)_sg_mc_max_depth)
441       req = MC_state_get_request(state);
442     else
443       req = nullptr;
444
445     if (req != nullptr && visited_state == nullptr) {
446
447       int req_num = state->transition.argument;
448
449       XBT_DEBUG("Execute: %s", simgrid::mc::request_to_string(req, req_num, simgrid::mc::RequestType::simix).c_str());
450
451       std::string req_str;
452       if (dot_output != nullptr)
453         req_str = simgrid::mc::request_get_dot_output(req, req_num);
454
455       mc_model_checker->executed_transitions++;
456
457       /* TODO : handle test and testany simcalls */
458       e_mc_call_type_t call = MC_CALL_TYPE_NONE;
459       if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
460         call = MC_get_call_type(req);
461
462       /* Answer the request */
463       mc_model_checker->handle_simcall(state->transition);
464       /* After this call req is no longer useful */
465
466       if (not this->initial_communications_pattern_done)
467         MC_handle_comm_pattern(call, req, req_num, initial_communications_pattern, 0);
468       else
469         MC_handle_comm_pattern(call, req, req_num, nullptr, 0);
470
471       /* Wait for requests (schedules processes) */
472       mc_model_checker->wait_for_requests();
473
474       /* Create the new expanded state */
475       std::unique_ptr<simgrid::mc::State> next_state =
476           std::unique_ptr<simgrid::mc::State>(new simgrid::mc::State(++expandedStatesCount_));
477
478       /* If comm determinism verification, we cannot stop the exploration if some communications are not finished (at
479        * least, data are transferred). These communications  are incomplete and they cannot be analyzed and compared
480        * with the initial pattern. */
481       bool compare_snapshots = all_communications_are_finished() && this->initial_communications_pattern_done;
482
483       if (_sg_mc_max_visited_states != 0)
484         visited_state = visitedStates_.addVisitedState(expandedStatesCount_, next_state.get(), compare_snapshots);
485       else
486         visited_state = nullptr;
487
488       if (visited_state == nullptr) {
489
490         /* Get enabled actors and insert them in the interleave set of the next state */
491         for (auto& actor : mc_model_checker->process().actors())
492           if (simgrid::mc::actor_is_enabled(actor.copy.getBuffer()))
493             next_state->addInterleavingSet(actor.copy.getBuffer());
494
495         if (dot_output != nullptr)
496           fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n",
497             state->num,  next_state->num, req_str.c_str());
498
499       } else if (dot_output != nullptr)
500         fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num,
501                 visited_state->original_num == -1 ? visited_state->num : visited_state->original_num, req_str.c_str());
502
503       stack_.push_back(std::move(next_state));
504
505     } else {
506
507       if (stack_.size() > (std::size_t) _sg_mc_max_depth)
508         XBT_WARN("/!\\ Max depth reached! /!\\ ");
509       else if (visited_state != nullptr)
510         XBT_DEBUG("State already visited (equal to state %d), exploration stopped on this path.",
511             visited_state->original_num == -1 ? visited_state->num : visited_state->original_num);
512       else
513         XBT_DEBUG("There are no more processes to interleave. (depth %zu)", stack_.size());
514
515       if (not this->initial_communications_pattern_done)
516         this->initial_communications_pattern_done = 1;
517
518       /* Trash the current state, no longer needed */
519       XBT_DEBUG("Delete state %d at depth %zu", state->num, stack_.size());
520       stack_.pop_back();
521
522       visited_state = nullptr;
523
524       /* Check for deadlocks */
525       if (mc_model_checker->checkDeadlock()) {
526         MC_show_deadlock();
527         throw simgrid::mc::DeadlockError();
528       }
529
530       while (not stack_.empty()) {
531         std::unique_ptr<simgrid::mc::State> state = std::move(stack_.back());
532         stack_.pop_back();
533         if (state->interleaveSize() && stack_.size() < (std::size_t)_sg_mc_max_depth) {
534           /* We found a back-tracking point, let's loop */
535           XBT_DEBUG("Back-tracking to state %d at depth %zu", state->num, stack_.size() + 1);
536           stack_.push_back(std::move(state));
537
538           this->restoreState();
539
540           XBT_DEBUG("Back-tracking to state %d at depth %zu done", stack_.back()->num, stack_.size());
541
542           break;
543         } else {
544           XBT_DEBUG("Delete state %d at depth %zu", state->num, stack_.size() + 1);
545         }
546       }
547     }
548   }
549
550   simgrid::mc::session->logState();
551 }
552
553 void CommunicationDeterminismChecker::run()
554 {
555   XBT_INFO("Check communication determinism");
556   simgrid::mc::session->initialize();
557
558   this->prepare();
559
560   this->main();
561 }
562
563 Checker* createCommunicationDeterminismChecker(Session& session)
564 {
565   return new CommunicationDeterminismChecker(session);
566 }
567
568 }
569 }