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){
84 xbt_dynar_remove_at(visited_states, cursor, NULL);
85 xbt_dynar_insert_at(visited_states, cursor, &new_state);
92 /* Search another state with same number of chunks used */
93 previous_cursor = cursor - 1;
94 while(previous_cursor >= 0){
95 state_test = (mc_safety_visited_state_t)xbt_dynar_get_as(visited_states, previous_cursor, mc_safety_visited_state_t);
96 chunks_used_test = mmalloc_get_chunks_used((xbt_mheap_t)(state_test->system_state)->regions[get_heap_region_index(state_test->system_state)]->data);
97 if(chunks_used_test != current_chunks_used)
99 if(snapshot_compare(new_state->system_state, state_test->system_state, NULL, NULL) == 0){
100 xbt_dynar_remove_at(visited_states, previous_cursor, NULL);
101 xbt_dynar_insert_at(visited_states, previous_cursor, &new_state);
110 next_cursor = cursor + 1;
111 while(next_cursor < xbt_dynar_length(visited_states)){
112 state_test = (mc_safety_visited_state_t)xbt_dynar_get_as(visited_states, next_cursor, mc_safety_visited_state_t);
113 chunks_used_test = mmalloc_get_chunks_used((xbt_mheap_t)(state_test->system_state)->regions[get_heap_region_index(state_test->system_state)]->data);
114 if(chunks_used_test != current_chunks_used)
116 if(snapshot_compare(new_state->system_state, state_test->system_state, NULL, NULL) == 0){
117 xbt_dynar_remove_at(visited_states, next_cursor, NULL);
118 xbt_dynar_insert_at(visited_states, next_cursor, &new_state);
131 if(xbt_dynar_length(visited_states) == _sg_mc_visited){
132 int min = nb_visited_states;
133 unsigned int cursor2 = 0;
135 xbt_dynar_foreach(visited_states, cursor2, state_test){
136 if(state_test->num < min){
138 min = state_test->num;
141 xbt_dynar_remove_at(visited_states, index, NULL);
147 if(chunks_used_test < current_chunks_used)
148 xbt_dynar_insert_at(visited_states, cursor + 1, &new_state);
150 xbt_dynar_insert_at(visited_states, cursor, &new_state);
163 * \brief Initialize the DPOR exploration algorithm
168 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
170 mc_state_t initial_state = NULL;
171 smx_process_t process;
173 /* Create the initial state and push it into the exploration stack */
176 initial_state = MC_state_new();
177 visited_states = xbt_dynar_new(sizeof(mc_safety_visited_state_t), visited_state_free_voidp);
181 XBT_DEBUG("**************************************************");
182 XBT_DEBUG("Initial state");
184 /* Wait for requests (schedules processes) */
185 MC_wait_for_requests();
189 /* Get an enabled process and insert it in the interleave set of the initial state */
190 xbt_swag_foreach(process, simix_global->process_list){
191 if(MC_process_is_enabled(process)){
192 MC_state_interleave_process(initial_state, process);
193 XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
197 xbt_fifo_unshift(mc_stack_safety, initial_state);
210 * \brief Perform the model-checking operation using a depth-first search exploration
211 * with Dynamic Partial Order Reductions
218 smx_simcall_t req = NULL, prev_req = NULL;
219 s_smx_simcall_t req2;
220 mc_state_t state = NULL, prev_state = NULL, next_state = NULL, restore_state=NULL;
221 smx_process_t process = NULL;
222 xbt_fifo_item_t item = NULL;
224 int interleave_proc[simix_process_maxpid];
226 while (xbt_fifo_size(mc_stack_safety) > 0) {
228 /* Get current state */
230 xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_safety));
232 XBT_DEBUG("**************************************************");
233 XBT_DEBUG("Exploration depth=%d (state=%p)(%u interleave)",
234 xbt_fifo_size(mc_stack_safety), state,
235 MC_state_interleave_size(state));
237 /* Update statistics */
238 mc_stats->visited_states++;
240 /* If there are processes to interleave and the maximum depth has not been reached
241 then perform one step of the exploration algorithm */
242 if (xbt_fifo_size(mc_stack_safety) < _sg_mc_max_depth &&
243 (req = MC_state_get_request(state, &value))) {
245 /* Debug information */
246 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
247 req_str = MC_request_to_string(req, value);
248 XBT_DEBUG("Execute: %s", req_str);
252 MC_state_set_executed_request(state, req, value);
253 mc_stats->executed_transitions++;
255 /* Answer the request */
256 SIMIX_simcall_pre(req, value); /* After this call req is no longer usefull */
258 /* Wait for requests (schedules processes) */
259 MC_wait_for_requests();
261 /* Create the new expanded state */
264 next_state = MC_state_new();
266 if(!is_visited_state()){
268 /* Get an enabled process and insert it in the interleave set of the next state */
269 xbt_swag_foreach(process, simix_global->process_list){
270 if(MC_process_is_enabled(process)){
271 MC_state_interleave_process(next_state, process);
272 XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
276 if(_sg_mc_checkpoint && ((xbt_fifo_size(mc_stack_safety) + 1) % _sg_mc_checkpoint == 0)){
277 next_state->system_state = MC_take_snapshot();
282 XBT_DEBUG("State already visited !");
286 xbt_fifo_unshift(mc_stack_safety, next_state);
289 /* Let's loop again */
291 /* The interleave set is empty or the maximum depth is reached, let's back-track */
294 if(xbt_fifo_size(mc_stack_safety) == _sg_mc_max_depth)
295 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
297 XBT_DEBUG("There are no more processes to interleave.");
299 /* Trash the current state, no longer needed */
301 xbt_fifo_shift(mc_stack_safety);
302 MC_state_delete(state);
305 /* Check for deadlocks */
306 if(MC_deadlock_check()){
307 MC_show_deadlock(NULL);
312 /* Traverse the stack backwards until a state with a non empty interleave
313 set is found, deleting all the states that have it empty in the way.
314 For each deleted state, check if the request that has generated it
315 (from it's predecesor state), depends on any other previous request
316 executed before it. If it does then add it to the interleave set of the
317 state that executed that previous request. */
319 while ((state = xbt_fifo_shift(mc_stack_safety)) != NULL) {
320 req = MC_state_get_internal_request(state);
321 xbt_fifo_foreach(mc_stack_safety, item, prev_state, mc_state_t) {
322 if(MC_request_depend(req, MC_state_get_internal_request(prev_state))){
323 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
324 XBT_DEBUG("Dependent Transitions:");
325 prev_req = MC_state_get_executed_request(prev_state, &value);
326 req_str = MC_request_to_string(prev_req, value);
327 XBT_DEBUG("%s (state=%p)", req_str, prev_state);
329 prev_req = MC_state_get_executed_request(state, &value);
330 req_str = MC_request_to_string(prev_req, value);
331 XBT_DEBUG("%s (state=%p)", req_str, state);
337 }else if(req->issuer == MC_state_get_internal_request(prev_state)->issuer){
339 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
344 MC_state_remove_interleave_process(prev_state, req->issuer);
345 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);
350 if (MC_state_interleave_size(state)) {
351 /* We found a back-tracking point, let's loop */
352 if(_sg_mc_checkpoint){
353 if(state->system_state != NULL){
354 MC_restore_snapshot(state->system_state);
355 xbt_fifo_unshift(mc_stack_safety, state);
358 pos = xbt_fifo_size(mc_stack_safety);
359 item = xbt_fifo_get_first_item(mc_stack_safety);
361 restore_state = (mc_state_t) xbt_fifo_get_item_content(item);
362 if(restore_state->system_state != NULL){
365 item = xbt_fifo_get_next_item(item);
369 MC_restore_snapshot(restore_state->system_state);
370 xbt_fifo_unshift(mc_stack_safety, state);
372 MC_replay(mc_stack_safety, pos);
375 xbt_fifo_unshift(mc_stack_safety, state);
377 MC_replay(mc_stack_safety, -1);
382 for(i=0; i<simix_process_maxpid; i++)
383 interleave_proc[i] = 0;
385 while((i < MC_state_interleave_size(state))){
387 prev_req = MC_state_get_request(state, &value);
388 if(prev_req != NULL){
389 MC_state_set_executed_request(state, prev_req, value);
390 prev_req = MC_state_get_internal_request(state);
391 if(MC_request_depend(&req2, prev_req)){
392 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);
393 interleave_proc[prev_req->issuer->pid] = 1;
395 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);
396 MC_state_remove_interleave_process(state, prev_req->issuer);
400 xbt_swag_foreach(process, simix_global->process_list){
401 if(interleave_proc[process->pid] == 1)
402 MC_state_interleave_process(state, process);
404 XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_stack_safety));
408 MC_state_delete(state);
414 MC_print_statistics(mc_stats);