| | 1 | = Module and Function Dependencies = |
| | 2 | |
| | 3 | == Concerning terminology == |
| | 4 | We say that a module A is '''dependent''' on another '''module''' ''B'' (''A -> B'') if there is |
| | 5 | at least one function call from ''A'' to ''B''. \\ |
| | 6 | A '''cyclic dependency''' appears, when ''B'' is |
| | 7 | also dependent directly (''B -> A'') or indirectly (e.g. ''B -> C -> A'') from ''A''. \\ |
| | 8 | Note that it is possible to have a cyclic dependency among the modules while having |
| | 9 | no cyclic dependencies among the functions. \\ For example, a function call from |
| | 10 | ''A:foo'' to ''B:foo'', and from ''B:foo2'' to ''A:foo2'' implies a cyclic dependency on the |
| | 11 | module level. \\ |
| | 12 | If one wants to have a deeper analysis and pays more |
| | 13 | attention to the concerning functions, a '''function''' level query should be done. \\ In |
| | 14 | our previous example, no function level cycle appears, unless ''A:foo'' calls ''B:foo'', |
| | 15 | and ''B:foo'' calls ''A:foo''. \\ |
| | 16 | \\ |
| | 17 | |
| | 18 | == Possible Analysis == |
| | 19 | |
| | 20 | |
| | 21 | The following examinations can be done considering dependencies:\\ |
| | 22 | * ''Checking'' whether there are ''cycles'', if so, ''listing'' them out |
| | 23 | * ''Printing out'' the cycles, meaning the modules/functions will not be represented by their proper graph node, but with their ''names'' (instead {{{ {'$gn', module, 3} }}} there will be {{{test}}}). |
| | 24 | * Checking for cycle ''from one or more nodes'' as starting points |
| | 25 | * ''Drawing'' the dependency graph |
| | 26 | * Drawing the dependency graph from a starting node |
| | 27 | * Drawing the cyclic part of the dependency graph if one exists (you can also give a cyclic node as a starting node) \\ |
| | 28 | \\ |
| | 29 | Dependency analysis can be done through '''two''' interfaces: \\ |
| | 30 | |
| | 31 | 1. ''ri'' (using RefactorErl through console interface) |
| | 32 | 2. using the ''web'' interface. \\ |
| | 33 | |
| | 34 | |
| | 35 | The two interface functions are: |
| | 36 | |
| | 37 | 1. {{{ri:draw_dep/1}}} - for drawing |
| | 38 | 2. {{{ri:print_dep/1}}} - for listing, printing out to the standard output \\ |
| | 39 | \\ |
| | 40 | \\ |
| | 41 | \\ |
| | 42 | To call the desired query, the user should give a ''proplist'', stating the different requirements. \\ |
| | 43 | The options and the keys for the functions are: |
| | 44 | * {{{{level, Level} }}} |
| | 45 | {{{Level = mod | func}}} |
| | 46 | Stating the level of the query, module or function level. |
| | 47 | * {{{{type, Type}}}} \\ |
| | 48 | {{{Type = all | cycles}}} |
| | 49 | The investigation should be done on the whole graph/table, or just on the cycle part (if it exists). \\ |
| | 50 | When listing out the cycles, {{{all}}} gives back the result in their graph node form, while {{{cycles}}} returns with their proper |
| | 51 | names. |
| | 52 | |
| | 53 | |
| | 54 | === Examples for listing results === |
| | 55 | |
| | 56 | |
| | 57 | |
| | 58 | * Checking for cycles in module level. \\ |
| | 59 | {{{ri:print_dep([{level, mod}, {type, all}]). }}} |
| | 60 | |
| | 61 | |
| | 62 | * Checking for cycles in function level, and printing out the whole names of the functions (Module:Function/Arity). \\ |
| | 63 | {{{ri:print_dep([{level, func}, {type, cycles}]). }}} |
| | 64 | |
| | 65 | {{{{6 cycle(s), }}} \\ |
| | 66 | {{{[['foo:fv4/1','foo:fv4/1'],}}} \\ |
| | 67 | {{{['test3:p/1','test:fv6/1','test3:p/1'],}}} \\ |
| | 68 | {{{['cycle4:f4/1','cycle3:f3/1','cycle4:f4/1'],}}} \\ |
| | 69 | {{{['cycle2:fv2/1','cycle1:fv1/0','cycle2:fv2/1'],}}} \\ |
| | 70 | {{{['test:fv5/1','test:fv4/2','test:fv5/1'],}}} \\ |
| | 71 | {{{['cycle4:f5/1','cycle3:f6/1','cycle4:f5/1']] }}} \\ |
| | 72 | |
| | 73 | |
| | 74 | * Checking for cycles in function level, and printing out the graph nodes of the functions (notice the changed "type" in the proplist) \\ |
| | 75 | {{{ri:print_dep([{level, func}, {type, all}]).}}} |
| | 76 | |
| | 77 | {{{{"6 cycle(s)",}}} \\ |
| | 78 | {{{[[{'$gn',func,28},{'$gn',func,28}], }}} \\ |
| | 79 | {{{[{'$gn',func,29},{'$gn',func,37},{'$gn',func,29}],}}} \\ |
| | 80 | {{{[{'$gn',func,7},{'$gn',func,9},{'$gn',func,7}],}}} \\ |
| | 81 | {{{[{'$gn',func,2},{'$gn',func,1},{'$gn',func,2}],}}} \\ |
| | 82 | {{{[{'$gn',func,36},{'$gn',func,35},{'$gn',func,36}],}}} \\ |
| | 83 | {{{[{'$gn',func,8},{'$gn',func,6},{'$gn',func,8}]]}}}} \\ |
| | 84 | |
| | 85 | * Checking for cycles in module level from an exact node \\ |
| | 86 | {{{ri:print_dep([{level, mod}, {gnode, {'$gn', module, 24}}]). }}} |
| | 87 | |
| | 88 | {{{{true,[[{'$gn',module,24},}}} \\ |
| | 89 | {{{{'$gn',module,25},}}} \\ |
| | 90 | {{{{'$gn',module,24}]]}}}} \\ |
| | 91 | |
| | 92 | |
| | 93 | * Checking for cycles in function level from an exact node given with its whole name \\ |
| | 94 | {{{ri:print_dep([{level, func}, {gnode, "cycle4:f5/1"}]). }}} |
| | 95 | |
| | 96 | == Representation == |
| | 97 | |
| | 98 | === Function Level === |
| | 99 | Let's take an example to explain the meaning of the representation of |
| | 100 | dependency graphs. A {{{ri:draw_dep([{level, func}, {type, all}])}}} |
| | 101 | call was made, which generated a ''Graphviz dot file''. \\ |
| | 102 | |
| | 103 | !!TODO: add figure!! |
| | 104 | |
| | 105 | Explanation of the figure: |
| | 106 | |
| | 107 | * ROOT triangle - no actual purpose, functioning as a starting point, only appears in the representation |
| | 108 | * Rectangle/box nodes (eg.: {{{cycle1, a, test2}}}) - representing modules (colour: ''deep purple'') |
| | 109 | * Hexagon nodes (eg.: {{{f1/1, apply/3, test2/2}}}) - representing functions (colour: ''black'') |
| | 110 | * Double octagon nodes - representing opaque nodes (colour: ''black'', label colour: ''gray'') |
| | 111 | * Solid, continuous edge, normal arrowhead - normal edge indicating the modules from the root, and the |
| | 112 | modules and their definitions of functions (colour: ''black'') |
| | 113 | * Dashed edge, normal arrowhead - indicates that a function calls another function ({{{funcall}}}) (colour: ''black'') |
| | 114 | * Dashed edge, special arrowhead - indicated a function call, but also that it is a cyclic edge (colour: ''red'') |
| | 115 | |
| | 116 | |
| | 117 | The next figure was made after a {{{ri:anal_dyn()}}} was run, which is a dynamic analyser. Due to its work the call graph changes a bit, |
| | 118 | new types of nodes and edges are introduced. |
| | 119 | |
| | 120 | !!TODO: add figure!! |
| | 121 | |
| | 122 | Explanation of figure, new nodes, edges: |
| | 123 | |
| | 124 | * Double octagon nodes - representing opaque, -1 arity nodes (colour: ''black'', label colour: ''gray'') |
| | 125 | * Dotted edge, normal arrowhead - indicates an {{{ambcall, dyncall, may_be edge}}} (colour: ''black'') |
| | 126 | |
| | 127 | Every node and edge have tooltips. In the case of nodes it shows the |
| | 128 | adequate graph node, while considering edges it depicts the type of |
| | 129 | function call ({{{funcall, may_be, ambcall, dyncall}}}). Static calls are labelled by {{{funcall}}}. |
| | 130 | |
| | 131 | {{{Dyncall}}} means unambiguous dynamic calls, when the identifiers |
| | 132 | of the callee may be defined not at the call but at another program |
| | 133 | part, and their values are can be calculated by data-flow |
| | 134 | reaching. {{{Ambcall}}} relation denotes the fact that some of the |
| | 135 | arguments of the dynamic function call can not be detected |
| | 136 | statically. If the number of parameters is uncertain, then after the |
| | 137 | arity of the function will be -1. It is also indicated with a special |
| | 138 | node. For further details about the dynamic calls and their |
| | 139 | representation can be found in (TODO: Reference for dynamic calls). When the |
| | 140 | applied function or module is uncertain, the tool represents it with |
| | 141 | an {{{opaque}}} node, and connects the possible functions/modules |
| | 142 | with {{{may_be}}} edges. The representation in the analysis now |
| | 143 | follows this, indicating the opaque nodes differently (described in |
| | 144 | the previous section, concerning drawings). |
| | 145 | |
| | 146 | We note here that tooltips may not be shown under certain browsers |
| | 147 | (for example Mozilla Firefox 7.0.1). If this happens, please try |
| | 148 | another browser. |
| | 149 | |
| | 150 | |
| | 151 | === Module Level === |
| | 152 | |
| | 153 | Similarly, at module level, after calling {{{ri:draw_dep([{level, mod}, {type, all}])}}, an analogous figure can be achieved. \\ |
| | 154 | |
| | 155 | !! TODO Figure !! |
| | 156 | |
| | 157 | Explanation of figure: |
| | 158 | * Rectangle/box nodes (eg.: {{{cycle1, erlang, test2}}}) - representing modules (colour: ''deep purple'') |
| | 159 | * Doubleoctagon nodes (no example on the figure) - representing opaque nodes (colour: ''black'', label colour: ''gray'') |
| | 160 | * Dotted edge, normal arrowhead - indicates that a module calls another module (colour: ''black'') |
| | 161 | * Dotted edge, special arrowhead - indicated a module call, but also that it is a cyclic edge (colour: ''red'') |
| | 162 | |
| | 163 | |
| | 164 | The tooltip for edges shows a list the function pair: \\ |
| | 165 | {{{Call = {callee, called}, Tooltip = [] | [Call | Tooltip]}}} \\ |
| | 166 | Latter makes a connection between the modules with this call. |
| | 167 | |
| | 168 | === Examples for the representation of the results === |
| | 169 | |
| | 170 | |
| | 171 | * {{{ri:draw_dep([{level, mod}, {gnode, erlang}]).}}} |
| | 172 | * {{{ri:draw_dep([{level, mod}, {gnode, erlang}, {dot, "/home/working/dot/test.dot" }]).}}} |
| | 173 | * {{{ri:draw_dep([{level, func}, {gnode, "lists:hd/1"}]). }}} |
| | 174 | * {{{ri:draw_dep([{level, mod},{gnode, {'$gn', module, 4}}]). }}} |
| | 175 | * {{{ri:draw_dep([{type, cycles}, {level, func}, {gnode, {'$gn', func, 36}}]). }}} |