Usage
This module allows you to produce a call graph of one or more modules, where
nodes (boxes) represent predicates and an edge between
two predicates indicates that one (the source end) calls the other
(the pointy end).
By default, node styles are used to indicate whether or not the predicate is
exported (bold outline), dynamic (italic label, filled), multifile (box with diagonals
in the corners).
For dynamic predicates, dashed edges are used to represent operations which
mutate (assert to or retract from) the predicate.
Items in the recorded database are also represented, as they consitute mutable
state much like dynamic predicates. Recorded items are labelled as Key:Functor/Arity
and drawn in a filled octagonal box. Dashed edges represents writing to the
recorded database and ordinary solid edges represent reading.
Basic method of usage is:
- Load the module you want to graph.
- Load this module.
- Generate and write the module call graph to a PDF document:
?- module_dotpdf(ModuleName,[]).
See module_dot/2 for options that affect graph content and style, and
module_dotpdf/2 for options that affect rendering.
Multi-module graphs
The predicates modules_dotpdf/3 and modules_dot/3 support graphing multiple
modules. Each module is drawn inside a box (a Graphviz cluster). Items in
the recorded database are outside the module system. They can optionally
be collected into one cluster or into several clusters by key.
Implementation notes
NB. This is very preliminary. The intereface is not necessarily stable.
The dot DCG implementation is a bit embarassing but it does the job for now.
Three parts to this:
- Using prolog_walk_code/1 to compile a database of inter-predicate calls
into dynamic predicate edge/3.
- Possible transformations of graph (eg pruning).
- Collect information about desired modules/predicates into a Dot graph
structure as defined by
dotdct.pl
Types used internally
- pred_head
- Predicate specifier as Modue:Head where Head is a term with same
name and arity of the predicate concerned.
- module
- Module name as an atom.
- record_head
- Term like Key:Term, reference to recorded database terms with
Term and given Key.
- node
- Node name as Atom:Name/Arity.
module == atom.
functor ---> atom/natural.
pred_head ---> module:term.
node ---> atom:functor.
record_head ---> atom:term.
edge_spec ---> dynamic(module,pred_head,list(edge_type))
; recorded(edge_type,record_head).
edge_type ---> calls ; mutates ; reads ; writes.
- module_dot(+ModuleName, Opts) is det
- Writes a call graph for named module as a dot file named "[ModuleName].dot".
This predicate also accepts various options (some of the these types
refer to the GraphViz attribute types):
- prune(Prune:bool)/false
- If true, then graph subtrees are removed using prune_subtrees/0.
- recursive(bool)/false
- If true, then looping edges are used to decorate predicates that call themselves
directly. Otherwise, such direct recursion is hidden.
- hide_list(list(pred_ind))/[]
- A list of predicate (name/arity) to hide from the graph.
- arrowhead(arrow_type)/vee
- Dot arrowhead name as an atom, for all call edges.
- export_style(node_style)/bold
- Dot node style for exported predicates.
- dynamic_shape(node_shape)/box
- Dot node shape for dynamic predicates.
- dynamic_style(node_style)/filled
- Dot node style for dynamic predicates.
- multifile_shape(node_shape)/box
- Dot node shape for multifile predicates.
- multifile_style(node_style)/diagonals
- Dot node style for multifile predicates.
- recorded_shape(node_shape)/octagon
- Dot node shape for recorded facts.
- recorded_style(node_style)/filled
- Dot node style for recorded facts.
- mutate_style(line_style)/dashed
- Dot line style for edges representing mutation of a dynamic predicate.
- read_style(line_style)/solid
- Dot line style for edges representing readed of a recorded fact.
- write_style(line_style)/dashed
- Dot line style for edges representing writing of a recored fact.
- font(S:string)
- Font family (as a list of codes) for all labels. How these names are
interpreted depends on your host operating system. On Mac OS X, I find
I am able to use any font available in the "Font Book" application with
the name written exactly (including spaces) as in the "Font" column.
Default is "Times".
- linkbase(Base:atom)
- If present, each predicate node will have a URL attribute pointing to
a URL formed by appending Module:Name/Arity to Base. Thus, if the output
format supports links, you will be able to click on the nodes to follow
the links, eg to an SWI documentation server..
Types for Dot attributes:
see http://graphviz.org/Documentation.php for more details on
line_style ---> solid ; dashed ; dotted ; bold.
arrow_type ---> normal ; vee ; empty ; box ; none ; dot ; ... .
node_shape ---> box ; ellipse ; circle ; diamond ; trapezium ; parallelogram
; house ; square ; pentagon ; hexagon ; septagon ; octagon ; ... .
node_style ---> solid ; dashed ; dotted ; bold ; rounded
; diagonals ; filled ; striped ; wedged.
- module_dotpdf(+Mod, Opts) is det
- Writes a call graph for module Mod as a PDF file named "[Mod].pdf".
Equivalent to module_render/2 with
format(pdf)
option supplied.
- module_render(+Mod, Opts) is det
- Writes a call graph for module Mod as a file named "<Mod>.<Fmt>" where
Fmt is one of the formats supported by Graphviz and is supplied as an option
As well as the options accepted by module_dot/2, this predicate also accepts:
- format(atom)/pdf
- Any of the formats supported by Graphviz, eg pdf, ps, svg, png etc.
- method(Method:graphviz_method)/unflatten
- Determines which GraphViz programs are used to render the graph. The type
graphviz_method is defined as:
graphviz_method ---> dot ; neato; fdp ; sfdp ; circo ; twopi
; unflatten(list(unflatten_opt))
; unflatten.
unflatten_opt ---> l(N:natural) % -l<N>
; fl(N:natural) % -f -l<N>
; c(natural). % -c<N>
The unflatten methods filter the graph through unflatten before passing
on to dot.
- modules_dot(+Modules:list(module), +Opts, +Name) is det
- Mostly like module_dot/2, but takes a list of module names instead of
a single module name. Output is written to a dot file named Name.
It understands the same options, but in addition:
- cluster_recorded(Flag:oneof([false, true, by_key]))/false
- If true, then all recorded items are collected into a seperate cluster.
If by_key, then all recorded items are collected multiple clusters, one
for each distinct key..
- modules_dotpdf(+Modules:list(module), +Opts, +Name) is det
- Equivalent to modules_render/3 with
format(pdf)
option supplied.
- modules_render(+Modules:list(module), +Opts, +Name) is det
- Mostly like module_render/2, but takes a list of module names instead of
a single module name. Output is written to a PDF file named Name.
It understands the same options, but in addition:
- cluster_recorded(Flag:oneof([false, true, by_key]))/false
- If true, then all recorded items are collected into a seperate cluster.
If by_key, then all recorded items are collected multiple clusters, one
for each distinct key..