aboutsummaryrefslogtreecommitdiffstats
path: root/lib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tools')
-rw-r--r--lib/tools/c_src/Makefile.in8
-rw-r--r--lib/tools/doc/src/book.xml4
-rw-r--r--lib/tools/doc/src/cover.xml2
-rw-r--r--lib/tools/doc/src/cover_chapter.xml4
-rw-r--r--lib/tools/doc/src/cprof.xml4
-rw-r--r--lib/tools/doc/src/cprof_chapter.xml4
-rw-r--r--lib/tools/doc/src/eprof.xml2
-rw-r--r--lib/tools/doc/src/erlang_mode.xml4
-rw-r--r--lib/tools/doc/src/erlang_mode_chapter.xml4
-rw-r--r--lib/tools/doc/src/fascicules.xml2
-rw-r--r--lib/tools/doc/src/fprof.xml4
-rw-r--r--lib/tools/doc/src/fprof_chapter.xml4
-rw-r--r--lib/tools/doc/src/instrument.xml4
-rw-r--r--lib/tools/doc/src/lcnt.xml4
-rw-r--r--lib/tools/doc/src/lcnt_chapter.xml4
-rw-r--r--lib/tools/doc/src/make.xml4
-rw-r--r--lib/tools/doc/src/notes.xml109
-rw-r--r--lib/tools/doc/src/notes_history.xml4
-rw-r--r--lib/tools/doc/src/part.xml4
-rw-r--r--lib/tools/doc/src/part_notes.xml4
-rw-r--r--lib/tools/doc/src/part_notes_history.xml4
-rw-r--r--lib/tools/doc/src/ref_man.xml4
-rw-r--r--lib/tools/doc/src/tags.xml4
-rw-r--r--lib/tools/doc/src/xref.xml2
-rw-r--r--lib/tools/doc/src/xref_chapter.xml4
-rw-r--r--lib/tools/emacs/erlang-skels.el24
-rw-r--r--lib/tools/emacs/erlang.el52
-rw-r--r--lib/tools/emacs/test.erl.indented29
-rw-r--r--lib/tools/emacs/test.erl.orig29
-rw-r--r--lib/tools/src/cover.erl185
-rw-r--r--lib/tools/src/lcnt.erl360
-rw-r--r--lib/tools/src/tools.app.src22
-rw-r--r--lib/tools/src/tools.appup.src40
-rw-r--r--lib/tools/src/xref_compiler.erl4
-rw-r--r--lib/tools/src/xref_reader.erl10
-rw-r--r--lib/tools/src/xref_utils.erl4
-rw-r--r--lib/tools/test/cover_SUITE.erl141
-rw-r--r--lib/tools/test/cover_SUITE_data/f.erl7
-rw-r--r--lib/tools/test/eprof_SUITE.erl18
-rw-r--r--lib/tools/test/lcnt_SUITE.erl153
-rw-r--r--lib/tools/test/lcnt_SUITE_data/ehb_3_3_hist.lcntbin0 -> 601135 bytes
-rw-r--r--lib/tools/test/tools_SUITE.erl8
-rw-r--r--lib/tools/test/xref_SUITE.erl18
-rw-r--r--lib/tools/test/xref_SUITE_data/read/read.erl27
-rw-r--r--lib/tools/vsn.mk2
45 files changed, 853 insertions, 481 deletions
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index aea5686ae9..b1eb69f9dc 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -96,8 +96,11 @@ DRIVERS=
ifneq ($(strip $(ETHR_LIB_NAME)),)
# Need ethread package for emem
+ifneq ($(findstring ose,$(TARGET)),ose)
+# Do not build on OSE
PROGS += $(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@
endif
+endif
EMEM_OBJ_DIR=$(OBJ_DIR)/emem
CREATE_DIRS += $(EMEM_OBJ_DIR)
@@ -148,7 +151,12 @@ ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE
_create_dirs := $(shell mkdir -p $(CREATE_DIRS))
+ifneq ($(findstring ose,$(TARGET)),ose)
all: $(PROGS) $(DRIVERS)
+else
+# Do not build dynamic files on OSE
+all:
+endif
$(ERTS_LIB):
$(make_verbose)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
diff --git a/lib/tools/doc/src/book.xml b/lib/tools/doc/src/book.xml
index 96f6c426c3..6260bcdf3a 100644
--- a/lib/tools/doc/src/book.xml
+++ b/lib/tools/doc/src/book.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE book SYSTEM "book.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml
index beefd4ee8d..07ffa65e3d 100644
--- a/lib/tools/doc/src/cover.xml
+++ b/lib/tools/doc/src/cover.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
diff --git a/lib/tools/doc/src/cover_chapter.xml b/lib/tools/doc/src/cover_chapter.xml
index 5083b01f1d..f29f59bee0 100644
--- a/lib/tools/doc/src/cover_chapter.xml
+++ b/lib/tools/doc/src/cover_chapter.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2001</year><year>2011</year>
+ <year>2001</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/cprof.xml b/lib/tools/doc/src/cprof.xml
index 2dc419d29c..553597837e 100644
--- a/lib/tools/doc/src/cprof.xml
+++ b/lib/tools/doc/src/cprof.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>2002</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/cprof_chapter.xml b/lib/tools/doc/src/cprof_chapter.xml
index cf6a6f843a..6536d43e0f 100644
--- a/lib/tools/doc/src/cprof_chapter.xml
+++ b/lib/tools/doc/src/cprof_chapter.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2002</year><year>2009</year>
+ <year>2002</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml
index 8b4986297a..3ebacf5546 100644
--- a/lib/tools/doc/src/eprof.xml
+++ b/lib/tools/doc/src/eprof.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
diff --git a/lib/tools/doc/src/erlang_mode.xml b/lib/tools/doc/src/erlang_mode.xml
index 794224d601..747c41d554 100644
--- a/lib/tools/doc/src/erlang_mode.xml
+++ b/lib/tools/doc/src/erlang_mode.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2003</year><year>2011</year>
+ <year>2003</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/erlang_mode_chapter.xml b/lib/tools/doc/src/erlang_mode_chapter.xml
index 4ffa224ea5..3be1d53ca2 100644
--- a/lib/tools/doc/src/erlang_mode_chapter.xml
+++ b/lib/tools/doc/src/erlang_mode_chapter.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2003</year><year>2011</year>
+ <year>2003</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/fascicules.xml b/lib/tools/doc/src/fascicules.xml
index 0678195e07..37feca543f 100644
--- a/lib/tools/doc/src/fascicules.xml
+++ b/lib/tools/doc/src/fascicules.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
<fascicules>
diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml
index 8babf50033..ef8b82c9fa 100644
--- a/lib/tools/doc/src/fprof.xml
+++ b/lib/tools/doc/src/fprof.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2001</year><year>2009</year>
+ <year>2001</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/fprof_chapter.xml b/lib/tools/doc/src/fprof_chapter.xml
index 3f40d93f40..462b3f9579 100644
--- a/lib/tools/doc/src/fprof_chapter.xml
+++ b/lib/tools/doc/src/fprof_chapter.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2001</year><year>2009</year>
+ <year>2001</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml
index b7e48ea306..3f278b63cd 100644
--- a/lib/tools/doc/src/instrument.xml
+++ b/lib/tools/doc/src/instrument.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1998</year><year>2011</year>
+ <year>1998</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml
index 3c55e4e422..9754b107fe 100644
--- a/lib/tools/doc/src/lcnt.xml
+++ b/lib/tools/doc/src/lcnt.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>2009</year>
- <year>2010</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/lcnt_chapter.xml b/lib/tools/doc/src/lcnt_chapter.xml
index 8f44b23f59..1b8595749d 100644
--- a/lib/tools/doc/src/lcnt_chapter.xml
+++ b/lib/tools/doc/src/lcnt_chapter.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2009</year><year>2010</year>
+ <year>2009</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/make.xml b/lib/tools/doc/src/make.xml
index 1c8df67abf..f4d64fa9e2 100644
--- a/lib/tools/doc/src/make.xml
+++ b/lib/tools/doc/src/make.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1996</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 2e4c354fbd..faee5efd43 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -30,6 +30,115 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 2.7</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add log2 histogram to lcnt for lock wait time</p>
+ <p>
+ Own Id: OTP-12059</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 2.6.15</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed <c>erlang:bitstr_to_list/1</c> and
+ <c>erlang:list_to_bitstr/1</c>. They were added by
+ mistake, and have always raised an <c>undefined</c>
+ exception when called.</p>
+ <p>
+ Own Id: OTP-11942</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 2.6.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed the support for the query keyword from emacs mode
+ (Thanks to Paul Oliver)</p>
+ <p>
+ Own Id: OTP-11568</p>
+ </item>
+ <item>
+ <p>
+ Emacs mode improvements (Thanks to Steve Vinoski)</p>
+ <p>
+ Own Id: OTP-11601</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ The emacs erlang mode now match erlang keywords more
+ carefully (Thanks to Steve Vinoski)</p>
+ <p>
+ Own Id: OTP-11786</p>
+ </item>
+ <item>
+ <p>
+ The emacs erlang-mode now auto loads for more file types
+ (Thanks to Phil Hagelberg)</p>
+ <p>
+ Own Id: OTP-11788</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ <c>cover</c> can run on itself. Also, support for reading
+ BEAM files produced by ancient OTP versions before R9C
+ has been removed.</p>
+ <p>
+ Own Id: OTP-11692</p>
+ </item>
+ <item>
+ <p>
+ Support maps in cover</p>
+ <p>
+ Own Id: OTP-11764</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.6.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/doc/src/notes_history.xml b/lib/tools/doc/src/notes_history.xml
index 3791d5270a..2058dd8fde 100644
--- a/lib/tools/doc/src/notes_history.xml
+++ b/lib/tools/doc/src/notes_history.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/part.xml b/lib/tools/doc/src/part.xml
index bf9e1ebbec..5b03e1db55 100644
--- a/lib/tools/doc/src/part.xml
+++ b/lib/tools/doc/src/part.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2010</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/part_notes.xml b/lib/tools/doc/src/part_notes.xml
index b8b67889c2..3527d5e3d9 100644
--- a/lib/tools/doc/src/part_notes.xml
+++ b/lib/tools/doc/src/part_notes.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2009</year>
+ <year>2004</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/part_notes_history.xml b/lib/tools/doc/src/part_notes_history.xml
index da637f380a..43c0abd05a 100644
--- a/lib/tools/doc/src/part_notes_history.xml
+++ b/lib/tools/doc/src/part_notes_history.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part>
<header>
<copyright>
<year>2006</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/ref_man.xml b/lib/tools/doc/src/ref_man.xml
index d4861af9f3..7b68e18a75 100644
--- a/lib/tools/doc/src/ref_man.xml
+++ b/lib/tools/doc/src/ref_man.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE application SYSTEM "application.dtd">
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2010</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/tags.xml b/lib/tools/doc/src/tags.xml
index 54b5a4914c..0aa0ca8e35 100644
--- a/lib/tools/doc/src/tags.xml
+++ b/lib/tools/doc/src/tags.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1998</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/xref.xml b/lib/tools/doc/src/xref.xml
index 891a81639a..da16efa005 100644
--- a/lib/tools/doc/src/xref.xml
+++ b/lib/tools/doc/src/xref.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
diff --git a/lib/tools/doc/src/xref_chapter.xml b/lib/tools/doc/src/xref_chapter.xml
index 566776eab0..db9f774186 100644
--- a/lib/tools/doc/src/xref_chapter.xml
+++ b/lib/tools/doc/src/xref_chapter.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2000</year><year>2012</year>
+ <year>2000</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el
index 527e812444..7379215d68 100644
--- a/lib/tools/emacs/erlang-skels.el
+++ b/lib/tools/emacs/erlang-skels.el
@@ -109,32 +109,32 @@ include separators of the form %%--...")
;; Expression templates:
(defvar erlang-skel-case
'((erlang-skel-skip-blank) o >
- "case " p " of" n> p "_ ->" n> p "ok" n> "end" p)
+ "case " p " of" n> p "_ ->" n> p "ok" n "end" > p)
"*The skeleton of a `case' expression.
Please see the function `tempo-define-template'.")
(defvar erlang-skel-if
'((erlang-skel-skip-blank) o >
- "if" n> p " ->" n> p "ok" n> "end" p)
+ "if" n> p " ->" n> p "ok" n "end" > p)
"The skeleton of an `if' expression.
Please see the function `tempo-define-template'.")
(defvar erlang-skel-receive
'((erlang-skel-skip-blank) o >
- "receive" n> p "_ ->" n> p "ok" n> "end" p)
+ "receive" n> p "_ ->" n> p "ok" n "end" > p)
"*The skeleton of a `receive' expression.
Please see the function `tempo-define-template'.")
(defvar erlang-skel-receive-after
'((erlang-skel-skip-blank) o >
- "receive" n> p "_ ->" n> p "ok" n> "after " p "T ->" n>
- p "ok" n> "end" p)
+ "receive" n> p "_ ->" n> p "ok" n "after " > p "T ->" n>
+ p "ok" n "end" > p)
"*The skeleton of a `receive' expression with an `after' clause.
Please see the function `tempo-define-template'.")
(defvar erlang-skel-receive-loop
'(& o "loop(" p ") ->" n> "receive" n> p "_ ->" n>
- "loop(" p ")" n> "end.")
+ "loop(" p ")" n "end." >)
"*The skeleton of a simple `receive' loop.
Please see the function `tempo-define-template'.")
@@ -256,8 +256,8 @@ Please see the function `tempo-define-template'.")
"loop(From) ->" n>
"receive" n>
p "_ ->" n>
- "loop(From)" n>
- "end." n
+ "loop(From)" n
+ "end." > n
)
"*Template of a small server.
Please see the function `tempo-define-template'.")
@@ -291,8 +291,8 @@ Please see the function `tempo-define-template'.")
"{ok, Pid} ->" n>
"{ok, Pid};" n>
"Error ->" n>
- "Error" n>
- "end." n
+ "Error" n
+ "end." > n
n
(erlang-skel-separator-start 2)
"%% @private" n
@@ -421,8 +421,8 @@ Please see the function `tempo-define-template'.")
"{ok, Pid} ->" n>
"{ok, Pid, #state{}};" n>
"Error ->" n>
- "Error" n>
- "end." n
+ "Error" n
+ "end." > n
n
(erlang-skel-separator-start 2)
"%% @private" n
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index c395d22356..c56759ebb9 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -7,7 +7,7 @@
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 1996-2013. All Rights Reserved.
+;; Copyright Ericsson AB 1996-2014. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
@@ -73,6 +73,8 @@
;; M-x set-variable RET debug-on-error RET t RET
;;; Code:
+(eval-when-compile (require 'cl))
+
;; Variables:
(defconst erlang-version "2.7"
@@ -620,7 +622,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"if"
"let"
"of"
- "query"
"receive"
"try"
"when")
@@ -663,6 +664,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"is_function"
"is_integer"
"is_list"
+ "is_map"
"is_number"
"is_pid"
"is_port"
@@ -714,7 +716,8 @@ resulting regexp is surrounded by \\_< and \\_>."
"pos_integer"
"string"
"term"
- "timeout")
+ "timeout"
+ "map")
"Erlang type specs types"))
(eval-and-compile
@@ -771,6 +774,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"is_function"
"is_integer"
"is_list"
+ "is_map"
"is_number"
"is_pid"
"is_port"
@@ -790,6 +794,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"list_to_tuple"
"load_module"
"make_ref"
+ "map_size"
"max"
"min"
"module_loaded"
@@ -848,7 +853,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"append_element"
"await_proc_exit"
"await_sched_wall_time_modifications"
- "bitstr_to_list"
"bump_reductions"
"call_on_load_function"
"cancel_timer"
@@ -882,6 +886,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"flush_monitor_message"
"format_cpu_topology"
"fun_info"
+ "fun_info_mfa"
"fun_to_list"
"function_exported"
"garbage_collect_message_area"
@@ -894,7 +899,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"hibernate"
"insert_element"
"is_builtin"
- "list_to_bitstr"
"load_nif"
"loaded"
"localtime"
@@ -1415,6 +1419,10 @@ Other commands:
(if (boundp 'after-change-major-mode-hook)
(run-hooks 'after-change-major-mode-hook)))
+;;;###autoload
+(dolist (r '("\\.erl$" "\\.app\\.src$" "\\.escript"
+ "\\.hrl$" "\\.xrl$" "\\.yrl" "/ebin/.+\\.app"))
+ (add-to-list 'auto-mode-alist (cons r 'erlang-mode)))
(defun erlang-syntax-table-init ()
(if (null erlang-mode-syntax-table)
@@ -2565,9 +2573,9 @@ Value is list (stack token-start token-type in-what)."
(erlang-pop stack))
(if (and stack (memq (car (car stack)) '(icr begin fun try)))
(erlang-pop stack))))
- ((looking-at "catch.*of")
+ ((looking-at "catch\\b.*of")
t)
- ((looking-at "catch\\s *\\($\\|%\\|.*->\\)")
+ ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
;; Must pop top icr layer, `catch' in try/catch
;;will push a new layer next.
(progn
@@ -2600,18 +2608,24 @@ Value is list (stack token-start token-type in-what)."
(if (save-excursion
(goto-char (match-end 1))
(erlang-skip-blank to)
+ ;; Use erlang-variable-regexp here to look for an
+ ;; optional variable name to match EEP37 named funs.
+ (if (looking-at erlang-variable-regexp)
+ (progn
+ (goto-char (match-end 0))
+ (erlang-skip-blank to)))
(eq (following-char) ?\())
(erlang-push (list 'fun token (current-column)) stack)))
- ((looking-at "\\(begin\\|query\\)[^_a-zA-Z0-9]")
+ ((looking-at "\\(begin\\)[^_a-zA-Z0-9]")
(erlang-push (list 'begin token (current-column)) stack))
;; Normal when case
;;((looking-at "when\\s ")
;;((looking-at "when\\s *\\($\\|%\\)")
((looking-at "when[^_a-zA-Z0-9]")
(erlang-push (list 'when token (current-column)) stack))
- ((looking-at "catch.*of")
+ ((looking-at "catch\\b.*of")
t)
- ((looking-at "catch\\s *\\($\\|%\\|.*->\\)")
+ ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
(erlang-push (list 'icr token (current-column)) stack))
;;(erlang-push (list '-> token (current-column)) stack))
;;((looking-at "^of$")
@@ -2902,7 +2916,7 @@ Return nil if inside string, t if in a comment."
(if stack
(erlang-caddr (car stack))
0))
- ((looking-at "catch\\($\\|[^_a-zA-Z0-9]\\)")
+ ((looking-at "catch\\b\\($\\|[^_a-zA-Z0-9]\\)")
;; Are we in a try
(let ((start (if (eq (car stack-top) '->)
(car (cdr stack))
@@ -3038,7 +3052,7 @@ This assumes that the preceding expression is either simple
\(i.e. an atom) or parenthesized."
(save-excursion
(or arg (setq arg 1))
- (forward-sexp (- arg))
+ (ignore-errors (forward-sexp (- arg)))
(let ((col (current-column)))
(skip-chars-backward " \t")
;; Special hack to handle: (note line break)
@@ -3112,13 +3126,13 @@ This assumes that the preceding expression is either simple
(defun erlang-at-keyword ()
"Are we looking at an Erlang keyword which will increase indentation?"
- (looking-at (concat "\\(when\\|if\\|fun\\|case\\|begin\\|query\\|"
- "of\\|receive\\|after\\|catch\\|try\\)[^_a-zA-Z0-9]")))
+ (looking-at (concat "\\(when\\|if\\|fun\\|case\\|begin\\|"
+ "of\\|receive\\|after\\|catch\\|try\\)\\b")))
(defun erlang-at-operator ()
"Are we looking at an Erlang operator?"
(looking-at
- "\\(bnot\\|div\\|mod\\|band\\|bor\\|bxor\\|bsl\\|bsr\\)[^_a-zA-Z0-9]"))
+ "\\(bnot\\|div\\|mod\\|band\\|bor\\|bxor\\|bsl\\|bsr\\)\\b"))
(defun erlang-comment-indent ()
"Compute Erlang comment indentation.
@@ -3645,6 +3659,10 @@ Normally used in conjunction with `erlang-beginning-of-clause', e.g.:
(setq cont nil))
((looking-at "\\s *\\($\\|%\\)")
(forward-line 1))
+ ((looking-at "\\s *<<[^>]*?>>")
+ (when (zerop res)
+ (setq res (+ 1 res)))
+ (goto-char (match-end 0)))
((looking-at "\\s *,")
(setq res (+ 1 res))
(goto-char (match-end 0)))
@@ -3926,7 +3944,7 @@ non-whitespace characters following the point on the current line."
(self-insert-command arg)
;; Was this the second char in bit-syntax open (`<<')?
- (unless (< (point) 2)
+ (unless (<= (point) 2)
(save-excursion
(backward-char 2)
(when (and (eq (char-after (point)) ?<)
@@ -3947,7 +3965,7 @@ non-whitespace characters following the point on the current line."
(defun erlang-after-bitsyntax-close ()
"Return t if point is immediately after a bit-syntax close parenthesis (`>>')."
- (and (>= (point) 2)
+ (and (>= (point) 3)
(save-excursion
(backward-char 2)
(and (eq (char-after (point)) ?>)
diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented
index 7e61bcc45b..1c1086ca58 100644
--- a/lib/tools/emacs/test.erl.indented
+++ b/lib/tools/emacs/test.erl.indented
@@ -483,6 +483,19 @@ indent_fun() ->
Y = true andalso
kalle
end),
+ %% check EEP37 named funs
+ Fn1 = fun Fact(N) when N > 0 ->
+ F = Fact(N-1),
+ N * F;
+ Fact(0) ->
+ 1
+ end,
+ %% check anonymous funs too
+ Fn2 = fun(0) ->
+ 1;
+ (N) ->
+ N
+ end,
ok.
indent_try_catch() ->
@@ -731,3 +744,19 @@ commas_first() ->
] }
]
}.
+
+
+%% this used to result in a scan-sexp error
+[{
+ }].
+
+%% this used to result in 2x the correct indentation within the function
+%% body, due to the function name being mistaken for a keyword
+catcher(N) ->
+ try generate_exception(N) of
+ Val -> {N, normal, Val}
+ catch
+ throw:X -> {N, caught, thrown, X};
+ exit:X -> {N, caught, exited, X};
+ error:X -> {N, caught, error, X}
+ end.
diff --git a/lib/tools/emacs/test.erl.orig b/lib/tools/emacs/test.erl.orig
index 932758997d..a9d09000d2 100644
--- a/lib/tools/emacs/test.erl.orig
+++ b/lib/tools/emacs/test.erl.orig
@@ -483,6 +483,19 @@ Var = spawn(fun(X)
Y = true andalso
kalle
end),
+%% check EEP37 named funs
+Fn1 = fun Fact(N) when N > 0 ->
+ F = Fact(N-1),
+ N * F;
+Fact(0) ->
+ 1
+ end,
+%% check anonymous funs too
+ Fn2 = fun(0) ->
+1;
+ (N) ->
+ N
+ end,
ok.
indent_try_catch() ->
@@ -731,3 +744,19 @@ commas_first() ->
] }
]
}.
+
+
+%% this used to result in a scan-sexp error
+[{
+}].
+
+%% this used to result in 2x the correct indentation within the function
+%% body, due to the function name being mistaken for a keyword
+catcher(N) ->
+try generate_exception(N) of
+Val -> {N, normal, Val}
+catch
+throw:X -> {N, caught, thrown, X};
+exit:X -> {N, caught, exited, X};
+error:X -> {N, caught, error, X}
+end.
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 13d9aefb0c..113fa24bd5 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -89,8 +89,9 @@
flush/1,
stop/0, stop/1]).
-export([remote_start/1,get_main_node/0]).
-%-export([bump/5]).
--export([transform/4]). % for test purposes
+
+%% Used internally to ensure we upgrade the code to the latest version.
+-export([main_process_loop/1,remote_process_loop/1]).
-record(main_state, {compiled=[], % [{Module,File}]
imported=[], % [{Module,File,ImportFile}]
@@ -110,7 +111,6 @@
-define(BUMP_REC_NAME,bump).
-record(vars, {module, % atom() Module name
- vsn, % atom()
init_info=[], % [{M,F,A,C,L}]
@@ -230,25 +230,9 @@ compile_directory(Dir) when is_list(Dir) ->
compile_directory(Dir, Options) when is_list(Dir), is_list(Options) ->
case file:list_dir(Dir) of
{ok, Files} ->
-
- %% Filter out all erl files (except cover.erl)
- ErlFileNames =
- lists:filter(fun("cover.erl") ->
- false;
- (File) ->
- case filename:extension(File) of
- ".erl" -> true;
- _ -> false
- end
- end,
- Files),
-
- %% Create a list of .erl file names (incl path) and call
- %% compile_modules/2 with the list of file names.
- ErlFiles = lists:map(fun(ErlFileName) ->
- filename:join(Dir, ErlFileName)
- end,
- ErlFileNames),
+ ErlFiles = [filename:join(Dir, File) ||
+ File <- Files,
+ filename:extension(File) =:= ".erl"],
compile_modules(ErlFiles, Options);
Error ->
Error
@@ -262,7 +246,7 @@ compile_modules([File|Files], Options, Result) ->
R = call({compile, File, Options}),
compile_modules(Files,Options,[R|Result]);
compile_modules([],_Opts,Result) ->
- reverse(Result).
+ lists:reverse(Result).
filter_options(Options) ->
lists:filter(fun(Option) ->
@@ -320,25 +304,9 @@ compile_beam_directory() ->
compile_beam_directory(Dir) when is_list(Dir) ->
case file:list_dir(Dir) of
{ok, Files} ->
-
- %% Filter out all beam files (except cover.beam)
- BeamFileNames =
- lists:filter(fun("cover.beam") ->
- false;
- (File) ->
- case filename:extension(File) of
- ".beam" -> true;
- _ -> false
- end
- end,
- Files),
-
- %% Create a list of .beam file names (incl path) and call
- %% compile_beam/1 for each such file name
- BeamFiles = lists:map(fun(BeamFileName) ->
- filename:join(Dir, BeamFileName)
- end,
- BeamFileNames),
+ BeamFiles = [filename:join(Dir, File) ||
+ File <- Files,
+ filename:extension(File) =:= ".beam"],
compile_beams(BeamFiles);
Error ->
Error
@@ -350,7 +318,7 @@ compile_beams([File|Files],Result) ->
R = compile_beam(File),
compile_beams(Files,[R|Result]);
compile_beams([],Result) ->
- reverse(Result).
+ lists:reverse(Result).
%% analyse(Module) ->
@@ -613,8 +581,11 @@ main_process_loop(State) ->
Compiled = add_compiled(Module, File,
State#main_state.compiled),
Imported = remove_imported(Module,State#main_state.imported),
- main_process_loop(State#main_state{compiled = Compiled,
- imported = Imported});
+ NewState = State#main_state{compiled = Compiled,
+ imported = Imported},
+ %% This module (cover) could have been reloaded. Make
+ %% sure we run the new code.
+ ?MODULE:main_process_loop(NewState);
error ->
reply(From, {error, File}),
main_process_loop(State)
@@ -639,8 +610,11 @@ main_process_loop(State) ->
end,
reply(From,Reply),
Imported = remove_imported(Module,State#main_state.imported),
- main_process_loop(State#main_state{compiled = Compiled,
- imported = Imported});
+ NewState = State#main_state{compiled = Compiled,
+ imported = Imported},
+ %% This module (cover) could have been reloaded. Make
+ %% sure we run the new code.
+ ?MODULE:main_process_loop(NewState);
{error,no_beam} ->
%% The module has first been compiled from .erl, and now
%% someone tries to compile it from .beam
@@ -857,7 +831,7 @@ remote_process_loop(State) ->
{remote,load_compiled,Compiled} ->
Compiled1 = load_compiled(Compiled,State#remote_state.compiled),
remote_reply(State#remote_state.main_node, ok),
- remote_process_loop(State#remote_state{compiled=Compiled1});
+ ?MODULE:remote_process_loop(State#remote_state{compiled=Compiled1});
{remote,unload,UnloadedModules} ->
unload(UnloadedModules),
@@ -1257,12 +1231,12 @@ add_imported(M, F1, ImportFile, [{M,_F2,ImportFiles}|Imported], Acc) ->
dont_import;
false ->
NewEntry = {M, F1, [ImportFile | ImportFiles]},
- {ok, reverse([NewEntry | Acc]) ++ Imported}
+ {ok, lists:reverse([NewEntry | Acc]) ++ Imported}
end;
add_imported(M, F, ImportFile, [H|Imported], Acc) ->
add_imported(M, F, ImportFile, Imported, [H|Acc]);
add_imported(M, F, ImportFile, [], Acc) ->
- {ok, reverse([{M, F, [ImportFile]} | Acc])}.
+ {ok, lists:reverse([{M, F, [ImportFile]} | Acc])}.
%% Removes a module from the list of imported modules and writes a warning
%% This is done when a module is compiled.
@@ -1383,9 +1357,9 @@ do_compile_beam(Module,Beam,UserOptions) ->
{error,E};
encrypted_abstract_code=E ->
{error,E};
- {Vsn,Code} ->
+ {raw_abstract_v1,Code} ->
Forms0 = epp:interpret_file_attribute(Code),
- {Forms,Vars} = transform(Vsn, Forms0, Module, Beam),
+ {Forms,Vars} = transform(Forms0, Module),
%% We need to recover the source from the compilation
%% info otherwise the newly compiled module will have
@@ -1400,7 +1374,7 @@ do_compile_beam(Module,Beam,UserOptions) ->
{module, Module} ->
%% Store info about all function clauses in database
- InitInfo = reverse(Vars#vars.init_info),
+ InitInfo = lists:reverse(Vars#vars.init_info),
ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}),
%% Store binary code so it can be loaded on remote nodes
@@ -1411,7 +1385,11 @@ do_compile_beam(Module,Beam,UserOptions) ->
_Error ->
do_clear(Module),
error
- end
+ end;
+ {_VSN,_Code} ->
+ %% Wrong version of abstract code. Just report that there
+ %% is no abstract code.
+ {error,no_abstract_code}
end.
get_abstract_code(Module, Beam) ->
@@ -1445,28 +1423,9 @@ get_compile_info(Module, Beam) ->
[]
end.
-transform(Vsn, Code, Module, Beam) when Vsn=:=abstract_v1; Vsn=:=abstract_v2 ->
- Vars0 = #vars{module=Module, vsn=Vsn},
- MainFile=find_main_filename(Code),
- {ok, MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on),
-
- %% Add module and export information to the munged forms
- %% Information about module_info must be removed as this function
- %% is added at compilation
- {ok, {Module, [{exports,Exports1}]}} = beam_lib:chunks(Beam, [exports]),
- Exports2 = lists:filter(fun(Export) ->
- case Export of
- {module_info,_} -> false;
- _ -> true
- end
- end,
- Exports1),
- Forms = [{attribute,1,module,Module},
- {attribute,2,export,Exports2}]++ MungedForms,
- {Forms,Vars};
-transform(Vsn=raw_abstract_v1, Code, Module, _Beam) ->
+transform(Code, Module) ->
MainFile=find_main_filename(Code),
- Vars0 = #vars{module=Module, vsn=Vsn},
+ Vars0 = #vars{module=Module},
{ok,MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on),
{MungedForms,Vars}.
@@ -1486,7 +1445,7 @@ transform_2([Form0|Forms],MungedForms,Vars,MainFile,Switch) ->
transform_2(Forms,[MungedForm|MungedForms],Vars2,MainFile,NewSwitch)
end;
transform_2([],MungedForms,Vars,_,_) ->
- {ok, reverse(MungedForms), Vars}.
+ {ok, lists:reverse(MungedForms), Vars}.
%% Expand short-circuit Boolean expressions.
expand(Expr) ->
@@ -1553,14 +1512,9 @@ aux_var(Vars, N) ->
end.
%% This code traverses the abstract code, stored as the abstract_code
-%% chunk in the BEAM file, as described in absform(3) for Erlang/OTP R8B
-%% (Vsn=abstract_v2).
-%% The abstract format after preprocessing differs slightly from the abstract
-%% format given eg using epp:parse_form, this has been noted in comments.
-%% The switch is turned off when we encounter other files then the main file.
+%% chunk in the BEAM file, as described in absform(3).
+%% The switch is turned off when we encounter other files than the main file.
%% This way we will be able to exclude functions defined in include files.
-munge({function,0,module_info,_Arity,_Clauses},_Vars,_MainFile,_Switch) ->
- ignore; % module_info will be added again when the forms are recompiled
munge({function,Line,Function,Arity,Clauses},Vars,_MainFile,on) ->
Vars2 = Vars#vars{function=Function,
arity=Arity,
@@ -1618,7 +1572,7 @@ munge_clauses([Clause|Clauses], Vars, Lines, MClauses) ->
MClauses])
end;
munge_clauses([], Vars, Lines, MungedClauses) ->
- {reverse(MungedClauses), Vars#vars{lines = Lines}}.
+ {lists:reverse(MungedClauses), Vars#vars{lines = Lines}}.
munge_body(Expr, Vars) ->
munge_body(Expr, Vars, [], []).
@@ -1662,7 +1616,7 @@ munge_body([Expr|Body], Vars, MungedBody, LastExprBumpLines) ->
munge_body(Body, Vars3, MungedExprs1, NewBumps)
end;
munge_body([], Vars, MungedBody, _LastExprBumpLines) ->
- {reverse(MungedBody), Vars}.
+ {lists:reverse(MungedBody), Vars}.
%%% Fix last expression (OTP-8188). A typical example:
%%%
@@ -1800,16 +1754,35 @@ munge_expr({match,Line,ExprL,ExprR}, Vars) ->
munge_expr({tuple,Line,Exprs}, Vars) ->
{MungedExprs, Vars2} = munge_exprs(Exprs, Vars, []),
{{tuple,Line,MungedExprs}, Vars2};
-munge_expr({record,Line,Expr,Exprs}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedExprName, Vars2} = munge_expr(Expr, Vars),
+munge_expr({record,Line,Name,Exprs}, Vars) ->
+ {MungedExprFields, Vars2} = munge_exprs(Exprs, Vars, []),
+ {{record,Line,Name,MungedExprFields}, Vars2};
+munge_expr({record,Line,Arg,Name,Exprs}, Vars) ->
+ {MungedArg, Vars2} = munge_expr(Arg, Vars),
{MungedExprFields, Vars3} = munge_exprs(Exprs, Vars2, []),
- {{record,Line,MungedExprName,MungedExprFields}, Vars3};
+ {{record,Line,MungedArg,Name,MungedExprFields}, Vars3};
munge_expr({record_field,Line,ExprL,ExprR}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{record_field,Line,MungedExprL,MungedExprR}, Vars3};
+ {MungedExprR, Vars2} = munge_expr(ExprR, Vars),
+ {{record_field,Line,ExprL,MungedExprR}, Vars2};
+munge_expr({map,Line,Fields}, Vars) ->
+ %% EEP 43
+ {MungedFields, Vars2} = munge_exprs(Fields, Vars, []),
+ {{map,Line,MungedFields}, Vars2};
+munge_expr({map,Line,Arg,Fields}, Vars) ->
+ %% EEP 43
+ {MungedArg, Vars2} = munge_expr(Arg, Vars),
+ {MungedFields, Vars3} = munge_exprs(Fields, Vars2, []),
+ {{map,Line,MungedArg,MungedFields}, Vars3};
+munge_expr({map_field_assoc,Line,Name,Value}, Vars) ->
+ %% EEP 43
+ {MungedName, Vars2} = munge_expr(Name, Vars),
+ {MungedValue, Vars3} = munge_expr(Value, Vars2),
+ {{map_field_assoc,Line,MungedName,MungedValue}, Vars3};
+munge_expr({map_field_exact,Line,Name,Value}, Vars) ->
+ %% EEP 43
+ {MungedName, Vars2} = munge_expr(Name, Vars),
+ {MungedValue, Vars3} = munge_expr(Value, Vars2),
+ {{map_field_exact,Line,MungedName,MungedValue}, Vars3};
munge_expr({cons,Line,ExprH,ExprT}, Vars) ->
{MungedExprH, Vars2} = munge_expr(ExprH, Vars),
{MungedExprT, Vars3} = munge_expr(ExprT, Vars2),
@@ -1871,18 +1844,12 @@ munge_expr({'try',Line,Body,Clauses,CatchClauses,After}, Vars) ->
{MungedAfter, Vars4} = munge_body(After, Vars3),
{{'try',Line,MungedBody,MungedClauses,MungedCatchClauses,MungedAfter},
Vars4};
-%% Difference in abstract format after preprocessing: Funs get an extra
-%% element Extra.
-%% NOT NECESSARY FOR Vsn=raw_abstract_v1
-munge_expr({'fun',Line,{function,Name,Arity},_Extra}, Vars) ->
- {{'fun',Line,{function,Name,Arity}}, Vars};
-munge_expr({'fun',Line,{clauses,Clauses},_Extra}, Vars) ->
- {MungedClauses,Vars2}=munge_clauses(Clauses, Vars),
- {{'fun',Line,{clauses,MungedClauses}}, Vars2};
munge_expr({'fun',Line,{clauses,Clauses}}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
{MungedClauses,Vars2}=munge_clauses(Clauses, Vars),
{{'fun',Line,{clauses,MungedClauses}}, Vars2};
+munge_expr({named_fun,Line,Name,Clauses}, Vars) ->
+ {MungedClauses,Vars2}=munge_clauses(Clauses, Vars),
+ {{named_fun,Line,Name,MungedClauses}, Vars2};
munge_expr({bin,Line,BinElements}, Vars) ->
{MungedBinElements,Vars2} = munge_exprs(BinElements, Vars, []),
{{bin,Line,MungedBinElements}, Vars2};
@@ -1901,7 +1868,7 @@ munge_exprs([Expr|Exprs], Vars, MungedExprs) ->
{MungedExpr, Vars2} = munge_expr(Expr, Vars),
munge_exprs(Exprs, Vars2, [MungedExpr|MungedExprs]);
munge_exprs([], Vars, MungedExprs) ->
- {reverse(MungedExprs), Vars}.
+ {lists:reverse(MungedExprs), Vars}.
%% Every qualifier is decorated with a counter.
munge_qualifiers(Qualifiers, Vars) ->
@@ -1920,7 +1887,7 @@ munge_qs([Expr|Qs], Vars, MQs) ->
{MungedExpr, Vars2} = munge_expr(Expr, Vars),
munge_qs1(Qs, L, MungedExpr, Vars, Vars2, MQs);
munge_qs([], Vars, MQs) ->
- {reverse(MQs), Vars}.
+ {lists:reverse(MQs), Vars}.
munge_qs1(Qs, Line, NQ, Vars, Vars2, MQs) ->
case new_bumps(Vars2, Vars) of
@@ -2113,7 +2080,7 @@ merge_clauses([{{M,F,A,_C1},R1},{{M,F,A,C2},R2}|Clauses], MFun, Result) ->
merge_clauses([{{M,F,A,_C},R}|Clauses], MFun, Result) ->
merge_clauses(Clauses, MFun, [{{M,F,A},R}|Result]);
merge_clauses([], _Fun, Result) ->
- reverse(Result).
+ lists:reverse(Result).
merge_functions([{_MFA,R}|Functions], MFun) ->
merge_functions(Functions, MFun, R);
@@ -2434,14 +2401,6 @@ not_loaded(_Module,_Else, State) ->
%%%--Div-----------------------------------------------------------------
-reverse(List) ->
- reverse(List,[]).
-reverse([H|T],Acc) ->
- reverse(T,[H|Acc]);
-reverse([],Acc) ->
- Acc.
-
-
escape_lt_and_gt(Rawline,HTML) when HTML =/= true ->
Rawline;
escape_lt_and_gt(Rawline,_HTML) ->
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index f13a297ecf..f1251fddab 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -1,4 +1,3 @@
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -62,6 +61,8 @@
locations/1,
inspect/1,
inspect/2,
+ histogram/1,
+ histogram/2,
information/0,
swap_pid_keys/0,
% set options
@@ -90,14 +91,14 @@
duration = 0
}).
-
-record(stats, {
- file,
- line,
- tries,
- colls,
- time, % us
- nt % #timings collected
+ file :: atom(),
+ line :: non_neg_integer(),
+ tries :: non_neg_integer(),
+ colls :: non_neg_integer(),
+ time :: non_neg_integer(), % us
+ nt :: non_neg_integer(), % #timings collected
+ hist :: tuple() % histogram
}).
-record(lock, {
@@ -116,7 +117,9 @@
colls,
cr, % collision ratio
time,
- dtr % time duration ratio
+ dtr, % time duration ratio
+ %% new
+ hist % log2 histogram of lock wait_time
}).
@@ -128,7 +131,7 @@
%% -------------------------------------------------------------------- %%
start() -> gen_server:start({local, ?MODULE}, ?MODULE, [], []).
-stop() -> gen_server:cast(?MODULE, stop).
+stop() -> gen_server:call(?MODULE, stop, infinity).
init([]) -> {ok, #state{ locks = [], duration = 0 } }.
%% -------------------------------------------------------------------- %%
@@ -172,6 +175,8 @@ conflicts() -> call({conflicts, []}).
conflicts(Opts) -> call({conflicts, Opts}).
inspect(Lock) -> call({inspect, Lock, []}).
inspect(Lock, Opts) -> call({inspect, Lock, Opts}).
+histogram(Lock) -> call({histogram, Lock, []}).
+histogram(Lock, Opts)-> call({histogram, Lock, Opts}).
information() -> call(information).
swap_pid_keys() -> call(swap_pid_keys).
raw() -> call(raw).
@@ -284,14 +289,14 @@ handle_call({locations, InOpts}, _From, #state{ locks = Locks } = State) when is
{reply, ok, State};
-handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, locks = Locks } = State) when is_list(InOpts) ->
+handle_call({inspect, Lockname, InOpts}, _From, #state{ duration=Duration, locks=Locks } = State) when is_list(InOpts) ->
Default = [
{sort, time},
{reverse, false},
- {print, [name,id,tries,colls,ratio,time,duration]},
+ {print, [name,id,tries,colls,ratio,time,duration,histogram]},
{max_locks, 20},
{combine, false},
- {thresholds, [] },
+ {thresholds, []},
{locations, false}],
Opts = options(InOpts, Default),
@@ -300,7 +305,7 @@ handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, loc
{true, true} -> locks_ids(Filtered);
_ -> []
end,
- Combos = combine_classes(Filtered, proplists:get_value(combine, Opts)),
+ Combos = combine_classes(Filtered, proplists:get_value(combine, Opts)),
case proplists:get_value(locations, Opts) of
true ->
lists:foreach(fun
@@ -314,17 +319,14 @@ handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, loc
[] ->
ok;
_ ->
- %io:format("Combined ~p~n", [Combined]),
print("lock: " ++ term2string(Name)),
print("id: " ++ IdString),
print("type: " ++ term2string(Type)),
Ps = stats2print(Combined, Duration),
- Opts1 = options([{print, [entry, tries,colls,ratio,time,duration]},
+ Opts1 = options([{print, [entry, tries,colls,ratio,time,duration,histogram]},
{thresholds, [{tries, -1}, {colls, -1}, {time, -1}]}], Opts),
print_lock_information(filter_print(Ps, Opts1), proplists:get_value(print, Opts1))
end
- % (#lock{ name = Name, id = Id}) ->
- % io:format("Empty lock ~p ~p~n", [Name, Id])
end, Combos);
_ ->
Print1 = locks2print(Combos, Duration),
@@ -333,6 +335,34 @@ handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, loc
end,
{reply, ok, State};
+%% histogram
+
+handle_call({histogram, Lockname, InOpts}, _From, #state{ duration=Duration, locks=Locks} = State)->
+ Default = [
+ {sort, time},
+ {reverse, false},
+ {print, [name,id,tries,colls,ratio,time,duration,histogram]},
+ {max_locks, 20},
+ {combine, true},
+ {thresholds, []},
+ {locations, false}],
+
+ Opts = options(InOpts, Default),
+ Filtered = filter_locks(Locks, Lockname),
+ Combos = combine_classes(Filtered, proplists:get_value(combine, Opts)),
+ lists:foreach(fun
+ (#lock{ stats = Stats }=L) ->
+ SumStats = summate_stats(Stats),
+ Opts1 = options([{print, [name,id,tries,colls,ratio,time,duration]},
+ {thresholds, [{tries, -1}, {colls, -1}, {time, -1}]}], Opts),
+ Prints = locks2print([L], Duration),
+ print_lock_information(Prints, proplists:get_value(print, Opts1)),
+ print_full_histogram(SumStats#stats.hist),
+ io:format("~n")
+ end, Combos),
+
+ {reply, ok, State};
+
handle_call(raw, _From, #state{ locks = Locks} = State)->
{reply, Locks, State};
@@ -348,7 +378,6 @@ handle_call(swap_pid_keys, _From, #state{ locks = Locks } = State)->
(L) ->
L
end, Locks),
-
{reply, ok, State#state{ locks = SwappedLocks}};
% settings
@@ -381,6 +410,8 @@ handle_call({save, Filename}, _From, State) ->
{reply, {error, Error}, State}
end;
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
handle_call(Command, _From, State) ->
{reply, {error, {undefined, Command}}, State}.
@@ -391,8 +422,6 @@ handle_call(Command, _From, State) ->
%%
%% -------------------------------------------------------------------- %%
-handle_cast(stop, State) ->
- {stop, normal, State};
handle_cast(_, State) ->
{noreply, State}.
@@ -433,15 +462,32 @@ code_change(_OldVsn, State, _Extra) ->
summate_locks(Locks) -> summate_locks(Locks, #stats{ tries = 0, colls = 0, time = 0, nt = 0}).
summate_locks([], Stats) -> Stats;
-summate_locks([L|Ls], #stats{ tries = Tries, colls = Colls, time = Time, nt = Nt}) ->
+summate_locks([L|Ls], #stats{ tries = Tries, colls = Colls, time = Time, nt = Nt, hist = Hist}) ->
S = summate_stats(L#lock.stats),
- summate_locks(Ls, #stats{ tries = Tries + S#stats.tries, colls = Colls + S#stats.colls, time = Time + S#stats.time, nt = Nt + S#stats.nt}).
+ summate_locks(Ls, #stats{
+ tries = Tries + S#stats.tries,
+ colls = Colls + S#stats.colls,
+ time = Time + S#stats.time,
+ nt = Nt + S#stats.nt,
+ hist = summate_histogram(Hist, S#stats.hist)
+ }).
summate_stats(Stats) -> summate_stats(Stats, #stats{ tries = 0, colls = 0, time = 0, nt = 0}).
summate_stats([], Stats) -> Stats;
-summate_stats([S|Ss], #stats{ tries = Tries, colls = Colls, time = Time, nt = Nt}) ->
- summate_stats(Ss, #stats{ tries = Tries + S#stats.tries, colls = Colls + S#stats.colls, time = Time + S#stats.time, nt = Nt + S#stats.nt}).
-
+summate_stats([S|Ss], #stats{ tries = Tries, colls = Colls, time = Time, nt = Nt, hist = Hist}) ->
+ summate_stats(Ss, #stats{
+ tries = Tries + S#stats.tries,
+ colls = Colls + S#stats.colls,
+ time = Time + S#stats.time,
+ nt = Nt + S#stats.nt,
+ hist = summate_histogram(Hist, S#stats.hist)
+ }).
+
+%% first call is undefined
+summate_histogram(Tup,undefined) when is_tuple(Tup) -> Tup;
+summate_histogram(undefined,Tup) when is_tuple(Tup) -> Tup;
+summate_histogram(Hs1,Hs2) ->
+ list_to_tuple([ A + B || {A,B} <- lists:zip(tuple_to_list(Hs1),tuple_to_list(Hs2))]).
%% manipulators
filter_locks_type(Locks, undefined) -> Locks;
@@ -466,17 +512,16 @@ filter_print(PLs, Opts) ->
TLs = threshold_locks(PLs, proplists:get_value(thresholds, Opts, [])),
SLs = sort_locks(TLs, proplists:get_value(sort, Opts, time)),
CLs = cut_locks(SLs, proplists:get_value(max_locks, Opts, none)),
- reverse_locks(CLs, proplists:get_value(reverse, Opts, false)).
-
-sort_locks(Locks, Type) -> lists:reverse(sort_locks0(Locks, Type)).
-sort_locks0(Locks, name) -> lists:keysort(#print.name, Locks);
-sort_locks0(Locks, id) -> lists:keysort(#print.id, Locks);
-sort_locks0(Locks, type) -> lists:keysort(#print.type, Locks);
-sort_locks0(Locks, tries) -> lists:keysort(#print.tries, Locks);
-sort_locks0(Locks, colls) -> lists:keysort(#print.colls, Locks);
-sort_locks0(Locks, ratio) -> lists:keysort(#print.cr, Locks);
-sort_locks0(Locks, time) -> lists:keysort(#print.time, Locks);
-sort_locks0(Locks, _) -> sort_locks0(Locks, time).
+ reverse_locks(CLs, not proplists:get_value(reverse,Opts, false)).
+
+sort_locks(Locks, name) -> lists:keysort(#print.name, Locks);
+sort_locks(Locks, id) -> lists:keysort(#print.id, Locks);
+sort_locks(Locks, type) -> lists:keysort(#print.type, Locks);
+sort_locks(Locks, tries) -> lists:keysort(#print.tries, Locks);
+sort_locks(Locks, colls) -> lists:keysort(#print.colls, Locks);
+sort_locks(Locks, ratio) -> lists:keysort(#print.cr, Locks);
+sort_locks(Locks, time) -> lists:keysort(#print.time, Locks);
+sort_locks(Locks, _) -> sort_locks(Locks, time).
% cut locks not above certain thresholds
threshold_locks(Locks, Thresholds) ->
@@ -557,45 +602,61 @@ locks_ids(Locks) -> locks_ids(Locks, []).
locks_ids([], Out) -> Out;
locks_ids([#lock{ name = Key } = L|Ls], Out) ->
case proplists:get_value(Key, Out) of
- undefined ->
- locks_ids(Ls, [{Key, [L#lock.id] } | Out]);
- Ids ->
- locks_ids(Ls, [{Key, [L#lock.id | Ids] } | proplists:delete(Key,Out)])
+ undefined -> locks_ids(Ls, [{Key, [L#lock.id]}|Out]);
+ Ids -> locks_ids(Ls, [{Key, [L#lock.id|Ids]}|proplists:delete(Key,Out)])
end.
stats2print(Stats, Duration) ->
lists:map(fun
(S) ->
- #print{
- entry = term2string("~tp:~p", [S#stats.file, S#stats.line]),
- colls = S#stats.colls,
- tries = S#stats.tries,
- cr = percent(S#stats.colls, S#stats.tries),
- time = S#stats.time,
- dtr = percent(S#stats.time, Duration)
- }
+ #print{entry = term2string("~tp:~p", [S#stats.file, S#stats.line]),
+ colls = S#stats.colls,
+ tries = S#stats.tries,
+ cr = percent(S#stats.colls, S#stats.tries),
+ time = S#stats.time,
+ dtr = percent(S#stats.time, Duration),
+ hist = format_histogram(S#stats.hist)}
end, Stats).
locks2print(Locks, Duration) ->
lists:map( fun
(L) ->
- Tries = lists:sum([T || #stats{ tries = T} <- L#lock.stats]),
- Colls = lists:sum([C || #stats{ colls = C} <- L#lock.stats]),
- Time = lists:sum([T || #stats{ time = T} <- L#lock.stats]),
- Cr = percent(Colls, Tries),
- Dtr = percent(Time, Duration),
- #print{
- name = L#lock.name,
- id = L#lock.id,
- type = L#lock.type,
- tries = Tries,
- colls = Colls,
- cr = Cr,
- time = Time,
- dtr = Dtr
- }
+ #stats{tries = Tries,
+ colls = Colls,
+ time = Time,
+ hist = Hist} = summate_stats(L#lock.stats),
+ Cr = percent(Colls, Tries),
+ Dtr = percent(Time, Duration),
+ #print{name = L#lock.name,
+ id = L#lock.id,
+ type = L#lock.type,
+ tries = Tries,
+ colls = Colls,
+ hist = format_histogram(Hist),
+ cr = Cr,
+ time = Time,
+ dtr = Dtr}
end, Locks).
+
+format_histogram(Tup) when is_tuple(Tup) ->
+ Vs = tuple_to_list(Tup),
+ Max = lists:max(Vs),
+ case Max of
+ 0 -> string_histogram(Vs);
+ _ -> string_histogram([case V of 0 -> 0; _ -> V/Max end || V <- Vs])
+ end.
+
+string_histogram([0|Vs]) ->
+ [$\s|string_histogram(Vs)];
+string_histogram([V|Vs]) when V > 0.66 ->
+ [$X|string_histogram(Vs)];
+string_histogram([V|Vs]) when V > 0.33 ->
+ [$x|string_histogram(Vs)];
+string_histogram([_|Vs]) ->
+ [$.|string_histogram(Vs)];
+string_histogram([]) -> [].
+
%% state making
data2state(Data, State) ->
@@ -607,22 +668,32 @@ data2state(Data, State) ->
locks = Locks
}.
-locks2records(Locks) -> locks2records(Locks, []).
-locks2records([], Out) -> Out;
-locks2records([{Name, Id, Type, Stats}|Locks], Out) ->
- Lock = #lock{
- name = Name,
- id = clean_id_creation(Id),
- type = Type,
- stats = [ #stats{
- file = File,
- line = Line,
- tries = Tries,
- colls = Colls,
- time = time2us({S, Ns}),
- nt = N
- } || {{File, Line}, {Tries, Colls, {S, Ns, N}}} <- Stats] },
- locks2records(Locks, [Lock|Out]).
+locks2records([{Name, Id, Type, Stats}|Locks]) ->
+ [#lock{name = Name,
+ id = clean_id_creation(Id),
+ type = Type,
+ stats = stats2record(Stats)}|locks2records(Locks)];
+locks2records([]) -> [].
+
+%% new stats with histogram
+stats2record([{{File,Line},{Tries,Colls,{S,Ns,N}},Hist}|Stats]) ->
+ [#stats{file = File,
+ line = Line,
+ hist = Hist,
+ tries = Tries,
+ colls = Colls,
+ time = time2us({S, Ns}),
+ nt = N} | stats2record(Stats)];
+%% old stats without histogram
+stats2record([{{File,Line},{Tries,Colls,{S,Ns,N}}}|Stats]) ->
+ [#stats{file = File,
+ line = Line,
+ hist = {},
+ tries = Tries,
+ colls = Colls,
+ time = time2us({S, Ns}),
+ nt = N} | stats2record(Stats)];
+stats2record([]) -> [].
clean_id_creation(Id) when is_pid(Id) ->
Bin = term_to_binary(Id),
@@ -648,22 +719,45 @@ state2list(State) ->
(X, Y) -> {X,Y}
end, record_info(fields, state), Values).
-list2state(List) -> list2state(record_info(fields, state), List, [state]).
-list2state([], _, Out) -> list_to_tuple(lists:reverse(Out));
-list2state([locks|Fs], List, Out) ->
- Locks = [ list2lock(Lock) || Lock <- proplists:get_value(locks, List, [])],
- list2state(Fs, List, [Locks|Out]);
-list2state([F|Fs], List, Out) -> list2state(Fs, List, [proplists:get_value(F, List, state_default(F))|Out]).
-
lock_default(Field) -> proplists:get_value(Field, lock2list(#lock{})).
lock2list(Lock) ->
[_|Values] = tuple_to_list(Lock),
lists:zip(record_info(fields, lock), Values).
-list2lock(List) -> list2lock(record_info(fields, lock), List, [lock]).
-list2lock([], _, Out) -> list_to_tuple(lists:reverse(Out));
-list2lock([F|Fs], List, Out) -> list2lock(Fs, List, [proplists:get_value(F, List, lock_default(F))|Out]).
+
+list2state(List) ->
+ list_to_tuple([state|list2state(record_info(fields, state), List)]).
+list2state([], _) -> [];
+list2state([locks|Fs], List) ->
+ Locks = [list2lock(Lock) || Lock <- proplists:get_value(locks, List, [])],
+ [Locks|list2state(Fs,List)];
+list2state([F|Fs], List) ->
+ [proplists:get_value(F, List, state_default(F))|list2state(Fs, List)].
+
+list2lock(Ls) ->
+ list_to_tuple([lock|list2lock(record_info(fields, lock), Ls)]).
+
+list2lock([],_) -> [];
+list2lock([stats=F|Fs], Ls) ->
+ Stats = stats2stats(proplists:get_value(F, Ls, lock_default(F))),
+ [Stats|list2lock(Fs, Ls)];
+list2lock([F|Fs], Ls) ->
+ [proplists:get_value(F, Ls, lock_default(F))|list2lock(Fs, Ls)].
+
+%% process old stats (hack)
+%% old stats had no histograms
+%% in future versions stats should be serialized as a list, not a record
+
+stats2stats([]) -> [];
+stats2stats([Stat|Stats]) ->
+ Sz = tuple_size(#stats{}),
+ [stat2stat(Stat,Sz)|stats2stats(Stats)].
+
+stat2stat(Stat,Sz) when tuple_size(Stat) =:= Sz -> Stat;
+stat2stat(Stat,_) ->
+ %% assume no histogram at the end
+ list_to_tuple(tuple_to_list(Stat) ++ [{0}]).
%% printing
@@ -684,7 +778,7 @@ auto_print_width(Locks, Print) ->
({print,print}, Out) -> [print|Out];
({Str, Len}, Out) -> [erlang:min(erlang:max(length(s(Str))+1,Len),80)|Out]
end, [], lists:zip(tuple_to_list(L), tuple_to_list(Max)))))
- end, #print{ id = 4, type = 5, entry = 5, name = 6, tries = 8, colls = 13, cr = 16, time = 11, dtr = 14 },
+ end, #print{ id = 4, type = 5, entry = 5, name = 6, tries = 8, colls = 13, cr = 16, time = 11, dtr = 14, hist=20 },
Locks),
% Setup the offsets for later pruning
Offsets = [
@@ -696,7 +790,9 @@ auto_print_width(Locks, Print) ->
{colls, R#print.colls},
{ratio, R#print.cr},
{time, R#print.time},
- {duration, R#print.dtr}],
+ {duration, R#print.dtr},
+ {histogram, R#print.hist}
+ ],
% Prune offsets to only allow specified print options
lists:foldr(fun
({Type, W}, Out) -> [{Type, W}|Out];
@@ -706,9 +802,7 @@ auto_print_width(Locks, Print) ->
print_lock_information(Locks, Print) ->
% remake Print to autosize entries
AutoPrint = auto_print_width(Locks, Print),
-
print_header(AutoPrint),
-
lists:foreach(fun
(L) ->
print_lock(L, AutoPrint)
@@ -725,7 +819,8 @@ print_header(Opts) ->
colls = "#collisions",
cr = "collisions [%]",
time = "time [us]",
- dtr = "duration [%]"
+ dtr = "duration [%]",
+ hist = "histogram"
},
Divider = #print{
name = lists:duplicate(1 + length(Header#print.name), 45),
@@ -736,39 +831,44 @@ print_header(Opts) ->
colls = lists:duplicate(1 + length(Header#print.colls), 45),
cr = lists:duplicate(1 + length(Header#print.cr), 45),
time = lists:duplicate(1 + length(Header#print.time), 45),
- dtr = lists:duplicate(1 + length(Header#print.dtr), 45)
+ dtr = lists:duplicate(1 + length(Header#print.dtr), 45),
+ hist = lists:duplicate(1 + length(Header#print.hist), 45)
},
print_lock(Header, Opts),
print_lock(Divider, Opts),
ok.
-print_lock(L, Opts) -> print_lock(L, Opts, []).
-print_lock(_, [], Formats) -> print(strings(lists:reverse(Formats)));
-print_lock(L, [Opt|Opts], Formats) ->
+print_lock(L, Opts) ->
+ print(strings(format_lock(L, Opts))).
+
+format_lock(_, []) -> [];
+format_lock(L, [Opt|Opts]) ->
case Opt of
- id -> print_lock(L, Opts, [{space, 25, s(L#print.id) } | Formats]);
- {id, W} -> print_lock(L, Opts, [{space, W, s(L#print.id) } | Formats]);
- type -> print_lock(L, Opts, [{space, 18, s(L#print.type) } | Formats]);
- {type, W} -> print_lock(L, Opts, [{space, W, s(L#print.type) } | Formats]);
- entry -> print_lock(L, Opts, [{space, 30, s(L#print.entry)} | Formats]);
- {entry, W} -> print_lock(L, Opts, [{space, W, s(L#print.entry)} | Formats]);
- name -> print_lock(L, Opts, [{space, 22, s(L#print.name) } | Formats]);
- {name, W} -> print_lock(L, Opts, [{space, W, s(L#print.name) } | Formats]);
- tries -> print_lock(L, Opts, [{space, 12, s(L#print.tries)} | Formats]);
- {tries, W} -> print_lock(L, Opts, [{space, W, s(L#print.tries)} | Formats]);
- colls -> print_lock(L, Opts, [{space, 14, s(L#print.colls)} | Formats]);
- {colls, W} -> print_lock(L, Opts, [{space, W, s(L#print.colls)} | Formats]);
- ratio -> print_lock(L, Opts, [{space, 20, s(L#print.cr) } | Formats]);
- {ratio, W} -> print_lock(L, Opts, [{space, W, s(L#print.cr) } | Formats]);
- time -> print_lock(L, Opts, [{space, 15, s(L#print.time) } | Formats]);
- {time, W} -> print_lock(L, Opts, [{space, W, s(L#print.time) } | Formats]);
- duration -> print_lock(L, Opts, [{space, 20, s(L#print.dtr) } | Formats]);
- {duration, W} -> print_lock(L, Opts, [{space, W, s(L#print.dtr) } | Formats]);
- _ -> print_lock(L, Opts, Formats)
+ id -> [{space, 25, s(L#print.id) } | format_lock(L, Opts)];
+ {id, W} -> [{space, W, s(L#print.id) } | format_lock(L, Opts)];
+ type -> [{space, 18, s(L#print.type) } | format_lock(L, Opts)];
+ {type, W} -> [{space, W, s(L#print.type) } | format_lock(L, Opts)];
+ entry -> [{space, 30, s(L#print.entry)} | format_lock(L, Opts)];
+ {entry, W} -> [{space, W, s(L#print.entry)} | format_lock(L, Opts)];
+ name -> [{space, 22, s(L#print.name) } | format_lock(L, Opts)];
+ {name, W} -> [{space, W, s(L#print.name) } | format_lock(L, Opts)];
+ tries -> [{space, 12, s(L#print.tries)} | format_lock(L, Opts)];
+ {tries, W} -> [{space, W, s(L#print.tries)} | format_lock(L, Opts)];
+ colls -> [{space, 14, s(L#print.colls)} | format_lock(L, Opts)];
+ {colls, W} -> [{space, W, s(L#print.colls)} | format_lock(L, Opts)];
+ ratio -> [{space, 20, s(L#print.cr) } | format_lock(L, Opts)];
+ {ratio, W} -> [{space, W, s(L#print.cr) } | format_lock(L, Opts)];
+ time -> [{space, 15, s(L#print.time) } | format_lock(L, Opts)];
+ {time, W} -> [{space, W, s(L#print.time) } | format_lock(L, Opts)];
+ duration -> [{space, 20, s(L#print.dtr) } | format_lock(L, Opts)];
+ {duration, W} -> [{space, W, s(L#print.dtr) } | format_lock(L, Opts)];
+ histogram -> [{space, 0, s(L#print.hist) } | format_lock(L, Opts)];
+ {histogram, W} -> [{space, W, s(L#print.hist) } | format_lock(L, Opts)];
+ _ -> format_lock(L, Opts)
end.
-print_state_information(#state{ locks = Locks} = State) ->
+print_state_information(#state{locks = Locks} = State) ->
Stats = summate_locks(Locks),
print("information:"),
print(kv("#locks", s(length(Locks)))),
@@ -780,9 +880,25 @@ print_state_information(#state{ locks = Locks} = State) ->
print(kv("percent of duration", s(Stats#stats.time/State#state.duration*100) ++ " %")),
ok.
+
+print_full_histogram(T) when is_tuple(T) ->
+ Vs = tuple_to_list(T),
+ Max = lists:max(Vs),
+ W = 60,
+ print_full_histogram(0,Vs,Max,W).
+
+print_full_histogram(_,[],_,_) -> ok;
+print_full_histogram(Ix,[V|Vs],0,W) ->
+ io:format("~2w = log2 : ~8w |~n", [Ix,V]),
+ print_full_histogram(Ix+1,Vs,0,W);
+print_full_histogram(Ix,[V|Vs],Max,W) ->
+ io:format("~2w = log2 : ~8w | ~s~n", [Ix,V,lists:duplicate(trunc(W*(V/Max)), $#)]),
+ print_full_histogram(Ix+1,Vs,Max,W).
+
+
%% AUX
-time2us({S, Ns}) -> round(S*1000000 + Ns/1000).
+time2us({S, Ns}) -> S*1000000 + (Ns div 1000).
percent(_,0) -> 0.0;
percent(T,N) -> T/N*100.
@@ -809,7 +925,7 @@ s(T) -> term2string(T).
strings(Strings) -> strings(Strings, []).
strings([], Out) -> Out;
-strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string("~~~ps", [N]), [S]));
+strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string("~~~ws", [N]), [S]));
strings([{format, Format, S} | Ss], Out) -> strings(Ss, Out ++ term2string(Format, [S]));
strings([S|Ss], Out) -> strings(Ss, Out ++ term2string("~ts", [S])).
@@ -826,7 +942,7 @@ term2string(Term) when is_pid(Term) ->
term2string(Term) -> term2string("~w", [Term]).
term2string(Format, Terms) -> lists:flatten(io_lib:format(Format, Terms)).
-%%% AUD id binary
+%%% AUX id binary
bytes16(Value) ->
B0 = Value band 255,
diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src
index 553c5eb96b..ec5b6f3a82 100644
--- a/lib/tools/src/tools.app.src
+++ b/lib/tools/src/tools.app.src
@@ -39,23 +39,9 @@
{applications, [kernel, stdlib]},
{env, [{file_util_search_methods,[{"", ""}, {"ebin", "esrc"}, {"ebin", "src"}]}
]
- }
+ },
+ {runtime_dependencies, ["webtool-0.8.10","stdlib-2.0","runtime_tools-1.8.14",
+ "kernel-3.0","inets-5.10","erts-6.0",
+ "compiler-5.0"]}
]
}.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/tools/src/tools.appup.src b/lib/tools/src/tools.appup.src
index 8de1ec76c9..9a27456a81 100644
--- a/lib/tools/src/tools.appup.src
+++ b/lib/tools/src/tools.appup.src
@@ -1,19 +1,21 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2009. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-{"%VSN%",[],[]}.
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%",
+ [{<<".*">>,[{restart_application, tools}]}],
+ [{<<".*">>,[{restart_application, tools}]}]
+}.
diff --git a/lib/tools/src/xref_compiler.erl b/lib/tools/src/xref_compiler.erl
index f0fed502a5..c4b5c04c12 100644
--- a/lib/tools/src/xref_compiler.erl
+++ b/lib/tools/src/xref_compiler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -885,7 +885,7 @@ evaluate([pop | P], T, [_ | S]) ->
evaluate([], T, [R]) ->
{T, R}.
-%% (PossibleGraph, 1 | -1, dict()) -> dict()
+%% (PossibleGraph, 1 | -1, dict:dict()) -> dict:dict()
%% Use the same table for everything... Here: Reference counters for digraphs.
update_graph_counter(Value, Inc, T) ->
case catch digraph:info(Value) of
diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl
index d3601c6ea0..142d28ebe6 100644
--- a/lib/tools/src/xref_reader.erl
+++ b/lib/tools/src/xref_reader.erl
@@ -171,6 +171,11 @@ expr({'fun', Line, {function, Name, Arity}, _Extra}, S) ->
handle_call(local, S#xrefr.module, Name, Arity, Line, S);
expr({'fun', _Line, {clauses, Cs}, _Extra}, S) ->
clauses(Cs, S);
+expr({named_fun, _Line, '_', Cs, _Extra}, S) ->
+ clauses(Cs, S);
+expr({named_fun, _Line, Name, Cs, _Extra}, S) ->
+ S1 = S#xrefr{funvars = [Name | S#xrefr.funvars]},
+ clauses(Cs, S1);
expr({call, Line, {atom, _, Name}, As}, S) ->
S1 = handle_call(local, S#xrefr.module, Name, length(As), Line, S),
expr(As, S1);
@@ -186,6 +191,9 @@ expr({match, _Line, {var,_,Var}, {'fun', _, {clauses, Cs}, _Extra}}, S) ->
%% that are passed around by the "expansion" of list comprehension.
S1 = S#xrefr{funvars = [Var | S#xrefr.funvars]},
clauses(Cs, S1);
+expr({match, _Line, {var,_,Var}, {named_fun, _, _, _, _} = Fun}, S) ->
+ S1 = S#xrefr{funvars = [Var | S#xrefr.funvars]},
+ expr(Fun, S1);
expr({match, _Line, {var,_,Var}, E}, S) ->
%% Used for resolving code like
%% Args = [A,B], apply(m, f, Args)
@@ -288,6 +296,8 @@ funarg({'fun', _, _Clauses, _Extra}, _S) -> true;
funarg({'fun', _, {function,_,_,_}}, _S) ->
%% New abstract format for fun M:F/A in R15.
true;
+funarg({named_fun, _, _, _, _}, _S) ->
+ true;
funarg({var, _, Var}, S) -> member(Var, S#xrefr.funvars);
funarg(_, _S) -> false.
diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl
index 7b72165e6f..49c397a140 100644
--- a/lib/tools/src/xref_utils.erl
+++ b/lib/tools/src/xref_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -437,7 +437,7 @@ regexpr({ModExpr, FunExpr, ArityExpr}, Var) ->
V2
end.
-%% -> digraph()
+%% -> digraph:graph()
relation_to_graph(S) ->
G = digraph:new(),
Fun = fun({From, To}) ->
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 29b26c7a76..80807b1d38 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -22,13 +22,16 @@
suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([start/1, compile/1, analyse/1, misc/1, stop/1,
+-export([coverage/1, coverage_analysis/1,
+ start/1, compile/1, analyse/1, misc/1, stop/1,
distribution/1, reconnect/1, die_and_reconnect/1,
dont_reconnect_after_stop/1, stop_node_after_disconnect/1,
export_import/1,
otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1,
otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1,
- otp_10979_hanging_node/1, compile_beam_opts/1]).
+ otp_10979_hanging_node/1, compile_beam_opts/1, eep37/1]).
+
+-export([do_coverage/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -46,25 +49,25 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
+ NoStartStop = [eif,otp_5305,otp_5418,otp_7095,otp_8273,
+ otp_8340,otp_8188,compile_beam_opts,eep37],
+ StartStop = [start, compile, analyse, misc, stop,
+ distribution, reconnect, die_and_reconnect,
+ dont_reconnect_after_stop, stop_node_after_disconnect,
+ export_import, otp_5031, otp_6115,
+ otp_8270, otp_10979_hanging_node],
case whereis(cover_server) of
undefined ->
- [start, compile, analyse, misc, stop,
- distribution, reconnect, die_and_reconnect,
- dont_reconnect_after_stop, stop_node_after_disconnect,
- export_import, otp_5031, eif, otp_5305, otp_5418,
- otp_6115, otp_7095, otp_8188, otp_8270, otp_8273,
- otp_8340, otp_10979_hanging_node, compile_beam_opts];
+ [coverage,StartStop ++ NoStartStop];
_pid ->
- {skip,
- "It looks like the test server is running "
- "cover. Can't run cover test."}
+ [coverage|NoStartStop++[coverage_analysis]]
end.
groups() ->
[].
init_per_suite(Config) ->
- Config.
+ [{ct_is_running_cover,whereis(cover_server) =/= undefined}|Config].
end_per_suite(_Config) ->
ok.
@@ -90,13 +93,64 @@ init_per_testcase(TC, Config) when TC =:= misc;
init_per_testcase(_TestCase, Config) ->
Config.
-end_per_testcase(TestCase, _Config) ->
- case lists:member(TestCase,[start,compile,analyse,misc]) of
+end_per_testcase(TestCase, Config) ->
+ NoStop = [start,compile,analyse,misc],
+ DontStop = proplists:get_bool(ct_is_running_cover, Config) orelse
+ lists:member(TestCase, NoStop),
+ case DontStop of
true -> ok;
false -> cover:stop()
end,
ok.
+coverage(Config) when is_list(Config) ->
+ {ok,?MODULE} = cover:compile_beam(?MODULE),
+ ?MODULE:do_coverage(Config).
+
+do_coverage(Config) ->
+ Outdir = ?config(priv_dir, Config),
+ ExportFile = filename:join(Outdir, "export"),
+ ok = cover:export(ExportFile, ?MODULE),
+ {error,{already_started,_}} = cover:start(),
+ {error,_} = cover:compile_beam(non_existing_module),
+ _ = cover:which_nodes(),
+ _ = cover:modules(),
+ _ = cover:imported(),
+ {error,{not_cover_compiled,lists}} = cover:analyze(lists),
+
+ %% Cover escaping of '&' in HTML files.
+
+ case proplists:get_bool(ct_is_running_cover, Config) of
+ false ->
+ %% Cover server was implicitly started when this module
+ %% was cover-compiled. We must stop the cover server, but
+ %% we must ensure that this module is not on the call
+ %% stack when it is unloaded. Therefore, the call that
+ %% follows MUST be tail-recursive.
+ cover:stop();
+ true ->
+ %% Cover server was started by common_test; don't stop it.
+ ok
+ end.
+
+%% This test case will only be run when common_test is running cover.
+coverage_analysis(Config) when is_list(Config) ->
+ {ok,Analysis1} = cover:analyze(?MODULE),
+ io:format("~p\n", [Analysis1]),
+ {ok,Analysis2} = cover:analyze(?MODULE, calls),
+ io:format("~p\n", [Analysis2]),
+ {ok,_Analysis3} = cover:analyze(?MODULE, calls, line),
+
+ Outdir = ?config(priv_dir, Config),
+ Outfile = filename:join(Outdir, ?MODULE),
+
+ {ok,Outfile} = cover:analyze_to_file(?MODULE, Outfile),
+ {ok,Contents} = file:read_file(Outfile),
+ ok = file:delete(Outfile),
+ ok = io:put_chars(Contents),
+ {ok,Outfile} = cover:analyze_to_file(?MODULE, Outfile, [html]),
+ ok.
+
start(suite) -> [];
start(Config) when is_list(Config) ->
?line ok = file:set_cwd(?config(data_dir, Config)),
@@ -462,13 +516,11 @@ reconnect(Config) ->
cover:flush(N1),
rpc:call(N1,f,f1,[]),
- %% This will cause a call to f:f2() when nodes()==[] on N1
+ %% This will cause first casue the N1 node to initiate a
+ %% disconnect and then call f:f2() when nodes() =:= [] on N1.
rpc:cast(N1,f,call_f2_when_isolated,[]),
-
- %% Disconnect and check that node is removed from main cover node
- net_kernel:disconnect(N1),
timer:sleep(500), % allow some to detect disconnect and for f:f2() call
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
%% Do some add one module (b) and remove one module (a)
code:purge(a),
@@ -476,7 +528,7 @@ reconnect(Config) ->
{ok,b} = cover:compile(b),
cover_compiled = code:which(b),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
check_f_calls(1,0), % only the first call - before the flush
%% Reconnect the node and check that b and f are cover compiled but not a
@@ -519,7 +571,7 @@ die_and_reconnect(Config) ->
%% Kill the node
rpc:call(N1,erlang,halt,[]),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
check_f_calls(1,0), % only the first call - before the flush
@@ -560,7 +612,7 @@ dont_reconnect_after_stop(Config) ->
%% Stop cover on the node, then terminate the node
cover:stop(N1),
rpc:call(N1,erlang,halt,[]),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
check_f_calls(1,0),
@@ -568,7 +620,7 @@ dont_reconnect_after_stop(Config) ->
{ok,N1} = ?t:start_node(NodeName,peer,
[{args," -pa " ++ DataDir},{start_cover,false}]),
timer:sleep(300),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
Beam = rpc:call(N1,code,which,[f]),
false = (Beam==cover_compiled),
@@ -613,7 +665,7 @@ stop_node_after_disconnect(Config) ->
{ok,N1} = ?t:start_node(NodeName,peer,
[{args," -pa " ++ DataDir},{start_cover,false}]),
timer:sleep(300),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
Beam = rpc:call(N1,code,which,[f]),
false = (Beam==cover_compiled),
@@ -759,7 +811,6 @@ eif(Config) when is_list(Config) ->
%% in cover_inc.beam - not the ones from the included file.
?line cover_inc:func(),
?line {ok, [_, _]} = cover:analyse(cover_inc, line),
- ?line cover:stop(),
ok.
otp_5305(suite) -> [];
@@ -775,7 +826,6 @@ otp_5305(Config) when is_list(Config) ->
">>,
?line ok = file:write_file(File, Test),
?line {ok, t} = cover:compile(File),
- ?line cover:stop(),
?line ok = file:delete(File),
ok.
@@ -790,7 +840,6 @@ otp_5418(Config) when is_list(Config) ->
?line ok = file:write_file(File, Test),
?line {ok, t} = cover:compile(File),
?line {ok,{t,{0,0}}} = cover:analyse(t, module),
- ?line cover:stop(),
?line ok = file:delete(File),
ok.
@@ -952,7 +1001,6 @@ otp_7095(Config) when is_list(Config) ->
{{t,67},1},{{t,69},1},{{t,71},1},{{t,74},1},
{{t,76},0},{{t,78},1},
{{t,82},2}]} = cover:analyse(t, calls, line),
- ?line cover:stop(),
?line ok = file:delete(File),
ok.
@@ -1028,7 +1076,6 @@ otp_8273(Config) when is_list(Config) ->
">>,
?line File = cc_mod(t, Test, Config),
?line ok = t:t(),
- ?line cover:stop(),
?line ok = file:delete(File),
ok.
@@ -1066,7 +1113,6 @@ otp_8188(Config) when is_list(Config) ->
?line File = cc_mod(t, Test, Config),
?line false = t:test(nok),
?line {ok,[{{t,11},1},{{t,12},1}]} = cover:analyse(t, calls, line),
- ?line cover:stop(),
?line ok = file:delete(File),
%% Bit string comprehensions are now traversed;
@@ -1382,6 +1428,20 @@ comprehension_8188(Cf) ->
ok.
+eep37(Config) when is_list(Config) ->
+ [{{t,1},1},{{t,2},1},{{t,4},6},{{t,6},1},{{t,8},1}] =
+ analyse_expr(<<"begin\n" % 1
+ " F =\n" % 1
+ " fun Fact(N) when N > 0 ->\n"
+ " N * Fact(N - 1);\n" % 6
+ " Fact(0) ->\n"
+ " 1\n" % 1
+ " end,\n"
+ " F(6)\n" % 1
+ "end\n">>,
+ Config),
+ ok.
+
otp_10979_hanging_node(_Config) ->
P1 = processes(),
@@ -1419,6 +1479,8 @@ compile_beam_opts(Config) when is_list(Config) ->
export_all,
debug_info,
return_errors]),
+ code:purge(t),
+ code:delete(t),
Exports =
[{func1,0},
{macro, 0},
@@ -1429,7 +1491,6 @@ compile_beam_opts(Config) when is_list(Config) ->
Exports = t:module_info(exports),
{ok, t} = cover:compile_beam("t"),
Exports = t:module_info(exports),
- cover:stop(),
ok = file:delete("t.beam"),
ok = file:set_cwd(Cwd),
ok.
@@ -1512,3 +1573,21 @@ is_unloaded(What) ->
check_f_calls(F1,F2) ->
{ok,[{{f,f1,0},F1},{{f,f2,0},F2}|_]} = cover:analyse(f,calls,function).
+
+cover_which_nodes(Expected) ->
+ case cover:which_nodes() of
+ Expected ->
+ ok;
+ Other ->
+ {Time,ok} = timer:tc(fun Retry() ->
+ case cover:which_nodes() of
+ Expected -> ok;
+ _ ->
+ ?t:sleep(100),
+ Retry()
+ end
+ end),
+ io:format("~p ms before cover:which_nodes() returned ~p",
+ [Time,Expected]),
+ Expected = Other
+ end.
diff --git a/lib/tools/test/cover_SUITE_data/f.erl b/lib/tools/test/cover_SUITE_data/f.erl
index ce2963014a..a29a67b388 100644
--- a/lib/tools/test/cover_SUITE_data/f.erl
+++ b/lib/tools/test/cover_SUITE_data/f.erl
@@ -10,10 +10,15 @@ f2() ->
f2_line2.
call_f2_when_isolated() ->
+ [Other] = nodes(),
+ net_kernel:disconnect(Other),
+ do_call_f2_when_isolated().
+
+do_call_f2_when_isolated() ->
case nodes() of
[] ->
f2();
_ ->
timer:sleep(100),
- call_f2_when_isolated()
+ do_call_f2_when_isolated()
end.
diff --git a/lib/tools/test/eprof_SUITE.erl b/lib/tools/test/eprof_SUITE.erl
index 26685a6a84..04b522de4a 100644
--- a/lib/tools/test/eprof_SUITE.erl
+++ b/lib/tools/test/eprof_SUITE.erl
@@ -104,7 +104,7 @@ basic(Config) when is_list(Config) ->
profiling = eprof:profile([A]),
true = exit(A, kill_it),
profiling_stopped = eprof:stop_profiling(),
- {error,_} = eprof:profile(fun() -> a = b end),
+ {error,_} = eprof:profile(fun() -> a = id(b) end),
%% with mfa
@@ -127,6 +127,14 @@ basic(Config) when is_list(Config) ->
ok.
basic_option(Config) when is_list(Config) ->
+ %% Eprof is not supported on native-compile code.
+ case lists:module_info(native_addresses) of
+ [] -> basic_option_1(Config);
+ [_|_] -> {skip,"lists is native-compiled"}
+ end.
+
+basic_option_1(Config) ->
+
%% load eprof_test and change directory
{ok, OldCurDir} = file:get_cwd(),
@@ -141,8 +149,7 @@ basic_option(Config) when is_list(Config) ->
% vanilla
{ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [{set_on_spawn, true}]),
- [{_, MfasDo1},{_, MfasLists1}] = eprof:dump(),
- Mfas1 = MfasDo1 ++ MfasLists1,
+ Mfas1 = lists:foldl(fun({_,Mfas},Out) -> Mfas ++ Out end, [], eprof:dump()),
{value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas1),
{value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas1),
@@ -151,8 +158,7 @@ basic_option(Config) when is_list(Config) ->
{ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [set_on_spawn]),
- [{_, MfasDo2},{_, MfasLists2}] = eprof:dump(),
- Mfas2 = MfasDo2 ++ MfasLists2,
+ Mfas2 = lists:foldl(fun({_,Mfas},Out) -> Mfas ++ Out end, [], eprof:dump()),
{value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas2),
{value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas2),
{value, {_, { 9, _}}} = lists:keysearch({lists, split_2,5}, 1, Mfas2),
@@ -247,3 +253,5 @@ ensure_eprof_stopped() ->
Pid ->
stopped=eprof:stop()
end.
+
+id(I) -> I.
diff --git a/lib/tools/test/lcnt_SUITE.erl b/lib/tools/test/lcnt_SUITE.erl
index 1bee6021ab..010dffe138 100644
--- a/lib/tools/test/lcnt_SUITE.erl
+++ b/lib/tools/test/lcnt_SUITE.erl
@@ -27,11 +27,11 @@
%% Test cases
-export([
- load_v1/1,
- conflicts/1,
- locations/1,
- swap_keys/1
- ]).
+ t_load/1,
+ t_conflicts/1,
+ t_locations/1,
+ t_swap_keys/1
+ ]).
%% Default timetrap timeout (set in init_per_testcase)
-define(default_timeout, ?t:minutes(4)).
@@ -54,48 +54,52 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
- [load_v1, conflicts, locations, swap_keys].
+all() -> [t_load, t_conflicts, t_locations, t_swap_keys].
-groups() ->
- [].
+groups() -> [].
-init_per_group(_GroupName, Config) ->
- Config.
+init_per_group(_GroupName, Config) -> Config.
-end_per_group(_GroupName, Config) ->
- Config.
+end_per_group(_GroupName, Config) -> Config.
%%----------------------------------------------------------------------
%% Tests
%%----------------------------------------------------------------------
-load_v1(suite) ->
- [];
-load_v1(doc) ->
- ["Load data from file."];
-load_v1(Config) when is_list(Config) ->
- ?line {ok, _} = lcnt:start(),
- ?line Path = ?config(data_dir, Config),
- ?line File = filename:join([Path,"big_bang_40.lcnt"]),
- ?line ok = lcnt:load(File),
- ?line ok = lcnt:stop(),
+t_load(suite) -> [];
+t_load(doc) -> ["Load data from file."];
+t_load(Config) when is_list(Config) ->
+ Path = ?config(data_dir, Config),
+ Files = [filename:join([Path,"big_bang_40.lcnt"]),
+ filename:join([Path,"ehb_3_3_hist.lcnt"])],
+ ok = t_load_file(Files),
ok.
-conflicts(suite) ->
- [];
-conflicts(doc) ->
- ["API: conflicts"];
-conflicts(Config) when is_list(Config) ->
- ?line {ok, _} = lcnt:start(),
- ?line Path = ?config(data_dir, Config),
- ?line File = filename:join([Path,"big_bang_40.lcnt"]),
- ?line ok = lcnt:load(File),
- ?line ok = lcnt:conflicts(),
- THs = [-1, 0, 100, 1000],
- Print = [name , id , type , entry , tries , colls , ratio , time , duration],
- Opts = [
+t_load_file([]) -> ok;
+t_load_file([File|Files]) ->
+ {ok, _} = lcnt:start(),
+ ok = lcnt:load(File),
+ ok = lcnt:stop(),
+ t_load_file(Files).
+
+t_conflicts(suite) -> [];
+t_conflicts(doc) -> ["API: conflicts"];
+t_conflicts(Config) when is_list(Config) ->
+ Path = ?config(data_dir, Config),
+ Files = [filename:join([Path,"big_bang_40.lcnt"]),
+ filename:join([Path,"ehb_3_3_hist.lcnt"])],
+ ok = t_conflicts_file(Files),
+ ok.
+
+t_conflicts_file([]) -> ok;
+t_conflicts_file([File|Files]) ->
+ {ok, _} = lcnt:start(),
+ ok = lcnt:load(File),
+ ok = lcnt:conflicts(),
+ THs = [-1, 0, 100, 1000],
+ Print = [name , id , type , entry , tries , colls , ratio , time , duration],
+ Opts = [
[{sort, Sort}, {reverse, Rev}, {max_locks, ML}, {combine, Combine}, {thresholds, [TH]}, {print, [Print]}] ||
Sort <- [name , id , type , tries , colls , ratio , time , entry],
ML <- [none, 1 , 32, 4096],
@@ -103,28 +107,33 @@ conflicts(Config) when is_list(Config) ->
TH <- [{tries, Tries} || Tries <- THs] ++ [{colls, Colls} || Colls <- THs] ++ [{time, Time} || Time <- THs],
Rev <- [true, false]
],
- ?line ok = test_conflicts_opts(Opts),
- ?line ok = lcnt:stop(),
- ok.
+ ok = test_conflicts_opts(Opts),
+ ok = lcnt:stop(),
+ t_conflicts_file(Files).
+
test_conflicts_opts([]) -> ok;
test_conflicts_opts([Opt|Opts]) ->
- ?line ok = lcnt:conflicts(Opt),
+ ok = lcnt:conflicts(Opt),
test_conflicts_opts(Opts).
-locations(suite) ->
- [];
-locations(doc) ->
- ["API: locations"];
-locations(Config) when is_list(Config) ->
- ?line {ok, _} = lcnt:start(),
- ?line Path = ?config(data_dir, Config),
- ?line File = filename:join([Path,"big_bang_40.lcnt"]),
- ?line ok = lcnt:load(File),
- ?line ok = lcnt:locations(),
- THs = [-1, 0, 100, 1000],
- Print = [name , id , type , entry , tries , colls , ratio , time , duration],
- Opts = [
+t_locations(suite) -> [];
+t_locations(doc) -> ["API: locations"];
+t_locations(Config) when is_list(Config) ->
+ Path = ?config(data_dir, Config),
+ Files = [filename:join([Path,"big_bang_40.lcnt"]),
+ filename:join([Path,"ehb_3_3_hist.lcnt"])],
+ ok = t_locations_file(Files),
+ ok.
+
+t_locations_file([]) -> ok;
+t_locations_file([File|Files]) ->
+ {ok, _} = lcnt:start(),
+ ok = lcnt:load(File),
+ ok = lcnt:locations(),
+ THs = [-1, 0, 100, 1000],
+ Print = [name , id , type , entry , tries , colls , ratio , time , duration],
+ Opts = [
[{full_id, Id}, {sort, Sort}, {max_locks, ML}, {combine, Combine}, {thresholds, [TH]}, {print, Print}] ||
Sort <- [name , id , type , tries , colls , ratio , time , entry],
ML <- [none, 1 , 64],
@@ -132,30 +141,34 @@ locations(Config) when is_list(Config) ->
TH <- [{tries, Tries} || Tries <- THs] ++ [{colls, Colls} || Colls <- THs] ++ [{time, Time} || Time <- THs],
Id <- [true, false]
],
- ?line ok = test_locations_opts(Opts),
- ?line ok = lcnt:stop(),
- ok.
+ ok = test_locations_opts(Opts),
+ ok = lcnt:stop(),
+ t_locations_file(Files).
test_locations_opts([]) -> ok;
test_locations_opts([Opt|Opts]) ->
- ?line ok = lcnt:locations(Opt),
+ ok = lcnt:locations(Opt),
test_locations_opts(Opts).
-swap_keys(suite) ->
- [];
-swap_keys(doc) ->
- ["Test interchanging port/process id with class"];
-swap_keys(Config) when is_list(Config) ->
- ?line {ok, _} = lcnt:start(),
- ?line Path = ?config(data_dir, Config),
- ?line File = filename:join([Path,"big_bang_40.lcnt"]),
- ?line ok = lcnt:load(File),
- ?line ok = lcnt:conflicts(),
- ?line ok = lcnt:swap_pid_keys(),
- ?line ok = lcnt:conflicts(),
- ?line ok = lcnt:stop(),
+t_swap_keys(suite) -> [];
+t_swap_keys(doc) -> ["Test interchanging port/process id with class"];
+t_swap_keys(Config) when is_list(Config) ->
+ Path = ?config(data_dir, Config),
+ Files = [filename:join([Path,"big_bang_40.lcnt"]),
+ filename:join([Path,"ehb_3_3_hist.lcnt"])],
+ ok = t_swap_keys_file(Files),
ok.
+t_swap_keys_file([]) -> ok;
+t_swap_keys_file([File|Files]) ->
+ {ok, _} = lcnt:start(),
+ ok = lcnt:load(File),
+ ok = lcnt:conflicts(),
+ ok = lcnt:swap_pid_keys(),
+ ok = lcnt:conflicts(),
+ ok = lcnt:stop(),
+ t_swap_keys_file(Files).
+
%%----------------------------------------------------------------------
%% Auxiliary tests
diff --git a/lib/tools/test/lcnt_SUITE_data/ehb_3_3_hist.lcnt b/lib/tools/test/lcnt_SUITE_data/ehb_3_3_hist.lcnt
new file mode 100644
index 0000000000..ff5bdcbdaa
--- /dev/null
+++ b/lib/tools/test/lcnt_SUITE_data/ehb_3_3_hist.lcnt
Binary files differ
diff --git a/lib/tools/test/tools_SUITE.erl b/lib/tools/test/tools_SUITE.erl
index ea3f59dbe1..e3582b995b 100644
--- a/lib/tools/test/tools_SUITE.erl
+++ b/lib/tools/test/tools_SUITE.erl
@@ -30,12 +30,12 @@
-export([init_per_testcase/2, end_per_testcase/2]).
%% Test cases must be exported.
--export([app_test/1]).
+-export([app_test/1, appup_test/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test].
+ [app_test, appup_test].
groups() ->
[].
@@ -71,3 +71,7 @@ app_test(suite) ->
[];
app_test(Config) when is_list(Config) ->
?line ?t:app_test(tools, tolerant).
+
+%% Test that the .appup file does not contain any `basic' errors
+appup_test(Config) when is_list(Config) ->
+ ok = ?t:appup_test(tools).
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index dc06678b8e..6870aefe5c 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -1,8 +1,7 @@
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1048,7 +1047,7 @@ read_expected(Version) ->
POS1 = 28, POS2 = POS1+10, POS3 = POS2+6, POS4 = POS3+6, POS5 = POS4+10,
POS6 = POS5+5, POS7 = POS6+6, POS8 = POS7+6, POS9 = POS8+8,
POS10 = POS9+10, POS11 = POS10+7, POS12 = POS11+8, POS13 = POS12+10,
- POS14 = POS13+18, % POS15 = POS14+23,
+ POS14 = POS13+18, POS15 = POS14+23,
FF = {read,funfuns,0},
U = [{POS1+5,{FF,{dist,'$F_EXPR',0}}},
@@ -1197,11 +1196,6 @@ read_expected(Version) ->
{0,{FF,{modul,'$F_EXPR',179}}}]
++ O1;
_ ->
-% [{POS15+2,{{read,bi,0},{foo,t,0}}},
-% {POS15+3,{{read,bi,0},{bar,t,0}}},
-% {POS15+6,{{read,bi,0},{read,local,0}}},
-% {POS15+8,{{read,bi,0},{foo,t,0}}},
-% {POS15+10,{{read,bi,0},{bar,t,0}}}] ++
[{16,{FF,{read,'$F_EXPR',178}}},
{17,{FF,{modul,'$F_EXPR',179}}}]
++
@@ -1212,7 +1206,7 @@ read_expected(Version) ->
OKB1 = [{POS13+1,{FF,{erts_debug,apply,4}}},
{POS13+2,{FF,{erts_debug,apply,4}}},
{POS13+3,{FF,{erts_debug,apply,4}}},
- {POS1+3, {FF,{erlang,binary_to_term,1}}},
+ {POS1+3, {FF,{erlang,binary_to_term,1}}},
{POS3+1, {FF,{erlang,spawn,3}}},
{POS3+2, {FF,{erlang,spawn,3}}},
{POS3+3, {FF,{erlang,spawn_link,3}}},
@@ -1228,7 +1222,11 @@ read_expected(Version) ->
_ ->
[{POS13+16, {{read,bi,0},{erlang,'!',2}}},
{POS13+16, {{read,bi,0},{erlang,'-',1}}},
- {POS13+16, {{read,bi,0},{erlang,self,0}}}]
+ {POS13+16, {{read,bi,0},{erlang,self,0}}},
+ {POS15+1, {{read,bi,0},{erlang,'>',2}}},
+ {POS15+2, {{read,bi,0},{erlang,'-',2}}},
+ {POS15+2, {{read,bi,0},{erlang,'*',2}}},
+ {POS15+8, {{read,bi,0},{erlang,'/',2}}}]
end
++ [{POS14+19, {{read,bi,0},{erlang,'+',2}}},
{POS14+21, {{read,bi,0},{erlang,'+',2}}},
diff --git a/lib/tools/test/xref_SUITE_data/read/read.erl b/lib/tools/test/xref_SUITE_data/read/read.erl
index 19694c9e25..5f388194b0 100644
--- a/lib/tools/test/xref_SUITE_data/read/read.erl
+++ b/lib/tools/test/xref_SUITE_data/read/read.erl
@@ -156,20 +156,19 @@ bi() ->
<<D:16, E, F/binary>> = Bin3,
X = 9, <<(X+1):8>>,
_Fyy = <<X:4/little-signed-integer-unit:8>>,
- D + E + F.
-%bi() ->
-% %% POS15=POS14+13
-% try
-% foo:t(),
-% bar:t()
-% of
-% {v,1} ->
-% local();
-% {v,2} ->
-% foo:t()
-% catch
-% {'EXIT',_} -> bar:t()
-% end.
+ D + E + F;
+bi() ->
+ %% EEP37. POS15=POS14+23
+ F = fun Fact(N) when N > 0 ->
+ N * Fact(N - 1);
+ Fact(0) ->
+ 1
+ end,
+ F(6),
+ G = fun _(foo) -> bar;
+ _(X) -> X / 3
+ end,
+ G(foo).
local() ->
true.
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 0cead00554..3acb8d38e2 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.6.13
+TOOLS_VSN = 2.7