wiki:Dependency/Functions

Module and Function Dependencies

Concerning terminology

We say that module A depends on module B (A -> B) if there is at least one function call from A to B. There is a cyclic dependency, if B also depends directly (B -> A) or indirectly (e.g. B -> C -> A) on A.

Apparently, dependency can be defined on the function level as well. For instance, in our previous example, function level cycle is only present if both A and B define functions called foo, such that A:foo calls B:foo and B:foo calls A:foo.

Note that it is possible to have a cyclic dependency among modules while having no cyclic dependencies among their functions. For example, function calls from A:foo to B:foo and from B:foo2 to A:foo2 imply a cyclic dependency on the module level, but no one on the function level.

Capabilities

Mainly, you can check for cycles among entities within the RefactorErl database. This means that the program looks for loops on the given level, and returns with paths of cycles.

In case of vast databases, dependencies can be very complex, and hard to represent. To avoid producing useless, huge dependency graphs, we provide some options that you can use for narrowing down the result. For instance, you can reduce the graph to only contain the cycles, or you can exclude the standard OTP modules from the result. You can also specify a list of entities, called exceptions, that should be excluded from the analysis. Additionally, you can specify a list of those entities, called leaves, which should be included in the analysis, but their children should not (and consequently the children become exceptions). Also, you can ask to only cover dependencies starting from given function(s) or module(s).

Visualisation

If you would like to visualise the result, you can put it into a graph. Namely, we generate a .dot graph description file, which can be converted to any desired image format. On function level, for example, the graph shows the modules and their functions along with the calls between the functions, while red edges represent cycles.

Usage

Dependency analysis can be done via the following interfaces:

Semantics of dependency graphs

Function Level

Function dependency graphs look like the following.

dep_fun_before

In such graphs,

  • ROOT triangle represents a formal starting point if no one has been specified
  • Rectangle nodes (e.g. cycle1, a, test2) represent modules (deep purple)
  • Hexagon nodes (e.g. f1/1, apply/3, test2/2) represent functions (black)
  • Solid, continuous edge, normal arrowhead: to modules from the root, and the from modules to their functions (black)
  • Dashed edge, normal arrowhead indicates that a function calls another function (funcall) (black)
  • Dashed edge, special arrowhead indicates a function call, but also that it is a cyclic edge (red)

After performing dynamic call analysis, dynamic function calls are put into the call graph, and this obviously changes some dependency relations. The following figure shows a graph with dynamic function call dependencies.

dep_fun_after

In such graphs,

  • Double octagon nodes represent opaque nodes (black/gray)
  • Dotted edge, normal arrowhead indicates an ambcall, dyncall or may_be edge (black)

Every node and edge has tooltips. In the case of nodes it shows the corresponding graph node within the database, while considering edges it depicts the type of the function call (funcall, may_be, ambcall, dyncall). Static calls are labelled by funcall.

Module Level

Module dependency graphs capture call relations on a higher level.

dep_mod

In module dependency graphs,

  • Rectangle nodes (e.g. cycle1, erlang, test2) represent modules (deep purple)
  • Dotted edge, normal arrowhead indicates that a module calls another module (black)
  • Dotted edge, special arrowhead indicates a call loop (red)

Examples

ri:draw_dep([{level, mod}, {gnode, erlang}]).
ri:draw_dep([{level, mod}, {gnode, erlang}, {dot, "/home/working/dot/test.dot" }]).
ri:draw_dep([{level, func}, {gnode, ["lists:hd/1"]}]).
 ri:draw_dep([{level, mod},{gnode, [ri, ris]}]).
ri:draw_dep([{type, all}, {level, func}, {gnode, ["ri:q/1"]}, {otp, true}]).
ri:draw_dep([{type, all}, {level, mod}, {otp, true}, {exception, [ri, ris]}, {leaves, [reflib_ui]}]).
Last modified 11 years ago Last modified on May 9, 2013, 3:51:51 PM

Attachments (3)

Download all attachments as: .zip