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;
12 int nb_visited_states = 0;
14 static int is_visited_state(void);
15 static void visited_state_free(mc_safety_visited_state_t state);
16 static void visited_state_free_voidp(void *s);
18 static void visited_state_free(mc_safety_visited_state_t state){
20 MC_free_snapshot(state->system_state);
25 static void visited_state_free_voidp(void *s){
26 visited_state_free((mc_safety_visited_state_t) * (void **) s);
29 static int is_visited_state(){
33 if(_sg_mc_visited == 0)
36 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
40 mc_safety_visited_state_t new_state = NULL;
41 new_state = xbt_new0(s_mc_safety_visited_state_t, 1);
42 new_state->system_state = MC_take_snapshot();
43 new_state->num = nb_visited_states;
47 if(xbt_dynar_is_empty(visited_states)){
50 xbt_dynar_push(visited_states, &new_state);
62 size_t current_chunks_used = mmalloc_get_chunks_used((xbt_mheap_t)(new_state->system_state)->regions[get_heap_region_index(new_state->system_state)]->data);
64 unsigned int cursor = 0;
65 int previous_cursor = 0, next_cursor = 0;
67 int end = xbt_dynar_length(visited_states) - 1;
69 mc_safety_visited_state_t state_test = NULL;
70 size_t chunks_used_test;
71 int same_chunks_not_found = 1;
73 while(start <= end && same_chunks_not_found){
74 cursor = (start + end) / 2;
75 state_test = (mc_safety_visited_state_t)xbt_dynar_get_as(visited_states, cursor, mc_safety_visited_state_t);
76 chunks_used_test = mmalloc_get_chunks_used((xbt_mheap_t)(state_test->system_state)->regions[get_heap_region_index(state_test->system_state)]->data);
77 if(chunks_used_test < current_chunks_used)
79 if(chunks_used_test > current_chunks_used)
81 if(chunks_used_test == current_chunks_used){
82 same_chunks_not_found = 0;
83 if(snapshot_compare(new_state->system_state, state_test->system_state, NULL, NULL) == 0){
90 /* Search another state with same number of chunks used */
91 previous_cursor = cursor - 1;
92 while(previous_cursor >= 0){
93 state_test = (mc_safety_visited_state_t)xbt_dynar_get_as(visited_states, previous_cursor, mc_safety_visited_state_t);
94 chunks_used_test = mmalloc_get_chunks_used((xbt_mheap_t)(state_test->system_state)->regions[get_heap_region_index(state_test->system_state)]->data);
95 if(chunks_used_test != current_chunks_used)
97 if(snapshot_compare(new_state->system_state, state_test->system_state, NULL, NULL) == 0){
106 next_cursor = cursor + 1;
107 while(next_cursor < xbt_dynar_length(visited_states)){
108 state_test = (mc_safety_visited_state_t)xbt_dynar_get_as(visited_states, next_cursor, mc_safety_visited_state_t);
109 chunks_used_test = mmalloc_get_chunks_used((xbt_mheap_t)(state_test->system_state)->regions[get_heap_region_index(state_test->system_state)]->data);
110 if(chunks_used_test != current_chunks_used)
112 if(snapshot_compare(new_state->system_state, state_test->system_state, NULL, NULL) == 0){
125 if(xbt_dynar_length(visited_states) == _sg_mc_visited){
126 int min = nb_visited_states;
127 unsigned int cursor2 = 0;
129 xbt_dynar_foreach(visited_states, cursor2, state_test){
130 if(state_test->num < min){
132 min = state_test->num;
135 xbt_dynar_remove_at(visited_states, index, NULL);
141 if(chunks_used_test < current_chunks_used)
142 xbt_dynar_insert_at(visited_states, cursor + 1, &new_state);
144 xbt_dynar_insert_at(visited_states, cursor, &new_state);
157 * \brief Initialize the DPOR exploration algorithm
162 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
164 mc_state_t initial_state = NULL;
165 smx_process_t process;
167 /* Create the initial state and push it into the exploration stack */
170 initial_state = MC_state_new();
171 visited_states = xbt_dynar_new(sizeof(mc_safety_visited_state_t), visited_state_free_voidp);
175 XBT_DEBUG("**************************************************");
176 XBT_DEBUG("Initial state");
178 /* Wait for requests (schedules processes) */
179 MC_wait_for_requests();
183 /* Get an enabled process and insert it in the interleave set of the initial state */
184 xbt_swag_foreach(process, simix_global->process_list){
185 if(MC_process_is_enabled(process)){
186 MC_state_interleave_process(initial_state, process);
187 XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
191 xbt_fifo_unshift(mc_stack_safety, initial_state);
204 * \brief Perform the model-checking operation using a depth-first search exploration
205 * with Dynamic Partial Order Reductions
212 smx_simcall_t req = NULL, prev_req = NULL;
213 s_smx_simcall_t req2;
214 mc_state_t state = NULL, prev_state = NULL, next_state = NULL, restore_state=NULL;
215 smx_process_t process = NULL;
216 xbt_fifo_item_t item = NULL;
218 int interleave_proc[simix_process_maxpid];
220 while (xbt_fifo_size(mc_stack_safety) > 0) {
222 /* Get current state */
224 xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_safety));
226 XBT_DEBUG("**************************************************");
227 XBT_DEBUG("Exploration depth=%d (state=%p)(%u interleave)",
228 xbt_fifo_size(mc_stack_safety), state,
229 MC_state_interleave_size(state));
231 /* Update statistics */
232 mc_stats->visited_states++;
234 /* If there are processes to interleave and the maximum depth has not been reached
235 then perform one step of the exploration algorithm */
236 if (xbt_fifo_size(mc_stack_safety) < _sg_mc_max_depth &&
237 (req = MC_state_get_request(state, &value))) {
239 /* Debug information */
240 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
241 req_str = MC_request_to_string(req, value);
242 XBT_DEBUG("Execute: %s", req_str);
246 MC_state_set_executed_request(state, req, value);
247 mc_stats->executed_transitions++;
249 /* Answer the request */
250 SIMIX_simcall_pre(req, value); /* After this call req is no longer usefull */
252 /* Wait for requests (schedules processes) */
253 MC_wait_for_requests();
255 /* Create the new expanded state */
258 next_state = MC_state_new();
260 if(!is_visited_state()){
262 /* Get an enabled process and insert it in the interleave set of the next state */
263 xbt_swag_foreach(process, simix_global->process_list){
264 if(MC_process_is_enabled(process)){
265 MC_state_interleave_process(next_state, process);
266 XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
270 if(_sg_mc_checkpoint && ((xbt_fifo_size(mc_stack_safety) + 1) % _sg_mc_checkpoint == 0)){
271 next_state->system_state = MC_take_snapshot();
276 XBT_DEBUG("State already visited !");
280 xbt_fifo_unshift(mc_stack_safety, next_state);
283 /* Let's loop again */
285 /* The interleave set is empty or the maximum depth is reached, let's back-track */
288 if(xbt_fifo_size(mc_stack_safety) == _sg_mc_max_depth)
289 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
291 XBT_DEBUG("There are no more processes to interleave.");
293 /* Trash the current state, no longer needed */
295 xbt_fifo_shift(mc_stack_safety);
296 MC_state_delete(state);
299 /* Check for deadlocks */
300 if(MC_deadlock_check()){
301 MC_show_deadlock(NULL);
306 /* Traverse the stack backwards until a state with a non empty interleave
307 set is found, deleting all the states that have it empty in the way.
308 For each deleted state, check if the request that has generated it
309 (from it's predecesor state), depends on any other previous request
310 executed before it. If it does then add it to the interleave set of the
311 state that executed that previous request. */
313 while ((state = xbt_fifo_shift(mc_stack_safety)) != NULL) {
314 req = MC_state_get_internal_request(state);
315 xbt_fifo_foreach(mc_stack_safety, item, prev_state, mc_state_t) {
316 if(MC_request_depend(req, MC_state_get_internal_request(prev_state))){
317 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
318 XBT_DEBUG("Dependent Transitions:");
319 prev_req = MC_state_get_executed_request(prev_state, &value);
320 req_str = MC_request_to_string(prev_req, value);
321 XBT_DEBUG("%s (state=%p)", req_str, prev_state);
323 prev_req = MC_state_get_executed_request(state, &value);
324 req_str = MC_request_to_string(prev_req, value);
325 XBT_DEBUG("%s (state=%p)", req_str, state);
331 }else if(req->issuer == MC_state_get_internal_request(prev_state)->issuer){
333 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
338 MC_state_remove_interleave_process(prev_state, req->issuer);
339 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);
344 if (MC_state_interleave_size(state)) {
345 /* We found a back-tracking point, let's loop */
346 if(_sg_mc_checkpoint){
347 if(state->system_state != NULL){
348 MC_restore_snapshot(state->system_state);
349 xbt_fifo_unshift(mc_stack_safety, state);
352 pos = xbt_fifo_size(mc_stack_safety);
353 item = xbt_fifo_get_first_item(mc_stack_safety);
355 restore_state = (mc_state_t) xbt_fifo_get_item_content(item);
356 if(restore_state->system_state != NULL){
359 item = xbt_fifo_get_next_item(item);
363 MC_restore_snapshot(restore_state->system_state);
364 xbt_fifo_unshift(mc_stack_safety, state);
366 MC_replay(mc_stack_safety, pos);
369 xbt_fifo_unshift(mc_stack_safety, state);
371 MC_replay(mc_stack_safety, -1);
376 for(i=0; i<simix_process_maxpid; i++)
377 interleave_proc[i] = 0;
379 while((i < MC_state_interleave_size(state))){
381 prev_req = MC_state_get_request(state, &value);
382 if(prev_req != NULL){
383 MC_state_set_executed_request(state, prev_req, value);
384 prev_req = MC_state_get_internal_request(state);
385 if(MC_request_depend(&req2, prev_req)){
386 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);
387 interleave_proc[prev_req->issuer->pid] = 1;
389 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);
390 MC_state_remove_interleave_process(state, prev_req->issuer);
394 xbt_swag_foreach(process, simix_global->process_list){
395 if(interleave_proc[process->pid] == 1)
396 MC_state_interleave_process(state, process);
398 XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_stack_safety));
402 MC_state_delete(state);
408 MC_print_statistics(mc_stats);