1 /* Copyright (c) 2008-2014. The SimGrid Team.
2 * All rights reserved. */
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. */
8 #include "mc_request.h"
10 #include "mc_private.h"
11 #include "mc_record.h"
13 #include "xbt/mmalloc/mmprivate.h"
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_safety, mc,
16 "Logging specific to MC safety verification ");
19 * \brief Initialize the DPOR exploration algorithm
21 void MC_pre_modelcheck_safety()
23 mc_state_t initial_state = NULL;
24 smx_process_t process;
26 xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
28 if (_sg_mc_visited > 0)
29 visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
31 initial_state = MC_state_new();
35 XBT_DEBUG("**************************************************");
36 XBT_DEBUG("Initial state");
38 /* Wait for requests (schedules processes) */
39 MC_wait_for_requests();
43 /* Get an enabled process and insert it in the interleave set of the initial state */
44 xbt_swag_foreach(process, simix_global->process_list) {
45 if (MC_process_is_enabled(process)) {
46 MC_state_interleave_process(initial_state, process);
47 if (mc_reduce_kind != e_mc_reduce_none)
52 xbt_fifo_unshift(mc_stack, initial_state);
53 mmalloc_set_current_heap(heap);
57 /** \brief Model-check the application using a DFS exploration
58 * with DPOR (Dynamic Partial Order Reductions)
60 void MC_modelcheck_safety(void)
65 smx_simcall_t req = NULL, prev_req = NULL;
66 mc_state_t state = NULL, prev_state = NULL, next_state = NULL;
67 smx_process_t process = NULL;
68 xbt_fifo_item_t item = NULL;
69 mc_visited_state_t visited_state = NULL;
71 while (xbt_fifo_size(mc_stack) > 0) {
73 /* Get current state */
74 state = (mc_state_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
76 XBT_DEBUG("**************************************************");
78 ("Exploration depth=%d (state=%p, num %d)(%u interleave, user_max_depth %d)",
79 xbt_fifo_size(mc_stack), state, state->num,
80 MC_state_interleave_size(state), user_max_depth_reached);
82 /* Update statistics */
83 mc_stats->visited_states++;
85 /* If there are processes to interleave and the maximum depth has not been reached
86 then perform one step of the exploration algorithm */
87 if (xbt_fifo_size(mc_stack) <= _sg_mc_max_depth && !user_max_depth_reached
88 && (req = MC_state_get_request(state, &value)) && visited_state == NULL) {
90 char* req_str = MC_request_to_string(req, value);
91 XBT_DEBUG("Execute: %s", req_str);
94 if (dot_output != NULL) {
96 req_str = MC_request_get_dot_output(req, value);
100 MC_state_set_executed_request(state, req, value);
101 mc_stats->executed_transitions++;
103 /* Answer the request */
104 SIMIX_simcall_handle(req, value);
106 /* Wait for requests (schedules processes) */
107 MC_wait_for_requests();
109 /* Create the new expanded state */
112 next_state = MC_state_new();
114 if ((visited_state = is_visited_state(next_state)) == NULL) {
116 /* Get an enabled process and insert it in the interleave set of the next state */
117 xbt_swag_foreach(process, simix_global->process_list) {
118 if (MC_process_is_enabled(process)) {
119 MC_state_interleave_process(next_state, process);
120 if (mc_reduce_kind != e_mc_reduce_none)
125 if (dot_output != NULL)
126 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
130 if (dot_output != NULL)
131 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, visited_state->other_num == -1 ? visited_state->num : visited_state->other_num, req_str);
135 xbt_fifo_unshift(mc_stack, next_state);
137 if (dot_output != NULL)
142 /* Let's loop again */
144 /* The interleave set is empty or the maximum depth is reached, let's back-track */
147 if ((xbt_fifo_size(mc_stack) > _sg_mc_max_depth) || user_max_depth_reached || visited_state != NULL) {
149 if (user_max_depth_reached && visited_state == NULL)
150 XBT_DEBUG("User max depth reached !");
151 else if (visited_state == NULL)
152 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
154 XBT_DEBUG("State already visited (equal to state %d), exploration stopped on this path.", visited_state->other_num == -1 ? visited_state->num : visited_state->other_num);
158 XBT_DEBUG("There are no more processes to interleave. (depth %d)", xbt_fifo_size(mc_stack) + 1);
164 /* Trash the current state, no longer needed */
165 xbt_fifo_shift(mc_stack);
166 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
167 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
171 visited_state = NULL;
173 /* Check for deadlocks */
174 if (MC_deadlock_check()) {
175 MC_show_deadlock(NULL);
180 /* Traverse the stack backwards until a state with a non empty interleave
181 set is found, deleting all the states that have it empty in the way.
182 For each deleted state, check if the request that has generated it
183 (from it's predecesor state), depends on any other previous request
184 executed before it. If it does then add it to the interleave set of the
185 state that executed that previous request. */
187 while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
188 if (mc_reduce_kind == e_mc_reduce_dpor) {
189 req = MC_state_get_internal_request(state);
190 xbt_fifo_foreach(mc_stack, item, prev_state, mc_state_t) {
191 if (MC_request_depend(req, MC_state_get_internal_request(prev_state))) {
192 if (XBT_LOG_ISENABLED(mc_safety, xbt_log_priority_debug)) {
193 XBT_DEBUG("Dependent Transitions:");
194 prev_req = MC_state_get_executed_request(prev_state, &value);
195 req_str = MC_request_to_string(prev_req, value);
196 XBT_DEBUG("%s (state=%d)", req_str, prev_state->num);
198 prev_req = MC_state_get_executed_request(state, &value);
199 req_str = MC_request_to_string(prev_req, value);
200 XBT_DEBUG("%s (state=%d)", req_str, state->num);
204 if (!MC_state_process_is_done(prev_state, req->issuer))
205 MC_state_interleave_process(prev_state, req->issuer);
207 XBT_DEBUG("Process %p is in done set", req->issuer);
211 } else if (req->issuer == MC_state_get_internal_request(prev_state)->issuer) {
213 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
218 XBT_DEBUG("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant",
219 req->call, req->issuer->pid, state->num,
220 MC_state_get_internal_request(prev_state)->call,
221 MC_state_get_internal_request(prev_state)->issuer->pid,
228 if (MC_state_interleave_size(state) && xbt_fifo_size(mc_stack) < _sg_mc_max_depth) {
229 /* We found a back-tracking point, let's loop */
230 XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
231 xbt_fifo_unshift(mc_stack, state);
233 XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, xbt_fifo_size(mc_stack));
236 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
237 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
243 MC_print_statistics(mc_stats);