<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Procedural Code Representation in a Flow Procedural Code Representation in a Flow Graph Graph</article-title>
      </title-group>
      <contrib-group>
        <aff id="aff0">
          <label>0</label>
          <institution>Michal Brabec and David Bedn ́arek Michal Brabec and David Bednarek Parallel Architectures/Algorithms/Applications Research Group Parallel ArchiDteecptuarretms/eAnltgoorfitShomftsw/aAreppElincgaitnioeenrsinRgesearch Group Faculty of MathDeempaatritcms eanntdoPfhSyosfticwsa,rCehEanrlgeisneUenriinvgersity in Prague Faculty ofMMalaotshtermanastki ́cesnaa ́nmd.</institution>
          <addr-line>P25h,ysPicrsa,guCeh,aCrlzeescUhnRiveeprusbitlyicin Prague Malosbtrraanbeskce,bneadmna.r2e5k</addr-line>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2015</year>
      </pub-date>
      <volume>1343</volume>
      <fpage>89</fpage>
      <lpage>100</lpage>
      <abstract>
        <p>Modern scientific computing often combines extensive calculation with complex structure of data; however, the programming methodologies and languages of high-performance computing significantly differ from those of databases. This impedance mismatch leads many projects to the use of either primitive (like JSON) or overly general (like distributed file systems) methods of data access, ignoring the decades of development in database technology. In this paper, we investigate the possibility to represent procedural code fragments using a network of operators similar to query plans used in relational database systems. Such a unified representation forms the necessary step towards an integrated computational-database platform. We propose a flow graph representation that allows us to analyze, transform and optimize applications more efficiently and without additional data. Along with the graph, we designed an algorithm that transforms a procedural code into the graph.</p>
      </abstract>
      <kwd-group>
        <kwd>compiler</kwd>
        <kwd>graph</kwd>
        <kwd>optimization</kwd>
        <kwd>parallelism</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Introduction</title>
      <p>
        Modern data processing often combines complex data layouts with intensive
calculations. Despite the ongoing effort in the area of no-SQL databases, the
traditional relational paradigm, especially in its column-based version [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ], still
offers unmatched maturity and efficiency up to multi-terabyte ranges. However,
the database systems were not designed with general computing in mind.
      </p>
      <p>
        Systems based on the MapReduce paradigm allow the programmer to
integrate general procedural code with a distributed data storage more easily.
Despite of their popularity, MapReduce implementations may still be outperformed
by parallel databases even in brute-force tasks where the sophisticated database
approach has seemingly no advantage [
        <xref ref-type="bibr" rid="ref20">20</xref>
        ]. However, the same experiments also
show that the performance dominance of parallel databases is limited to
workloads implemented by built-in functions; as soon as user-defined functions are
required, the performance falls rapidly.
      </p>
      <p>
        This observation shows that the runtime stages of modern parallel database
systems are extremely efficient even under brute-force computing load.
However, this efficiency is degraded by the inability of the relational optimizers to
efficiently handle procedural code fragments contained in user-defined functions
[
        <xref ref-type="bibr" rid="ref15">15</xref>
        ]. Nevertheless, with a different front-end, a parallel database system may
become a suitable runtime for parallel computing.
      </p>
      <p>
        Such a front-end would have to compile procedural code into physical
execution plans used in database systems. Modern databases, as well as streaming
systems, use graph-based execution plans whose nodes are not limited to
relational algebra operators, as shown by the successful adaptation of many
relational engines to XML or RDF [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ].
      </p>
      <p>In this paper, we present flow graphs – an intermediate code capable to
represent procedural code with its complex control-flow. Unlike typical intermediate
representations used in compilers, the flow graphs are designed to be similar to
pipeline-based models used in many database, streaming, and general parallel
platforms.</p>
      <p>Besides the introduction of flow graphs, we also describe the key algorithms
which take part in the transformation of procedural code into flow graphs. The
algorithms described here are applied after language-specific phases like parsing
and semantic analysis and they also make use of analytical algorithms which are
already frequently used in compilers.</p>
      <p>The rest of the paper is organized as follows: After reviewing the related
work, flow graphs are defined in Section 3. Section 4 presents the transformation
algorithms; in Section 5, we revise possible optimizations of the flow graph.
2</p>
    </sec>
    <sec id="sec-2">
      <title>Related Work</title>
      <p>
        The flow graph described in this paper is similar but not identical to other
modeling languages, like Petri nets [
        <xref ref-type="bibr" rid="ref21">21</xref>
        ] or Kahn process networks [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ]. The
main difference is that the flow graph was designed for automatic generation
from the source code, where the other languages are generally used to model the
application prior to implementation [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ] or to verify a finished system [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ]. The
flow graph is similar to the graph transformation system [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ], which can be used
to design and analyze applications, but it is not convenient for execution. There
are frameworks that generate GTS from procedural code like Java [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ], though
the produced graphs are difficult to optimize. The flow graph has similar traits
to frameworks that allow applications to be generated from graphs, like UML
diagrams [
        <xref ref-type="bibr" rid="ref12">12</xref>
        ] [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ], but we concentrate both on graph extraction and execution.
      </p>
      <p>
        The flow graph is closely related to graphs used in compilers, mainly the
dependence and control flow graphs [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], where the flow graph merges the
information from both. The construction of the flow graph and its subsequent
optimization relies on compiler techniques, mainly points-to analysis [
        <xref ref-type="bibr" rid="ref23">23</xref>
        ], dependence
testing [
        <xref ref-type="bibr" rid="ref18">18</xref>
        ] and control-flow analysis [
        <xref ref-type="bibr" rid="ref22">22</xref>
        ]. In compilers, graphs resulting from
these techniques are typically used as additional annotation over intermediate
code.
      </p>
      <p>
        The flow graph is not only a compiler data representation, it is a processing
model as well, similar to KPN graphs [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ]. It can be used as a source code for
specialized processing environments, where frameworks for pipeline parallelism
are the best target, since these frameworks use similar models for applications
[
        <xref ref-type="bibr" rid="ref19">19</xref>
        ]. One such a system is the Bobox framework [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ], where the flow graph can
be used to generate the execution plan similarly to the way Bobox is used to
execute SPARQL queries [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ].
3
      </p>
    </sec>
    <sec id="sec-3">
      <title>Flow Graph</title>
      <p>The Flow graph was designed as a compact format for representation of
procedural code. Once constructed, it contains the code along with the information
about its structure, including control flow and data flow, and it can be
transformed back into procedural code. In this section, we define the flow graph and
we explain its relation to other processing models.</p>
      <p>A flow graph is a directed graph, where nodes represent operations and edges
represent data exchange among the operations. The direction of the edge
indicates the direction of data flow (source and sink operations). Figure 1 shows
an unoptimized flow graph for a function without branches (see Listing 1 for
source code). The gray nodes denote dead code and they will be removed during
later optimization steps. The flow graph can become complicated once control
flow is introduced – see Figure 5 for an example of a more complex graph that
implements a program with a loop.
void S t a t e m e n t s ( ) {
i n t a = 3 ;
i n t b = 5 ;
i n t c = 0 ;
c = a + b ;
p r i n t ( c ) ;
}
ldc 5
ldc 3
stl b
stl a
ldl b
ldl a
add
stl c
ldl c
call
Listing 1. Simple function without Fig. 1. Simple function transformed to
branches an unoptimized flow graph</p>
      <p>For a particular domain of application, a specific flow graph language is
defined that contains a set of basic operations and a set of data types. We construct
flow graphs based on such platform specific language. Both nodes and edges
contain information about the represented operation or data type respectively. Each
edge is connected to a specific input or output of the node according to the
represented operation (the data type must be compatible).</p>
      <p>
        As our research is focused on C#, we use CIL [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] instructions to specify node
operations. In this paper, there are four most common instruction types: ldl x
(load variable or constant), stl x (write to a variable), ble (conditional branch),
add etc. (mathematical operations). We omit data types for the edges, because
they are not important for the graph construction.
3.1
      </p>
      <sec id="sec-3-1">
        <title>Execution Model</title>
        <p>The flow graph execution model defines the way nodes process data and
communicate. Nodes represent operations and edges represent unbounded queues
(FIFO).</p>
        <p>Operations have three states - waiting for input, processing and inactive. Each
operation starts waiting for input, it fires once input is available, processes the
input and produces an output. Once the input is processed, the operation again
waits for data. Nodes without input (loading constants) fire at the beginning of
the execution, produce data and then they become inactive.</p>
        <p>The queues transport single values of the assigned data type (based on the
edge). Nodes must always consume their input, they cannot simply check the
data and leave them in the queue. For example a simple node, which adds two
numbers, fires when there are data in both its incoming queues, it consumes
both numbers and then is stores the result in its outgoing queue.
3.2</p>
      </sec>
      <sec id="sec-3-2">
        <title>Special Nodes</title>
        <p>Loops and branches of the source language are transformed into a graph of
platform independent special nodes which interact with the data-flow carried
through the basic nodes that perform the basic operations.</p>
        <p>An extended primary node is a special version of any basic operation without
parameters, like load constant value. The extended version has a single input
and it restarts whenever the input contains data.</p>
        <p>A broadcast node has a single input and a variable number of outputs. It
represents a simple operation that creates a copy of the input for each output.
This node is created whenever an operation must pass its result to multiple
operations and the number of receivers defines the number of outputs. A loop
feedback node is a special type broadcast node that distributes the positive result
of a conditional branch to all extended primary nodes.</p>
        <p>A merge node has a single output and three inputs. It represents an operation
that accepts data from two sources and passes them to a single operation and
it is used to merge data flow after a conditional branch. The node has an extra
input used to get feedback from another node, generally a conditional branch.
The node fires when all three inputs contain data.</p>
        <p>
          A loop merge node is a special version of a merge node with two inputs for
conditional branches, it is used to merge data in loops. The input is split into
two pairs, where each contains one data input and one branch input. The node
fires, whenever both inputs in a pair contain data. The node is either positive
or negative, where the conditional inputs are required to be either positive or
negative, for passing data into a loop or outside a loop.
add
In this section, we present a two-phase algorithm that transforms a procedural
code to a flow graph. The input to the algorithm is an intermediate code; in our
case, the CIL. For simplicity, we assume that the CIL code was compiled from a
C# source without unsafe code and goto. We also assume that the code is first
subjected to a points-to analysis [
          <xref ref-type="bibr" rid="ref23">23</xref>
          ] which resolves potential aliasing problems.
        </p>
        <p>The basic idea of the algorithm is that each CIL instruction is transformed
into a node. Edges are generated according to the data used by each instruction.
Edges correspond to the inputs / outputs of the instructions. When the basic
graph is ready, we add special nodes for broadcasting and merging data according
to branches and loops in the code. For simplicity, we ignore function calls in this
description – see Section 4.1 for more information on function handling.
Basic Graph Construction The first step of the algorithm is to create basic
nodes according to the instructions of the source code. We use basic operations
in the first part, the special operations are introduced in the second part.
Algorithm 1 contains all the necessary steps and it produces the basic nodes N and
edges E of the graph.</p>
        <p>We can create a node for every CIL instruction, because we defined the
operations based on the instruction set (lines 1 to 3 in Algorithm 1).</p>
        <p>Next, we analyze how instructions exchange data, either using registers or
stack, and we create edges that connect the source and sink instruction. CIL
instructions communicate using virtual stack and we use a stack simulator to
analyze the way the instructions exchange data. Then we create edges between
nodes representing instructions that exchange data (lines 4 to 6 in Algorithm 1),
along with the appropriate data type. The analysis is similar when the
instructions communicate through registers, only instead of stack simulator, we have
to connect instructions that use the same register.</p>
        <p>Then, we have to take into account the data passing through variables. We
have to create edges between nodes representing variable access, from write to
read. This step is more complex, because we have to connect every variable
read with the nearest write, along all the possible execution paths, which means
analyzing the control flow.</p>
        <p>We generate basic blocks for the input code. In every basic block, we locate
all the instruction that access any variable (lines 7 to 11 in Algorithm 1). First
we create edges inside every block, where we connect variable writes to reads if</p>
        <p>Statements ( ) c i l
void p r i n t ( i n t 3 2 )
Listing 2. CIL code of Statements
function
void BranchElse ( ) {
int a = 3 ;
int c = 0 ;
i f ( a &gt; 0 )</p>
        <p>c = 4 ;
e l s e</p>
        <p>c = −4;
p r i n t ( c ) ;
}</p>
        <p>Listing 3. Simple branch
both access the same variable but only if the read is after the write and there
is no other write between them (lines 12 to 16 in Algorithm 1). Results of this
step are illustrated in Figure 1 which shows the intermediate flow graph based
on the CIL code in Listing 2, generated from the source code in Listing 1.</p>
        <p>Next, we have to connect variables between basic blocks. We locate all reads
before the first write in every block, for every variable. We call them accessible
reads. We connect the last write in a basic block to all the accessible reads in
the blocks that follow the original, until one of them contains an instruction
that writes to the same variable (lines 17 to 26 in Algorithm 1). Basically, we
perform an exhaustive search through the block graph, where we stop at nodes
that change the studied variable. This way the data is propagated through the
control flow.</p>
        <p>Figure 3 shows a flow graph generated from the function in Listing 3. There
is one conditional jump that produced the two edges that lead to the node
ldl c. The branch instruction must decide which input is used (Section 4). It is
important that the initialization of c to 0 is identified as unused code.
Control Flow Management In this section, we present algorithms necessary
to make the graph produced by the Algorithm 1 deterministic and compliant
to the flow graph definition. We must make sure that the nodes have a proper
number of inputs and outputs and that the branching conditions
deterministically decide what value is used at every time, especially in loops. Algorithm 2
contains all the transformations for handling control flow.</p>
        <p>We start this algorithm by locating loops in the basic block graph. We locate
all the blocks L of the inner-most loop and we locate the block Lb that contains
the backward conditional jump b that restarts the loop (it is sufficient to locate
the backward jump, because we consider a restricted C#). We duplicate the
entire block Lb as Lbi , the copy drives the first iteration which is different, since
it uses data initialized before the loop started (initialization of variables). See</p>
        <p>Algorithm 1. Basic graph construction
Require: I – set of instructions i</p>
        <p>B – basic blocks
M – set containing all memory locations (variables)
Ci – all instructions consuming the output of the instruction i
Ri – variables read by instruction i</p>
        <p>Wi – variables read by instruction i
Ensure: N – nodes of the flow graph</p>
        <p>E – edges of the flow graph
1: for all i ∈ I do
2: N = N ∪ {Ni : operation(Ni) = Oi} – nodes based on instructions
3: end for
4: for all Ni ∈ N do
5: E = E ∪ ENiNj : j ∈ Ci – edges based on instruction communication (stack)
6: end for
7: for all b ∈ B do
8: Loadbm = {i ∈ b : m ∈ Ri ∧ w ∈ b &lt; i =⇒ m 6∈ Ww} – read before update
9: Loadbmj = {i ∈ b : m ∈ Ri ∧ j &lt; i ∧ w ∈ [j, i] =⇒ m 6∈ Ww} – read after write
10: Storebm = {i ∈ b : m ∈ Wi ∧ w ∈ b &gt; i =⇒ m 6∈ Ww} – last update in block
11: end for
12: for all b ∈ B do
13: for all m ∈ M do
14: E = E ∪ ENjNi : i ∈ Loadbmj – edges based on variable access
15: end for
16: end for
17: for all m ∈ M do
18: for all b ∈ B do
19: for all n0 ∈ B : next(b, n0) do
20: E = E ∪ ENjNi : j ∈ Storebm ∧ i ∈ Loadbn0 – edges between blocks
21: if Storebn = ∅ then
22: recursion for {n1 ∈ B : next(n0, n1)}
23: end if
24: end for
25: end for
26: end for
Listing 4 where i is first compared while it still has the value of 1. We locate
all nodes ni inside the loop with more incoming edges than inputs (line 1 in
Algorithm 2). We create loop merge nodes m for all ni (line 2 in Algorithm 2),
redirect the incoming edges to the merge nodes (line 3 in Algorithm 2). We add
edge Emni. Finally we connect the merge nodes to the conditional branches and
we pair the input coming from outside the loop to the duplicate branch in bi in
Lbi and the other with the branch b in Lb (line 4 in Algorithm 2). This ensures
that the first iteration takes the data from outside and all the rest take the
internal data. See Figure 5 for complete loop with merge nodes.</p>
        <p>When the loops are fitted with merge nodes, we add a loop feedback node
that restarts all the nodes without input. We replace all nodes without input in
ldc 3
stl a
ldl a
ldc 0
ldc 4</p>
        <p>ldc -4
stl c
blec
stl c
ldl c
call
a loop by their extended version, see Section 3.2. We connect the feedback node
to the branch in Brl and to all the extended nodes in the loop (lines 6 to 10
in Algorithm 2). Figure 5 shows a complete loop, where the Brl and Brcl are
outlined by a dashed rectangle and the entire loop by a solid rectangle.</p>
        <p>When all loops are transformed, we must locate all remaining nodes n with
more incoming edges than inputs (line 11 in Algorithm 2), the multiple inputs are
the result of conditional branches. Figure 3 shows the situation where two edges
lead to a node with a single input (ldl c). We solve this situation by introducing
a merge node m along with the edge Emn (lines 12 to 13 in Algorithm 2). Then
we redirect the two input edges to the m (line 14 in Algorithm 2). Finally, we
have to locate the conditional branch responsible for the merge and connect it
to the merge node. We can do this by following the paths from source nodes,
where we locate the branch just before the paths join, blec (branch if a ≤ 0)
in Figure 3. The result of this algorithm is in Figure 4, where the edge with a
square is the positive input and the triangle is negative.</p>
        <p>The final step is to locate all nodes n with more outgoing edges than outputs.
This is solved simply by using a broadcast node. We create a new broadcast node
b, we add an edge Enb and we change the outgoing edges to start in b (lines 16
to 20 in Algorithm 2).
Methods are analyzed starting with the main function and then the graph is
constructed as additional methods are called. Whenever a method call is located,
we create a flow graph for the called method, treating its parameters as local
variables. We connect the parameters to their actual values (source variables or
constants). This approach is equivalent to complete procedure integration and
it is applicable only for programs whose call graph is acyclic and contains
reasonable number of paths. Using additional special nodes, any program might be
transformed; however, at the cost of additional operations which correspond to
the call-return pairs in conventional program execution. In the supposed
application domain, the general approach is probably unnecessary.
4.2</p>
      </sec>
      <sec id="sec-3-3">
        <title>Objects and Arrays</title>
        <p>
          A variable of complex data type (object or array) can contain a number of
memory locations (members or elements) that can be accessed using special
instructions. We treat member data of objects as separate variables where the
same members of two independent objects are different variables. Arrays can be
viewed as objects with a single member - data, where the data contains multiple
independent values. Arrays are treated this way by many compiler algorithms
[
          <xref ref-type="bibr" rid="ref23">23</xref>
          ].
5
        </p>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>Graph Optimizations</title>
      <p>A flow graph produced by the algorithm presented in Section 4 is generally very
big, since we transform every instruction into a single node, which is not very
convenient for execution, but it can be efficiently analyzed and optimized. In
this section, we shortly introduce optimizations that can produce more compact
graphs.</p>
      <p>Each node in a flow graph, as defined in Section 3, represents a basic or special
operation. We introduce the merge rules, to allow optimizations of the graph.
The merge rules define the way the operations are combined to produce complex
operations. They define the behavior (source code) of the complex operation and
its inputs and output along with their data types. The merge rules are added to
the definition of the specific flow graph language.</p>
      <p>A complex operation is created by merging other operations, either basic or
complex, according to the merge rules defined along with the graph. The merge
rules for CIL instructions contain for instance chaining of the instructions. For
example, when merging the addition instr. in A + B + C, we create a complex
operation that is equal to P3</p>
      <p>1 Ini.</p>
      <p>Another transformation is aimed at simple loops controlled by a single
variable. Figure 5 shows a very simple loop that is controlled by the variable i,
updated in every iteration. The loop creates many unnecessary dependences.
stl i</p>
      <p>
        ldc 1
gen i
When we locate such a simple situation, we can merge the entire loop into a
single node that just generates appropriate values in this case {1, 2, 3, 4}. We
can utilize algorithms used in compilers [
        <xref ref-type="bibr" rid="ref18">18</xref>
        ] to locate the loops, because the
graph contains all the information found in the original source code. Figure 6
shows how the loop from Figure 5 is optimized. This optimization is essential
for improving the efficiency of the flow graph, compare the optimized graph to
an unoptimized graph implementing the computation of a factorial, Figure 7.
6
      </p>
    </sec>
    <sec id="sec-5">
      <title>Conclusions</title>
      <p>
        We designed the flow graph to represent a procedural code along with important
information about its structure and behavior. We designed an algorithm that
allows us to create a flow graph for an application implemented in a subset of
C# and compiled to CIL. This transformation becomes a part of a toolchain
that allows the transformation of C# programs into a stream-based parallel
computing platform [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ]. The algorithm can be modified for other languages, like
Java bytecode [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ].
      </p>
      <p>The flow graph is a powerful tool for application analysis and optimization.
Besides generating pipeline-based execution plans, the flow graph can be used
for automatic parallelization. For such use, the original flow graph may be too
fine-grained – in this case, it has to be transformed using a set of merge rules to
make the final parallel application efficient.</p>
    </sec>
    <sec id="sec-6">
      <title>Acknowledgements</title>
      <p>This paper was supported by Czech Science Foundation (GACˇ R) project
P10313-08195, and by the Grant Agency of Charles University Grant Agency (GAUK)
project 122214.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <surname>TG3. Common Language Infrastructure (CLI). Standard</surname>
          </string-name>
          ECMA-
          <volume>335</volume>
          , June 2005
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <surname>Abadi</surname>
            ,
            <given-names>D.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Boncz</surname>
            ,
            <given-names>P.A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Harizopoulos</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Idreos</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Madden</surname>
            ,
            <given-names>S.:</given-names>
          </string-name>
          <article-title>The design and implementation of modern column-oriented database systems</article-title>
          .
          <source>Foundations and Trends in Databases</source>
          <volume>5</volume>
          (
          <issue>3</issue>
          ),
          <fpage>197</fpage>
          -
          <lpage>280</lpage>
          (
          <year>2013</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <surname>Allen</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Kennedy</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          :
          <article-title>Optimizing compilers for modern architectures</article-title>
          . Morgan Kaufmann San Francisco (
          <year>2002</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <string-name>
            <surname>Balasubramanian</surname>
            ,
            <given-names>D.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Narayanan</surname>
            , A., van Buskirk,
            <given-names>C.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Karsai</surname>
            ,
            <given-names>G.</given-names>
          </string-name>
          :
          <article-title>The graph rewriting and transformation language: Great. Electronic Communications of the EASST 1 (</article-title>
          <year>2007</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <string-name>
            <surname>Brabec</surname>
            ,
            <given-names>M.</given-names>
          </string-name>
          , Bedna´rek,
          <string-name>
            <surname>D.</surname>
          </string-name>
          , Maly´,
          <string-name>
            <surname>P.</surname>
          </string-name>
          :
          <article-title>Transformation of pipeline stage algorithms to event-driven code</article-title>
          . In: Kurkova,
          <string-name>
            <given-names>V.</given-names>
            ,
            <surname>Bajer</surname>
          </string-name>
          ,
          <string-name>
            <surname>L.</surname>
          </string-name>
          , Sva´tek, V. (eds.)
          <source>Proceedings of the 14th Conference on Information Technologies - Applications and Theory</source>
          , Jasna, Slovakia,
          <year>2014</year>
          .
          <source>CEUR Workshop Proceedings</source>
          , vol.
          <volume>1214</volume>
          , pp.
          <fpage>13</fpage>
          -
          <lpage>20</lpage>
          . CEUR-WS.org (
          <year>2014</year>
          ), http://ceur-ws.
          <source>org/</source>
          Vol-1214
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          6.
          <string-name>
            <surname>Chambers</surname>
            ,
            <given-names>C.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Raniwala</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Perry</surname>
            ,
            <given-names>F.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Adams</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Henry</surname>
            ,
            <given-names>R.R.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Bradshaw</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Weizenbaum</surname>
          </string-name>
          , N.:
          <article-title>FlumeJava: easy, efficient data-parallel pipelines</article-title>
          .
          <source>In: ACM Sigplan Notices</source>
          . vol.
          <volume>45</volume>
          , pp.
          <fpage>363</fpage>
          -
          <lpage>375</lpage>
          . ACM (
          <year>2010</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7.
          <string-name>
            <surname>Corradini</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Dotti</surname>
            ,
            <given-names>F.L.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Foss</surname>
            ,
            <given-names>L.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Ribeiro</surname>
            ,
            <given-names>L.</given-names>
          </string-name>
          :
          <article-title>Translating java code to graph transformation systems</article-title>
          .
          <source>In: Graph Transformations</source>
          , pp.
          <fpage>383</fpage>
          -
          <lpage>398</lpage>
          . Springer (
          <year>2004</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <string-name>
            <surname>Ehrig</surname>
            ,
            <given-names>H.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Ehrig</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Prange</surname>
            ,
            <given-names>U.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Taentzer</surname>
          </string-name>
          , G.:
          <article-title>Graph transformation systems</article-title>
          .
          <source>Fundamentals of Algebraic Graph</source>
          Transformation pp.
          <fpage>37</fpage>
          -
          <lpage>71</lpage>
          (
          <year>2006</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          9.
          <string-name>
            <surname>Ezpeleta</surname>
            ,
            <given-names>J.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Colom</surname>
            ,
            <given-names>J.M.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Martinez</surname>
            ,
            <given-names>J.:</given-names>
          </string-name>
          <article-title>A Petri net based deadlock prevention policy for flexible manufacturing systems</article-title>
          .
          <source>Robotics and Automation, IEEE Transactions on 11(2)</source>
          ,
          <fpage>173</fpage>
          -
          <lpage>184</lpage>
          (
          <year>1995</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          10.
          <string-name>
            <surname>Falt</surname>
            ,
            <given-names>Z.</given-names>
          </string-name>
          , Kruliˇs,
          <string-name>
            <surname>M.</surname>
          </string-name>
          , Bedna´rek,
          <string-name>
            <given-names>D.</given-names>
            ,
            <surname>Yaghob</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            ,
            <surname>Zavoral</surname>
          </string-name>
          ,
          <string-name>
            <surname>F.</surname>
          </string-name>
          :
          <article-title>Locality aware task scheduling in parallel data stream processing</article-title>
          . In: Camacho,
          <string-name>
            <given-names>D.</given-names>
            ,
            <surname>Braubach</surname>
          </string-name>
          ,
          <string-name>
            <given-names>L.</given-names>
            ,
            <surname>Venticinque</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            ,
            <surname>Badica</surname>
          </string-name>
          , C. (eds.)
          <string-name>
            <surname>Intelligent Distributed Computing</surname>
            <given-names>VIII</given-names>
          </string-name>
          ,
          <source>Studies in Computational Intelligence</source>
          , vol.
          <volume>570</volume>
          , pp.
          <fpage>331</fpage>
          -
          <lpage>342</lpage>
          . Springer International Publishing (
          <year>2015</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          11.
          <string-name>
            <surname>Falt</surname>
            ,
            <given-names>Z.</given-names>
          </string-name>
          , Cˇerma´k, M.,
          <string-name>
            <surname>Dokulil</surname>
            ,
            <given-names>J.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Zavoral</surname>
            ,
            <given-names>F.</given-names>
          </string-name>
          :
          <article-title>Parallel SPARQL query processing using Bobox</article-title>
          .
          <source>International Journal On Advances in Intelligent Systems 5(3 and 4)</source>
          ,
          <fpage>302</fpage>
          -
          <lpage>314</lpage>
          (
          <year>2012</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          12.
          <string-name>
            <surname>Geiger</surname>
            ,
            <given-names>L.</given-names>
          </string-name>
          , Zu¨ndorf, A.:
          <article-title>Graph based debugging with fujaba</article-title>
          .
          <source>Electr. Notes Theor. Comput. Sci</source>
          .
          <volume>72</volume>
          (
          <issue>2</issue>
          ),
          <volume>112</volume>
          (
          <year>2002</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          13.
          <string-name>
            <surname>Geilen</surname>
            ,
            <given-names>M.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Basten</surname>
            ,
            <given-names>T.</given-names>
          </string-name>
          :
          <article-title>Requirements on the execution of Kahn process networks</article-title>
          .
          <source>In: Programming languages and systems</source>
          , pp.
          <fpage>319</fpage>
          -
          <lpage>334</lpage>
          . Springer (
          <year>2003</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          14.
          <string-name>
            <surname>Gilles</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          :
          <article-title>The semantics of a simple language for parallel programming</article-title>
          .
          <source>In: Information Processing: Proceedings of the IFIP Congress</source>
          . vol.
          <volume>74</volume>
          , pp.
          <fpage>471</fpage>
          -
          <lpage>475</lpage>
          (
          <year>1974</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          15.
          <string-name>
            <surname>Guravannavar</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Sudarshan</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          :
          <article-title>Rewriting procedures for batched bindings</article-title>
          .
          <source>Proceedings of the VLDB Endowment</source>
          <volume>1</volume>
          (
          <issue>1</issue>
          ),
          <fpage>1107</fpage>
          -
          <lpage>1123</lpage>
          (
          <year>2008</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          16.
          <string-name>
            <surname>Josephs</surname>
          </string-name>
          , M.B.:
          <article-title>Models for data-flow sequential processes</article-title>
          .
          <source>In: Communicating Sequential Processes. The First 25 Years</source>
          , pp.
          <fpage>85</fpage>
          -
          <lpage>97</lpage>
          . Springer (
          <year>2005</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          17.
          <string-name>
            <surname>Mayer</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Grust</surname>
            ,
            <given-names>T.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Van Keulen</surname>
            ,
            <given-names>M.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Teubner</surname>
            ,
            <given-names>J.:</given-names>
          </string-name>
          <article-title>An injection with tree awareness: adding staircase join to postgresql</article-title>
          .
          <source>In: Proceedings of the Thirtieth international conference on Very large data bases-Volume</source>
          <volume>30</volume>
          . pp.
          <fpage>1305</fpage>
          -
          <lpage>1308</lpage>
          . VLDB Endowment (
          <year>2004</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          18.
          <string-name>
            <surname>Muchnick</surname>
            ,
            <given-names>S.S.:</given-names>
          </string-name>
          <article-title>Advanced compiler design implementation</article-title>
          . Morgan Kaufmann Publishers (
          <year>1997</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          19.
          <string-name>
            <surname>Navarro</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Asenjo</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Tabik</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Cascaval</surname>
            ,
            <given-names>C.</given-names>
          </string-name>
          :
          <article-title>Analytical modeling of pipeline parallelism</article-title>
          .
          <source>In: Parallel Architectures and Compilation Techniques</source>
          ,
          <year>2009</year>
          . PACT'
          <volume>09</volume>
          . 18th International Conference on. pp.
          <fpage>281</fpage>
          -
          <lpage>290</lpage>
          . IEEE (
          <year>2009</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref20">
        <mixed-citation>
          20.
          <string-name>
            <surname>Pavlo</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Paulson</surname>
            ,
            <given-names>E.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Rasin</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Abadi</surname>
            ,
            <given-names>D.J.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>DeWitt</surname>
          </string-name>
          , D.J.,
          <string-name>
            <surname>Madden</surname>
            ,
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Stonebraker</surname>
            ,
            <given-names>M.:</given-names>
          </string-name>
          <article-title>A comparison of approaches to large-scale data analysis</article-title>
          .
          <source>In: Proceedings of the 2009 ACM SIGMOD International Conference on Management of data</source>
          . pp.
          <fpage>165</fpage>
          -
          <lpage>178</lpage>
          . ACM (
          <year>2009</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref21">
        <mixed-citation>
          21.
          <string-name>
            <surname>Peterson</surname>
            ,
            <given-names>J.L.</given-names>
          </string-name>
          :
          <article-title>Petri nets</article-title>
          .
          <source>ACM Comput. Surv</source>
          .
          <volume>9</volume>
          (
          <issue>3</issue>
          ),
          <fpage>223</fpage>
          -
          <lpage>252</lpage>
          (
          <year>Sep 1977</year>
          ), http://doi.acm.
          <source>org/10</source>
          .1145/356698.356702
        </mixed-citation>
      </ref>
      <ref id="ref22">
        <mixed-citation>
          22.
          <string-name>
            <surname>Reps</surname>
            ,
            <given-names>T.</given-names>
          </string-name>
          :
          <article-title>Program analysis via graph reachability</article-title>
          .
          <source>Information and software technology 40(11)</source>
          ,
          <fpage>701</fpage>
          -
          <lpage>726</lpage>
          (
          <year>1998</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref23">
        <mixed-citation>
          23.
          <string-name>
            <surname>Sridharan</surname>
            ,
            <given-names>M.</given-names>
          </string-name>
          , Bod´ık, R.:
          <article-title>Refinement-based context-sensitive points-to analysis for Java</article-title>
          .
          <source>ACM SIGPLAN Notices</source>
          <volume>41</volume>
          (
          <issue>6</issue>
          ),
          <fpage>387</fpage>
          -
          <lpage>400</lpage>
          (
          <year>2006</year>
          )
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>