Age | Commit message (Collapse) | Author |
|
José Valim noticed that code such as:
match(1) -> 1;
match(2) -> 2;
match(3) -> 3;
...
match(1000) -> 1000.
would compile very slowly. The culprit is opt/3 in beam_jump.
What happens is that opt/3 will rewrite this code:
select_val ...
label 1
jump 1000
label 2
jump 1000
...
label 999
jump 1000
label 1000
return
very slowly to this code:
select_val ...
label 1
label 2
...
label 999
label 1000
return
The reason for the slowness is that when opt/3 sees this
sequence:
label 1
jump 1000
...
it will remove the label (storing it in a dictionary),
and pick up the previously processed instruction from
the accumulator:
select_val ...
jump 1000
label 2
jump 1000
...
That is done in order to process all labels before the
jump and also to get rid of the jump instruction if the
previous instruction is an "unreachable after". In this
case, re-processing the sequence will remove the now
unreachable jump instruction:
select_val ...
label 2
jump 1000
...
The problem is that re-processing the select_val instruction is
expensive. The instruction has a list of 1000 labels, all of which
will be added (again) to the set of referenced labels. The
select_val instruction will be re-processed again and again
until all labels and jumps have been gobbled up.
In the original version of beam_jump, opt/3 was not called
repeatedly until a fixpoint was found, but was expected to do
all its optimizations in one pass. The fixpoint iteration was
added later.
Since we now have the fixpoint iteration, there is no need
to do everything in a single pass. When we encounter a jump, we will
collect all previously seen labels and put them into the dictionary,
and then we will move on.
As a further optimization, we will look for sequences like this:
jump X
label ...
jump X
and replace them with:
label ...
jump X
In the example above, that will avoid 1000 updates of the dictionary.
After applying this optimization, compilation of the
pattern went from roughly 55 s to 0.1 s for the example
above but with 10000 clauses.
Reported-by: José Valim
|
|
* ia/ssl/soft-upgrade-test:
ssl: Prepare for 18
ssl: Add soft upgrade test suite
|
|
|
|
* ia/ssl/os-timestamp:
ssl: erlang:timestamp -> os:timestamp Complements commit 450773958165539951cd431a9233ce7666ec20e2
|
|
Complements commit 450773958165539951cd431a9233ce7666ec20e2
|
|
|
|
* emauton/mnesia_create_table_docfix:
Fix index for #person.address in create_table/2
|
|
|
|
* crownedgrouse/fix_mnesia_subscribe_doc:
Fix xml doc return value mnesia:(un)subscribe
|
|
|
|
* yannayl/patch-1:
Fixed fun_test examples
|
|
|
|
|
|
|
|
* origin/hb/dialyzer/fix_map_type/OTP-12472:
[dialyzer] Fix a bug concerning map() types
|
|
Removed false example from fun_test.erl
Removed unused code from fun_test.erl
|
|
* richcarl/dcd-dumps:
Make Mnesia DCD dump behaviour available via API
Make Mnesia DCD dump behaviour available via configuration
OTP-12481
|
|
|
|
* derek121/getting-started-typos:
Fix typos
OTP-12478
|
|
* maint:
mnesia: Check nodes after protocol negotiation
|
|
'dumbbell/mnesia-hang-if-remote-stopped-after-proto-negotiation' into maint
* dumbbell/mnesia-hang-if-remote-stopped-after-proto-negotiation:
mnesia: Check nodes after protocol negotiation
OTP-12473
|
|
During Mnesia startup, after protocol negotiation, the list of connected
nodes is written to "recover_nodes". This list is later used to merge
the schema.
If Mnesia was stopped on a remote node between the protocol negotiation
and the moment the list is stored in "recover_nodes", the remote node
is still considered running: the value of "recover_nodes" stored during
mnesia_down/1 is overwritten. Therefore, this node may be used to
acquire a write lock on the schema in order to perform the merge. In
this case, the remote node never answers to the lock request and Mnesia
hang forever (application:start(mnesia) never returns).
To fix the problem, we check the list one last time and remove from it
all nodes where Mnesia is stopped. And because there is still a chance
for missing mnesia_down event, handle_cast({mnesia_down, ...}, ...)
writes to recover_nodes again, in addition to mnesia_down/1.
|
|
It is allowed in Erlang/OTP 17 to redefine the map() types. However,
Dialyzer did not handle local map() types correctly.
|
|
Fixed a number of typos.
|
|
|
|
* ia/ssl/timestamp:
ssl: erlang:timestamp -> os:timestamp
|
|
For comparison with file time stamps os:timestamp makes more sense
and is present in 17 as well as 18.
|
|
Conflicts:
lib/ssl/doc/src/ssl_app.xml
lib/ssl/src/ssl_manager.erl
|
|
* ia/ssl/pem-cache/OTP-12464:
ssl: Improve PEM cache by validating entries
|
|
The PEM cache is now validated by a background process, instead of
always keeping it if it is small enough and clearing it otherwhiss.
That strategy required that small caches where cleared by API function
if a file changes on disk.
However document the clearing API function as it can still be usefull.
|
|
* maint:
Fix ssh:connect erroneus error msg at timeout
|
|
* hans/ssh/error_timeout/OTP-12369:
Fix ssh:connect erroneus error msg at timeout
|
|
|
|
|
|
* scrapinghub/httpc_set_cookie_with_empty_values:
inets: parse correctly 'Set-Cookie' header with empty value
OTP-12455
|
|
|
|
* bjorn/compiler/dup-bug-fix/OTP-12453:
Teach case_opt/3 to avoid unnecessary building
sys_core_fold: Optimize let statements more aggressively
Suppress warnings for expressions that are assigned to '_'
trace_bif_SUITE: Ensure that a call to time/0 is not removed
|
|
* bjorn/compiler/map-core-syntax/OTP-12454:
Make the syntax for map pairs readable
|
|
* maint:
Update primary bootstrap
Correct unsafe optimization of '==' and '/='
Conflicts:
bootstrap/lib/compiler/ebin/sys_core_fold.beam
|
|
|
|
* bjorn/compiler/maps-comparison/OTP-12456:
Correct unsafe optimization of '==' and '/='
|
|
Since '=:=' is cheaper than '==', the compiler tries to replace
'==' with '=:=' if the result of comparison will be the same.
As an example:
V == {a,b}
can be rewritten to:
V =:= {a,b}
since the literal on the right side contains no numeric values
that '==' would compare differently to '=:='.
With the introduction of maps, we will need to take them into
account. Since the comparison of maps is planned to change in 18.0,
we will be very conservative and only do the optimization if
both keys and values are non-numeric.
|
|
* henrik/fix-master:
fix faulty merge
|
|
|
|
Conflicts:
OTP_VERSION
erts/emulator/sys/unix/sys.c
erts/vsn.mk
|
|
|
|
Given this code:
f(S) ->
F0 = F1 = {S,S},
[F0,F1].
case_opt/3 would "optimize" it like this:
f(S) ->
F1 = {S,S},
F0 = {S,S},
[F0,F1].
Similarly, this code:
g({a,_,_}=T) ->
{b,
[_,_] = [T,none],
x}.
would be rewritten to:
g({a,Tmp1,Tmp2}=T) ->
Tmp3 = {a,Tmp1,Tmp2},
{b,
[Tmp3,none],
x}.
where the tuple is rebuilt instead of using the T variable.
Rewrite case_opt/3 to be more careful while optimizing.
|
|
httpc_cookie should parse cookies with empty values
and no attributes set in the 'Set-Cookie' headers.
|
|
I originally decided that in 'value' context, rewriting a let statement
where the variables were not in the body to a sequence was not worth
it, because the variables would be unused in only one let in a
thousand lets (roughly).
I have reconsidered.
The main reason is that if we do the rewrite, core_lib:is_var_used/2
will be used much more frequently, which will help us to find bugs
in it sooner.
Another reason is that the way letify/2 is currently implemented
with its own calls to core_lib:is_var_used/2 is only safe as long
as all the bindings are independent of each other. We could make
letify/2 smarter, but if we introduce this new optimization there
is no need.
Measuring compilation speed, I have not seen any significant slowdown.
It seems that although core_lib:is_var_used/2 is called much more
frequently, most calls will be fast because is_var_used/2 will quickly
find a use of the variable.
Also add a test case to cover a line opt_guard_try/1 that was
no longer covered.
|
|
In c34ad2d5, the compiler learned to silence some warnings for
expressions that were explicitly assigned to the '_' variable,
as in this example:
_ = list_to_integer(S),
ok
That commit intentionally only made it possible to silence warnings
for BIFs that could cause an exception. Warnings would still be
produced for:
_ = date(),
ok
because date/0 can never fail and thus making the call completely
useless. The reasoning was that such warnings can always be
eliminated by eliminating the offending code.
While that is true, there is the question about rules and their
consistency. It is surprising that '_' can be used to silence
some warnings, but has no effect on other warnings.
Therefore, we will teach the compiler to silence warnings for
the following constructs:
* Calls to safe BIFs such as date/0
* Expressions that will cause an exception such as 'X/0'
* Terms that are built but not used, such as '{x,X}'
|