• Aucun résultat trouvé

Optimising the compilation of Petri net models

N/A
N/A
Protected

Academic year: 2021

Partager "Optimising the compilation of Petri net models"

Copied!
16
0
0

Texte intégral

(1)

HAL Id: hal-00666661

https://hal.archives-ouvertes.fr/hal-00666661

Submitted on 29 Nov 2013

HAL is a multi-disciplinary open access

archive for the deposit and dissemination of

sci-entific research documents, whether they are

pub-lished or not. The documents may come from

teaching and research institutions in France or

abroad, or from public or private research centers.

L’archive ouverte pluridisciplinaire HAL, est

destinée au dépôt et à la diffusion de documents

scientifiques de niveau recherche, publiés ou non,

émanant des établissements d’enseignement et de

recherche français ou étrangers, des laboratoires

publics ou privés.

Lukasz Fronc, Franck Pommereau

To cite this version:

Lukasz Fronc, Franck Pommereau. Optimising the compilation of Petri net models. Second

In-ternational Workshop on Scalable and Usable Model Checking for Petri Net and other models of

Concurrency (SUMO 2011), Jun 2011, Kanazawa, Japan. pp.49–64. �hal-00666661�

(2)

Lukasz Fronc and Franck Pommereau

IBISC, University of ´Evry, Tour ´Evry 2 523 place des terrasses de l’Agora, 91000 ´Evry, France

{fronc,pommereau}@ibisc.univ-evry.fr

Abstract. Compilation of a Petri net model is one way to accelerate its analysis through state space exploration. In this approach, code to explore the Petri net states is generated, which avoids the use of a fixed exploration tool involving an interpretation of the Petri net structure. In this paper, we present a code generation framework for coloured Petri nets targeting various languages (Python, C and LLVM) and featuring optimisations based on peculiarities in models like places types, bound-edness, invariants, etc. When adequate modelling tools are used, these properties can be known by construction and we show that exploiting them does not introduce any additional cost while further optimising the generated code. The accelerations resulting from this optimised compi-lation are then evaluated on various Petri net models, showing speedups and execution times competing with state-of-the-art tools.

Keywords:explicit model-checking, acceleration, model compilation

1

Introduction

System verification through model-checking is one of the major research domains in computer science [3]. It consists in defining a formal model of the system to be analysed and then use an automated tool to check whether the expected properties are met or not. In this paper, we consider more particularly the do-main of coloured Petri nets [18], widely used for modelling, and the explicit model-checking approach that enumerates all the reachable states of a model (contrasting with symbolic model-checking that handles directly sets of states). Among the numerous techniques to speedup explicit model-checking, model compilation may be used to generate source code then compiled into machine code to produce a high-performance implementation of the state space explo-ration. For instance, this approach is successfully used by Helena [5, 24] that generates C code and the same approach is also used by the well-known model-checker Spin [16]. This accelerates computation by avoiding an interpretation of the model that is instead dispatched within a specially generated analyser.

The compilation approach can be further improved by exploiting peculiari-ties in the model of interest in order to optimise the generated code [19]. For instance, we will see in the paper how 1-boundedness of places may be exploited. Crucially, this information about the model can often be known by construction if adequate modelling techniques are used [27], avoiding any analysis before state

(3)

space exploration, which would reduce the overall efficiency of the approach. This differs from other optimisations (that can be also implemented at compile time) like transitions agglomeration implemented in Helena [6].

In this paper, we present a Petri net compiler infrastructure and consider simple optimisations, showing how they can accelerate state space computation. Theses optimisations are not fundamentally new and similar ideas can be found in Spin for example. However, to the best of our knowledge, this is the first time such optimisations are considered for coloured Petri nets. This allows us for in-stance to outperform the well-known tool Helena, often regarded as the most efficient explicit model-checker for coloured Petri nets. Moreover, our approach makes use of a flexible high-level programming language, Python, as the colour domain of Petri nets, which enables for quick and easy modelling. By exploiting place types provided in the model, most of Python code in the model can be actu-ally staticactu-ally typed, allowing to generate efficient machine code to implement it instead of resorting to Python interpretation. This results in a flexible modelling framework that is efficient at the same time, which are in general contradictory objectives. Exploiting a carefully chosen set of languages and technologies, our framework enables the modeller for using an incremental development process based on quick prototyping, profiling and optimisation.

The rest of the paper is organised as follows: we first recall the main no-tions about coloured Petri nets and show how they can be compiled into a set of algorithms and data structures dedicated to state space exploration. Then section 3 discusses basic optimisations of these elements and section 4 presents benchmarks to evaluate the resulting performances, including a comparison with Helena. For simplicity, we restrict our algorithms to the computation of reacha-bility sets, but they can be easily generalised to compute reachareacha-bility graphs.

2

Coloured Petri nets and their compilation

A (coloured) Petri net involves a colour domain that provides data values, vari-ables, operators, a syntax for expressions, possibly typing rules, etc. Usually, elaborated colour domains are used to ease modelling; in particular, one may consider a functional programming language [18, 29] or the functional fragment (expressions) of an imperative programming language [24, 26]. In this paper we will consider Python as a concrete colour domain. Concrete colour domains can be seen as implementations of a more general abstract colour domain providing Dthe set of data values, V the set of variables and E the set of expressions. Let e ∈ E, we denote by vars(e) the set of variables from V involved in e. Moreover, variables or values may be considered as (simple) expressions, i.e., we assume D∪ V ⊆ E. At this abstract level, we do not make any assumption about the typing or syntactical correctness of expressions; instead, we assume that any ex-pression can be evaluated, possibly to ⊥ /∈ D (undefined value) in case of any error. More precisely, a binding is a partial function β : V → D ∪ {⊥}. Then, let e ∈ E and β be a binding, we extend the application of β to denote by β(e) the evaluation of e under β; if the domain of β does not include vars(e) then

(4)

β(e)df

= ⊥. The evaluation of an expression under a binding is naturally extended to sets and multisets of expressions.

Definition 1 (Petri nets). A Petri net is a tuple (S, T, ℓ) where S is the finite set of places, T , disjoint from S, is the finite set of transitions, and ℓ is a labelling function such that:

– for all s ∈ S, ℓ(s) ⊆ D is the type of s, i.e., the values that s may contain; – for all t ∈ T , ℓ(t) ∈ E is the guard of t, i.e., a condition for its execution; – for all (x, y) ∈ (S × T ) ∪ (T × S), ℓ(x, y) is a multiset over E and defines the

arc from x toward y.

Amarking of a Petri net is a map that associates to each place s ∈ S a multiset of values from ℓ(s). From a marking M , a transition t can be fired using a binding β and yielding a new marking M′, which is denoted byM [t, βiM, iff:

– there are enough tokens: for all s ∈ S, M (s) ≥ β(ℓ(s, t)); – the guard is validated: β(ℓ(t)) is true;

– place types are respected: for all s ∈ S, β(ℓ(t, s)) is a multiset over ℓ(s); – M′

is M with tokens consumed and produced according to the arcs: for all s ∈ S, M′(s) = M (s) − β(ℓ(s, t)) + β(ℓ(t, s)).

Such a bindingβ is called a mode of t at marking M . For a Petri net nodex ∈ S ∪ T , we define•xdf

= {y ∈ S ∪ T | ℓ(y, x) 6= ∅} and x•= {y ∈ S ∪ T | ℓ(x, y) 6= ∅} where ∅ is the empty multiset. Finally, we extenddf

the notation vars to a transition by taking the union of the variable sets in its guard and connected arcs.

In the rest of this section and in the next two sections, we consider a fixed Petri net N = (S, T, ℓ) to be compiled.df

2.1 Compilation of coloured Petri nets

In order to allow for translating a Petri net into a library, we need to make further assumptions about its annotations. First, we assume that the considered Petri net is such that, for all transition t ∈ T , and all s ∈ S, ℓ(s, t) is either empty or contains a single variable (i.e., ℓ(s, t) = {xs,t} ⊂ V). We also assume

that vars(t) = Ss∈Svars(ℓ(s, t)), i.e., all the variables involved in a transition

can be bound using input arcs. The second assumption is a classical one that allows to simplify the discovery of modes. The first assumption is made without loss of generality to simplify the presentation.

The following definition allows to relate the Petri net to be compiled to the chosen target language, assuming it defines notions of types (statical or dynamical) and functions (with parameters). We need to concretise place types and implement expressions.

(5)

– for all place s ∈ S, ℓ(s) is a type of the target language, interpreted as a subset of D;

– for all transition t ∈ T , ℓ(t) is a call to a Boolean function whose parameters are the elements of vars(t);

– for all s ∈ t•

,ℓ(t, s) can be evaluated calling a function ft,swhose parameters

are the elements of vars(t) and that returns a multiset over ℓ(s), i.e., ft,s is

equivalent to a single instruction “return ℓ(t, s)”; – all the functions involved in the annotations terminate.

Given an initial marking M0, we want to compute the set R of reachable

markings, i.e., the smallest set such that M0∈ R, and if M ∈ R and M [t, βiM′

then M′∈ R also. To achieve this computation, we compile the underlying Petri

net into a library. The compilation process aims to avoid the use of a Petri net data structure by providing exploration primitives that are specific to the model. These primitives manipulate a unique data structure, Marking, that stores a state of the Petri net. The generated library will be used by a client program, a model-checker or a simulator for instance, and used to explore the state space. Thus, it has to respect a fixed API to ensure a correct interfacing with the client program. Moreover, the library relies on primitives (like an implementation of sets) that are assumed to be predefined, as well as code directly taken from the compiled model. This structure is presented in figure 1.

The compiled library is formed of two main parts, data structures which contain the marking structure plus auxiliary structures, and functions for state space exploration. The marking structure is generated following peculiarities of

client program(e.g., model-checker)

model code interfaces

predefined code(core lib, model libs)

exploration primitives data structures: – Marking –· · · functions: – succ – succt1 –· · · – init – firet1 –· · · hand written by tool programmer generated by compiler assumed by compiler provided by existing libraries hand written by modeller

Fig. 1.The compiler generates a library (data structures and functions) that is used by a client program (e.g., a model-checker or a simulator) to explore the state space. This library uses code from the model (i.e., Petri nets annotations) as well as existing data structures (e.g., sets and multisets) forming a core libraries, and accesses them through normalised interfaces. Model code itself may use existing code but it is not expected to do it through any particular interface.

(6)

the Petri net in order to produce an efficient data structure. This may include fully generated components or reuse generic ones, the latter have been hand-written and forms a core library that can be reused by the compiler. To make this reusing possible as well as to allow for using alternative implementations of generic components, we have defined a set of interfaces that each generic component implementation has to respect.

A firing function is generated for each transition t to implement the successor relation M [t, βiM′: given M and the valuation corresponding to β, it computes

M′. A successor function succ

tis also generated for each transition t to compute

{M′| M [t, βiM} given a marking M . More precisely, this function searches for

all modes at the given marking and produces the set resulting from the corre-sponding firing function calls. We also produce a function init that returns the initial marking of the Petri net, and a global successor function succ that com-putes {M′ | M [t, βiM

, t ∈ T } given a marking M , and thus calls all the transi-tion specific successor functransi-tions. These algorithms are presented in the following.

Let t ∈ T be a transition such that•t = {s

1, . . . , sn} and t•= {s′1, . . . , s ′ m}.

Then, the transition firing function firetcan be written as shown in figure 2. This

function simply creates a copy M′ of M , removes from it the consumed tokens

(xt,s1, . . . , xt,sn) and adds the produced ones before to return M

. One could

remark that it avoids a loop over the Petri net places but instead it executes a sequence of statements. Indeed, this is more efficient (no branching penalties, no loop overhead, no array for the functions ft,s′

j, . . . ) and the resulting code is

simpler to produce. It is important to notice that we do not need a data structure for the modes. Indeed, for each transition t we use a fixed order on •t, which

allows to implicitly represent a mode though function parameters and avoids data structure allocation and queries.

The algorithm to compute the successors of a marking through a transition enumerates all the combinations of tokens from the input places. If a combination validates the guard then the suitable transition firing function is called and produce a new marking. This is shown in figure 3. The nesting of loops avoids an iteration over•t, which saves from querying the Petri net structure and avoids

the explicit construction of a binding. Moreover, like ft,s′jabove, gtis embedded

in the generated code instead of being interpreted.

The global successor function succ returns the set of all the successors of a marking by calling all transition specific successor functions and accumulating the discovered markings into the same set. This is shown in figure 4.

2.2 Structure of our compilation framework

Our compilation framework comprises a frontend part that translate a Petri net model into an abstract representation of the target library (including abstracted algorithms and data structures). This representation is then optimised exploiting Petri net peculiarities. For each target language, a dedicated backend is respon-sible for translating the abstract representation into code in the target language, and integrate the result with existing components from the core library as well as with the code embedded within the Petri net annotations.

(7)

firet: M, xt,s1, . . . , xt,sn→ M ′

M′← copy(M ) // copy marking M

M′(s 1) ← M′(s1) − {xt,s1} // consume tokens · · · M′(s n) ← M′(sn) − {xt,sn} M′(s′ 1) ← M′(s′1) + ft,s′ 1(xt,s1, . . . , xt,sn) // produce tokens · · · M′(s′ m) ← M′(s′m) + ft,s′m(xt,s1, . . . , xt,sn) returnM′ // return the successor marking

Fig. 2.Transition firing algorithm.

succt: M, next → ⊥

forxt,sn inM (sn) do // enumerate place sn · · ·

forxt,s1 inM (s1) do // enumerate place s1

if gt(xt,s1, . . . , xt,sn) then // guard check

next← next ∪ {firet(M, xt,s1, . . . , xt,sn)} // add a successor marking endif

endfor · · · endfor

Fig. 3.Transition specific successors computation algorithm.

succ: M → next next← ∅ succt1(M , next) succt2(M , next) · · · succtn(M , next) returnnext

Fig. 4.Computation of a marking successors.

We currently have implemented three backends targeting respectively Python, Cython and LLVM languages. Python is a well-known high-level, dynamically typed, interpreted language [28] that is nowadays widely used for scientific com-puting [23]. Cython is an extension of Python with types annotations, which allows Cython code to be compiled into efficient C code, thus removing most of the overheads introduced by the Python interpretation [1]. The resulting C code is then compiled to a library that can be loaded as a Python module or from any program in a C-compatible language. The Cython backend is thus also a C backend. LLVM is a compiler infrastructure that features a high-level, machine-independent, intermediate representation that can be seen as a typed assembly

(8)

Petri net model peculiarities structure annotations frontend abstract code compiler optimisers backend core lib code generator target code

Fig. 5.Structure of the compilation framework.

language [21]. This LLVM code can be executed using a just-in-time compiler or compiled to machine code on every platform supported by the LLVM project.

We consider Petri nets models using Python as their colour domain. The compatibility with the Python and Cython backends is thus straightforward. In order to implement the LLVM backend, we reuse the Cython backend to generate a stripped down version of the target library including only the annotations from the model. This simplified library is then compiled by Cython into C code that can be handled by the LLVM toolchain.

3

Optimisations guided by Petri net structures

In this section, we introduces different kinds of optimisations that are indepen-dent and can be applied separately or simultaneously.

3.1 Statically typing a dynamically typed colour domain

This optimisation aims at statically typing the Python code embedded in a Petri net model. In this setting, place types are specified as Python classes among which some are built-in primitive types (e.g., int, str , bool , etc.) actually imple-mented in C. The idea is to use place types to discover the types of variables, choosing the universal type (object in Python) when a non-primitive type is found. When all the variables involved in the computation of a Python expres-sion can be typed with primitive types, the Cython compiler produces for it an efficient C implementation, without resorting to the Python interpreter. This results in an efficient pure C implementation of a Python function, similar to the primitive functions already embedded in Python.

In the benchmarks presented in the next section, this optimisation is always turned on. Indeed, without it, the generated code runs at the speed of the Python interpreter, that may dramatically slower, especially when most of data can be statically typed to primitive types (see section 4.3).

(9)

3.2 Implementing a known optimisation

Each function succtenumerates the variables from the input arcs in an arbitrary

order. The order of the loops thus has no incidence on the algorithm correction, but it can produce an important speedup as shown in [8]. For instance, consider two places s1, s2 ∈ •t. If we know that s1 is 1-bounded but not s2, then it is

more efficient to enumerate tokens in s1 before those in s2 because the former

enumeration is cheaper than the latter and thus we can iterate on s2 only if

necessary. More generally, the optimisation consists in choosing an ordering of the input arcs to enumerate first the tokens from places with a lower boundary or a type with a smaller domain. The optimisation presented in [8] is actually more general and also relies on observations about the order in which variables are bound, which is off-topic in our case considering the restrictions we have imposed on input arcs and guard parameters. However, in the more general setting of our implementation, we are using the full optimisation as described in [8].

In general, place-bounds for an arbitrary Petri net are usually discovered by computing the state space or place invariants [14, 17]. However, using ade-quate modelling tools or formalisms, this property may be known by construction for many places: in particular, control-flow places in algebras of coloured Petri nets [27] can be guaranteed to be 1-bounded by construction.

3.3 Exploiting 1-bounded places

Let M be a marking and assume a place sk ∈•t that is 1-bounded. In such a

case, we can replace the kth“for” loop by an “if ” block in the t-specific successor

algorithm. Indeed, we know that sk may contain at most one token and so,

iterating over M (sk) is equivalent to check whether sk is not empty and then

retrieve its unique token. This is shown in figure 6, combined with the following optimisation.

3.4 Efficient implementations of places

This optimisation consists in replacing a data structure by another one but preserving the interfaces. As a first example, let us consider a 1-bounded place of type {•}. This is the case for instance for control-flow places in algebras of coloured Petri nets [27]. The optimisation consists in replacing the generic data structure for multisets by a much more efficient implementation storing only a Boolean value (i.e., one bit) to indicate whether the place is marked or not.

Similarly, a 1-bounded coloured place may be implemented using a single value to store a token value together with a Boolean to know whether a token is actually present or not. (Another implementation could use a pointer to the token value that would be null whenever the place is empty, but this version suffers from the penalty of dynamic memory management.) An example is given in figure 6 in conjunction with the optimisation from section 3.3.

Finally, a place whose type is bool may be implemented as a pair of counters to store the number of occurrences of each Boolean value present in the place.

(10)

succt: M, next → ⊥

. . . // as in figure 3

forxt,sk−1 inM (sk−1) do

if M (sk) 6= ∅ then // tests one bit

xt,k← getsk(M, 1) // directly accesses the unique token forxt,sk+1 inM (sk+1) do . . . // as in figure 3 endfor endif endfor . . . // as in figure 3

Fig. 6. An optimisation of the algorithm presented in figure 3 where function

getsk(M, i) returns the i-th token in the domain of M (sk).

This is likely to be more efficient than a hashtable-based implementation and may be generalised to most types with a small domain.

4

Experimental results

The compilation approach presented in this paper is currently being imple-mented. We use a mixture of different programming languages: LLVM, C, Python and Cython (both to generate C from Python, and as a glue language to inter-face all the others). More precisely, we use the SNAKES toolkit [25, 26], a library for quickly prototyping Petri net tools, it is used here to import Petri nets and explore their structure. We also use LLVM-Py [22], a Python binding of the LLVM library to write LLVM programs in a “programmatic” way, i.e., avoiding to directly handle source code. It is used here to generate all the LLVM code for state space algorithms. Finally, the core library is implemented using either Python, Cython, LLVM and C. For instance, we directly reuse the efficient sets implementation built into Python, multisets are hand-written in Cython on the top of Python dictionaries (based on hash tables) and a few auxiliary data struc-tures are hand-written directly in C or LLVM. All these language can be mixed smoothly because they are all compatible with C (Python itself is implemented in C and its internal API is fully accessible). The compiler is fully implemented in Python, which is largely efficient enough as shown by our experiments below. As explained already, the compilation process starts with the front-end that analyses the Petri net and produces an abstract representation (AR) of the algorithms and data structures to be generated. Algorithmic optimisations are performed by the front-end directly on the AR. Then, depending on the selected target language, a dedicated backend is invoked to generate and compile the target code. Further optimisations on data-structure implementation are actually performed during this stage. To integrate these generated code with predefined data structures, additional glue code is generated by the backend. The result

(11)

is a dynamic library that can be loaded from the Python interpreter as well as called from a C or LLVM program.

The rest of the section presents three case studies allowing to demonstrate the speedups introduced by the optimisations presented above. The machine used for benchmarks was a standard laptop PC equipped with an Intel i5-520M processor (2.4GHz, 3MB, Dual Core) and 4GB of RAM (2x2GB, 1333MHz DDR3) with virtual memory swapping disabled. We compare our implemen-tation with Helena (version 1.5) and focus on three main aspects of computa-tion: total execution time, model compilation time and state space search time. Each reported measure is expressed in seconds and was obtained as the aver-age of ten independent runs. Finally, in order to ensure that both tools use the same model and compute the same state space, static reduction were disabled in Helena. In order to generate the state space, a trivial client program was produced to systematically explore and store all the successors of all reached markings. All the presented results are obtained using the Cython backend that is presently the most efficient of our three backends, and is as expressive as Python. All the files and programs used for these benchmarks may be obtained at hhttp://www.ibisc.fr/~lfronc/SUMO-2011i.

4.1 Dinning Philosophers

The first test case consists in computing the state space of a Petri net model of the Dinning Philosophers problem, borrowed from [4]. The considered Petri is a 1-bounded P/T net so we use the corresponding optimisation discussed above. The results for different numbers of philosophers are presented in table 1. We can observe that our implementation is always more efficient than Helena and that the optimisations introduce a notable speedup with improved compilation times (indeed, optimisation actually simplifies things). In particular, we would like to stress that the compilation time is very satisfactory, which validates the fact that it is not crucial to optimise the compiler itself.

We also observe that without optimisations our library cannot compute the state space for more than 33 philosophers, and with the optimisations turned on, it can reach up to 36 philosophers. Helena can reach up to 37 philosophers but fails with 38, which can be explained by its use of a state space compression technique that stores about only one out of twenty states [5, 9]. The main conclu-sion we draw from this example is that our implementation is much faster than Helena on P/T nets, even without optimisations and that compilation times are much shorter. We observe also that it is also more efficient on bigger state spaces (cases 35 and 36). Following [15], we believe that this is mainly due to avoidance of hash clashes and state comparison when storing states, which validates the efficiency of the model-specific hash functions we generate.

4.2 A railroad crossing model

This test case is a model of a railroad crossing system, that generalises the simpler one presented in [27, sec. 3.3] to an arbitrary number of tracks. This

(12)

n states not optimised optimised speedup Helena speedup t c s t c s t c s 24 103 682 4,7 3,8 0,9 2,4 1,8 0,6 2,0 14,7 12,1 2,6 6,2 25 167 761 5,7 4,0 1,6 3,0 1,8 1,2 1,9 17,5 13,0 4,5 5,8 26 271 443 7,0 4,1 3,0 4,1 1,9 2,2 1,7 20,8 13,0 7,8 5,1 27 439 204 9,6 4,3 5,3 5,9 1,9 4,0 1,6 27,5 14,0 13,5 4,7 28 710 647 14,0 4,8 9,2 9,0 2,0 7,0 1,6 39,1 14,0 25,1 4,3 29 1 149 851 20,9 4,8 16,1 14,9 2,1 12,8 1,4 57,7 15,0 42,7 3,9 30 1 860 498 34,3 5,0 29,3 24,5 2,1 22,4 1,4 92,5 15,0 77,5 3,8 31 3 010 349 56,6 5,4 51,2 41,2 2,1 39,1 1,4 158,0 16,0 142,0 3,8 32 4 870 847 92,8 5,7 87,1 69,8 2,2 67,6 1,3 277,5 16,0 261,5 4,0 33 7 881 196 155,7 6,0 149,8 114,2 2,3 111,9 1,4 437,1 17,0 420,1 3,8 34 12 752 043 - - - 193,4 2,3 191,1 - 860,1 17,0 843,1 4,4 35 20 633 239 - - - 345.1 2.4 342.7 - 1905.7 18.5 1887.2 5.5 36 33 385 282 - - - 598.9 2.4 596.5 - 4253.8 18.5 4235.3 7.1 37 54 018 521 - - - 10217 19.0 10198.1

-Table 1. Performance tests based on n philosophers, where t is the total execution time, s is the total state space search time and c is the compilation time. The left-most column entitled “speedup” corresponds to the total time in the unoptimised model divided by the total time in the optimised model. The right-most “speedup” column is the total time spent by Helena divided by the total time in the optimised model.

n states not optimised optimised speedup Helena speedup

t c s t c s t c s 7 30 626 3.7 3.5 0.2 2.2 2.1 0.2 1.6 14.4 14.0 0.4 6.4 8 124 562 5.1 3.9 1.2 3.1 2.2 0.9 1.6 17.4 15.0 2.4 5.6 9 504 662 10.6 4.3 6.3 6.7 2.4 4.3 1.6 28.9 17.0 11.9 4.3 10 2 038 166 33.9 4.8 29.1 23.8 2.6 21.3 1.4 73.0 18.0 55.0 3.1 11 8 211 530 140.7 5.2 135.5 108.5 2.8 105.7 1.3 345.0 20.0 325.0 3.2 12 33 023 066 - - - 2721.6 23.0 2698.6

-Table 2.Performance tests based on n tracks of the railroad model, where t, s, c and “speedup” are as in table 1.

system comprises a gate, a set of tracks equipped with green lights, as well as a controller to count trains and command the gates accordingly. For n tracks, this Petri net has 5n + 11 black-token 1-bounded places (control flow or flags), 2 typed 1-bounded places (counter of trains and gate position), 3 integer-typed colour-safe places (tracks green lights) and 1 black-token n-bounded place (signals from track to controller). The benchmarks results are shown in table 2. As above, we notice that our implementation is faster than Helena even without optimisations, and that the optimisations result in similar speedups. We could compute the state space for at most 11 tracks while Helena can reach 12 tracks but fails at 13.

(13)

not optimised optimised speedupexploration t c s t c s speedup with Python 5.00 0.07 4.93 4.18 0.07 4.11 1.20 1.20 attacker Cython 5.50 2.36 3.14 4.83 2.02 2.82 1.14 1.11 without Python 2.58 0.07 2.51 1.85 0.07 1.78 1.40 1.41 attacker Cython 3.32 2.36 0.97 2.79 2.02 0.77 1.19 1.26

Table 3.Computation of the state space of the security protocol model, where t, s, c and “speedup” columns are as in table 1.

3 4 5 6 7 0 2 4 6 8 10 12 not optimised optimised

Cython faster than Python Cython slower than Python

117,649 states

n = 6 not optimised optimised speedup

Python 403.9 109.1 3.7

Cython 37.4 29.2 1.3

Fig. 7.Speedup of Cython compared with Python for n sessions of the protocol.

4.3 Security protocol model

The last test case is a model of the Needham-Schroeder public key cryptographic protocol, borrowed from [13]. It embeds about 350 lines of Python code to im-plement the learning algorithm of a Dolev-Yao attacker. This model comprises 17 places optimised as discussed above whenever possible: 11 are black-token bounded places to implement the control-flow of agents; 6 are coloured 1-bounded places to store the agents’ knowledge; 1 is an un1-bounded coloured place to store the attacker’s knowledge. Coloured tokens are Python objects or tuples of Python objects. Such a Petri net structure is typical for models of cryptographic protocols like those considered in [13].

For this example, it is not possible to draw a direct comparison with Helena since there is no possible translation of the Python part of the model into the language embedded in Helena. However, compared with a Helena model of the same protocol from [2], we observe equivalent execution times for a SNAKES-based exhaustive simulation and a Helena run. The state space exploration is much faster using Helena but its compilation time is very long (SNAKES does not compile). In our current experiment, we can observe that the compilation time is as good as with other models because the annotations in this model are Python expressions that can be directly copied to the generated code, while Helena needs to translate the annotation of its Petri net model into C code.

(14)

have first presented the whole execution times, then when have excluded the time spent in the Dolev-Yao attacker algorithms that is user-defined external code that no Petri net compiler could optimise. This allows to extract a more relevant speedup that is similar with the previous tests. However, one could observe that the Python version outperforms the Cython version and executes faster and with better speedups. This is actually due to the small size of the state space (only 1234 states), which has two consequences. First, it gives more weight to the compilation time: the Python backend only needs to produce code, whereas the Cython backend also calls Cython and a C compiler. Second, the benefits from Cython can be better observed on the long run because it optimises loops in particular. This is indeed shown in figure 7 that depicts the speedups obtained by compiling to Cython instead of Python with respect to the number of parallel session of the Needham-Schroeder protocol without attacker. To provide an order of magnitude, we have also shown the number of states for 6 sessions and the speedups obtained from the optimisations. This also allows to observe that our optimisations perform very well on Python also and reduce the execution times, which in turn reduces benefits of using Cython. This is not true in general but holds specially on this model that comprises many Python objects that cannot be translated to C efficient code. So, the Cython code suffers from many context switching between C and Python parts.

We would like to note also that the modelling time and effort is much larger when developing a model using the language embedded in Helena rather than using a full-featured language like Python. So, there exists a trade-off between modelling, compilation and verification times that is worth considering. This is why we consider as crucial for our compiler to enable the modeller for quick prototyping with incremental optimisation, as explained in [1]. In our case, the Python implementation of the attacker may be compiled using Cython and op-timised by typing critical parts (i.e., main loops). Compared with the imple-mentation of the Dolev-Yao attacker using Helena colour language from [2], the Python implementation we have used is algorithmically better because it could use Python efficient hash-based data structures (sets and dictionaries) while He-lena only offers sequential data structures (arrays and lists), which is another argument in favour of using a full-featured colour language.

As a conclusion about performances for this test case, let us sum up inter-esting facts: SNAKES and Helena version run in comparable times, the latter spends much more time in compilation but the former has more efficient data structures; our compilation is very efficient; our Python backend is typically 10 times faster than SNAKES simulation; our Cython backend is typically 2 to 4 times faster than the Python backend. So we could reasonably expect very good performances on a direct comparison with Helena.

5

Conclusion

We have shown how a coloured Petri net can be compiled to produce a library that provides primitives to compute the state space. Then, we have shown how

(15)

different kinds of optimisations can be considered, taking into account peculiari-ties in the model. We have considered places types and boundaries in particular. Finally, our experiments have demonstrated the relevance of the approach, show-ing both the benefits of the optimisations (up to almost 2 times faster) and the overall performance with respect to the state-of-the-art tool Helena (up to 7 times faster). Moreover, we have shown that a well chosen mixture of high- and low-level programming languages enables the modeller for quick prototyping with incremental optimisation, which allows to obtain results with reduced time and efforts. Our comparison with Helena also showed that our compilation process is much faster in every case (around 7 times faster). Our optimisations rely on model-specific properties, like place types and boundaries, and do not introduce additional compilation time, instead optimisation may actually simplifies things and fasten compilation.

The idea of exploiting models properties has been defended in [27] and suc-cessfully applied to the development of a massively parallel state space explo-ration algorithm for Petri net models of security protocols [13], or in [20] to reduce the state space of models of multi-threaded systems. Let us also remark that the LLVM implementation of the algorithms and code transformations (i.e., optimisations) presented in this paper has been formally proved in [11, 12], which is an important aspect when it comes to perform verification. Crucially, these proofs rely on our careful modular design using fixed and formalised interfaces between components.

Our current work is focused toward finalising our compiler, and then in-troducing more optimisations. In particular, we would like to improve memory consumption by introducing memory sharing, and to exploit more efficiently the control flow places from models specified using algebras of Petri nets [27]. In par-allel, we will develop more case studies to assess the efficiency of our approach. We are also investigating a replacement of the Helena compilation engine with ours, allowing to bring our performances and flexible modelling environment to Helena while taking advantage of its infrastructure, in particular the memory management strategies [7, 9, 10] and the static Petri nets reductions [6].

References

1. S. Behnel, R. Bradshaw, C. Citro, L. Dalcin, D. Seljebotn, and K. Smith. Cython: The best of both worlds. Computing in Science & Engineering, 13(2), 2011. 2. R. Bouroulet, H. Klaudel, and E. Pelz. Modelling and verification of authentication

using enhanced net semantics of SPL (Security Protocol Language). In ACSD’06. IEEE Computer Society, 2006.

3. E. Clarke, A. Emerson, and J. Sifakis. Model checking: Algorithmic verification and debugging. ACM Turing Award, 2007.

4. R. Esser. Dining philosophers Petri net. hhttp://goo.gl/jOFh5i, 1998.

5. S. Evangelista. M´ethodes et outils de v´erification pour les r´eseaux de Petri de haut

niveau. PhD thesis, CNAM, Paris, France, 2006.

6. S. Evangelista, S. Haddad, and J.-F. Pradat-Peyre. Syntactical colored Petri nets reductions. In ATVA’05, volume 3707 of LNCS. Springer, 2005.

(16)

7. S. Evangelista and L. Kristensen. Search-order independent state caching.

ToP-NOC III, to appear, 2010.

8. S. Evangelista and J.-F. Pradat-Peyre. An efficient algorithm for the enabling test of colored Petri nets. In CPN’04, number 570 in DAIMI report PB. University of ˚

Arhus, Denmark, 2004.

9. S. Evangelista and J.-F. Pradat-Peyre. Memory efficient state space storage in explicit software model checking. In SPIN’05, volume 3639 of LNCS. Springer, 2005.

10. S. Evangelista, M. Westergaard, and L. Kristensen. The ComBack method revis-ited: caching strategies and extension with delayed duplicate detection. ToPNOC

III, 5800:189–215, 2009.

11. L. Fronc. Analyse efficace des r´eseaux de Petri par des techniques de compilation. Master’s thesis, MPRI, university of Paris 7, 2010.

12. L. Fronc and F. Pommereau. Proving a Petri net model-checker implementation. Technical report, IBISC, 2011. Submitted paper.

13. F. Gava, M. Guedj, and F. Pommereau. A BSP algorithm for the state space construction of security protocols. In PDMC’10. IEEE Computer Society, 2010. 14. H. Genrich and K. Lautenbach. S-invariance in predicate/transition nets. In

Eu-ropean Workshop on Applications and Theory of Petri Nets, 1982.

15. G. Holzmann. An improved protocol reachability analysis technique. Software,

Practice and Experience, 18(2), 1988.

16. G. Holzmann and al. Spin, formal verification. hhttp://spinroot.comi.

17. K. J. Coloured Petri nets and the invariant-method. Theoretical Computer Science, 14(3), 1981.

18. K. Jensen and L. Kristensen. Coloured Petri Nets: Modelling and Validation of

Concurrent Systems. Springer, 2009, ISBN 978-3-642-00283-0.

19. R. Jourdier. Compilation de r´eseaux de Petri color´es. Master’s thesis, University of ´Evry, 2009.

20. H. Klaudel, M. Koutny, E. Pelz, and F. Pommereau. State space reduction for dynamic process creation. Scientific Annals of Computer Science, 20, 2010. 21. C. Lattner and al. The LLVM compiler infrastructure. hhttp://llvm.orgi. 22. R. Mahadevan. Python bindings for LLVM. hhttp://www.mdevan.org/llvm-pyi. 23. K. Millman and M. Aivazis, editors. Python for Scientists and Engineers, volume

13(2) of Computing in Science & Engineering. IEEE Computer Society, 2011. 24. C. Pajault and S. Evangelista. Helena: a high level net analyzer. hhttp://helena.

cnam.fri.

25. F. Pommereau. SNAKES is the net algebra kit for editors and simulators. hhttp: //www.ibisc.univ-evry.fr/~fpommereau/snakes.htmi.

26. F. Pommereau. Quickly prototyping Petri nets tools with SNAKES. Petri net

newsletter, 2008.

27. F. Pommereau. Algebras of coloured Petri nets. LAMBERT Academic Publishing, October 2010, ISBN 978-3-8433-6113-2.

28. Python Software Foundation. Python programming language. hhttp://www. python.orgi.

29. C. Reinke. Haskell-coloured Petri nets. In IFL’99, volume 1868 of LNCS. Springer, 1999.

Figure

Fig. 1. The compiler generates a library (data structures and functions) that is used by a client program (e.g., a model-checker or a simulator) to explore the state space.
Fig. 2. Transition firing algorithm.
Fig. 5. Structure of the compilation framework.
Fig. 6. An optimisation of the algorithm presented in figure 3 where function get s
+3

Références

Documents relatifs

We examine this question for a case with even more demanding side conditions: An important part of the OECD study ”PIAAC” (Programme for the International Assessment of

As a conclusion about performances for this test case, let us sum up inter- esting facts: SNAKES and Helena versions run in comparable times, the latter spends much more time

In earlier work [5], we have proposed the PetriCode approach and a support- ing software tool [7] has been developed for automatically generating protocol implementations based on

Moreover, one can compute the minimum and maximum elapsed time through every path of the graph which permits on- the-fly verification of timed reachability properties (e.g., is

Section 3 introduces real-time properties and Time Petri Net; Section 4 gives an overview of property specific reduction methods; Section 5 defines two real- time behavior

Keywords : component compatibility, component interfaces, software architecture, component-based software, Petri nets, deadlock detection..

In contrast to previous methods using Petri nets for prediction, we allow the model to encode correlations to previous observed values at given stations in the process, i.e., at

In this paper, after giving basic definitions of Petri net and modeling method, we introduced dependent shrink method and its properties to find dependent subnet3. Further, we