Tools for programming with Erlang

Text editors

vim

Vim can be used for editing Erlang programs. Vim supports syntax highlighting and parenthesis matching which are both very useful. Unfortunately vim does not indents erlang programs automatically. Thus considerable effort is required in manually indenting the program.


Emacs

Emacs supports syntax highlighting, parenthesis matching and indentation. Emacs also allows running erlang shell in emacs buffer. To indent Erlang programs with emacs following configuration is required:

;;Setting up Emacs for use with Erlang
;;Update the below mentioned paths appropriately based on installation
(add-to-list 'load-path "/usr/local/lib/erlang/lib/tools-2.6.7/emacs/")
(require 'erlang-start)

(add-to-list 'auto-mode-alist '("\\.erl?$" . erlang-mode))
(add-to-list 'auto-mode-alist '("\\.hrl?$" . erlang-mode))
(add-to-list 'auto-mode-alist '("\\.yaws?$" . erlang-mode))
(add-to-list 'auto-mode-alist '("\\.escript?$" . erlang-mode))

(setq erlang-root-dir "/usr/local/lib/erlang")
(add-to-list 'exec-path "/usr/local/lib/erlang/bin")
(setq erlang-man-root-dir "/usr/local/lib/erlang/man")

Please note that path and version number in tools folder can be different in each system. One can use 'locate | grep erlang | grep tools | gre emacs' to find appropriate path on current system. Also note that for .yaws instead of trying to use now unsupported two-mode-mode, default is set to erlang-mode which assumes entire yaws code to be written between <erl></erl> with ehtml output.



Debuggers

debugger

To debug Erlang programs module 'debugger' can be used. To debug a program using debugger use following steps :

  1. Compile program similar to 'c(example.erl, [debug_info])' with debug_info flag.
  2. Start debugger using 'debugger:start()'
  3. Set desired break-points. Also enable auto-attach on first-call and break.
  4. Run the program to be debugged. The debugger will automatically break the program at first-call. Now you can step, next, continue or finish the program. At each break-point values of variables bound in current scope along with messages left in message queue can be seen.
debugger modules supports debugging of concurrent and distributed programs. Hence even if a new process is spawned on same node or other node using the module being debugged, then full debugging functionality would be available for spawned process too.



Profiling

cprof

cprof can be used to find out how many times each function has been called. This information can later be used to optimize functions which are called more often. This profiling is not as good as other methods as it does not reports time taken by each function, but it has advantage of being lightwieght. To use cprof following steps can be used:

  1. Start a new erlang shell for this particular profiling.
  2. Start cprof using : 'cprof:start().'
  3. Run the program / function to be profiled.
  4. Get analysis results for interesting modules using: 'cprof:analyze(<module_name>).'where <module_name> should be replaced by appropriate module name.


eprof

Eprof can be used when total time each function takes to execute is required. This information can be useful in optimizing functions which consume most time and hence provide higher benefits with optimization. To use eprof for profiling following steps can be used:

  1. Execute the function to be profiled using eprof:profile() function. The function supplied as argument must have arity 0. Example invocation is 'eprof:profile(fun sample:main/0).'
  2. When function completes execution, profiling analysis can be obtained using:'eprof:analyze()'


fprof

fprof provides more advanced profiling in comparison to both cprof and eprof. fprof analysis includes information call information about which functions called which other functions and how many times. Recursives calls are captured and used appropriately to determine own execution time and accumulated execution time. To use fprof for profiling use:

  1. Execute function using fprof:apply as: 'fprof:apply(fun mod:name/arity, [Args]).'
  2. Profile the collected trace information in temporary file fprof.trace using: 'fprof:profile().'
  3. Analyze the profiled output using:'fprof:analyze().'
In fprof output for each function there is a three-tuple {[List of callers], Function, [List of called functions]}. Every line in list of callers, function and lists of called function displays {function name, number of times function was called, total accumulated time (i.e. time taken by function to execute including time taken by called functions to execute), own time (i.e. time taken by operations of this function}


percept

Percept is concurrency profiling tool which can help in verifying or learning how much concurrency does a particular application or function has? This information can be later used to optimize concurrency by adjusting number of concurrent processes or blocking receives or messages to improve the overall performance of the program in multi-core or distributed environments. To use percept for concurrency profiling following steps can be used:

  1. Profile concurrent application or function by executing it via percept as : 'percept:profile("temp.percept", {M, F, A}, [procs]).'Here temp.percept can be replaced by any other temporary file name where percept can store its profile information. {M, F, A} should be replaced by module, function and argument list for the entry function.
  2. Analyze profiled information using: 'percept:analyze("temp.percept").'
  3. Start percept webserver using: 'percept:start_webserver().'
  4. Open webbrowser and browse to http://localhost:<port> where value for <port> can be seen in output of start_webserver() call.
Simple rule of thumb while using percept to profile concurrent application is to maximize area under curve, ie to make the graph as rectangular as possible. If graph is not rectangular but appears traingular, semi-circular etc. then there are stages during execution of application where it is not very concurrent.



Documentation

edoc

edoc allows javadoc style documentation for erlang programs. An example module commented with edoc documentation comments is linked here. An example overview.edoc file which is used to generate contents of title page is linked here.
To run edoc to obtain documentation from linked examples use:

  1. Download edoc_example.erl and overview.edoc files linked above to a temporary folder.
  2. Create a folder named documentation inside temporary folder.
  3. Move overview.edoc file to documentation folder. One can also create symbolic link instead of moving original source file. Note that we will create documentation inside documentation folder. But strangely edoc expects one of the input files (overview.edoc) to be present in output folder, so we must place it there before running edoc.
  4. Run edoc from linux terminal using: erl -noshell -run edoc_run packages '[""]' '[{source_path, ["."]}, {dir, "documentation"}]'
    Other option is to run edoc from erl shell using: edoc:run([], [], [{source_path, ["."]}, {dir, "documentation"}]).



Type checking

typer

typer can be used to generate type inferences or -spec() declarations of functions automatically which can later be used by dialyzer for type-checking program. To use typer run: typer dialyzer_example.erl where dialyzer_example.erl can be downloaded from here.


dialyzer

typer explained before just generates -spec() declaration but does not type checks actual program. For type checking program using given -spec() declarations or through success typing following steps can be used: (dialyzer_example.erl)

  1. Build PLT table for dialyzer using: dialyzer --build_plt --apps kernel stdlib erts mnesia eunit
    To add more modules to plt use: dialyzer --add_to_plt --apps crypto sasl common_test ssl reltool ssh inets
    Note that this step may take very long time, sometimes up to 30 minutes or more.
  2. Use dialyzer dialyzer_example.erl to check example program for type errors.
A very nice tutorial on dialyzer and type checking is available at http://learnyousomeerlang.com/dialyzer



Coverage analysis

cover

cover can be used to see which lines of code are getting executed and also see count of how many times each line has been executed. This can be helpful in ensuring that unit tests check all possible control flow and logic statements. Following steps can be used for obtaining coverage analysis using cover module :

  1. Start cover using cover:start().
  2. Compile the module to be tested with appropriate debug flags using cover:compile("erl-source-file", [{d, 'TEST'}]).
  3. Run all tests using something similar to <module>:test().
  4. Export coverage analysis to html file using cover:analyse_to_file(<module>, "html-file", [html]).