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"
16 #include "xbt/mmalloc/mmprivate.h"
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_safety, mc,
19 "Logging specific to MC safety verification ");
22 * \brief Initialize the DPOR exploration algorithm
24 void MC_pre_modelcheck_safety()
26 mc_state_t initial_state = NULL;
27 smx_process_t process;
29 xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
31 if (_sg_mc_visited > 0)
32 visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
34 initial_state = MC_state_new();
37 XBT_DEBUG("**************************************************");
38 XBT_DEBUG("Initial state");
40 /* Wait for requests (schedules processes) */
41 MC_wait_for_requests();
45 /* Get an enabled process and insert it in the interleave set of the initial state */
46 MC_EACH_SIMIX_PROCESS(process,
47 if (MC_process_is_enabled(process)) {
48 MC_state_interleave_process(initial_state, process);
49 if (mc_reduce_kind != e_mc_reduce_none)
54 xbt_fifo_unshift(mc_stack, initial_state);
55 mmalloc_set_current_heap(heap);
59 /** \brief Model-check the application using a DFS exploration
60 * with DPOR (Dynamic Partial Order Reductions)
62 void MC_modelcheck_safety(void)
67 smx_simcall_t req = NULL, prev_req = NULL;
68 mc_state_t state = NULL, prev_state = NULL, next_state = NULL;
69 smx_process_t process = NULL;
70 xbt_fifo_item_t item = NULL;
71 mc_visited_state_t visited_state = NULL;
73 while (xbt_fifo_size(mc_stack) > 0) {
75 /* Get current state */
76 state = (mc_state_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
78 XBT_DEBUG("**************************************************");
80 ("Exploration depth=%d (state=%p, num %d)(%u interleave, user_max_depth %d)",
81 xbt_fifo_size(mc_stack), state, state->num,
82 MC_state_interleave_size(state), user_max_depth_reached);
84 /* Update statistics */
85 mc_stats->visited_states++;
87 /* If there are processes to interleave and the maximum depth has not been reached
88 then perform one step of the exploration algorithm */
89 if (xbt_fifo_size(mc_stack) <= _sg_mc_max_depth && !user_max_depth_reached
90 && (req = MC_state_get_request(state, &value)) && visited_state == NULL) {
92 char* req_str = MC_request_to_string(req, value);
93 XBT_DEBUG("Execute: %s", req_str);
96 if (dot_output != NULL) {
98 req_str = MC_request_get_dot_output(req, value);
102 MC_state_set_executed_request(state, req, value);
103 mc_stats->executed_transitions++;
105 /* Answer the request */
106 MC_simcall_handle(req, value);
108 /* Wait for requests (schedules processes) */
109 MC_wait_for_requests();
111 /* Create the new expanded state */
114 next_state = MC_state_new();
116 if ((visited_state = is_visited_state(next_state)) == NULL) {
118 /* Get an enabled process and insert it in the interleave set of the next state */
119 MC_EACH_SIMIX_PROCESS(process,
120 if (MC_process_is_enabled(process)) {
121 MC_state_interleave_process(next_state, process);
122 if (mc_reduce_kind != e_mc_reduce_none)
127 if (dot_output != NULL)
128 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
132 if (dot_output != NULL)
133 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, visited_state->other_num == -1 ? visited_state->num : visited_state->other_num, req_str);
137 xbt_fifo_unshift(mc_stack, next_state);
139 if (dot_output != NULL)
144 /* Let's loop again */
146 /* The interleave set is empty or the maximum depth is reached, let's back-track */
149 if ((xbt_fifo_size(mc_stack) > _sg_mc_max_depth) || user_max_depth_reached || visited_state != NULL) {
151 if (user_max_depth_reached && visited_state == NULL)
152 XBT_DEBUG("User max depth reached !");
153 else if (visited_state == NULL)
154 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
156 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);
160 XBT_DEBUG("There are no more processes to interleave. (depth %d)", xbt_fifo_size(mc_stack) + 1);
166 /* Trash the current state, no longer needed */
167 xbt_fifo_shift(mc_stack);
168 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
169 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
173 visited_state = NULL;
175 /* Check for deadlocks */
176 if (MC_deadlock_check()) {
177 MC_show_deadlock(NULL);
182 /* Traverse the stack backwards until a state with a non empty interleave
183 set is found, deleting all the states that have it empty in the way.
184 For each deleted state, check if the request that has generated it
185 (from it's predecesor state), depends on any other previous request
186 executed before it. If it does then add it to the interleave set of the
187 state that executed that previous request. */
189 while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
190 if (mc_reduce_kind == e_mc_reduce_dpor) {
191 req = MC_state_get_internal_request(state);
192 const smx_process_t issuer = MC_smx_simcall_get_issuer(req);
193 xbt_fifo_foreach(mc_stack, item, prev_state, mc_state_t) {
194 if (MC_request_depend(req, MC_state_get_internal_request(prev_state))) {
195 if (XBT_LOG_ISENABLED(mc_safety, xbt_log_priority_debug)) {
196 XBT_DEBUG("Dependent Transitions:");
197 prev_req = MC_state_get_executed_request(prev_state, &value);
198 req_str = MC_request_to_string(prev_req, value);
199 XBT_DEBUG("%s (state=%d)", req_str, prev_state->num);
201 prev_req = MC_state_get_executed_request(state, &value);
202 req_str = MC_request_to_string(prev_req, value);
203 XBT_DEBUG("%s (state=%d)", req_str, state->num);
207 if (!MC_state_process_is_done(prev_state, issuer))
208 MC_state_interleave_process(prev_state, issuer);
210 XBT_DEBUG("Process %p is in done set", req->issuer);
214 } else if (req->issuer == MC_state_get_internal_request(prev_state)->issuer) {
216 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
221 const smx_process_t previous_issuer = MC_smx_simcall_get_issuer(MC_state_get_internal_request(prev_state));
222 XBT_DEBUG("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant",
223 req->call, issuer->pid, state->num,
224 MC_state_get_internal_request(prev_state)->call,
225 previous_issuer->pid,
232 if (MC_state_interleave_size(state) && xbt_fifo_size(mc_stack) < _sg_mc_max_depth) {
233 /* We found a back-tracking point, let's loop */
234 XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
235 xbt_fifo_unshift(mc_stack, state);
237 XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, xbt_fifo_size(mc_stack));
240 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
241 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
247 MC_print_statistics(mc_stats);