| 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}}]). }}} |