1 /* Copyright (c) 2008-2012. Da SimGrid Team. All rights reserved. */
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. */
6 #include "mc_private.h"
8 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dpor, mc,
9 "Logging specific to MC DPOR exploration");
11 xbt_dynar_t visited_states;
13 static int is_visited_state(void);
15 static int is_visited_state(){
17 if(_sg_mc_visited == 0)
20 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
24 mc_snapshot_t new_state = NULL;
25 new_state = MC_take_snapshot();
29 if(xbt_dynar_is_empty(visited_states)){
32 xbt_dynar_push(visited_states, &new_state);
44 unsigned int cursor = 0;
45 mc_snapshot_t state_test = NULL;
47 xbt_dynar_foreach(visited_states, cursor, state_test){
48 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug))
49 XBT_DEBUG("****** Pair visited #%d ******", cursor + 1);
50 if(snapshot_compare(new_state, state_test, NULL, NULL) == 0){
60 if(xbt_dynar_length(visited_states) == _sg_mc_visited){
61 mc_snapshot_t state_to_remove = NULL;
62 xbt_dynar_shift(visited_states, &state_to_remove);
63 MC_free_snapshot(state_to_remove);
66 xbt_dynar_push(visited_states, &new_state);
79 * \brief Initialize the DPOR exploration algorithm
84 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
86 mc_state_t initial_state = NULL;
87 smx_process_t process;
89 /* Create the initial state and push it into the exploration stack */
92 initial_state = MC_state_new();
93 visited_states = xbt_dynar_new(sizeof(mc_snapshot_t), NULL);
97 XBT_DEBUG("**************************************************");
98 XBT_DEBUG("Initial state");
100 /* Wait for requests (schedules processes) */
101 MC_wait_for_requests();
105 /* Get an enabled process and insert it in the interleave set of the initial state */
106 xbt_swag_foreach(process, simix_global->process_list){
107 if(MC_process_is_enabled(process)){
108 MC_state_interleave_process(initial_state, process);
109 XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
113 xbt_fifo_unshift(mc_stack_safety, initial_state);
126 * \brief Perform the model-checking operation using a depth-first search exploration
127 * with Dynamic Partial Order Reductions
134 smx_simcall_t req = NULL, prev_req = NULL;
135 s_smx_simcall_t req2;
136 mc_state_t state = NULL, prev_state = NULL, next_state = NULL, restore_state=NULL;
137 smx_process_t process = NULL;
138 xbt_fifo_item_t item = NULL;
140 int interleave_proc[simix_process_maxpid];
142 while (xbt_fifo_size(mc_stack_safety) > 0) {
144 /* Get current state */
146 xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_safety));
148 XBT_DEBUG("**************************************************");
149 XBT_DEBUG("Exploration depth=%d (state=%p)(%u interleave)",
150 xbt_fifo_size(mc_stack_safety), state,
151 MC_state_interleave_size(state));
153 /* Update statistics */
154 mc_stats->visited_states++;
156 /* If there are processes to interleave and the maximum depth has not been reached
157 then perform one step of the exploration algorithm */
158 if (xbt_fifo_size(mc_stack_safety) < _sg_mc_max_depth &&
159 (req = MC_state_get_request(state, &value))) {
161 /* Debug information */
162 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
163 req_str = MC_request_to_string(req, value);
164 XBT_DEBUG("Execute: %s", req_str);
168 MC_state_set_executed_request(state, req, value);
169 mc_stats->executed_transitions++;
171 /* Answer the request */
172 SIMIX_simcall_pre(req, value); /* After this call req is no longer usefull */
174 /* Wait for requests (schedules processes) */
175 MC_wait_for_requests();
177 /* Create the new expanded state */
180 next_state = MC_state_new();
182 if(!is_visited_state()){
184 /* Get an enabled process and insert it in the interleave set of the next state */
185 xbt_swag_foreach(process, simix_global->process_list){
186 if(MC_process_is_enabled(process)){
187 MC_state_interleave_process(next_state, process);
188 XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
192 if(_sg_mc_checkpoint && ((xbt_fifo_size(mc_stack_safety) + 1) % _sg_mc_checkpoint == 0)){
193 next_state->system_state = MC_take_snapshot();
198 XBT_DEBUG("State already visited !");
202 xbt_fifo_unshift(mc_stack_safety, next_state);
205 /* Let's loop again */
207 /* The interleave set is empty or the maximum depth is reached, let's back-track */
210 if(xbt_fifo_size(mc_stack_safety) == _sg_mc_max_depth)
211 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
213 XBT_DEBUG("There are no more processes to interleave.");
215 /* Trash the current state, no longer needed */
217 xbt_fifo_shift(mc_stack_safety);
218 MC_state_delete(state);
221 /* Check for deadlocks */
222 if(MC_deadlock_check()){
223 MC_show_deadlock(NULL);
228 /* Traverse the stack backwards until a state with a non empty interleave
229 set is found, deleting all the states that have it empty in the way.
230 For each deleted state, check if the request that has generated it
231 (from it's predecesor state), depends on any other previous request
232 executed before it. If it does then add it to the interleave set of the
233 state that executed that previous request. */
235 while ((state = xbt_fifo_shift(mc_stack_safety)) != NULL) {
236 req = MC_state_get_internal_request(state);
237 xbt_fifo_foreach(mc_stack_safety, item, prev_state, mc_state_t) {
238 if(MC_request_depend(req, MC_state_get_internal_request(prev_state))){
239 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
240 XBT_DEBUG("Dependent Transitions:");
241 prev_req = MC_state_get_executed_request(prev_state, &value);
242 req_str = MC_request_to_string(prev_req, value);
243 XBT_DEBUG("%s (state=%p)", req_str, prev_state);
245 prev_req = MC_state_get_executed_request(state, &value);
246 req_str = MC_request_to_string(prev_req, value);
247 XBT_DEBUG("%s (state=%p)", req_str, state);
253 }else if(req->issuer == MC_state_get_internal_request(prev_state)->issuer){
255 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
260 MC_state_remove_interleave_process(prev_state, req->issuer);
261 XBT_DEBUG("Simcall %d in process %lu independant with simcall %d process %lu", req->call, req->issuer->pid, MC_state_get_internal_request(prev_state)->call, MC_state_get_internal_request(prev_state)->issuer->pid);
266 if (MC_state_interleave_size(state)) {
267 /* We found a back-tracking point, let's loop */
268 if(_sg_mc_checkpoint){
269 if(state->system_state != NULL){
270 MC_restore_snapshot(state->system_state);
271 xbt_fifo_unshift(mc_stack_safety, state);
274 pos = xbt_fifo_size(mc_stack_safety);
275 item = xbt_fifo_get_first_item(mc_stack_safety);
277 restore_state = (mc_state_t) xbt_fifo_get_item_content(item);
278 if(restore_state->system_state != NULL){
281 item = xbt_fifo_get_next_item(item);
285 MC_restore_snapshot(restore_state->system_state);
286 xbt_fifo_unshift(mc_stack_safety, state);
288 MC_replay(mc_stack_safety, pos);
291 xbt_fifo_unshift(mc_stack_safety, state);
293 MC_replay(mc_stack_safety, -1);
298 for(i=0; i<simix_process_maxpid; i++)
299 interleave_proc[i] = 0;
301 while((i < MC_state_interleave_size(state))){
303 prev_req = MC_state_get_request(state, &value);
304 if(prev_req != NULL){
305 MC_state_set_executed_request(state, prev_req, value);
306 prev_req = MC_state_get_internal_request(state);
307 if(MC_request_depend(&req2, prev_req)){
308 XBT_DEBUG("Simcall %d in process %lu dependant with simcall %d in process %lu", req2.call, req2.issuer->pid, prev_req->call, prev_req->issuer->pid);
309 interleave_proc[prev_req->issuer->pid] = 1;
311 XBT_DEBUG("Simcall %d in process %lu independant with simcall %d in process %lu", req2.call, req2.issuer->pid, prev_req->call, prev_req->issuer->pid);
312 MC_state_remove_interleave_process(state, prev_req->issuer);
316 xbt_swag_foreach(process, simix_global->process_list){
317 if(interleave_proc[process->pid] == 1)
318 MC_state_interleave_process(state, process);
320 XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_stack_safety));
324 MC_state_delete(state);
330 MC_print_statistics(mc_stats);