Logo AND Algorithmique Numérique Distribuée

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