|
Model Checking Guided tour
This page gives a quick overview of how the SMV model checking system is used. A simple example is presented, and its analysis performed. The example is extremely simple, and the analysis superficial for brevity. This demo just shows how the tool is used, and by no means indicates the size of problems that can be handled. The actual installation of SMV is quite simple, and we encourage you to try the real code. The complete tour takes about 5 pages.
An SMV program may consist of several modules. Each module is an encapsulated description that may be instantiated several times within the model. For example, the declaration defines proc as a module with 4 formal
parameters.
Within every module, local variables may be declared. The type of a variable may be boolean, an enumeration type or an integer subrange. Modules are also instantiated using variable
declarations. A module may contain instances of other modules, allowing a
structural hierarchy to be built. For example, the module main
declares the variable p0 as an instance of proc
Every SMV
description has to contain a module called main , with no formal
parameters. This module forms the root of the model hierarchy and the starting
point for building the finite-state model for a given description.
The value of the variables in each state are defined using The code above defines the initial value ofinit(state0) := noncritical; next(state0) := case (state0 = noncritical): {trying, noncritical}; (state0 = trying) & ((state1 = noncritical) | (state1 = trying)): ready; ... esac; state0 to be noncritical , and the value of that
variable in the next state as a function of the value of the variables in the
current state. Notice that if state0 is noncritical ,
then in the next state its value could be trying or
noncritical , and the choice is made nondeterministically.
This presentation briefly shows how to describe a system to be verified in the SMV language. Several features have been omitted for brevity. The reader is referred to the SMV manual for a more complete description.
The code for the example is presented below. It is a simple mutual exclusion algorithm for two processes: The variablesMODULE main VAR s0: {noncritical, trying, critical, ready}; s1: {noncritical, trying, critical, ready}; turn: boolean; pr0: process prc(s0, s1, turn, 0); pr1: process prc(s1, s0, turn, 1); s0 and s1 correspond
to the state of each process. turn is used to guarantee that no
starvation occurs. The processes are then instantiated using the
process keyword. This makes the processes execute asynchronously,
that is, at each step only one executes, and the choice is nondeterministic.
The initial value ofASSIGN init(turn) := 0; FAIRNESS !(s0 = critical) FAIRNESS !(s1 = critical) turn is set to false. The
fairness constraint FAIRNESS p indicates that only paths in which
p happens infinitely often will be traversed. In this example the
constraint states that both processes cannot stay in the critical region
indefinitely.
The code above defines the value of the process state during the execution. If the process is in the noncritical state, it can request mutual exclusion at any point (chosen nondeterministically), by going to theMODULE prc(state0, state1, turn, turn0) ASSIGN init(state0) := noncritical; next(state0) := case (state0 = noncritical) : {trying,noncritical}; (state0 = trying) & ((state1 = noncritical) | (state1 = trying) | (state1 = ready)): ready; (state0 = ready): critical; (state0 = trying) & (state1 = trying) & (turn = turn0): critical; (state0 = critical) : {critical,noncritical}; 1: state0; esac; next(turn) := case turn = turn0 & state0 = critical: !turn; 1: turn; esac; FAIRNESS running trying state. Once the conditions for mutual exclusion are
satisfied it goes to the ready state, and enters the critical
region one step later. In the critical region, the process can decide to go to
the noncritical region at any point. Finally, the value of the turn
variable is updated to avoid starvation. This completes the code for the
example. We will now see how specifications are written, and the results of the
verification.
Mutual exclusion is specified by the following temporal logic formulas: SPEC AG((s0 = critical) -> !(s1 = critical)) SPEC AG((s1 = critical) -> !(s0 = critical)) AG p means that in all possible execution
sequences (specified by the A part), it is globally true (the
G part) that p holds. In other words, p
is invariant. In this case we are saying that once a process is in the critical
region, the other process cannot be in its critical region.
Another useful property is expressed by the formulas above. They state that an invariant of the model is the fact that if a process is in theSPEC AG((s0 = trying) -> AF(s0 = critical)) SPEC AG((s1 = trying) -> AF(s1 = critical)) trying region, then in all possible execution sequences, at
some point in the future (indicated by the F part), it will be in
the critical region. In other words, a request for mutual exclusion will always
be granted.
However, the model above is not correct! SMV was able to determine that mutual exclusion is violated, and to produce a counterexample to show why this happens (only one counterexample is shown here): It shows that both processes can enter the
critical region at the same time, if the sequence of events showed occurs.
In more realistic situations, we would proceed and try to debug the problem.
However, this is out of the scope of this demonstration, and we leave solution
of this error as an exercise for the reader... Finally, after completing the verification, SMV outputs usage information: This example is verified almost
instantaneously, as can be seen above. More interesting usage information can be
seen below. This has been produced by a real example verified by our group:
|
Please send any comments and suggestions to Nishant Sinha - (nishants) at cs dot cmu dot edu. |