<!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>Analysing and visualising callback modules of Erlang generic server behaviours</article-title>
      </title-group>
      <contrib-group>
        <aff id="aff0">
          <label>0</label>
          <institution>ELTE Eötvös Loránd University, Faculty of Informatics Budapest</institution>
          ,
          <country country="HU">Hungary</country>
        </aff>
      </contrib-group>
      <fpage>23</fpage>
      <lpage>41</lpage>
      <abstract>
        <p>Understanding and maintaining the source code of industrial-scale software product is hard and time-consuming, and it is getting more difficult when the software implements parallel/concurrent/distributed computations and behaviours. Static source code analysis tools support program comprehension through detecting dependencies and relations among small (like functions and processes) or large (modules and components) software elements. For Erlang, which is a dynamic language, only an approximation of the real dependencies can be calculated statically. However it is possible to improve these analyses by adding application specific information, such as the most frequently used behaviours. In this paper we introduce an extension of the RefactorErl static source code analyser framework for Erlang that adds information about generic server behaviour implementations to the Semantic Program Graph of RefactorErl. In addition we define several views of the generic server based hidden communication.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Introduction</title>
      <p>Tools that support the software development life-cycle (such as code comprehension tools, refactoring tools,
visualisation tools, test selection tools, test coverage checkers, etc.) are frequently used by the industry. These
tools can reduce the time of bug fixing, code change requests, new feature requests and they also help to decrease
the number of faults in the system.</p>
      <p>Static analyser tools extract information from the source code without executing the program. Static analysis
is not straightforward for sequential programs and it is getting more difficult when we are to analyse complex
concurrent or distributed software.</p>
      <p>
        Erlang [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] is a concurrent functional programming language that was designed for developing telecommunication
systems in the 1980s. RefactorErl [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ] is a tool for Erlang, that aims to support semantics preserving source code
transformations and code comprehension. It represents the source code in a so-called Semantic Program Graph
(SPG). The SPG contains the abstract syntax tree of the source code, and in addition semantic nodes and edges
representing semantic information. For instance, functions and function calls, and the connections generated by
the usage of the built in communication primitives of the language, etc.
      </p>
      <p>
        Erlang provides patterns (so called behaviours) for concurrent and distributed application design. There are
several behaviours in the Erlang/OTP [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ] library, such as generic servers, finite state machines, supervisors, etc.
The main focus of our paper is the extension of the Semantic Program Graph with application specific semantic
information. We extend the communication and process semantic layer found in the SPG with the results of
generic server analysis. We also define a separate graph, a view of a static interaction model (communication and
message handling) of the generic server behaviour. This can be a vital tool when it comes to code comprehension
and discovering defects or anomalies in the behaviour of a generic server.
      </p>
      <p>The rest of this paper is structured as follows: Section 2 introduces the basic communication primitives of Erlang
and the generic server behaviour; Section 3 introduces RefactorErl and the Communication Graph; Section 4
presents the Erlang generic server analysis and visualisation; Section 6 shows an example of the resulted model;</p>
      <sec id="sec-1-1">
        <title>Section 7 discusses related work and Section 8 concludes the paper and highlights future directions.</title>
        <p>2</p>
      </sec>
    </sec>
    <sec id="sec-2">
      <title>Processes in Erlang</title>
      <p>Originally, Erlang was designed for developing concurrent and distributed software systems with soft real-time
characteristics. Erlang supports process creation and communication between processes with built in language
constructs.</p>
      <p>To start processes one can use the spawn* functions with different options, for message sending the ! operator
and for receiving messages the receive construct. Processes can be accessed either with their process identifier
(pid ) or can be registered and accessed by the registered name.
2.1</p>
      <p>
        Behaviours
Beside the communication primitives the Erlang OTP comes with a set of design patterns, so called behaviours [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ].
      </p>
      <sec id="sec-2-1">
        <title>Some well-known standard behaviours are:</title>
        <p>• gen_server – Generic server pattern for client-server applications.
• gen_fsm – Generic finite state machine.</p>
        <p>• gen_event – Generic event handler.</p>
        <p>Besides the standard behaviours we can extend the above list by defining our own behaviours. For this, we have
to define the required interface of the callback module and implement the general part of the behaviour.
2.2</p>
        <p>Generic server behaviour
In this paper we focus only on static analysis of source codes implementing the gen_server behaviour. Let
us introduce briefly the main features of the generic server behaviour, the additional features can be handled
analogously. In Section 6 the reader can find an example source code.</p>
        <sec id="sec-2-1-1">
          <title>2.2.1 Interface of the gen_server module</title>
          <p>The interface functions of the gen_server module are:
• start*/3,4 – The function starts the server with the provided callback module, arguments and options. The
server can be accessed by its pid or, if it is registered, by its name. The visibility of the registered server can
be local or global. For setting up the server process it uses the init/1 function from the callback module.
• call/3,4 – This function is for synchronous communication. The function sends the given request to
the addressed server and waits for the response. The calling process is suspended until the reply arrives.
Optionally it can be given a timeout value, that causes the function call to fail if there is no reply within
that time.
• cast/2 – This function is for asynchronous communication. The function sends the given message to the
addressed server asynchronously.
• reply/2 – With this function the server can send messages directly to the client. It can be used for delayed
answers to the client.
2.2.2</p>
          <p>Callback module
The callback module can be divided into two parts, the server API and the callback functions. The API
functions depend on the purpose of the server: starting and stopping the server, interface functions to hide the
communication with the server and forward correctly the requests to the server.</p>
          <p>Let us describe only the subset of the callback functions that are the most relevant to our analysis:
• init/1 – The function is called when the server is started, it initialises the server process using the input
arguments.
• terminate/2 – The function is evaluated if the server is stopping, it performs the necessary clean up
operations according to the provided reason of stopping and state of the server.
• handle_call/3 – The function is called when a synchronous request arrives to the server. The function gets
the request data, the client id and the current state of the server. There are three different types of return
values:
– reply : The return encloses the reply message to the client request, the new server state and an optional
timeout value or the hibernate atom. If timeout option is used, a timeout will occur if there is no new
request within this time. If the hibernate option is used, the server goes into hibernation until the
next request arrives.
– noreply : There are situations that require to delay the answer to the client, this option can be used
in this case. The return value encloses the new state and an optional timeout value or the hibernate
atom. The delayed answer can be returned to client later on with the reply/2 function.
– stop : The return value must enclose the reason of stopping, the new state, and an optional reply to the
request. If the request is not provided the reply must be handled with the reply/2 function directly.</p>
          <p>
            This return value causes the server to stop, the terminate/2 function is evaluated.
• handle_cast/2 – The function is called when an asynchronous request arrives to the server. The function
gets the request data and the current state of the server. There are two possible returns of this function:
– noreply : The return value encloses the new server state and an optional timeout value or the hibernate
atom.
– stop : This return causes the server to stop. The return value encloses the reason of stopping and the
new state of the server.
• handle_info/2 – The function is called when a message arrives to the server (in other ways than the provided
gen_server interface functions) or a timeout occurs. The server handles the message as asynchronous
communication, the return values are the same as at the handle_cast/2.
RefactorErl [
            <xref ref-type="bibr" rid="ref11">11</xref>
            ] is a source code analysis and transformation tool for Erlang. Besides the more than twenty
refactoring steps it provides a variety of features to support software maintenance and development (e.g. code
browsing and investigations controlled by semantic queries, duplicated code detection, dependence analysis and
visualisation).
          </p>
          <p>As the basis of further analysis RefactorErl uses a Semantic Program Graph (SPG ) to represent the Erlang source
code in a data structure designed to efficiently store and reuse the calculated lexical, syntactic and semantic
information. The tool has an asynchronous semantic analyser framework and provides several built-in analyses:
variable scoping, static and dynamic function call, data-flow, module, record, specification analyses.
3.1</p>
          <p>Semantic Program Graph schema
The SPG can be described as the following hextuple: SP G = (N; AN ; AV ; A; T; E),
where:
• N is the set of nodes,
• AN is the set of attribute names,
• AV is the set of possible attribute values,
• A : N</p>
          <p>AN ! AV is a node labelling partial function,
• T is the set of edge labels,
• E : N</p>
          <p>T</p>
          <p>N0 ! N a partial function that describes labelled, ordered edges between the nodes.</p>
          <p>The set N corresponds to the three layers of the SPG, it is the union of the lexical, syntactic and semantic nodes:</p>
        </sec>
      </sec>
      <sec id="sec-2-2">
        <title>The set Nsyn contains nodes of four distinct classes: file, form, clause and expression. Formally:</title>
        <p>N = Nlex [ Nsyn [ Nsem</p>
        <p>Nsyn = Nfile [ Nform [ Nclause [ Nexpr
The set Nsem contains nodes of several different classes, like module, function, variable, pid, behaviour, etc.</p>
      </sec>
      <sec id="sec-2-3">
        <title>Formally:</title>
        <p>Nsem = Nmodule [ Nfunc [ Npid [ Nbehaviour [ :::
In further sections we use the N ode 2 Nx notation which means that N ode is a node of class x.
3.2</p>
        <p>Nodes in the SPG
We introduce the node classes that are necessary for the generic server analysis:
• ROOT: Root node of the SPG
• Expr: Syntactic nodes representing expressions. The type attribute of the node describes the type of the
given expression, e.g. tuple, list, application, function parameter, etc.
• Clause: Syntactic nodes representing the clauses of functions and expressions.
• Func: Semantic nodes representing functions. The node describes the arity and the name of the function.
• Module: Semantic nodes representing modules.
• Behaviour: Semantic nodes of behaviours. Its type attribute describes the represented behaviour (e.g.</p>
        <p>gen_server).
• Pid: Semantic nodes representing processes. A node can either belong to a behaviour process or it can be
an interface function that can be started as a separate process.
3.3</p>
        <p>
          Data-Flow Reaching
To determine the identifiers of processes and the recipient of the messages we use data-flow analysis [
          <xref ref-type="bibr" rid="ref22">22</xref>
          ]. A
Data-Flow Graph is built during the initial analysis and we use the first order data-flow reaching relation ( ;1f ) to
calculate the possible values of certain expressions. The notation e1 ;1f e2 means that the value of expression e1
can flow to expression e2.
3.4
        </p>
        <p>Behaviour nodes in the SPG
The behaviour analysis is performed when a file is being added to the database of RefactorErl. It extends the
SPG with the behaviour information of modules. Whenever a behaviour attribute form is discovered in the source
code, a new semantic node and a new edge with the label beh is inserted between semantic module node and the
newly added behaviour node. Formally: M odule b!eh Behaviour
3.5</p>
        <p>
          Process analysis
The process relations are represented in the Semantic Program Graph as described in [
          <xref ref-type="bibr" rid="ref23">23</xref>
          ]. The process analysis
is a so called post analysis1, therefore it has to be started by the user after the source code has been added to the
database of RefactorErl.
        </p>
        <p>The process discovery analysis examines the function applications which can start new processes, these are
erlang:spawn/1,2,3,4 and erlang:spawn_link/1,2,3,4 and other spawn_* function applications. For each
discovered process a new semantic Pid node is created in the SPG. The algorithm tries to extract as much
information as possible about the started processes, such information are for example the registered names.
Messaging primitives such as send/2,3 function applications and receive expressions are examined as well to
identify the communication between the processes.</p>
        <p>
          The process analyser identifies gen_server processes and the synchronous and asynchronous requests from clients
to servers [
          <xref ref-type="bibr" rid="ref12">12</xref>
          ].
3.5.1
        </p>
        <p>SPG edges
Besides the semantic process identifier nodes several edges are created in the SPG to describe the communication
between gen_servers and clients:
pid
• pid: from the root node of the SPG to the process identifier nodes: ROOT ! P id
• eval_in: any expression that performs message passing (via communication primitives or gen_server
interface functions) is connected to the process it is evaluated in: Expr eva!l_in P id
1RefactorErl analyses the sources with its asynchronous incremental analyser framework, where each Erlang form is analysed in a
separate Erlang process. When we rely our analysis on interfunctional information, such as data-flow, we have to run our analysis
after the initial analysis is finished for the whole graph. These kinds of analyses are called post analyses.
• sync_call: process identifier nodes that perform gen_server:call/2,3 are connected to the Pid node of
the gen_server process: P id sny!c_call P id
• async_call: process identifier nodes that perform gen_server:cast/2 are connected to the Pid node of
the gen_server process: P id asyn!c_call P id
4</p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>Analysing generic server behaviours</title>
      <p>The gen_server analysis extends the behaviour nodes with the gathered information and adds new edges that
represent the communication between processes. The analysis uses the information from other analyses like
behaviour, process and data-flow analyses.</p>
      <p>The analyser first identifies the generic servers and for each server its possible registered name is determined. Next
the algorithm examines the communication between processes. The algorithm looks for expressions that could
potentially send messages to the gen_server process (using messaging primitives, synchronous or asynchronous
message passing) and it determines the possible reply values based on the sent messages. The sent messages and
possible replies are stored in the behaviour node. The next step is to insert new edges to the SPG. New edges are
inserted between the behaviour node and functions that define, start or stop the server, and to functions that
initiate message sending to the server process.
4.1</p>
      <p>Semantic Program Graph extension
The SPG schema is extended to allow for storing communication information in behaviour nodes and the addition
of new edges into the graph.</p>
      <sec id="sec-3-1">
        <title>Behaviour nodes are extended with the messages attribute:</title>
        <p>M essages
Npid
T erm
Nexpr
Nclause
P(T erm)</p>
      </sec>
      <sec id="sec-3-2">
        <title>In the described set, each message is described with a 5-tuple with the following elements:</title>
        <p>1. P id 2 Npid: The semantic process identifier node in the SPG of the message sender process.
2. M essage 2 T erm: The sent message, an Erlang term.
3. Expression 2 Nexpr: The expression node in the SPG that performs the message sending.
4. DestinationClause 2 Nclause: Syntactic node of the function clause that handles the message.
5. Replies 2 P(T erm): A list of Erlang terms that are possible replies to the message from the server side.
The message sending could be represented as edges from the process identifier nodes to the handling function
clause with the message as the edge label. The reason why we introduced this complex attribute instead of edge
labels was that the RefactorErl database has a fixed schema. This means every edge label has to be declared in
advance, they cannot be changed dynamically. The advantage of this representation is that there is no need to
perform costly queries in the graph, every piece of information is accessible directly from the semantic behaviour
node.</p>
        <p>The following new edges are introduced to the SPG:
• gs_def: Connects the gen_server behaviour semantic node to the init/1 function in its callback module.
• gs_call: Connects the gen_server behaviour semantic node to those functions that apply the
gen_server:call/2,3 function thus sending a synchronous request to the server process.
• gs_cast: Connects the gen_server behaviour semantic node those functions that apply the
gen_server:cast/2 function thus sending an asynchronous request to the server process.
• gs_start: Points from the gen_server node to those function nodes that could start server process. These
functions either call the gen_server:start/3,4 or gen_server:start_link/3,4 functions.
• gs_stop: Points from the gen_server node to those function nodes that could stop the server process. These
functions call the gen_server:stop/1,3 function.</p>
        <p>• gs_pid: Connects the gen_server node to the Pid node, representing the server process.
As the first step of the gen_server analysis it performs the process analysis. This step is shown in Algorithm 1,
as the analyse_processes() subroutine call. After this we query the gen_servers from the graph by calling the
genservers() subroutine and we apply the analysis for each found gen_server.</p>
        <p>Algorithm 1 analyse_genservers()
1: analyse_processes()
2: GenServers genservers()
3: for Server 2 GenServers do
4: analyse_genserver(Server)
5: end for
The algorithm for the genservers() subroutine is described in Algorithm 2. The subroutine filters and returns
the set of behaviour nodes of type gen_server.</p>
        <p>Algorithm 2 genservers()
1: GenServers ;
2: for Behaviour 2 Nbehaviour do
3: if is_genserver(Behaviour) then
4: GenServers GenServers [ fBehaviourg
5: end if
6: end for
7: return GenServers
The abstract algorithm of extending the SPG with semantic knowledge about a gen_server is shown in</p>
      </sec>
      <sec id="sec-3-3">
        <title>Algorithm 3.</title>
        <p>The routine gets a generic server semantic node as argument. As a first step the algorithm determines the
possible names for the gen_server and updates the node. The second step is to determine the possible messages
addressed to the examined server, the possible replies and update the node with the gathered information. The
further steps are to insert edges between the examined gen_server node and its Pid node, init/1 function, and
functions that make either synchronous or asynchronous requests, start or stop the server.
Algorithm 3 analyse_genserver(GenServer)
1: update_with_name(GenServer)
2: update_with_messages(GenServer)
3: create_gs_pid_edge(GenServer)
4: create_gs_def _edge(GenServer)
5: create_gs_call_edges(GenServer)
6: create_gs_cast_edges(GenServer)
7: create_gs_start_edges(GenServer)
8: create_gs_stop_edges(GenServer)</p>
        <p>The gen_server graph
The SPG itself contains an overwhelming amount of information, although it can be visualised with RefactorErl
it is not the most appropriate form for human readers. To extract information produced by the gen_server
analysis one can either generate views on different abstraction levels or query the information directly from the
SPG.</p>
        <p>In Section 4 we have presented how the SPG is extended with gen_server specific information. The most
comprehensible presentation of this information is through visualisation, therefore we defined the gen_server
communication graph to present the message passing between server processes and their clients.
We can generate the gen_server communication graph on three levels of abstraction, which correspond with the
abstraction levels of the language itself (functions, function clauses, expressions):
• Compact: Server processes, callback modules and functions sending requests to server processes are
displayed, along with the gen_server:handle* functions. Request and message contents are the labels of
edges leading to the handle functions from the function initiating them.
• Normal: The compact view is extended with the clauses of the functions gen_server:handle*. The edges
showing message passing are leading to the function clause handling them.
• Detailed: The normal view is extended with the actual expressions performing a request or sending a
message, these are the sources of the request edges in the graph.
5.1</p>
        <p>Graph definition</p>
      </sec>
      <sec id="sec-3-4">
        <title>Let Ggs be the gen_server communication graph in the following way:</title>
        <p>Ggs = (Vgs; Egs)
Vgs = Vserver [ Vmodule [ Vpid [ Vhandler [ Vclause [ Vexpr</p>
        <p>Egs Vgs Vgs LABEL
Where Vgs and Egs are the node and edge sets respectively. The set of nodes is composed of the following subsets:
• Vserver: nodes of generic servers
• Vmodule: nodes representing modules
• Vpid: nodes of processes
• Vhandler: nodes of gen_server:handle* functions of each server
• Vclause: nodes of clauses of the gen_server:handle* functions
• Vexpr: expression nodes (that initiate a request)</p>
      </sec>
      <sec id="sec-3-5">
        <title>Nodes in the communication graph have a label property, defining the visualised name of the node.</title>
        <p>Egs is the set of labelled edges, where each edge is represented with an ordered triple. The elements of the ordered
triple are the head node, the tail node and the label of the edge. The elements of the LABEL set are arbitrary</p>
      </sec>
      <sec id="sec-3-6">
        <title>Erlang terms.</title>
        <p>5.2</p>
        <p>Graph building rules
The graph building procedure can be described as declarative rules. The graph is built in a way that we match
the rules on the SPG and build the corresponding genserver graph nodes and edges. There are several rules that
are common for all three graph abstraction levels, and a few rules that are specific for the given abstraction level.
General rules
1. gen_server node: If a behaviour node represents a generic server in the SPG, it will be present in the
communication graph.</p>
        <p>is_genserver(GenServer) ^ callback_module(M odule; GenServer)</p>
        <p>GenServer0 2 Vserver ^ GenServer0:label = M odule:name
2. Callback module node: Each gen_server callback module is present in the graph, with the module name as
a label.</p>
        <p>callback_module(M odule; GenServer)</p>
        <p>M odule0 2 Vmodule ^ M odule0:label = M odule:name
3. Callback module edge: From the gen_server node an edge with the label "callback module" leads to the
callback module node.</p>
        <p>callback_module(M odule; GenServer)
(GenServer0; M odule0; "callback module") 2 Egs
4. handle_call/3 message handler: If a server callback module defines a handle_call/3 function, it will be
present in the graph.</p>
        <p>callback_module(M odule; GenServer) ^ M odule func F unction ^</p>
        <p>!
F unction:name = handle_call ^ F unction:arity = 3</p>
        <p>F unction0 2 Vhandler ^
F unction0:label = M odule:name : F unction:name=F unction:arity ^</p>
        <p>(M odule0; F unction0; "synchronous handler") 2 Egs
5. handle_cast/2 message handler: If a server callback module defines a handle_cast/2 function, it will be
present in the graph
6. handle_info/2 message handler: If a server callback module defines a handle_info/2 function, it will be
present in the graph.</p>
        <p>callback_module(M odule; GenServer) ^ M odule func F unction ^</p>
        <p>!
F unction:name = handle_cast ^ F unction:arity = 2</p>
        <p>F unction0 2 Vhandler ^
F unction0:label = M odule:name : F unction:name=F unction:arity ^</p>
        <p>(M odule0; F unction0; "asynchronous handler") 2 Egs
callback_module(M odule; GenServer) ^ M odule func F unction ^</p>
        <p>!
F unction:name = handle_inf o ^ F unction:arity = 2</p>
        <p>F unction0 2 Vhandler ^
F unction0:label = M odule:name : F unction:name=F unction:arity ^</p>
        <p>(M odule0; F unction0; "message handler") 2 Egs
7. Pid nodes: Process identifier nodes in the SPG will be present in the graph if they send a request to the
server process.</p>
      </sec>
      <sec id="sec-3-7">
        <title>8. Module of Pid: For process identifier nodes their module will be present in the graph as well.</title>
        <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages
P id0 2 Vpid ^ P id0:label = P id:module : P id:f unction=P id:arity</p>
        <p>is_genserver(GenServer) ^ M odule 2 Nmodule ^
(P id; M essage; Expression; DestClause; Replies) 2 g:messages ^</p>
        <p>M odule:name = P id:module
M odule0 2 VmoduleM odule0:label = M odule:name ^ (M odule0; P id0; "pid") 2 Egs
9. Function of clause:</p>
        <sec id="sec-3-7-1">
          <title>Compact graph rules</title>
          <p>F orm 2 Nform ^ Clause 2 Nclause ^ F unction 2 Nfunc ^</p>
          <p>F orm fu!ncl Clause ^ F orm fu!ndef F unction</p>
          <p>clause(Clause; F unction)
1. Requests: From every process that is a message source of a gen_server an edge leads to the proper message
handling function, with the message as an edge label.</p>
          <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages ^</p>
          <p>clause(DestClause; F unction)
(P id0; F unction0; M essage) 2 Egs
2. Responses: From the message handling functions an edge leads to the process that originally sent a request.</p>
        </sec>
      </sec>
      <sec id="sec-3-8">
        <title>The edge label is the response itself.</title>
        <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages ^
clause(DestClause; F unction) ^ Reply 2 Replies
(F unction0; P id0; Reply) 2 Egs</p>
        <sec id="sec-3-8-1">
          <title>Normal graph rules</title>
          <p>1. Function clauses: Each function clause of the message handling functions of the server will be present in the
graph.</p>
          <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages ^
clause(DestClause; F unction)</p>
          <p>DestClause0 2 Vclause ^</p>
          <p>DestClause0:label = text(DestClause) ^
(F unction0; DestClause0; "f unction clause") 2 Egs
2. Requests: From every process that is a message source of a gen_server an edge leads to the proper message
handling function clause, with the message as an edge label.</p>
          <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages</p>
          <p>(P id0; DestClause0; M essage) 2 Egs
3. Responses: From the message handling function clauses an edge leads to the process that originally sent a
request. The edge label is the response itself.
Detailed graph rules
1. Function clauses: Each function clause of the message handling functions of the server will be present in the
graph.</p>
          <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages ^
clause(DestClause; F unction)</p>
          <p>DestClause0 2 Vclause ^</p>
          <p>DestClause0:label = text(DestClause) ^
(F unction0; DestClause0; "f unction clause") 2 Egs
2. Message sending expressions: Each expression that is a message source will be a node in the communication
graph.</p>
          <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages
Expression0 2 Vexpression ^ (P id0; Expression0; "send expression") 2 Egs ^</p>
          <p>Expression0:label = text(Expression)
3. Requests: From every expression that is a message source of a gen_server an edge leads to the proper
message handling function clause, with the message as an edge label.</p>
          <p>is_genserver(GenServer) ^
(P id; M essage; Expression; DestClause; Replies) 2 GenServer:messages</p>
          <p>
            (P id0; Expression0; M essage) 2 Egs
4. Responses: From the message handling function clauses an edge leads to the process that originally sent a
request. The edge label is the response itself.
The introduced analysis technique has been applied to larger open-source project, such as RabbitMQ [
            <xref ref-type="bibr" rid="ref6">6</xref>
            ] and
          </p>
        </sec>
      </sec>
      <sec id="sec-3-9">
        <title>EMQTTD [3]. The results were published as a student research paper [17]. In this section we present a demonstrating example, a simplified chat client-server application, implemented with the generic server behaviour. We discuss the source code in detail and show the different views of the generic server graphs described in previous sections.</title>
        <p>The vital parts of the implemented chat server are introduced in Figure 1. There is a macro definition SrvRef
to make it easier to refer the server as it is registered globally. The functions of the server module are divided
into three groups: interface function for managing (starting, stopping) the server, interface functions for clients
(connecting to the server, sending messages) and the callback functions of the server.</p>
        <sec id="sec-3-9-1">
          <title>Server management</title>
          <p>The server can be started with the start/1 function. The argument of the function is the maximum number
of simultaneous users. The function starts the server with the given name, callback module and initialising
arguments.</p>
        </sec>
      </sec>
      <sec id="sec-3-10">
        <title>The generic server can be terminated with the stop/0 function.</title>
        <p>Client interface
The module provides interface function to the clients to hide specific information of the server. Such information
is the name of the server and how to interact with the server process.</p>
        <p>The client can connect to the server through evaluating the chatserver:connect/1 providing the nick as an
argument. The function performs a synchronous request to connect to the server with the given nick.
The client can disconnect from the server by calling the chatserver:disconnect/0. The function performs an
asynchronous request that sends the server the quit message.</p>
        <p>The texting to other chat clients is performed by the chatserver:send/1 function. The function sends the text
and the pid of the sender to the server. Messages can be sent directly to the server with the
chatserver:other_message/1 function.</p>
        <sec id="sec-3-10-1">
          <title>Callback functions</title>
        </sec>
      </sec>
      <sec id="sec-3-11">
        <title>The server receives requests and react to them using defined callback functions.</title>
        <p>The chatserver:init/1 function is called when the server is started, it performs the initialisation and returns
the initial state of the server.</p>
        <p>The synchronous requests sent with gen_server:call/2,3 functions are handled with handle_call/3 function
defined in the callback module. In our implementation there is a synchronous request when a client initiates
connection to the server process. When the request arrives the server checks whether the user limit has been
reached. If there is no free space in the chat room, a deny message is replied to the caller. In this case the state
remains unchanged. If the chat room is not full the user list is extended with the new member. The reply will be
the ok atom, and the state of the server is updated with the new user.</p>
        <p>The asynchronous requests sent with gen_server:cast/2 function are handled with the handle_cast/2 function
defined in the callback module. In our example implementation there are three different cases. The first clause of
the function handles the text broadcasting among the chat users in the chat room. It receives the message and
the identifier of the sender. From the identifier the server determines the nick of the user (it is assumed that the
sender is connected to the server) and sends the composed message for every member of the chat room. The
second clause handles the disconnection request from the users. The server omits the requested user from the list
of users and updates its sate. The third case is for stopping the server.</p>
        <p>The requests/messages sent in a non standard way to the generic server are handled with the handle_info/2
function definition of the callback module. In our case any unexpected message causes the server to stop.
6.2</p>
        <p>The client</p>
        <sec id="sec-3-11-1">
          <title>Interface functions</title>
          <p>The client is composed of two interface function start/1 and send/2 and two auxiliary functions loop/0 and
input/1.</p>
          <p>The function start/1 initiates the client process by sending a request connect to the server. The client is
terminated if a deny message is received. If the connection succeeded it spawns the input reading process and
continues executing the loop/0 function.</p>
          <p>The send/2 function is an interface function for the server process. With the help of this function the server can
send easily messages to clients.
%% Macro definition of server reference
-define(SrvRef, {global, chatserver}).
%% Interface functions
start(Max) -&gt; gen_server:start(?SrvRef, chatserver, [Max], []).
stop() -&gt; gen_server:cast(?SrvRef, stop).
%% Interface functions for clients
connect(Nick) -&gt; gen_server:call(?SrvRef, {connect, Nick}).
disconnect() -&gt; gen_server:cast(?SrvRef, {quit, self()}).
send(Text) -&gt; gen_server:cast(?SrvRef, {text, self(), Text}).
other_message(Message) -&gt; chatserver ! Message.
%% Callback functions
init(Max) -&gt; {ok, #state{users = [], max = Max}}.
handle_call({connect, Nick}, {Pid, _}, State = #state{users = Users}) -&gt;
if length(Users) &gt;= State#state.max -&gt; {reply, deny, State};
true -&gt;</p>
          <p>NewUsers = [#user{nick = Nick, pid = Pid} | Users],
{reply, ok, State#state{users = NewUsers}}
end.
handle_cast({text, From, Text}, State = #state{users = Users}) -&gt;</p>
          <p>Nick = get_nick(From, Users),
lists:foreach(
fun(#user{pid = Pid}) -&gt;</p>
          <p>chatclient:send(Pid, Nick ++ ": " ++ Text)
end,
Users),
{noreply, State};
handle_cast({quit, From}, State = #state{users = Users}) -&gt;</p>
          <p>NewUsers = omit_user(From, Users),
{noreply, State#state{users = NewUsers}};
handle_cast(stop, State) -&gt; {stop, normal, State}.
handle_info(_, State) -&gt; {stop, normal, State}.
start(Nick) when is_list(Nick)-&gt;
case chatserver:connect(Nick) of
deny -&gt; io:format("Connection failed~n",[]);
ok -&gt;</p>
          <p>Loop = self(),
spawn(fun() -&gt; input(Loop) end),
loop()
end.
loop() -&gt;
receive
quit -&gt; chatserver:disconnect(), quit;
{send, Text} -&gt; chatserver:send(Text), loop();
{text, Text} -&gt; io:format("~s~n", [Text]), loop()
end.
send(Pid, Text) -&gt; Pid ! {text, Text}.
input(Loop) -&gt;
case string:strip(io:get_line('--&gt; '), right, $\n) of
"#q" -&gt; Loop ! quit, ok;</p>
          <p>S -&gt; Loop ! {send, S}, input(Loop)
end.
The input process iteratively reads the standard input and forwards the read text or command to the client
process. The loop/0 function receives messages continuously and perform actions based on these messages. If
the loop receives the quit message the client disconnects from the server and exits looping. If a tuple with the
send tag is received a message is sent to the server process. If a tuple with text tag is received, that is a message
from the server with text of other chat users, it is printed to the standard output and continues looping.
The compact graph in Figure 3 shows the chatserver process, its callback module and the client module,
chatclient. The message sending functions and the message handlers are featured as well, with the messages
and responses as edges between them.</p>
          <p>The normal graph (Figure 4) compared to compact graph contains the individual function clauses of the message
handler functions. Each message is displayed as an edge from the sender to the handler clause.
The detailed graph in Figure 5 is the extension of the normal graph with the expressions that perform the message
sending.
7</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>Related work</title>
      <p>
        Supporting code comprehension by static analysis tool is not unique, several tools exist for different programming
languages [
        <xref ref-type="bibr" rid="ref2 ref4 ref5 ref7 ref8">2, 8, 5, 7, 4</xref>
        ]. A few static analysers exist for Erlang as well, but none of them is focusing on gen_server
based client-server implementation visualisation.
      </p>
      <p>
        However the Erlang Verification Tool [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ] is an interactive verification tool for proving correctness of distributed
systems implemented in Erlang, also capable of reasoning about servers implemented with the gen_server
behaviour.
      </p>
      <p>
        The paper [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ] introducing a message passing analysis for Erlang based on control flow graphs. The main purpose
of this work was to detect some common message passing errors in Erlang source code. The paper is not focusing
on the Erlang OTP behaviours. This tool is using some features of the static analyser tool, Dialyzer [
        <xref ref-type="bibr" rid="ref18">18</xref>
        ]. The
main goal of Dialyzer is to identify software discrepancies and defects. In [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ] the -callback attributes are
introduced and used to analyse the possible misuses of OTP behaviours based on Dialyzer.
Researches have been done in the area of formal analysis (verification) of problems related to message passing.
In paper [
        <xref ref-type="bibr" rid="ref20">20</xref>
        ] the authors defines race condition analysis, deadlock detection, etc. for MPI (Message Passing
      </p>
      <sec id="sec-4-1">
        <title>Interface).</title>
        <p>
          Message passing analyses have been developed to build accurate data- [
          <xref ref-type="bibr" rid="ref21">21</xref>
          ] and control-flow [
          <xref ref-type="bibr" rid="ref19 ref21">19, 21</xref>
          ] graphs of MPI
programs as well. The data-flow analysis technique presented in [
          <xref ref-type="bibr" rid="ref21">21</xref>
          ] is used for activity analysis and constant
reaching analysis. The former analysis is used to reduce the computation and storage requirements of MPI
programs.
        </p>
        <p>
          Percept2 [
          <xref ref-type="bibr" rid="ref15">15</xref>
          ] is a profiler and tracer tool for Erlang software, with heavy focus on processes and process
communication. It allows the visualisation of process hierarchies and the display of message passing between
processes. Percept2 does not differentiate between processes thus has no specific features for generic server
processes.
        </p>
        <p>
          Akka [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ] is a platform that allows for writing robust and fault tolerant software, using the same principles as
Erlang, in Scala or Java. It provides the same functionality as a generic server behaviour, as it supports the actor
model, but there is no specific static analysis tool available for Akka yet.
8
        </p>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>Summary</title>
      <p>Under the development and maintenance of a concurrent software the developer has to properly understand the
source code. In this paper we have introduced a static analyser tool that detects and visualise the communication
among processes implemented using the generic server behaviour and their clients.</p>
      <p>We have introduced a static source code analysis and transformation tool, RefactorErl. An extension of its
existing process analysis is presented to examine source code that implements a client-server architecture with</p>
      <sec id="sec-5-1">
        <title>Erlang generic server behaviour.</title>
        <p>We have described the visualisation of the communication between server processes and the clients that use
them, in the form of the gen_server Communication Graph. We have evaluated our tool on several open source
projects and it was able to produce a useful view of the server.</p>
        <p>In a distributed Erlang environment the process replacement is explicit, therefore the developer has to deal with
this information as well. Thus as a future work we aim to extend our analysis with distributed node analysis.
m
o
c
F
m
o
c</p>
      </sec>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          <article-title>[1] Akka documentation</article-title>
          . http://doc.akka.io/docs/akka/snapshot/general/. Accessed:
          <fpage>2016</fpage>
          -06-30.
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2] CodeCompass. https://github.com/Ericsson/codecompass. Accessed:
          <fpage>2017</fpage>
          -10-09.
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <surname>Erlang</surname>
            <given-names>MQTTD</given-names>
          </string-name>
          <article-title>Broker source</article-title>
          . https://github.com/emqtt/emqttd. Accessed:
          <fpage>2017</fpage>
          -10-01.
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <surname>Juliet</surname>
          </string-name>
          . http://infotectonica.com/. Accessed:
          <fpage>2017</fpage>
          -10-09.
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5] OpenGrok. http://opengrok.github.io/OpenGrok/. Accessed:
          <fpage>2017</fpage>
          -10-09.
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          <article-title>[6] RabbitMQ server source</article-title>
          . https://github.com/rabbitmq/rabbitmq-server.
          <source>Accessed: 2017-10-01.</source>
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7] SourceInsight. https://www.sourceinsight.com/. Accessed:
          <fpage>2017</fpage>
          -10-09.
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <surname>Understand</surname>
          </string-name>
          . https://scitools.com/features/. Accessed:
          <fpage>2017</fpage>
          -10-09.
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>Stavros</given-names>
            <surname>Aronis</surname>
          </string-name>
          and
          <string-name>
            <given-names>Konstantinos</given-names>
            <surname>Sagonas</surname>
          </string-name>
          .
          <article-title>Typed callbacks for more robust behaviours</article-title>
          .
          <source>In Proceedings of the 10th ACM SIGPLAN Workshop on Erlang, Erlang '11</source>
          , pages
          <fpage>23</fpage>
          -
          <lpage>29</lpage>
          , New York, NY, USA,
          <year>2011</year>
          . ACM.
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>Thomas</given-names>
            <surname>Arts</surname>
          </string-name>
          and
          <string-name>
            <given-names>Thomas</given-names>
            <surname>Noll. Verifying Generic Erlang Client-Server Implementations</surname>
          </string-name>
          , pages
          <fpage>37</fpage>
          -
          <lpage>52</lpage>
          . Springer Berlin Heidelberg, Berlin, Heidelberg,
          <year>2001</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <surname>István</surname>
            <given-names>Bozó</given-names>
          </string-name>
          , Dániel Horpácsi, Zoltán Horváth, Róbert Kitlei, Judit Kőszegi, Máté Tejfel, and Melinda Tóth. RefactorErl,
          <article-title>Source Code Analysis and Refactoring in Erlang</article-title>
          .
          <source>In Proceeding of the 12th Symposium on Programming Languages and Software Tools</source>
          , Tallin, Estonia,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <given-names>István</given-names>
            <surname>Bozó</surname>
          </string-name>
          and
          <string-name>
            <given-names>Melinda</given-names>
            <surname>Tóth</surname>
          </string-name>
          .
          <article-title>Analysing and visualising Erlang behaviours</article-title>
          .
          <source>AIP Conference Proceedings</source>
          ,
          <volume>1738</volume>
          (
          <issue>1</issue>
          ),
          <year>2016</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>Francesco</given-names>
            <surname>Cesarini</surname>
          </string-name>
          and
          <string-name>
            <given-names>Simon Thompson. Erlang</given-names>
            <surname>Programming. O'Reilly Media</surname>
          </string-name>
          ,
          <year>2009</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <given-names>Maria</given-names>
            <surname>Christakis</surname>
          </string-name>
          and
          <string-name>
            <given-names>Konstantinos</given-names>
            <surname>Sagonas</surname>
          </string-name>
          .
          <article-title>Detection of Asynchronous Message Passing Errors Using Static Analysis</article-title>
          .
          <source>In Ricardo Rocha</source>
          and John Launchbury, editors,
          <source>Practical Aspects of Declarative Languages</source>
          , volume
          <volume>6539</volume>
          of Lecture Notes in Computer Science, pages
          <fpage>5</fpage>
          -
          <lpage>18</lpage>
          . Springer Berlin Heidelberg,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <given-names>Huiqing</given-names>
            <surname>Li</surname>
          </string-name>
          and
          <string-name>
            <given-names>Simon</given-names>
            <surname>Thompson</surname>
          </string-name>
          .
          <article-title>Multicore Profiling for Erlang Programs Using Percept2</article-title>
          .
          <source>In Proceedings of the Twelfth ACM SIGPLAN Workshop on Erlang, Erlang '13</source>
          , pages
          <fpage>33</fpage>
          -
          <lpage>42</lpage>
          , New York, NY, USA,
          <year>2013</year>
          . ACM.
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          [16]
          <string-name>
            <surname>Martin</surname>
            <given-names>Logan</given-names>
          </string-name>
          , Eric Merritt, and Richard Carlsson. Erlang and OTP in Action. Manning Publications Co.,
          <string-name>
            <surname>Greenwich</surname>
            ,
            <given-names>CT</given-names>
          </string-name>
          , USA, 1st edition,
          <year>2010</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          [17]
          <string-name>
            <given-names>Mátyás</given-names>
            <surname>Kuti</surname>
          </string-name>
          .
          <source>Erlang viselkedések elemzése</source>
          ,
          <year>2016</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          [18]
          <string-name>
            <given-names>Konstantinos</given-names>
            <surname>Sagonas</surname>
          </string-name>
          .
          <article-title>Experience from Developing the Dialyzer: A Static Analysis Tool Detecting Defects in Erlang Applications</article-title>
          .
          <source>Talk presented at the 2005 Workshop on the Evaluation of Software Defect Detection Tools (Bugs'05)</source>
          , Chicago,
          <year>June 2005</year>
          . http://user.it.uu.se/~kostis/Papers/bugs05.pdf. Accessed:
          <fpage>2016</fpage>
          -06-30.
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          [19]
          <string-name>
            <surname>Dale</surname>
            <given-names>Shires</given-names>
          </string-name>
          , Lori Pollock, and
          <string-name>
            <given-names>Sara</given-names>
            <surname>Sprenkle</surname>
          </string-name>
          .
          <article-title>Program Flow Graph Construction for Static Analysis of MPI Programs</article-title>
          .
          <source>In Parallel and Distributed Processing Techniques and Applications</source>
          , pages
          <fpage>1847</fpage>
          -
          <lpage>1853</lpage>
          ,
          <year>Jun 1999</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref20">
        <mixed-citation>
          [20]
          <string-name>
            <surname>Stephen</surname>
            <given-names>F.</given-names>
          </string-name>
          <string-name>
            <surname>Siegel</surname>
            and
            <given-names>Ganesh</given-names>
          </string-name>
          <string-name>
            <surname>Gopalakrishnan</surname>
          </string-name>
          .
          <article-title>Formal Analysis of Message Passing</article-title>
          . In Ranjit Jhala and David Schmidt, editors,
          <source>Verification, Model Checking, and Abstract Interpretation</source>
          , volume
          <volume>6538</volume>
          of Lecture Notes in Computer Science, pages
          <fpage>2</fpage>
          -
          <lpage>18</lpage>
          . Springer Berlin Heidelberg,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref21">
        <mixed-citation>
          [21]
          <string-name>
            <given-names>Michelle</given-names>
            <surname>Mills</surname>
          </string-name>
          <string-name>
            <surname>Strout</surname>
          </string-name>
          , Barbara Kreaseck, and
          <string-name>
            <given-names>Paul D.</given-names>
            <surname>Hovland</surname>
          </string-name>
          .
          <article-title>Data-Flow Analysis for MPI Programs</article-title>
          .
          <source>In Proceedings of the 2006 International Conference on Parallel Processing, ICPP '06</source>
          , pages
          <fpage>175</fpage>
          -
          <lpage>184</lpage>
          , Washington, DC, USA,
          <year>2006</year>
          . IEEE Computer Society.
        </mixed-citation>
      </ref>
      <ref id="ref22">
        <mixed-citation>
          [22]
          <string-name>
            <given-names>Melinda</given-names>
            <surname>Tóth</surname>
          </string-name>
          and
          <string-name>
            <given-names>István</given-names>
            <surname>Bozó</surname>
          </string-name>
          .
          <source>Static Analysis of Complex Software Systems Implemented in Erlang. In Central European Functional Programming School</source>
          , volume
          <volume>7241</volume>
          of Lecture Notes in Computer Science, pages
          <fpage>440</fpage>
          -
          <lpage>498</lpage>
          . Springer,
          <year>2012</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref23">
        <mixed-citation>
          [23]
          <string-name>
            <given-names>Melinda</given-names>
            <surname>Tóth</surname>
          </string-name>
          and
          <string-name>
            <given-names>István</given-names>
            <surname>Bozó</surname>
          </string-name>
          .
          <source>Detecting and Visualising Process Relationships in Erlang. Procedia Computer Science</source>
          ,
          <volume>29</volume>
          (
          <issue>0</issue>
          ):
          <fpage>1525</fpage>
          -
          <lpage>1534</lpage>
          ,
          <year>2014</year>
          . 2014 International Conference on Computational Science.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>