aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2019-03-07 20:42:57 +0100
committerSverker Eriksson <[email protected]>2019-03-07 20:42:57 +0100
commit8dec35910330a44de3fa08573e3029f10b3aa4ae (patch)
treec40a9375b3b7623df83a7dcd34bc34959865a3d4
parentdb6059a9217767a6e42e93cec05089c0ec977d20 (diff)
downloadotp-8dec35910330a44de3fa08573e3029f10b3aa4ae.tar.gz
otp-8dec35910330a44de3fa08573e3029f10b3aa4ae.tar.bz2
otp-8dec35910330a44de3fa08573e3029f10b3aa4ae.zip
erts: Remove ets traversal yielding if heap fragment
Many heap fragments do no longer make the GC slow. Even worse, we are not guaranteed that a yield will provoke a GC removing the fragments, which might lead to a one-yield-per-bucket scenario if the heap fragment(s) still remains after each yield.
-rw-r--r--erts/emulator/beam/erl_bif_info.c11
-rw-r--r--erts/emulator/beam/erl_db_hash.c12
-rw-r--r--erts/emulator/beam/erl_db_tree.c14
-rw-r--r--lib/stdlib/test/ets_SUITE.erl57
4 files changed, 69 insertions, 25 deletions
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 4050fb6146..43d99db0b2 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -4459,7 +4459,16 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
refbin));
}
}
-
+ else if (ERTS_IS_ATOM_STR("mbuf", BIF_ARG_1)) {
+ Uint sz = size_object(BIF_ARG_2);
+ ErlHeapFragment* frag = new_message_buffer(sz);
+ Eterm *hp = frag->mem;
+ Eterm copy = copy_struct(BIF_ARG_2, sz, &hp, &frag->off_heap);
+ frag->next = BIF_P->mbuf;
+ BIF_P->mbuf = frag;
+ BIF_P->mbuf_sz += sz;
+ BIF_RET(copy);
+ }
}
BIF_ERROR(BIF_P, BADARG);
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index cf928a9035..47d304f860 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -1328,11 +1328,7 @@ static int match_traverse(Process* p, DbTableHash* tb,
unlock_hash_function(lck);
break;
}
- if (iterations_left <= 0 || MBUF(p)) {
- /*
- * We have either reached our limit, or just created some heap fragments.
- * Since many heap fragments will make the GC slower, trap and GC now.
- */
+ if (iterations_left <= 0) {
unlock_hash_function(lck);
ret_value = on_trap(context_ptr, slot_ix, got, &mpi.mp, ret);
goto done;
@@ -1451,11 +1447,7 @@ static int match_traverse_continue(Process* p, DbTableHash* tb,
unlock_hash_function(lck);
break;
}
- if (iterations_left <= 0 || MBUF(p)) {
- /*
- * We have either reached our limit, or just created some heap fragments.
- * Since many heap fragments will make the GC slower, trap and GC now.
- */
+ if (iterations_left <= 0) {
unlock_hash_function(lck);
ret_value = on_trap(context_ptr, slot_ix, got, mpp, ret);
goto done;
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 7c80e92e50..f222ac45ae 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -3344,13 +3344,6 @@ static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr,
if (is_value(ret)) {
sc->accum = CONS(hp, ret, sc->accum);
}
- if (MBUF(sc->p)) {
- /*
- * Force a trap and GC if a heap fragment was created. Many heap fragments
- * make the GC slow.
- */
- sc->max = 0;
- }
if (--(sc->max) <= 0) {
return 0;
}
@@ -3407,13 +3400,6 @@ static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr,
++(sc->got);
sc->accum = CONS(hp, ret, sc->accum);
}
- if (MBUF(sc->p)) {
- /*
- * Force a trap and GC if a heap fragment was created. Many heap fragments
- * make the GC slow.
- */
- sc->max = 0;
- }
if (--(sc->max) <= 0 || sc->got == sc->chunk_size) {
return 0;
}
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 1a8260b041..bbbbab2f60 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -58,6 +58,7 @@
-export([otp_5340/1]).
-export([otp_6338/1]).
-export([otp_6842_select_1000/1]).
+-export([select_mbuf_trapping/1]).
-export([otp_7665/1]).
-export([meta_wb/1]).
-export([grow_shrink/1, grow_pseudo_deleted/1, shrink_pseudo_deleted/1]).
@@ -125,6 +126,7 @@ all() ->
t_ets_dets, memory, t_select_reverse, t_bucket_disappears,
select_fail, t_insert_new, t_repair_continuation,
otp_5340, otp_6338, otp_6842_select_1000, otp_7665,
+ select_mbuf_trapping,
otp_8732, meta_wb, grow_shrink, grow_pseudo_deleted,
shrink_pseudo_deleted, {group, meta_smp}, smp_insert,
smp_fixed_delete, smp_unfix_fix, smp_select_replace,
@@ -5022,6 +5024,61 @@ otp_6338(Config) when is_list(Config) ->
[[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
ets:delete(T).
+%% OTP-15660: Verify select not doing excessive trapping
+%% when process have mbuf heap fragments.
+select_mbuf_trapping(Config) when is_list(Config) ->
+ select_mbuf_trapping_do(set),
+ select_mbuf_trapping_do(ordered_set).
+
+select_mbuf_trapping_do(Type) ->
+ T = ets:new(xxx, [Type]),
+ NKeys = 50,
+ [ets:insert(T, {K, value}) || K <- lists:seq(1,NKeys)],
+
+ {priority, Prio} = process_info(self(), priority),
+ Tracee = self(),
+ [SchedTracer]
+ = start_loopers(1, Prio,
+ fun (SC) ->
+ receive
+ {trace, Tracee, out, _} ->
+ SC+1;
+ done ->
+ Tracee ! {schedule_count, SC},
+ exit(normal)
+ end
+ end,
+ 0),
+
+ erlang:garbage_collect(),
+ 1 = erlang:trace(self(), true, [running,{tracer,SchedTracer}]),
+
+ %% Artificially create an mbuf heap fragment
+ MbufTerm = "Frag me up",
+ MbufTerm = erts_debug:set_internal_state(mbuf, MbufTerm),
+
+ Keys = ets:select(T, [{{'$1', value}, [], ['$1']}]),
+ NKeys = length(Keys),
+
+ 1 = erlang:trace(self(), false, [running]),
+ Ref = erlang:trace_delivered(Tracee),
+ receive
+ {trace_delivered, Tracee, Ref} ->
+ SchedTracer ! done
+ end,
+ receive
+ {schedule_count, N} ->
+ io:format("~p context switches: ~p", [Type,N]),
+ if
+ N < 3 -> ok;
+ true -> ct:fail(failed)
+ end
+ end,
+ true = ets:delete(T),
+ ok.
+
+
+
%% Elements could come in the wrong order in a bag if a rehash occurred.
otp_5340(Config) when is_list(Config) ->
repeat_for_opts(fun otp_5340_do/1).