Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
model-checker : unused variable
[simgrid.git] / src / mc / mc_comm_determinism.c
1 /* Copyright (c) 2008-2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "mc_state.h"
8 #include "mc_comm_pattern.h"
9 #include "mc_request.h"
10 #include "mc_safety.h"
11 #include "mc_private.h"
12 #include "mc_record.h"
13 #include "mc_smx.h"
14 #include "mc_client.h"
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_determinism, mc,
17                                 "Logging specific to MC communication determinism detection");
18
19 /********** Global variables **********/
20
21 xbt_dynar_t initial_communications_pattern;
22 xbt_dynar_t incomplete_communications_pattern;
23
24 /********** Static functions ***********/
25
26 static e_mc_comm_pattern_difference_t compare_comm_pattern(mc_comm_pattern_t comm1, mc_comm_pattern_t comm2) {
27   if(comm1->type != comm2->type)
28     return TYPE_DIFF;
29   if (strcmp(comm1->rdv, comm2->rdv) != 0)
30     return RDV_DIFF;
31   if (comm1->src_proc != comm2->src_proc)
32     return SRC_PROC_DIFF;
33   if (comm1->dst_proc != comm2->dst_proc)
34     return DST_PROC_DIFF;
35   if (comm1->tag != comm2->tag)
36     return TAG_DIFF;
37   if (comm1->data_size != comm2->data_size)
38     return DATA_SIZE_DIFF;
39   if(comm1->data == NULL && comm2->data == NULL)
40     return 0;
41   if(comm1->data != NULL && comm2->data !=NULL) {
42     if (!memcmp(comm1->data, comm2->data, comm1->data_size))
43       return 0;
44     return DATA_DIFF;
45   }else{
46     return DATA_DIFF;
47   }
48   return 0;
49 }
50
51 static char* print_determinism_result(e_mc_comm_pattern_difference_t diff, int process, mc_comm_pattern_t comm, unsigned int cursor) {
52   char *type, *res;
53
54   if(comm->type == SIMIX_COMM_SEND)
55     type = bprintf("The send communications pattern of the process %d is different!", process - 1);
56   else
57     type = bprintf("The recv communications pattern of the process %d is different!", process - 1);
58
59   switch(diff) {
60   case TYPE_DIFF:
61     res = bprintf("%s Different type for communication #%d", type, cursor);
62     break;
63   case RDV_DIFF:
64     res = bprintf("%s Different rdv for communication #%d", type, cursor);
65     break;
66   case TAG_DIFF:
67     res = bprintf("%s Different tag for communication #%d", type, cursor);
68     break;
69   case SRC_PROC_DIFF:
70       res = bprintf("%s Different source for communication #%d", type, cursor);
71     break;
72   case DST_PROC_DIFF:
73       res = bprintf("%s Different destination for communication #%d", type, cursor);
74     break;
75   case DATA_SIZE_DIFF:
76     res = bprintf("%s\n Different data size for communication #%d", type, cursor);
77     break;
78   case DATA_DIFF:
79     res = bprintf("%s\n Different data for communication #%d", type, cursor);
80     break;
81   default:
82     res = NULL;
83     break;
84   }
85
86   return res;
87 }
88
89 static void update_comm_pattern(mc_comm_pattern_t comm_pattern, smx_synchro_t comm_addr)
90 {
91   s_smx_synchro_t comm;
92   MC_process_read_simple(&mc_model_checker->process,
93     &comm, comm_addr, sizeof(comm));
94
95   smx_process_t src_proc = MC_smx_resolve_process(comm.comm.src_proc);
96   smx_process_t dst_proc = MC_smx_resolve_process(comm.comm.dst_proc);
97   comm_pattern->src_proc = src_proc->pid;
98   comm_pattern->dst_proc = dst_proc->pid;
99   comm_pattern->src_host = MC_smx_process_get_host_name(src_proc);
100   comm_pattern->dst_host = MC_smx_process_get_host_name(dst_proc);
101   if (comm_pattern->data_size == -1 && comm.comm.src_buff != NULL) {
102     size_t buff_size;
103     MC_process_read_simple(&mc_model_checker->process,
104       &buff_size, comm.comm.dst_buff_size, sizeof(buff_size));
105     comm_pattern->data_size = buff_size;
106     comm_pattern->data = xbt_malloc0(comm_pattern->data_size);
107     MC_process_read_simple(&mc_model_checker->process,
108       comm_pattern->data, comm.comm.src_buff, comm_pattern->data_size);
109   }
110 }
111
112 static void deterministic_comm_pattern(int process, mc_comm_pattern_t comm, int backtracking) {
113
114   mc_list_comm_pattern_t list =
115     xbt_dynar_get_as(initial_communications_pattern, process, mc_list_comm_pattern_t);
116
117   if(!backtracking){
118     mc_comm_pattern_t initial_comm =
119       xbt_dynar_get_as(list->list, list->index_comm, mc_comm_pattern_t);
120     e_mc_comm_pattern_difference_t diff =
121       compare_comm_pattern(initial_comm, comm);
122
123     if (diff != NONE_DIFF) {
124       if (comm->type == SIMIX_COMM_SEND){
125         initial_global_state->send_deterministic = 0;
126         if(initial_global_state->send_diff != NULL)
127           xbt_free(initial_global_state->send_diff);
128         initial_global_state->send_diff = print_determinism_result(diff, process, comm, list->index_comm + 1);
129       }else{
130         initial_global_state->recv_deterministic = 0;
131         if(initial_global_state->recv_diff != NULL)
132           xbt_free(initial_global_state->recv_diff);
133         initial_global_state->recv_diff = print_determinism_result(diff, process, comm, list->index_comm + 1);
134       }
135       if(_sg_mc_send_determinism && !initial_global_state->send_deterministic){
136         XBT_INFO("*********************************************************");
137         XBT_INFO("***** Non-send-deterministic communications pattern *****");
138         XBT_INFO("*********************************************************");
139         XBT_INFO("%s", initial_global_state->send_diff);
140         xbt_free(initial_global_state->send_diff);
141         initial_global_state->send_diff = NULL;
142         MC_print_statistics(mc_stats);
143         xbt_abort(); 
144       }else if(_sg_mc_comms_determinism && (!initial_global_state->send_deterministic && !initial_global_state->recv_deterministic)) {
145         XBT_INFO("****************************************************");
146         XBT_INFO("***** Non-deterministic communications pattern *****");
147         XBT_INFO("****************************************************");
148         XBT_INFO("%s", initial_global_state->send_diff);
149         XBT_INFO("%s", initial_global_state->recv_diff);
150         xbt_free(initial_global_state->send_diff);
151         initial_global_state->send_diff = NULL;
152         xbt_free(initial_global_state->recv_diff);
153         initial_global_state->recv_diff = NULL;
154         MC_print_statistics(mc_stats);
155         xbt_abort();
156       } 
157     }
158   }
159     
160   MC_comm_pattern_free(comm);
161
162 }
163
164 /********** Non Static functions ***********/
165
166 void MC_get_comm_pattern(xbt_dynar_t list, smx_simcall_t request, e_mc_call_type_t call_type, int backtracking)
167 {
168   const smx_process_t issuer = MC_smx_simcall_get_issuer(request);
169   mc_list_comm_pattern_t initial_pattern = xbt_dynar_get_as(
170     initial_communications_pattern, issuer->pid, mc_list_comm_pattern_t);
171   xbt_dynar_t incomplete_pattern = xbt_dynar_get_as(
172     incomplete_communications_pattern, issuer->pid, xbt_dynar_t);
173
174   mc_comm_pattern_t pattern = xbt_new0(s_mc_comm_pattern_t, 1);
175   pattern->data_size = -1;
176   pattern->data = NULL;
177   pattern->index =
178     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 = SIMIX_COMM_SEND;
183     pattern->comm_addr = simcall_comm_isend__get__result(request);
184
185     s_smx_synchro_t synchro;
186     MC_process_read_simple(&mc_model_checker->process,
187       &synchro, pattern->comm_addr, sizeof(synchro));
188
189     char* remote_name;
190     MC_process_read_simple(&mc_model_checker->process, &remote_name,
191       synchro.comm.rdv ? &synchro.comm.rdv->name : &synchro.comm.rdv_cpy->name,
192       sizeof(remote_name));
193     pattern->rdv =
194       MC_process_read_string(&mc_model_checker->process, remote_name);
195     pattern->src_proc = MC_smx_resolve_process(synchro.comm.src_proc)->pid;
196     pattern->src_host = MC_smx_process_get_host_name(issuer);
197
198     struct s_smpi_mpi_request mpi_request;
199     MC_process_read_simple(&mc_model_checker->process,
200       &mpi_request, (MPI_Request) simcall_comm_isend__get__data(request),
201       sizeof(mpi_request));
202     pattern->tag = mpi_request.tag;
203
204     if(synchro.comm.src_buff != NULL){
205       pattern->data_size = synchro.comm.src_buff_size;
206       pattern->data = xbt_malloc0(pattern->data_size);
207       MC_process_read_simple(&mc_model_checker->process,
208         pattern->data, synchro.comm.src_buff, pattern->data_size);
209     }
210     if(mpi_request.detached){
211       if (!initial_global_state->initial_communications_pattern_done) {
212         /* Store comm pattern */
213         xbt_dynar_push(
214           xbt_dynar_get_as(
215             initial_communications_pattern, pattern->src_proc, mc_list_comm_pattern_t
216           )->list,
217           &pattern);
218       } else {
219         /* Evaluate comm determinism */
220         deterministic_comm_pattern(pattern->src_proc, pattern, backtracking);
221         xbt_dynar_get_as(
222           initial_communications_pattern, pattern->src_proc, mc_list_comm_pattern_t
223         )->index_comm++;
224       }
225       return;
226     }
227   } else if (call_type == MC_CALL_TYPE_RECV) {                      
228     pattern->type = SIMIX_COMM_RECEIVE;
229     pattern->comm_addr = simcall_comm_irecv__get__result(request);
230
231     struct s_smpi_mpi_request mpi_request;
232     MC_process_read_simple(&mc_model_checker->process,
233       &mpi_request, (MPI_Request) simcall_comm_irecv__get__data(request),
234       sizeof(mpi_request));
235     pattern->tag = mpi_request.tag;
236
237     s_smx_synchro_t synchro;
238     MC_process_read_simple(&mc_model_checker->process,
239       &synchro, pattern->comm_addr, sizeof(synchro));
240
241     char* remote_name;
242     MC_process_read_simple(&mc_model_checker->process, &remote_name,
243       synchro.comm.rdv ? &synchro.comm.rdv->name : &synchro.comm.rdv_cpy->name,
244       sizeof(remote_name));
245     pattern->rdv =
246       MC_process_read_string(&mc_model_checker->process, remote_name);
247     pattern->dst_proc = MC_smx_resolve_process(synchro.comm.dst_proc)->pid;
248     pattern->dst_host = MC_smx_process_get_host_name(issuer);
249   } else {
250     xbt_die("Unexpected call_type %i", (int) call_type);
251   }
252
253   xbt_dynar_push(
254     xbt_dynar_get_as(incomplete_communications_pattern, issuer->pid, xbt_dynar_t),
255     &pattern);
256
257   XBT_DEBUG("Insert incomplete comm pattern %p for process %lu", pattern, issuer->pid);
258 }
259
260 void MC_complete_comm_pattern(xbt_dynar_t list, smx_synchro_t comm_addr, unsigned int issuer, int backtracking) {
261   mc_comm_pattern_t current_comm_pattern;
262   unsigned int cursor = 0;
263   mc_comm_pattern_t comm_pattern;
264   int completed = 0;
265
266   /* Complete comm pattern */
267   xbt_dynar_foreach(xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t), cursor, current_comm_pattern) {
268     if (current_comm_pattern->comm_addr == comm_addr) {
269       update_comm_pattern(current_comm_pattern, comm_addr);
270       completed = 1;
271       xbt_dynar_remove_at(
272         xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t),
273         cursor, &comm_pattern);
274       XBT_DEBUG("Remove incomplete comm pattern for process %u at cursor %u", issuer, cursor);
275       break;
276     }
277   }
278   if(!completed)
279     xbt_die("Corresponding communication not found!");
280
281   mc_list_comm_pattern_t pattern = xbt_dynar_get_as(
282     initial_communications_pattern, issuer, mc_list_comm_pattern_t);
283
284   if (!initial_global_state->initial_communications_pattern_done) {
285     /* Store comm pattern */
286     xbt_dynar_push(pattern->list, &comm_pattern);
287   } else {
288     /* Evaluate comm determinism */
289     deterministic_comm_pattern(issuer, comm_pattern, backtracking);
290     pattern->index_comm++;
291   }
292 }
293
294
295 /************************ Main algorithm ************************/
296
297 static void MC_modelcheck_comm_determinism_main(void);
298
299 static void MC_pre_modelcheck_comm_determinism(void)
300 {
301   MC_SET_MC_HEAP;
302
303   mc_state_t initial_state = NULL;
304   smx_process_t process;
305   int i;
306   const int maxpid = MC_smx_get_maxpid();
307
308   if (_sg_mc_visited > 0)
309     visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
310  
311   // Create initial_communications_pattern elements:
312   initial_communications_pattern = xbt_dynar_new(sizeof(mc_list_comm_pattern_t), MC_list_comm_pattern_free_voidp);
313   for (i=0; i < maxpid; i++){
314     mc_list_comm_pattern_t process_list_pattern = xbt_new0(s_mc_list_comm_pattern_t, 1);
315     process_list_pattern->list = xbt_dynar_new(sizeof(mc_comm_pattern_t), MC_comm_pattern_free_voidp);
316     process_list_pattern->index_comm = 0;
317     xbt_dynar_insert_at(initial_communications_pattern, i, &process_list_pattern);
318   }
319
320   // Create incomplete_communications_pattern elements:
321   incomplete_communications_pattern = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
322   for (i=0; i < maxpid; i++){
323     xbt_dynar_t process_pattern = xbt_dynar_new(sizeof(mc_comm_pattern_t), NULL);
324     xbt_dynar_insert_at(incomplete_communications_pattern, i, &process_pattern);
325   }
326
327   initial_state = MC_state_new();
328   MC_SET_STD_HEAP;
329   
330   XBT_DEBUG("********* Start communication determinism verification *********");
331
332   /* Wait for requests (schedules processes) */
333   MC_wait_for_requests();
334
335   MC_SET_MC_HEAP;
336
337   /* Get an enabled process and insert it in the interleave set of the initial state */
338   MC_EACH_SIMIX_PROCESS(process,
339     if (MC_process_is_enabled(process)) {
340       MC_state_interleave_process(initial_state, process);
341     }
342   );
343
344   xbt_fifo_unshift(mc_stack, initial_state);
345
346   MC_SET_STD_HEAP;
347
348 }
349
350 static void MC_modelcheck_comm_determinism_main(void)
351 {
352
353   char *req_str = NULL;
354   int value;
355   mc_visited_state_t visited_state = NULL;
356   smx_simcall_t req = NULL;
357   smx_process_t process = NULL;
358   mc_state_t state = NULL, next_state = NULL;
359
360   while (xbt_fifo_size(mc_stack) > 0) {
361
362     /* Get current state */
363     state = (mc_state_t) xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
364
365     XBT_DEBUG("**************************************************");
366     XBT_DEBUG("Exploration depth = %d (state = %d, interleaved processes = %d)",
367               xbt_fifo_size(mc_stack), state->num,
368               MC_state_interleave_size(state));
369
370     /* Update statistics */
371     mc_stats->visited_states++;
372
373     if ((xbt_fifo_size(mc_stack) <= _sg_mc_max_depth)
374         && (req = MC_state_get_request(state, &value))
375         && (visited_state == NULL)) {
376
377       req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX);
378       XBT_DEBUG("Execute: %s", req_str);
379       xbt_free(req_str);
380       
381       if (dot_output != NULL) {
382         MC_SET_MC_HEAP;
383         req_str = MC_request_get_dot_output(req, value);
384         MC_SET_STD_HEAP;
385       }
386
387       MC_state_set_executed_request(state, req, value);
388       mc_stats->executed_transitions++;
389
390       /* TODO : handle test and testany simcalls */
391       e_mc_call_type_t call = MC_CALL_TYPE_NONE;
392       if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
393         call = MC_get_call_type(req);
394       }
395
396       /* Answer the request */
397       MC_simcall_handle(req, value);    /* After this call req is no longer useful */
398
399       MC_SET_MC_HEAP;
400       if(!initial_global_state->initial_communications_pattern_done)
401         MC_handle_comm_pattern(call, req, value, initial_communications_pattern, 0);
402       else
403         MC_handle_comm_pattern(call, req, value, NULL, 0);
404       MC_SET_STD_HEAP;
405
406       /* Wait for requests (schedules processes) */
407       MC_wait_for_requests();
408
409       /* Create the new expanded state */
410       MC_SET_MC_HEAP;
411
412       next_state = MC_state_new();
413
414       if ((visited_state = is_visited_state(next_state)) == NULL) {
415
416         /* Get enabled processes and insert them in the interleave set of the next state */
417         MC_EACH_SIMIX_PROCESS(process,
418           if (MC_process_is_enabled(process)) {
419             MC_state_interleave_process(next_state, process);
420           }
421         );
422
423         if (dot_output != NULL)
424           fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num,  next_state->num, req_str);
425
426       } else {
427
428         if (dot_output != NULL)
429           fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, visited_state->other_num == -1 ? visited_state->num : visited_state->other_num, req_str);
430
431       }
432
433       xbt_fifo_unshift(mc_stack, next_state);
434
435       if (dot_output != NULL)
436         xbt_free(req_str);
437
438       MC_SET_STD_HEAP;
439
440     } else {
441
442       if (xbt_fifo_size(mc_stack) > _sg_mc_max_depth) {
443         XBT_WARN("/!\\ Max depth reached ! /!\\ ");
444       } else if (visited_state != NULL) {
445         XBT_DEBUG("State already visited (equal to state %d), exploration stopped on this path.", visited_state->other_num == -1 ? visited_state->num : visited_state->other_num);
446       } else {
447         XBT_DEBUG("There are no more processes to interleave. (depth %d)", xbt_fifo_size(mc_stack));
448       }
449
450       MC_SET_MC_HEAP;
451
452       if (!initial_global_state->initial_communications_pattern_done) 
453         initial_global_state->initial_communications_pattern_done = 1;
454
455       /* Trash the current state, no longer needed */
456       xbt_fifo_shift(mc_stack);
457       MC_state_delete(state, !state->in_visited_states ? 1 : 0);
458       XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
459
460       MC_SET_STD_HEAP;
461
462       visited_state = NULL;
463
464       /* Check for deadlocks */
465       if (MC_deadlock_check()) {
466         MC_show_deadlock(NULL);
467         return;
468       }
469
470       MC_SET_MC_HEAP;
471
472       while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
473         if (MC_state_interleave_size(state) && xbt_fifo_size(mc_stack) < _sg_mc_max_depth) {
474           /* We found a back-tracking point, let's loop */
475           XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
476           xbt_fifo_unshift(mc_stack, state);
477           MC_SET_STD_HEAP;
478
479           MC_replay(mc_stack);
480
481           XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, xbt_fifo_size(mc_stack));
482
483           break;
484         } else {
485           XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
486           MC_state_delete(state, !state->in_visited_states ? 1 : 0);
487         }
488       }
489
490       MC_SET_STD_HEAP;
491     }
492   }
493
494   MC_print_statistics(mc_stats);
495   MC_SET_STD_HEAP;
496
497   exit(0);
498 }
499
500 void MC_modelcheck_comm_determinism(void)
501 {
502   if (mc_mode == MC_MODE_CLIENT) {
503     // This will move somehwere else:
504     MC_client_handle_messages();
505   }
506
507   xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
508
509   /* Create exploration stack */
510   mc_stack = xbt_fifo_new();
511
512   MC_SET_STD_HEAP;
513
514   MC_pre_modelcheck_comm_determinism();
515
516   MC_SET_MC_HEAP;
517   initial_global_state = xbt_new0(s_mc_global_t, 1);
518   initial_global_state->snapshot = MC_take_snapshot(0);
519   initial_global_state->initial_communications_pattern_done = 0;
520   initial_global_state->recv_deterministic = 1;
521   initial_global_state->send_deterministic = 1;
522   initial_global_state->recv_diff = NULL;
523   initial_global_state->send_diff = NULL;
524
525   MC_SET_STD_HEAP;
526
527   MC_modelcheck_comm_determinism_main();
528
529   mmalloc_set_current_heap(heap);
530 }