1 / 39

Distributed Explicit State Model Checking

This lecture discusses distributed model checking using explicit state models. Topics covered include distributed reachability, partition functions, termination conditions, and the creation of dependency structures.

greggr
Download Presentation

Distributed Explicit State Model Checking

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Distributed Explicit State Model Checking Lecture 4 – 30.4.02 Lecturer: Karen Yorav

  2. References • “Distributed-Memory Model Checking with SPIN” • Flavio Lerda and Riccardo Sisto • “Distributed LTL Model-Checking in SPIN” • J. Barnat, L. Brim, and J. Stribrna

  3. Explicit State Sequential Reachability • Safety properties are verified by a reachability algorithm • Each state is a bit-vector • States are kept in a hash table • Reachability is done using a DFS algorithm • Recursion is simulated by a user defined stack

  4. Procedure Start(start_state) { V := {}; DFS(start_state); } Procedure DFS(state) { if (state not in V) then { if (error(state)) then report and terminate; V := V + state; for each st = successor of state do DFS(st); }; }

  5. Distributed Reachability • The state space is statically partitioned • partition(state) gives the node that owns state • When a node encounters a state that does not belong to it - the state is sent to the owner • Received states are kept in a FIFO queue • Verification ends when all nodes are idle and all queues are empty

  6. Procedure Start(i, start_state) { V[i] := {}; U[i] := {}; j := Partition(start_state); if (i=j) then U[i] := U[i] + start_state; Visit(i); } Procedure Visit(i) { while true do { while U[i] = {} do {} state := get(U[i]); DFV(i, S); } }

  7. Procedure DFV(i, start_state) { if (state not in V[i]) then { if (error(state)) then report and terminate; V[i] := V[i] + state; for each st = successor of state do { if (partition(st) = i) then DFV (i, st); else U[j] := U[j] + st; } }

  8. Choosing the partition function • Must depend only on the state • Should divide the space evenly • Should minimize cross-transitions • First solution - partition the space of the SPIN hash function • cannot be implemented on a heterogeneous network • even distribution • does not minimize cross transitions

  9. SPIN programs - PROMELA • Parallel composition of asynchronous processes • Uses “guarded commands” • Synchronized communication commands • Translation for model-checking: • each guarded command creates a “transition” • a transition is a (nd) function between states • a transition can be enabled or disabled in a state • a transition changes the local state of a process, or executes a communication command

  10. A better partition function Define the partition function according to the value of the component of a designated process • a global state contains a state component for each concurrent process • a transition generally involves one or two processes • minimizes cross-transitions • distributes the state-space evenly

  11. Termination • Processes inform manager when they become idle or busy • When all are idle - manager asks for confirmation • If a process became busy it sends a negative confirmation • Positive confirmation includes total number of messages sent & received • Termination - when numbers are equal

  12. Why it won’t work for LTL • When 2 nested-DFS run in parallel S1 S2 S3 S4

  13. Node A S1 S4 Node B S3 S2 S5 • The order matters A nested DFS should start from S iff all seeds below S have finished their nested DFS

  14. Definitions • Seed - an accepting state, from which a nested DFS should start • Border state - a state that causes the computation to move node • it belongs to a different node than its predecessor on the DFS

  15. Dependency Structure • Each node maintains its own DepS • Dynamic • Vertices are border states and seeds • Edges represent reachability • Underlying graph is a forest • A vertex contains: • a state • index - set of node names

  16. The creation of DepS • The primary DFS algorithm creates vertices on the way down • A state received from another node becomes a root • labeled with the sending node • Every accepting state becomes a vertex • Every border node becomes a leaf

  17. S1 S4 S3 S2 S5 Examples Node A Node B

  18. 15 5 1 2 3 4 6 7 8 9 10 12 14 13 11 Node A Node B Node C

  19. Deleting vertices from DepS • A vertex is deleted only if: • the primary DFS has already backtracked through the state • all of its successors were deleted • When a seed is deleted it is sent to the global Seed_queue • Manager process dequeues states and runs nDFS • the next seed is dequeued only after the nDFS of the previous one has finished

  20. The Algorithm • States have an extra bit to tell whether they are processed by DFV or NDFV • PV - queue of permanently visited states (seeds and border states) • V - queue of states visited while processing a single root. • <state in DepS> - the DepS node that holds state

  21. Vertices in DepS have the fields: • parent, successors • state • DFS_gone • index • CREATE_IN_DepS(s, came_from) - adds a root vertex to DepS and puts came_from in the index • ADD_TO_DepS(s1, s2) - adds s2 to DepS, and an edge from s1 to s2

  22. START: • sends start_state to the appropriate queue • runs the manager on node 0 and VISIT on all other nodes • VISIT: • receive a state, call DFS or NDFS • REMOVE: • sends seeds to the manager (to run the nested DFS) • removes vertex from DepS • recursively removes predecessors

  23. DFS: • primary DFS algorithm • builds DepS on the way down • destructs DepS on the way up • NDFS: • nested DFS algorithm • finds cycles through accepting states

  24. Example run

  25. S1 S4 S3 S2 S5 Another example Node A Node B

  26. Termination detection • Each node sends a message to the manager when changing state: • DFS status : busy / idle-empty-DepS / idle-nonempty-DepS • nDFS status: busy / idle • sent: # of sent messages overall • received: # of received messages overall

  27. Termination (cont.) • Termination is detected when: • for all nodes DFS status = idle-empty-DepS and nDFS status = idle • sum of #sent = sum of #received • Manager also detects situations in which: • for all nodes DFS statusbusy and nDFS status = idle • sum of #sent = sum of #received • some nodes have DFS status = idle-nonempty-DepS

  28. u • Manager requests DepS info from nodes • Each node sends a set of edges Xz --->Y where: • X is a vertex with nonempty index Z • Y is a border state that x is waiting for • u = 1 if there is a seed on the way, 0 otherwise • Manager builds a graph from these edges • Manager looks for a SCC with no outgoing edges • if there is a 1 edge -> counter example! • if not - send ACK to an arbitrary edge on the SCC

  29. Procedure START(i, start_state) { Initialize local variables if (partition(start_state) = i) then U[i] := U[i] + {start_state}; if (i=0) then MANAGER_PROCESS(); else VISIT(i); }

  30. Procedure VISIT(i) { while (PROCESS_INCOMING_PACKETS()) do { if (U[i] <> {}) then { get (state, came_from) from U[i]; toplevel := true; V[i] := {}; if (nested(state)) then { Seed := state.seed; NDFV(i, state); }

  31. } else { if (state not in PV[i]) then { DFV(i, state); if (<state in DepS>.successors = {}) then REMOVE(<state in DepS>); } else { if (state in DepS) then <state in DepS>.index := <state in DepS>.index + {came_from}; else ACK (<state in DepS>); }; }; }; }; }

  32. Procedure REMOVE(vertex) { if Accepting(vertex.state) then Seed_queue := Seed_queue + {vertex.state}; ACK(vertex); tmp := vertex.predecessors; forall (i in tmp) do i.successors := i.successors - {vertex}; free(vertex); forall (i in tmp) do if ((i.successors = {}) and (i <> nil) and (i.DFS_gone)) then REMOVE(i); }

  33. Procedure DFV(i,state) { if (partition(state) <> i) then { U[partition(state)] := U[partition(state)] + {state}; ADD_TO_DepS (last_visited, state); return; }

  34. } else { if (toplevel) then { PV[i] := PV[i] + state; CREATE_IN_DepS(state, came_from); last_visited := state; }; if (Accepting(state) & not(toplevel)) then { ADD_TO_DepS(last_visited, state); last_visited := state; PV[i] := PV[i] + state; }; toplevel := false; V[i] := V[i] + {state};

  35. } else { if (toplevel) then { PV[i] := PV[i] + state; CREATE_IN_DepS(state, came_from); last_visited := state; }; if (Accepting(state) & not(toplevel)) then { ADD_TO_DepS(last_visited, state); last_visited := state; PV[i] := PV[i] + state; }; toplevel := false; V[i] := V[i] + {state};

  36. forall (newstate in successors of state) do { if (newstate not in (V[i] + DepS + PV[i])) then DFV(i, newstate); else if ((newstate in DepS) and (not in stack)) then ADD_TO_DepS (last_visited, newstate); }; if (Accepting(state)) then { last_visited := <last_visited in DepS>.parent; <state in DepS>.DFS_gone := true; if (<state in DepS>.successors = {}) then REMOVE(<state in DepS>); }; }; }

  37. forall (newstate in successors of state) do { if (newstate not in (V[i] + DepS + PV[i])) then DFV(i, newstate); else if ((newstate in DepS) and (not in stack)) then ADD_TO_DepS (last_visited, newstate); }; if (Accepting(state)) then { last_visited := <last_visited in DepS>.parent; <state in DepS>.DFS_gone := true; if (<state in DepS>.successors = {}) then REMOVE(<state in DepS>); }; }; }

  38. Procedure NDFV(i, state) { if (partition(state) <> i) then { U[partition(state)] := U[partition(state)] + {state}; return; } else { PV[i] := PV[i] + state; forall (newstate in successors of state) do { if (Seed=newstate) then CYCLE_FOUND(); if (newstate not in (V[i] + PV[i])) then NDFV(i, newstate); }; }; }

  39. Procedure NDFV(i, state) { if (partition(state) <> i) then { U[partition(state)] := U[partition(state)] + {state}; return; } else { PV[i] := PV[i] + state; forall (newstate in successors of state) do { if (Seed=newstate) then CYCLE_FOUND(); if (newstate not in (V[i] + PV[i])) then NDFV(i, newstate); }; }; }

More Related