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 ");
18 static int is_exploration_stack_state(mc_state_t current_state){
21 mc_state_t stack_state;
22 for(item = xbt_fifo_get_first_item(mc_stack); item != NULL; item = xbt_fifo_get_next_item(item)) {
23 stack_state = (mc_state_t) xbt_fifo_get_item_content(item);
24 if(snapshot_compare(stack_state, current_state) == 0){
25 XBT_INFO("Non-progressive cycle : state %d -> state %d", stack_state->num, current_state->num);
33 * \brief Initialize the DPOR exploration algorithm
35 void MC_pre_modelcheck_safety()
38 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
40 mc_state_t initial_state = NULL;
41 smx_process_t process;
43 /* Create the initial state and push it into the exploration stack */
47 if (_sg_mc_visited > 0)
48 visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
50 initial_state = MC_state_new();
54 XBT_DEBUG("**************************************************");
55 XBT_DEBUG("Initial state");
57 /* Wait for requests (schedules processes) */
58 MC_wait_for_requests();
62 /* Get an enabled process and insert it in the interleave set of the initial state */
63 xbt_swag_foreach(process, simix_global->process_list) {
64 if (MC_process_is_enabled(process)) {
65 MC_state_interleave_process(initial_state, process);
66 if (mc_reduce_kind != e_mc_reduce_none)
71 xbt_fifo_unshift(mc_stack, initial_state);
78 /** \brief Model-check the application using a DFS exploration
79 * with DPOR (Dynamic Partial Order Reductions)
81 void MC_modelcheck_safety(void)
86 smx_simcall_t req = NULL, prev_req = NULL;
87 mc_state_t state = NULL, prev_state = NULL, next_state = NULL;
88 smx_process_t process = NULL;
89 xbt_fifo_item_t item = NULL;
90 mc_visited_state_t visited_state = NULL;
92 while (xbt_fifo_size(mc_stack) > 0) {
94 /* Get current state */
95 state = (mc_state_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
97 XBT_DEBUG("**************************************************");
99 ("Exploration depth=%d (state=%p, num %d)(%u interleave, user_max_depth %d)",
100 xbt_fifo_size(mc_stack), state, state->num,
101 MC_state_interleave_size(state), user_max_depth_reached);
103 /* Update statistics */
104 mc_stats->visited_states++;
106 /* If there are processes to interleave and the maximum depth has not been reached
107 then perform one step of the exploration algorithm */
108 if (xbt_fifo_size(mc_stack) <= _sg_mc_max_depth && !user_max_depth_reached
109 && (req = MC_state_get_request(state, &value)) && visited_state == NULL) {
111 char* req_str = MC_request_to_string(req, value);
112 XBT_DEBUG("Execute: %s", req_str);
115 if (dot_output != NULL) {
117 req_str = MC_request_get_dot_output(req, value);
121 MC_state_set_executed_request(state, req, value);
122 mc_stats->executed_transitions++;
124 /* Answer the request */
125 SIMIX_simcall_handle(req, value);
127 /* Wait for requests (schedules processes) */
128 MC_wait_for_requests();
130 /* Create the new expanded state */
133 next_state = MC_state_new();
135 if(_sg_mc_termination && is_exploration_stack_state(next_state)){
136 MC_show_non_termination();
140 if ((visited_state = is_visited_state(next_state)) == NULL) {
142 /* Get an enabled process and insert it in the interleave set of the next state */
143 xbt_swag_foreach(process, simix_global->process_list) {
144 if (MC_process_is_enabled(process)) {
145 MC_state_interleave_process(next_state, process);
146 if (mc_reduce_kind != e_mc_reduce_none)
151 if (dot_output != NULL)
152 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
156 if (dot_output != NULL)
157 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, visited_state->other_num == -1 ? visited_state->num : visited_state->other_num, req_str);
161 xbt_fifo_unshift(mc_stack, next_state);
163 if (dot_output != NULL)
168 /* Let's loop again */
170 /* The interleave set is empty or the maximum depth is reached, let's back-track */
173 if ((xbt_fifo_size(mc_stack) > _sg_mc_max_depth) || user_max_depth_reached || visited_state != NULL) {
175 if (user_max_depth_reached && visited_state == NULL)
176 XBT_DEBUG("User max depth reached !");
177 else if (visited_state == NULL)
178 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
180 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);
184 XBT_DEBUG("There are no more processes to interleave. (depth %d)", xbt_fifo_size(mc_stack) + 1);
190 /* Trash the current state, no longer needed */
191 xbt_fifo_shift(mc_stack);
192 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
193 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
197 visited_state = NULL;
199 /* Check for deadlocks */
200 if (MC_deadlock_check()) {
201 MC_show_deadlock(NULL);
206 /* Traverse the stack backwards until a state with a non empty interleave
207 set is found, deleting all the states that have it empty in the way.
208 For each deleted state, check if the request that has generated it
209 (from it's predecesor state), depends on any other previous request
210 executed before it. If it does then add it to the interleave set of the
211 state that executed that previous request. */
213 while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
214 if (mc_reduce_kind == e_mc_reduce_dpor) {
215 req = MC_state_get_internal_request(state);
216 xbt_fifo_foreach(mc_stack, item, prev_state, mc_state_t) {
217 if (MC_request_depend(req, MC_state_get_internal_request(prev_state))) {
218 if (XBT_LOG_ISENABLED(mc_safety, xbt_log_priority_debug)) {
219 XBT_DEBUG("Dependent Transitions:");
220 prev_req = MC_state_get_executed_request(prev_state, &value);
221 req_str = MC_request_to_string(prev_req, value);
222 XBT_DEBUG("%s (state=%d)", req_str, prev_state->num);
224 prev_req = MC_state_get_executed_request(state, &value);
225 req_str = MC_request_to_string(prev_req, value);
226 XBT_DEBUG("%s (state=%d)", req_str, state->num);
230 if (!MC_state_process_is_done(prev_state, req->issuer))
231 MC_state_interleave_process(prev_state, req->issuer);
233 XBT_DEBUG("Process %p is in done set", req->issuer);
237 } else if (req->issuer == MC_state_get_internal_request(prev_state)->issuer) {
239 XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
244 XBT_DEBUG("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant",
245 req->call, req->issuer->pid, state->num,
246 MC_state_get_internal_request(prev_state)->call,
247 MC_state_get_internal_request(prev_state)->issuer->pid,
254 if (MC_state_interleave_size(state) && xbt_fifo_size(mc_stack) < _sg_mc_max_depth) {
255 /* We found a back-tracking point, let's loop */
256 XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
257 xbt_fifo_unshift(mc_stack, state);
259 XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, xbt_fifo_size(mc_stack));
262 XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
263 MC_state_delete(state, !state->in_visited_states ? 1 : 0);
269 MC_print_statistics(mc_stats);