Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge master into mc-process
[simgrid.git] / src / mc / mc_state.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 "../simix/smx_private.h"
8 #include "xbt/fifo.h"
9 #include "mc_state.h"
10 #include "mc_request.h"
11 #include "mc_private.h"
12 #include "mc_comm_pattern.h"
13
14 static void copy_incomplete_communications_pattern(mc_state_t state) {
15   int i;
16   xbt_dynar_t incomplete_process_comms;
17   mc_comm_pattern_t comm;
18   unsigned int cursor;
19   state->incomplete_comm_pattern = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
20   for (i=0; i<simix_process_maxpid; i++) {
21     incomplete_process_comms = xbt_dynar_get_as(incomplete_communications_pattern, i, xbt_dynar_t);
22     xbt_dynar_t incomplete_process_comms_copy = xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp);
23     xbt_dynar_foreach(incomplete_process_comms, cursor, comm) {
24       mc_comm_pattern_t copy_comm = xbt_new0(s_mc_comm_pattern_t, 1);
25       copy_comm->index = comm->index;
26       copy_comm->type = comm->type;
27       copy_comm->comm = comm->comm;
28       copy_comm->rdv = strdup(comm->rdv);
29       copy_comm->data_size = -1;
30       copy_comm->data = NULL;
31       if(comm->type == SIMIX_COMM_SEND){
32         copy_comm->src_proc = comm->src_proc;
33         copy_comm->src_host = comm->src_host;
34         if (comm->data != NULL) {
35           copy_comm->data_size = comm->data_size;
36           copy_comm->data = xbt_malloc0(comm->data_size);
37           memcpy(copy_comm->data, comm->data, comm->data_size);
38         }
39       }else{
40         copy_comm->dst_proc = comm->dst_proc;
41         copy_comm->dst_host = comm->dst_host;
42       }
43       xbt_dynar_push(incomplete_process_comms_copy, &copy_comm);
44     }
45     xbt_dynar_insert_at(state->incomplete_comm_pattern, i, &incomplete_process_comms_copy);
46   }
47 }
48
49 static void copy_index_communications_pattern(mc_state_t state) {
50
51   state->index_comm = xbt_dynar_new(sizeof(unsigned int), NULL);
52   mc_list_comm_pattern_t list_process_comm;
53   unsigned int cursor;
54   xbt_dynar_foreach(initial_communications_pattern, cursor, list_process_comm){
55     xbt_dynar_push_as(state->index_comm, unsigned int, list_process_comm->index_comm);
56   }
57 }
58
59 /**
60  * \brief Creates a state data structure used by the exploration algorithm
61  */
62 mc_state_t MC_state_new()
63 {
64   mc_state_t state = NULL;
65
66   state = xbt_new0(s_mc_state_t, 1);
67   state->max_pid = simix_process_maxpid;
68   state->proc_status = xbt_new0(s_mc_procstate_t, state->max_pid);
69   state->system_state = NULL;
70   state->num = ++mc_stats->expanded_states;
71   state->in_visited_states = 0;
72   state->incomplete_comm_pattern = NULL;
73   /* Stateful model checking */
74   if(_sg_mc_checkpoint > 0 && mc_stats->expanded_states % _sg_mc_checkpoint == 0){
75     state->system_state = MC_take_snapshot(state->num);
76     if(_sg_mc_comms_determinism || _sg_mc_send_determinism){
77       copy_incomplete_communications_pattern(state);
78       copy_index_communications_pattern(state);
79     }
80   }
81   return state;
82 }
83
84 /**
85  * \brief Deletes a state data structure
86  * \param trans The state to be deleted
87  */
88 void MC_state_delete(mc_state_t state, int free_snapshot){
89   if (state->system_state && free_snapshot){
90     MC_free_snapshot(state->system_state);
91   }
92   if(_sg_mc_comms_determinism || _sg_mc_send_determinism){
93     xbt_free(state->index_comm);
94     xbt_free(state->incomplete_comm_pattern);
95   }
96   xbt_free(state->proc_status);
97   xbt_free(state);
98 }
99
100 void MC_state_interleave_process(mc_state_t state, smx_process_t process)
101 {
102   state->proc_status[process->pid].state = MC_INTERLEAVE;
103   state->proc_status[process->pid].interleave_count = 0;
104 }
105
106 void MC_state_remove_interleave_process(mc_state_t state, smx_process_t process)
107 {
108   if (state->proc_status[process->pid].state == MC_INTERLEAVE)
109     state->proc_status[process->pid].state = MC_DONE;
110 }
111
112 unsigned int MC_state_interleave_size(mc_state_t state)
113 {
114   unsigned int i, size = 0;
115
116   for (i = 0; i < state->max_pid; i++) {
117     if ((state->proc_status[i].state == MC_INTERLEAVE)
118         || (state->proc_status[i].state == MC_MORE_INTERLEAVE))
119       size++;
120   }
121
122   return size;
123 }
124
125 int MC_state_process_is_done(mc_state_t state, smx_process_t process)
126 {
127   return state->proc_status[process->pid].state == MC_DONE ? TRUE : FALSE;
128 }
129
130 void MC_state_set_executed_request(mc_state_t state, smx_simcall_t req,
131                                    int value)
132 {
133   state->executed_req = *req;
134   state->req_num = value;
135   smx_process_t process = NULL;
136   mc_procstate_t procstate = NULL;
137
138   /* The waitany and testany request are transformed into a wait or test request over the
139    * corresponding communication action so it can be treated later by the dependence
140    * function. */
141   switch (req->call) {
142   case SIMCALL_COMM_WAITANY:
143     state->internal_req.call = SIMCALL_COMM_WAIT;
144     state->internal_req.issuer = req->issuer;
145     state->internal_comm =
146         *xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value,
147                           smx_synchro_t);
148     simcall_comm_wait__set__comm(&state->internal_req, &state->internal_comm);
149     simcall_comm_wait__set__timeout(&state->internal_req, 0);
150     break;
151
152   case SIMCALL_COMM_TESTANY:
153     state->internal_req.call = SIMCALL_COMM_TEST;
154     state->internal_req.issuer = req->issuer;
155
156     if (value > 0)
157       state->internal_comm =
158           *xbt_dynar_get_as(simcall_comm_testany__get__comms(req), value,
159                             smx_synchro_t);
160
161     simcall_comm_test__set__comm(&state->internal_req, &state->internal_comm);
162     simcall_comm_test__set__result(&state->internal_req, value);
163     break;
164
165   case SIMCALL_COMM_WAIT:
166     state->internal_req = *req;
167     state->internal_comm = *(simcall_comm_wait__get__comm(req));
168     simcall_comm_wait__set__comm(&state->executed_req, &state->internal_comm);
169     simcall_comm_wait__set__comm(&state->internal_req, &state->internal_comm);
170     break;
171
172   case SIMCALL_COMM_TEST:
173     state->internal_req = *req;
174     state->internal_comm = *simcall_comm_test__get__comm(req);
175     simcall_comm_test__set__comm(&state->executed_req, &state->internal_comm);
176     simcall_comm_test__set__comm(&state->internal_req, &state->internal_comm);
177     break;
178
179   case SIMCALL_MC_RANDOM:
180     state->internal_req = *req;
181     if (value != simcall_mc_random__get__max(req)) {
182       xbt_swag_foreach(process, simix_global->process_list) {
183         procstate = &state->proc_status[process->pid];
184         if (process->pid == req->issuer->pid) {
185           procstate->state = MC_MORE_INTERLEAVE;
186           break;
187         }
188       }
189     }
190     break;
191
192   default:
193     state->internal_req = *req;
194     break;
195   }
196 }
197
198 smx_simcall_t MC_state_get_executed_request(mc_state_t state, int *value)
199 {
200   *value = state->req_num;
201   return &state->executed_req;
202 }
203
204 smx_simcall_t MC_state_get_internal_request(mc_state_t state)
205 {
206   return &state->internal_req;
207 }
208
209 smx_simcall_t MC_state_get_request(mc_state_t state, int *value)
210 {
211   smx_process_t process = NULL;
212   mc_procstate_t procstate = NULL;
213   unsigned int start_count;
214   smx_synchro_t act = NULL;
215
216   xbt_swag_foreach(process, simix_global->process_list) {
217     procstate = &state->proc_status[process->pid];
218
219     if (procstate->state == MC_INTERLEAVE
220         || procstate->state == MC_MORE_INTERLEAVE) {
221       if (MC_process_is_enabled(process)) {
222         switch (process->simcall.call) {
223         case SIMCALL_COMM_WAITANY:
224           *value = -1;
225           while (procstate->interleave_count <
226                  xbt_dynar_length(simcall_comm_waitany__get__comms
227                                   (&process->simcall))) {
228             if (MC_request_is_enabled_by_idx
229                 (&process->simcall, procstate->interleave_count++)) {
230               *value = procstate->interleave_count - 1;
231               break;
232             }
233           }
234
235           if (procstate->interleave_count >=
236               xbt_dynar_length(simcall_comm_waitany__get__comms
237                                (&process->simcall)))
238             procstate->state = MC_DONE;
239
240           if (*value != -1)
241             return &process->simcall;
242
243           break;
244
245         case SIMCALL_COMM_TESTANY:
246           start_count = procstate->interleave_count;
247           *value = -1;
248           while (procstate->interleave_count <
249                  xbt_dynar_length(simcall_comm_testany__get__comms
250                                   (&process->simcall))) {
251             if (MC_request_is_enabled_by_idx
252                 (&process->simcall, procstate->interleave_count++)) {
253               *value = procstate->interleave_count - 1;
254               break;
255             }
256           }
257
258           if (procstate->interleave_count >=
259               xbt_dynar_length(simcall_comm_testany__get__comms
260                                (&process->simcall)))
261             procstate->state = MC_DONE;
262
263           if (*value != -1 || start_count == 0)
264             return &process->simcall;
265
266           break;
267
268         case SIMCALL_COMM_WAIT:
269           act = simcall_comm_wait__get__comm(&process->simcall);
270           if (act->comm.src_proc && act->comm.dst_proc) {
271             *value = 0;
272           } else {
273             if (act->comm.src_proc == NULL && act->comm.type == SIMIX_COMM_READY
274                 && act->comm.detached == 1)
275               *value = 0;
276             else
277               *value = -1;
278           }
279           procstate->state = MC_DONE;
280           return &process->simcall;
281
282           break;
283
284         case SIMCALL_MC_RANDOM:
285           if (procstate->state == MC_INTERLEAVE)
286             *value = 0;
287           else {
288             if (state->req_num < simcall_mc_random__get__max(&process->simcall))
289               *value = state->req_num + 1;
290           }
291           procstate->state = MC_DONE;
292           return &process->simcall;
293           break;
294
295         default:
296           procstate->state = MC_DONE;
297           *value = 0;
298           return &process->simcall;
299           break;
300         }
301       }
302     }
303   }
304
305   return NULL;
306 }