Transcript Slide 1

COMP60621
Designing for Parallelism
Lecture 4
Promela, jSpin
and the problem of Interference
John Gurd, Graham Riley
Centre for Novel Computing
School of Computer Science
University of Manchester
November 2012
1
Introduction
• Review of interference.
• Overview of jSpin and the Promela modelling
language
• Use of assertions in model checking
– For checking safety properties
• Summary
November 2012
2
The Oriental Garden problem Interference
People enter an ornamental garden through either of two
turnstiles. Management wish to know how many are in the
garden at any time.
Garden
West
Turnstile
people
East
Turnstile
The concurrent program consists of two concurrent
threads and a shared people ‘value’ variable.
From Magee & Kramer
November 2012
3
Graphic of possible outcome
After the East and West turnstile threads have each
incremented the people count 20 times, the garden
people counter is not the sum of the counts displayed.
Counter increments have been lost. Why?
November 2012
Magee & Kramer
4
Concurrent processes!
Turnstyle threads for east and west may be executing
the code for the increment function ‘at the same time’.
west
PC
program
counter
shared code
increment:
read value
east
PC
program
counter
write value + 1
We know, that without some form of locking to ensure mutual
exclusion, writes can be lost and the wrong total computed.
November 2012
5
The modelling strategy
• Our approach is to use a modelling language to
explore the behaviour of parallel algorithms at the
design stage.
– We can, of course, always build models of existing systems
to investigate their behaviour.
• Our models will aim to capture the fundamental
aspects of the concurrent behaviour.
• We wish to use tools to help us explore the behaviour
of the models to help ensure that they are correct :
– do the right things, and don’t do wrong things
– i.e. have the right properties.
November 2012
6
Spin and Promela
• We will take a fairly pragmatic approach to the use of
the model checker tool, Spin, and its modelling
language Promela.
• The main aim will be to see how we can use Spin to
help us check that our parallel algorithms are
‘correct’.
• We will not worry too much about exactly how Spin
works.
– We take an engineering approach…
• Though we will recognise the important role that the
state diagram of a parallel program plays in the
process.
November 2012
7
jSpin overview
• A java front end to the Spin model checker
– Spin is widely used in industry
– See: http://spinroot.com
– See the Reference Sheet for installation instructions
• jSpin provides a simplified interface to the full Spin model
checker.
– Good for teaching purposes.
– Spin is a sophisticated model checker!
• Spin takes in models (of concurrent systems) written in the
Promela modelling language and provides support for checking
properties
– of the underlying state transition diagram of the model.
November 2012
8
Features of Spin
• Syntax checking of Promela models.
• ‘Random’ simulation of a Promela model.
– Executes a computation of the program.
• Promela supports non-deterministic programs so a program may have
many computations.
• Interleaving as well as non-determinism in IF and DO statements (see
later) is resolved randomly (i.e. a single computation is executed).
• ‘Interactive’ execution of a Promela model
– The user can explore computations by selecting the next statement
to be executed (i.e. the next transition to be taken).
• ‘Guided’ execution
– If Spin finds an error, it can leave a ‘trail’ of a computation which led
to the error, which can be examined in Guided mode.
November 2012
9
Getting a feel for jSpin
• An example of a sequential program in Promela can be found in
intDivisor.pml
– In ~griley/COMP60621/source/labs/extras/intDivisor
– Don’t worry about details of the syntax at this point.
– Load this program in jSpin.
– Execute it in Random mode.
– Use Interactive mode to step through the code.
– Note the use of assertions to check both pre- and post-conditions
on the state of the sequential program.
– Verify (shows no errors).
– Change dividend to be 16, change the statement:
• remainder >= divisor; to remainder > divisor;
– Verify and note the error reported.
November 2012
10
Example Promela code
• As an example of a parallel program, briefly look at
cs_attempt1.pml
– In ~griley/COMP60621/source/labs/extras/CriticalSection.
– Execute in Random mode.
– Execute in Interactive mode and see how the choices of
statements are mode available and change during
execution.
– Verify and note no errors are reported.
November 2012
11
More Spin features
• Spin can be used to check (verify) both safety and liveness
properties
– Safety mode for safety properties.
– Acceptance mode and Non Progress mode safety and liveness
properties specified in Temporal Logic – more later.
• Safety properties can be specified as assertions in the Promela
code.
– We will look at the use of assertions in a future lecture.
• Spin supports the description of properties in linear temporal
logic (LTL)
– Allows the checking of sophisticated safety and liveness properties.
– We will take an introductory look at LTL later.
November 2012
12
Promela modelling language
• See Chapter 1 of “Principles of the Spin model
Checker”, M. Ben-Ari, Springer, 2008.
– Available as an electronic resource from the John Rylands
library.
• Also see Principles of Concurrent and Distributer
Programming, 2nd Edition. Ben-Ari.
• A small language with a C-like syntax designed
specifically to build models of concurrent systems
that can be ‘checked’ using tools like Spin.
• Best way to learn a lauguage is to read and play!
– So, please read the book(s) and play with models using
jSpin.
November 2012
13
Programs in Promela
• Programs consist of a set of Processes
– Sequential units of execution
– Processes can have both global and local variables
• Programs do not have to have global variables. Promela
supports channels for modelling distributed systems.
– Small number of (small) data types bool, byte, int, unsigned
etc.
– Control statements based on guarded commands
• Introduced by Edgar Dijkstra.
• Well suited for expressing non-determinism.
• You may not be very familiar with guarded commands… yet.
November 2012
14
Example:
global variables
byte n=0;
active proctype P() {
byte temp;
temp = n+1;
Process definition.
Active means runs on
startup.
n = temp;
printf( “Process P, n=%d\n”,n);
}
local variables
active proctype Q() {
byte temp;
temp = n+1;
C-like print statement
n = temp;
printf( “Process Q, n=%d\n”,n);
}
November
2012
15
Notes
• In Promela, the semicolon (;) is used as a statement
separator NOT as a statement terminator, as in C and
Java… so they are not always necessary.
– This can be confusing… it is a language designers folly!
– Usually ok to use semicolons ‘naturally’, the compiler is fairly
tolerent.
November 2012
16
Modelling choices
• Statements in Promela are executed atomically.
– So n=n+1; is executed atomically in Promela
– but as we have seen, in most ‘real’ languages (C, Java, Fortran…)
this would be executed as an atomic read of n (to a register
variable) followed by an increment, followed by an atomic write
(from a register).’
• Allowing the possibility of interference.
– We can model this with three atomic statements:
• temp=n; temp=temp+1; n=temp;
– We could also model this in Promela as: temp=n+1; n=temp;
• Two atomic statements (or temp=n; n=temp+1;)
• We only need to model to the level which shows the effect we
are interested in!
– In this case, we are modelling interference, so two atomic
statements are sufficient.
November 2012
17
Alternative version
byte n;
proctype P() {
byte temp;
temp = n+1;
n = temp;
printf( “Process P, n=%d\n”);
}
init() {
Init() is special and
is the first process
to run. Used to init
globals and create
other processes.
n=0 ;
atomic {
run P();
run P();
}
November
2012
}
Atomic ensures
both instances of P
start together.
18
Init() and final output
init() {
n=0 ;
atomic {
run P();
run P();
}
(_nr_pr == 1) ->
printf(“n=%d\n”,n);
}
November 2012
Waits for the ‘builtin’ variable
containing the
number of active
processes to be 1
– i.e. only the init()
process is ‘alive’ before printing.
This is an example
of a guarded
command.
19
Guarded commands – beware!
• Any alternative whose
guard
command
If
:: a > 6 -> a+1;
:: a < 6 -> a-1;
:: else -> a=2*a;
fi;
November 2012
guard evaluates to true
may be executed.
– non-determinism
• The else is only
executed if none of the
guards is true.
• Not quite what you are
probably used to…
20
Guarded command – do loops
• Any alternative whose
guard
command
do
:: a > 6 -> a-1;
:: a < 6 -> a+1;
:: a==6 -> break;
guard evaluates to true
may be executed.
– non-determinism
• break exits the loop.
• Again, not quite what
you are probably used
to…
od;
November 2012
21
Counting loops – two ways
#define N 10;
#include “for.h”
active proctype P() {
#define N 10;
int sum=0;
active proctype P() {
byte i=1;
int sum=0;
do
for (i,1,N)
sum=sum+i;
:: i>N -> break;
rof(i);
:: else ->
sum=sum+1;
}
i++;
od;
}November 2012
A copy of file for.h needs to be
available in the local directory.
22
An unfamiliar concept(?) – blocking
statements in Promela
• In Promela, a conditional statement will only execute if it
evaluates to true
• Otherwise the statement will block
– i.e. the process will wait until the expression becomes true:
bool my_turn = false;
my_turn; /* if my_turn=false, the process blocks */
a=2;
/* statement executes once my_turn is set true */
The statement my_turn; is equivalent to my_turn==true;
We could have used, say, !his_turn; equivalently!
• This makes sense in a multi-process environment!
• It provides a synchronisation mechanism between processes
– Presumably, another process will act to make the conditional true at
some point to allow the blocked process to progress.
November 2012
23
Other features of Promela
• In Promela, the use of global variables enables the
simulation of ‘shared memory’ programs (for
execution on shared memory machines).
• Promela also supports the message passing
paradigm through channels.
– Channels can be used to pass data directly between the
local variables of processes without using shared memory.
– Channels enable the modelling of distributed algorithms for
use on distributed memory computers.
• We will focus on shared memory problems
– Relevant to programming multi-core processors.
November 2012
24
Ornamental Garden - model
#include "for.h"
init {
atomic {
byte n=0;
byte MAX=5
run T();
proctype T() {
run T();
byte temp;
}
for (i,1,MAX)
(_nr_pr == 1) ->
printf("The value is %d\n", n);
temp=n+1;
assert (n==2*MAX);
n=temp;
rof (i);
}
}
November 2012
25
Use jSpin to investigate…
• Use Random mode and Interactive mode to investigate
manually.
• Use the assertion on the result with Verify to generate a trail that
can be examined.
• Problem: the update to the global variable ‘value’ are not atomic.
The read and write statementent from both processes get
interleaved and so can produce wrong results.
• Solution: use locks to ensure ‘mutual exclusion’ in the updates
to the shared variable.
– i.e. only allow one process at a time to read and update.
• Do this in the model, to check all computations are ok, then in
the code, so any actual computation will be ok – if the
implementation is faithfull to the model.
– At least we will know the design is correct.
November 2012
26
Fix using locks… model
#include "for.h“
init {
#include “lock.pml”
atomic {
bool lock=false;
run T();
byte n=0;
run T();
byte MAX=5
}
proctype T() {
(_nr_pr == 1) ->
byte temp;
printf("The value is %d\n", n);
for (i,1,MAX)
setLock(lck);
assert (n==2*MAX);
}
temp=n+1;
n=temp;
releaseLock(lck);
rof (i);
November
2012
}
27
Test using jSpin and fix program
• Verify the assertion. That’s it! – tested for all possible
computations!
• Can also use Random and Interactive mode to get a
feel for how the program executes.
• Fix in the program and test:
for(arrive=0;arrive<GARDEN_MAX;arrive++) {
pthread_mutex_lock(&value_mutex);
value++;
pthread_mutex_unlock(&value_mutex);
}
November 2012
28
Hidden assumptions
• We have modelled the non-atomic behaviour of incrementing in ‘real’
programming languages, i.e. n=n+1;
– No reason to think we have missed anthing here.
• We have modelled the action of pthread locks in Promela (O.k, I
•
•
have...).
We appear to have modelled pthread locks to a level sufficient to
demonstrate solving the interference problem.
But note there are complexities in the behaviour of locks that we have
not modelled
– To do with more than two processes and fairness issues.
– Our (my!) Promela model does not necessarily generalise to more than two
processes.
– See this more clearly when we have looked at liveness and fairness.
• The lesson is to be aware of the limitations of a model.
– Practice and experience.
November 2012
29
Summary
• Interference bugs are generally extremely difficult to locate in
parallel programs.
• The general solution is to give processes mutually exclusive
access to shared data.
– Through, for example, the use of so-called monitor constructs.
• Encapsulated shared data and mutually exclusive access methods.
• Our next task is to choose an application to model and see how
jSpin can help us to check its correctness.
• We will choose the classic critical section problem.
– Illustrates most of the common, fundamental concurrency issues.
• The lessons learned generalise to real, complex applications.
November 2012
30