diff options
Diffstat (limited to 'lib/tools')
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 Binary files differnew file mode 100644 index 0000000000..ff5bdcbdaa --- /dev/null +++ b/lib/tools/test/lcnt_SUITE_data/ehb_3_3_hist.lcnt 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 |