Logo AND Algorithmique Numérique Distribuée

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