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. */
10 #include "mc_request.h"
11 #include "mc_safety.h"
12 #include "mc_private.h"
13 #include "mc_record.h"
15 #include "xbt/mmalloc/mmprivate.h"
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_safety, mc,
18 "Logging specific to MC safety verification ");
21 * \brief Initialize the DPOR exploration algorithm
23 void MC_pre_modelcheck_safety()
25 mc_state_t initial_state = NULL;
26 smx_process_t process;
28 xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
30 if (_sg_mc_visited > 0)
31 visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
33 initial_state = MC_state_new();
36 XBT_DEBUG("**************************************************");
37 XBT_DEBUG("Initial state");
39 /* Wait for requests (schedules processes) */
40 MC_wait_for_requests();
44 /* Get an enabled process and insert it in the interleave set of the initial state */
45 MC_EACH_SIMIX_PROCESS(process,
46 if (MC_process_is_enabled(process)) {
47 MC_state_interleave_process(initial_state, process);
48 if (mc_reduce_kind != e_mc_reduce_none)
53 xbt_fifo_unshift(mc_stack, initial_state);
54 mmalloc_set_current_heap(heap);
58 /** \brief Model-check the application using a DFS exploration
59 * with DPOR (Dynamic Partial Order Reductions)
61 void MC_modelcheck_safety(void)
66 smx_simcall_t req = NULL, prev_req = NULL;
67 mc_state_t state = NULL, prev_state = NULL, next_state = NULL;
68 smx_process_t process = NULL;
69 xbt_fifo_item_t item = NULL;
70 mc_visited_state_t visited_state = NULL;
72 while (xbt_fifo_size(mc_stack) > 0) {
74 /* Get current state */
75 state = (mc_state_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
77 XBT_DEBUG("**************************************************");
79 ("Exploration depth=%d (state=%p, num %d)(%u interleave, user_max_depth %d)",
80 xbt_fifo_size(mc_stack), state, state->num,
81 MC_state_interleave_size(state), user_max_depth_reached);
83 /* Update statistics */
84 mc_stats->visited_states++;
86 /* If there are processes to interleave and the maximum depth has not been reached
87 then perform one step of the exploration algorithm */
88 if (xbt_fifo_size(mc_stack) <= _sg_mc_max_depth && !user_max_depth_reached
89 && (req = MC_state_get_request(state, &value)) && visited_state == NULL) {
91 char* req_str = MC_request_to_string(req, value);
92 XBT_DEBUG("Execute: %s", req_str);
95 if (dot_output != NULL) {
97 req_str = MC_request_get_dot_output(req, value);
101 MC_state_set_executed_request(state, req, value);
102 mc_stats->executed_transitions++;
104 /* Answer the request */
105 MC_simcall_handle(req, value);
107 /* Wait for requests (schedules processes) */
108 MC_wait_for_requests();
110 /* Create the new expanded state */
113 next_state = MC_state_new();
115 if ((visited_state = is_visited_state(next_state)) == NULL) {
117 /* Get an enabled process and insert it in the interleave set of the next state */
118 MC_EACH_SIMIX_PROCESS(process,
119 if (MC_process_is_enabled(process)) {
120 MC_state_interleave_process(next_state, process);
121 if (mc_reduce_kind != e_mc_reduce_none)
126 if (dot_output != NULL)
127 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
131 if (dot_output != NULL)
132 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, visited_state->other_num == -1 ? visited_state->num : visited_state->other_num, req_str);
136 xbt_fifo_unshift(mc_stack, next_state);
138 if (dot_output != NULL)
143 /* Let's loop again */
145 /* The interleave set is empty or the maximum depth is reached, let's back-track */
148 if ((xbt_fifo_size(mc_stack) > _sg_mc_max_depth) || user_max_depth_reached || visited_state != NULL) {
150 if (user_max_depth_reached && visited_state == NULL)
151 XBT_DEBUG("User max depth reached !");
152 else if (visited_state == NULL)
153 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
155 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);
159 XBT_DEBUG("There are no more processes to interleave. (depth %d)", xbt_fifo_size(mc_stack) + 1);
165 /* Trash the current state, no longer needed */
166 xbt_fifo_shift(mc_stack);
167 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
168 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
172 visited_state = NULL;
174 /* Check for deadlocks */
175 if (MC_deadlock_check()) {
176 MC_show_deadlock(NULL);
181 /* Traverse the stack backwards until a state with a non empty interleave
182 set is found, deleting all the states that have it empty in the way.
183 For each deleted state, check if the request that has generated it
184 (from it's predecesor state), depends on any other previous request
185 executed before it. If it does then add it to the interleave set of the
186 state that executed that previous request. */
188 while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
189 if (mc_reduce_kind == e_mc_reduce_dpor) {
190 req = MC_state_get_internal_request(state);
191 const smx_process_t issuer = MC_process_get_issuer(&mc_model_checker->process, req);
192 xbt_fifo_foreach(mc_stack, item, prev_state, mc_state_t) {
193 if (MC_request_depend(req, MC_state_get_internal_request(prev_state))) {
194 if (XBT_LOG_ISENABLED(mc_safety, xbt_log_priority_debug)) {
195 XBT_DEBUG("Dependent Transitions:");
196 prev_req = MC_state_get_executed_request(prev_state, &value);
197 req_str = MC_request_to_string(prev_req, value);
198 XBT_DEBUG("%s (state=%d)", req_str, prev_state->num);
200 prev_req = MC_state_get_executed_request(state, &value);
201 req_str = MC_request_to_string(prev_req, value);
202 XBT_DEBUG("%s (state=%d)", req_str, state->num);
206 if (!MC_state_process_is_done(prev_state, issuer))
207 MC_state_interleave_process(prev_state, issuer);
209 XBT_DEBUG("Process %p is in done set", req->issuer);
213 } else if (req->issuer == MC_state_get_internal_request(prev_state)->issuer) {
215 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
220 const smx_process_t previous_issuer = MC_process_get_issuer(&mc_model_checker->process, MC_state_get_internal_request(prev_state));
221 XBT_DEBUG("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant",
222 req->call, issuer->pid, state->num,
223 MC_state_get_internal_request(prev_state)->call,
224 previous_issuer->pid,
231 if (MC_state_interleave_size(state) && xbt_fifo_size(mc_stack) < _sg_mc_max_depth) {
232 /* We found a back-tracking point, let's loop */
233 XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
234 xbt_fifo_unshift(mc_stack, state);
236 XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, xbt_fifo_size(mc_stack));
239 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
240 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
246 MC_print_statistics(mc_stats);