Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
2726-ETS-write_concurrency-auto-fixes-and-remov...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2726-ETS-write_concurrency-auto-fixes-and-remove-write_co.patch of Package erlang
From 1a8f7fb8521bad0efe7a137ed3abd9f54b96bec4 Mon Sep 17 00:00:00 2001 From: Kjell Winblad <kjellwinblad@gmail.com> Date: Tue, 19 Oct 2021 20:27:23 +0200 Subject: [PATCH 6/8] ETS {write_concurrency, auto} fixes and remove {write_concurrency, N} * make sure that ordered_set tables configured with {write_concurrency, auto} gives auto when ets:info(T, write_concurrency) is called * Remove the possibility to explicitly set the number of locks from the public interface by using the option {write_concurrency, N}. For performance "debuging" purposes there is still a hidden way explicitly set the number of locks for hash tables by using the option {write_concurrency, {debug_hash_fixed_number_of_locks, 2048}} --- erts/emulator/beam/atom.names | 3 +- erts/emulator/beam/erl_db.c | 57 ++++++-- erts/emulator/beam/erl_db_hash.c | 2 +- erts/emulator/beam/erl_db_util.h | 7 +- lib/stdlib/doc/src/ets.xml | 42 ++---- lib/stdlib/src/ets.erl | 2 +- lib/stdlib/test/ets_SUITE.erl | 228 ++++++++++++++++++++++--------- 7 files changed, 231 insertions(+), 110 deletions(-) diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 8715c0c440..80548bcab1 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -734,4 +734,5 @@ atom x86 atom yes atom yield atom nifs -atom auto \ No newline at end of file +atom auto +atom debug_hash_fixed_number_of_locks \ No newline at end of file diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 9cfc89c8e9..0a02c3e77b 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -2311,17 +2311,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) keypos = signed_val(tp[2]); } else if (tp[1] == am_write_concurrency) { - Sint number_of_locks_param; - if (is_integer(tp[2]) && - term_to_Sint(tp[2], &number_of_locks_param) && - number_of_locks_param >= DB_WRITE_CONCURRENCY_MIN_LOCKS && - number_of_locks_param <= DB_WRITE_CONCURRENCY_MAX_LOCKS) { - is_decentralized_counters = 1; - is_fine_locked = 1; - is_explicit_lock_granularity = 1; - is_write_concurrency_auto = 0; - number_of_locks = number_of_locks_param; - } else if (tp[2] == am_auto) { + if (tp[2] == am_auto) { is_decentralized_counters = 1; is_write_concurrency_auto = 1; is_fine_locked = 1; @@ -2340,6 +2330,23 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) is_explicit_lock_granularity = 0; is_write_concurrency_auto = 0; number_of_locks = -1; + } else if (is_tuple(tp[2])) { + Eterm *stp = tuple_val(tp[2]); + Sint number_of_locks_param; + if (arityval(stp[0]) == 2 && + stp[1] == am_debug_hash_fixed_number_of_locks && + is_integer(stp[2]) && + term_to_Sint(stp[2], &number_of_locks_param) && + number_of_locks_param >= DB_WRITE_CONCURRENCY_MIN_LOCKS && + number_of_locks_param <= DB_WRITE_CONCURRENCY_MAX_LOCKS) { + + is_decentralized_counters = 1; + is_fine_locked = 1; + is_explicit_lock_granularity = 1; + is_write_concurrency_auto = 0; + number_of_locks = number_of_locks_param; + + } else break; } else break; if (DB_LOCK_FREE(NULL)) is_fine_locked = 0; @@ -2403,6 +2410,24 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) status |= DB_CA_ORDERED_SET; status &= ~(DB_SET | DB_BAG | DB_DUPLICATE_BAG | DB_ORDERED_SET); status |= DB_FINE_LOCKED; + if (is_explicit_lock_granularity) { + /* + * The hidden debug option to explicitly set the number of locks, + * currently doesn't make sense for ordered_set. + */ + BIF_ERROR(BIF_P, BADARG); + } else if (is_write_concurrency_auto) { + /* + * ordered_set tables that are configured with + * {write_concurrency, true} or {write_concurrency, auto} + * currently get the same implementation but we record + * that the auto option was used anyway so that + * ets:info(T, write_concurrency) can return auto when the + * table has been configured with {write_concurrency, + * auto}. + */ + status |= DB_FINE_LOCKED_AUTO; + } } else if (IS_HASH_TABLE(status)) { meth = &db_hash; @@ -2419,6 +2444,9 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) } else if (IS_TREE_TABLE(status)) { meth = &db_tree; + if (is_explicit_lock_granularity) { + BIF_ERROR(BIF_P, BADARG); + } } else { BIF_ERROR(BIF_P, BADARG); @@ -5073,9 +5101,12 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) if ((tb->common.status & DB_FINE_LOCKED) && (tb->common.status & (DB_SET | DB_BAG | DB_DUPLICATE_BAG)) && (tb->common.status & DB_EXPLICIT_LOCK_GRANULARITY)) { - ret = erts_make_integer(tb->hash.nlocks, p); + Eterm* hp = HAlloc(p, 3); + ret = make_tuple(hp); + *hp++ = make_arityval(2); + *hp++ = am_debug_hash_fixed_number_of_locks; + *hp++ = erts_make_integer(tb->hash.nlocks, p); } else if ((tb->common.status & DB_FINE_LOCKED) && - (tb->common.status & (DB_SET | DB_BAG | DB_DUPLICATE_BAG)) && (tb->common.status & DB_FINE_LOCKED_AUTO)) { ret = am_auto; } else { diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 6b160eb97a..f18f2df40c 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -307,7 +307,7 @@ void erl_db_hash_adapt_number_of_locks(DbTable* tb) { db_hash_lock_array_resize_state current_state; DbTableHash* tbl; int new_number_of_locks; - if(!(tb->common.type & DB_FINE_LOCKED_AUTO)) { + if(!IS_HASH_WITH_AUTO_TABLE(tb->common.type)) { return; } current_state = erts_atomic_read_nob(&tb->hash.lock_array_resize_state); diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 1fdb0275c6..7945bbfd8b 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -351,8 +351,11 @@ typedef struct db_table_common { #define DB_CATREE_FORCE_SPLIT (1 << 31) /* erts_debug */ #define DB_CATREE_DEBUG_RANDOM_SPLIT_JOIN (1 << 30) /* erts_debug */ -#define IS_HASH_TABLE(Status) (!!((Status) & \ - (DB_BAG | DB_SET | DB_DUPLICATE_BAG))) +#define IS_HASH_TABLE(Status) (!!((Status) & \ + (DB_BAG | DB_SET | DB_DUPLICATE_BAG))) +#define IS_HASH_WITH_AUTO_TABLE(Status) \ + (((Status) & \ + (DB_ORDERED_SET | DB_CA_ORDERED_SET | DB_FINE_LOCKED_AUTO)) == DB_FINE_LOCKED_AUTO) #define IS_TREE_TABLE(Status) (!!((Status) & \ DB_ORDERED_SET)) #define IS_CATREE_TABLE(Status) (!!((Status) & \ diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index 16b8739780..434133b92f 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -1264,7 +1264,7 @@ ets:select(Table, MatchSpec),</code> operation that mutates (writes to) the table obtains exclusive access, blocking any concurrent access of the same table until finished. - If set to <c>true</c>, the table is optimized to concurrent + If set to <c>true</c>, the table is optimized for concurrent write access. Different objects of the same table can be mutated (and read) by concurrent processes. This is achieved to some degree at the expense of memory consumption and the performance @@ -1272,31 +1272,10 @@ ets:select(Table, MatchSpec),</code> <p>The <c>auto</c> alternative for the <c>write_concurrency</c> option is similar to the <c>true</c> option but automatically adjusts the - synchronization granularity at runtime depending on how the + synchronization granularity during runtime depending on how the table is used. This is the recommended <c>write_concurrency</c> option when using Erlang/OTP 25 and above as it performs well in most scenarios.</p> - <p>Users can also explicitly set the synchronization - granularity for tables of types <c>set</c>, <c>bag</c>, - and <c>duplicate_bag</c> by setting the - <c>write_concurrency</c> option to an integer in the range - <c>[2, 32768]</c>. Currently, the number automatically - rounds down to the nearest power of two. The likelihood of - conflicts between operations reduces with an increased - value. Explicitly setting the synchronization granularity - is not recommended unless it is possible to - do experimentation to figure out which synchronization - granularity gives the best performance. If you are unsure - what number to set this setting to, it is probably best to - use <c>{write_concurrency, auto}</c> instead. One should be - careful about combining the <c>{read_concurrency, true}</c> - setting with explicitly setting the synchronization - granularity as this can lead to worse performance and high - memory utilization. It is usually not a good idea to set - this setting to a number that is much greater than the - number of expected items in the table, as this can lead to - slow table traversals. The effect of this setting might - change in future versions of Erlang/OTP.</p> <p>The <c>write_concurrency</c> option can be combined with the options <seeerl marker="#new_2_read_concurrency"> <c>read_concurrency</c></seeerl> and @@ -1319,18 +1298,21 @@ ets:select(Table, MatchSpec),</code> <p>The memory consumption inflicted by both <c>write_concurrency</c> and <c>read_concurrency</c> is a constant overhead per table for <c>set</c>, <c>bag</c> and - <c>duplicate_bag</c> when the <c>auto</c> alternative for + <c>duplicate_bag</c> when the <c>true</c> alternative for the <c>write_concurrency</c> option is not used. For - <c>ordered_set</c> as well as <c>set</c>, <c>bag</c> and - <c>duplicate_bag</c> with the <c>auto</c> alternative the - memory overhead depends on the number of inserted objects - and the amount of actual detected concurrency during + all tables with the <c>auto</c> alternative and <c>ordered_set</c> + tables with <c>true</c> alternative the + memory overhead depends on the amount of actual detected concurrency during runtime. The memory overhead can be especially large when - both options are combined.</p> + both <c>write_concurrency</c> and <c>read_concurrency</c> are combined.</p> <note> <p>Prior to stdlib-3.7 (OTP-22.0) <c>write_concurrency</c> had no effect on <c>ordered_set</c>.</p> </note> + <note> + <p>The <c>auto</c> alternative for the <c>write_concurrency</c> + option is only available in OTP-25.0 and above.</p> + </note> <marker id="new_2_read_concurrency"></marker> </item> <tag><c>{read_concurrency,boolean()}</c></tag> @@ -1363,7 +1345,7 @@ ets:select(Table, MatchSpec),</code> <p> Performance tuning. Defaults to <c>true</c> for all tables with the <c>write_concurrency</c> option set - to something else than <c>true</c> or <c>false</c>. For + to <c>auto</c>. For tables of type <c>ordered_set</c> the option also defaults to true when the <c>write_concurrency</c> option is set to <c>true</c>. The option defaults to diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index e25289d80f..e4d94c3bd6 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -309,7 +309,7 @@ member(_, _) -> | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks, Type :: type(), Access :: access(), - WriteConcurrencyAlternative :: boolean() | auto | 2..32768, + WriteConcurrencyAlternative :: boolean() | auto, Tweaks :: {write_concurrency, WriteConcurrencyAlternative} | {read_concurrency, boolean()} | {decentralized_counters, boolean()} diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index c7a4b38c51..ee2428ca80 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -588,7 +588,8 @@ t_repair_continuation_do(Opts) -> MS = [{'_',[],[true]}], MS2 = [{{{'$1','_'},'_'},[],['$1']}], (fun() -> - T = ets_new(x,[ordered_set|Opts]), + T = ets_new(x, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end, F(1000,F), {_,C} = ets:select(T,MS,5), @@ -600,7 +601,8 @@ t_repair_continuation_do(Opts) -> true = ets:delete(T) end)(), (fun() -> - T = ets_new(x,[ordered_set|Opts]), + T = ets_new(x, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end, F(1000,F), {_,C} = ets:select(T,MS,1001), @@ -612,7 +614,8 @@ t_repair_continuation_do(Opts) -> end)(), (fun() -> - T = ets_new(x,[ordered_set|Opts]), + T = ets_new(x, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -627,7 +630,8 @@ t_repair_continuation_do(Opts) -> true = ets:delete(T) end)(), (fun() -> - T = ets_new(x,[ordered_set|Opts]), + T = ets_new(x, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{{integer_to_list(N),N},N}), F(N-1,F) @@ -890,7 +894,8 @@ whitebox_1(Opts) -> ok. whitebox_2(Opts) -> - T=ets_new(x,[ordered_set, {keypos,2} | Opts]), + T=ets_new(x, + replace_dbg_hash_fixed_nr_of_locks([ordered_set, {keypos,2} | Opts])), T2=ets_new(x,[set, {keypos,2}| Opts]), 0 = ets:select_delete(T,[{{hej},[],[true]}]), 0 = ets:select_delete(T,[{{hej,hopp},[],[true]}]), @@ -1063,7 +1068,8 @@ t_delete_object_do(Opts) -> 3999 = ets:info(T,size), 0 = get_kept_objects(T), ets:delete(T), - T1 = ets_new(x,[ordered_set | Opts]), + T1 = ets_new(x, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), filltabint(T1,4000), del_one_by_one_set(T1,1,4001), filltabint(T1,4000), @@ -2247,7 +2253,8 @@ update_element_opts(Opts) -> update_element_opts(Tuple,KeyPos,UpdPos,Opts) -> Set = ets_new(set,[{keypos,KeyPos} | Opts]), - OrdSet = ets_new(ordered_set,[ordered_set,{keypos,KeyPos} | Opts]), + OrdSet = ets_new(ordered_set, + replace_dbg_hash_fixed_nr_of_locks([ordered_set,{keypos,KeyPos} | Opts])), update_element(Set,Tuple,KeyPos,UpdPos), update_element(OrdSet,Tuple,KeyPos,UpdPos), true = ets:delete(Set), @@ -2336,7 +2343,8 @@ update_tuple([], Tpl) -> update_element_neg(Opts) -> Set = ets_new(set,Opts), - OrdSet = ets_new(ordered_set,[ordered_set | Opts]), + OrdSet = ets_new(ordered_set, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), update_element_neg_do(Set), update_element_neg_do(OrdSet), ets:delete(Set), @@ -2393,7 +2401,8 @@ update_counter(Config) when is_list(Config) -> update_counter_do(Opts) -> Set = ets_new(set,Opts), - OrdSet = ets_new(ordered_set,[ordered_set | Opts]), + OrdSet = ets_new(ordered_set, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), update_counter_for(Set), update_counter_for(OrdSet), ets:delete_all_objects(Set), @@ -2553,7 +2562,8 @@ uc_adder(Init, {_Pos, Add, Thres, Warp}) -> update_counter_neg(Opts) -> Set = ets_new(set,Opts), - OrdSet = ets_new(ordered_set,[ordered_set | Opts]), + OrdSet = ets_new(ordered_set, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), update_counter_neg_for(Set), update_counter_neg_for(OrdSet), ets:delete(Set), @@ -2684,7 +2694,7 @@ update_counter_with_default_do(Opts) -> 2 = ets:info(T1, size), %% Same with ordered set. - T2 = ets_new(b, [ordered_set | Opts]), + T2 = ets_new(b, replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), 3 = ets:update_counter(T2, foo, 2, {maroilles,1}), 1 = ets:info(T2, size), 5 = ets:update_counter(T2, foo, 2, {mimolette,1}), @@ -2740,7 +2750,8 @@ update_counter_table_growth(_Config) -> update_counter_table_growth_do(Opts) -> Set = ets_new(b, [set | Opts]), [ets:update_counter(Set, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)], - OrderedSet = ets_new(b, [ordered_set | Opts]), + OrderedSet = + ets_new(b, replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), [ets:update_counter(OrderedSet, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)], ok. @@ -3511,7 +3522,8 @@ interface_equality(Config) when is_list(Config) -> interface_equality_do(Opts) -> EtsMem = etsmem(), Set = ets_new(set,[set | Opts]), - OrderedSet = ets_new(ordered_set,[ordered_set | Opts]), + OrderedSet = ets_new(ordered_set, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), F = fun(X,T,FF) -> case X of 0 -> true; _ -> @@ -3570,7 +3582,7 @@ maybe_sort(Any) -> %% Test match, match_object and match_delete in ordered set's. ordered_match(Config) when is_list(Config)-> - repeat_for_opts(fun ordered_match_do/1). + repeat_for_opts_extra_opt(fun ordered_match_do/1, ordered_set). ordered_match_do(Opts) -> EtsMem = etsmem(), @@ -3616,7 +3628,7 @@ ordered_match_do(Opts) -> %% Test basic functionality in ordered_set's. ordered(Config) when is_list(Config) -> - repeat_for_opts(fun ordered_do/1). + repeat_for_opts_extra_opt(fun ordered_do/1, ordered_set). ordered_do(Opts) -> EtsMem = etsmem(), @@ -4053,8 +4065,16 @@ delete_large_tab(Config) when is_list(Config) -> delete_large_tab_do(Config, Opts,Data) -> delete_large_tab_1(Config, foo_hash, Opts, Data, false), - delete_large_tab_1(Config, foo_tree, [ordered_set | Opts], Data, false), - delete_large_tab_1(Config, foo_tree, [stim_cat_ord_set | Opts], Data, false), + delete_large_tab_1(Config, + foo_tree, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts]), + Data, + false), + delete_large_tab_1(Config, + foo_tree, + replace_dbg_hash_fixed_nr_of_locks([stim_cat_ord_set | Opts]), + Data, + false), delete_large_tab_1(Config, foo_hash_fix, Opts, Data, true). @@ -4143,8 +4163,14 @@ delete_large_named_table(Config) when is_list(Config) -> delete_large_named_table_do(Opts,Data) -> delete_large_named_table_1(foo_hash, [named_table | Opts], Data, false), - delete_large_named_table_1(foo_tree, [ordered_set,named_table | Opts], Data, false), - delete_large_named_table_1(foo_tree, [stim_cat_ord_set,named_table | Opts], Data, false), + delete_large_named_table_1(foo_tree, + replace_dbg_hash_fixed_nr_of_locks([ordered_set,named_table | Opts]), + Data, + false), + delete_large_named_table_1(foo_tree, + replace_dbg_hash_fixed_nr_of_locks([stim_cat_ord_set,named_table | Opts]), + Data, + false), delete_large_named_table_1(foo_hash, [named_table | Opts], Data, true). delete_large_named_table_1(Name, Flags, Data, Fix) -> @@ -4889,22 +4915,44 @@ info(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch ets:info(make_ref())), {'EXIT',{badarg,_}} = (catch ets:info(make_ref(), type)), - %% Test that one can set the synchronization granularity level for - %% tables of type set - T1 = ets:new(t1, [public, {write_concurrency, 1024}]), - 1024 = ets:info(T1, write_concurrency), - T2 = ets:new(t2, [public, {write_concurrency, 2048}]), - 2048 = ets:info(T2, write_concurrency), - T3 = ets:new(t3, [public, {write_concurrency, 1024}, {write_concurrency, true}]), - true = ets:info(T3, write_concurrency), - T4 = ets:new(t4, [private, {write_concurrency, 1024}]), - false = ets:info(T4, write_concurrency), - T5 = ets:new(t5, [public, {write_concurrency, auto}]), - auto = ets:info(T5, write_concurrency), - T6 = ets:new(t6, [private, {write_concurrency, true}]), - false = ets:info(T6, write_concurrency), - T7 = ets:new(t7, [private, {write_concurrency, auto}]), - false = ets:info(T7, write_concurrency), + case erlang:system_info(schedulers) of + 1 -> %% Fine grained locking is not activated when there is only one scheduler + lists:foreach( + fun(Type) -> + T1 = ets:new(t1, [public, Type, {write_concurrency, auto}]), + false = ets:info(T1, write_concurrency), + T2 = ets:new(t2, [public, Type, {write_concurrency, true}]), + false = ets:info(T2, write_concurrency) + end, + [set, bag, duplicate_bag, ordered_set]), + T2 = ets:new(t2, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 2049}}]), + false = ets:info(T2, write_concurrency); + _ -> + %% Test that one can set the synchronization granularity level for + %% tables of type set + T1 = ets:new(t1, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}]), + {debug_hash_fixed_number_of_locks, 1024} = ets:info(T1, write_concurrency), + T2 = ets:new(t2, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 2048}}]), + {debug_hash_fixed_number_of_locks, 2048} = ets:info(T2, write_concurrency), + T3 = ets:new(t3, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}, {write_concurrency, true}]), + true = ets:info(T3, write_concurrency), + T4 = ets:new(t4, [private, {write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}]), + false = ets:info(T4, write_concurrency), + %% Test the auto option + lists:foreach( + fun(Type) -> + T5 = ets:new(t5, [public, Type, {write_concurrency, auto}]), + auto = ets:info(T5, write_concurrency) + end, + [set, bag, duplicate_bag, ordered_set]), + T6 = ets:new(t6, [private, {write_concurrency, true}]), + false = ets:info(T6, write_concurrency), + T7 = ets:new(t7, [private, {write_concurrency, auto}]), + false = ets:info(T7, write_concurrency), + %% Test that the number of locks is rounded down to the nearest power of two + T8 = ets:new(t8, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 2049}}]), + {debug_hash_fixed_number_of_locks, 2048} = ets:info(T8, write_concurrency) + end, ok. info_do(Opts) -> @@ -5131,18 +5179,26 @@ test_table_size_concurrency(Config) when is_list(Config) -> case erlang:system_info(schedulers) of 1 -> {skip,"Only valid on smp > 1 systems"}; _ -> - BaseOptions = [public, {write_concurrency, true}], - test_table_counter_concurrency(size, [set | BaseOptions]), - test_table_counter_concurrency(size, [ordered_set | BaseOptions]) + lists:foreach( + fun(WriteConcurrencyOpt) -> + BaseOptions = [public, {write_concurrency, WriteConcurrencyOpt}], + test_table_counter_concurrency(size, [set | BaseOptions]), + test_table_counter_concurrency(size, [ordered_set | BaseOptions]) + end, + [true, auto]) end. test_table_memory_concurrency(Config) when is_list(Config) -> case erlang:system_info(schedulers) of 1 -> {skip,"Only valid on smp > 1 systems"}; _ -> - BaseOptions = [public, {write_concurrency, true}], - test_table_counter_concurrency(memory, [set | BaseOptions]), - test_table_counter_concurrency(memory, [ordered_set | BaseOptions]) + lists:foreach( + fun(WriteConcurrencyOpt) -> + BaseOptions = [public, {write_concurrency, WriteConcurrencyOpt}], + test_table_counter_concurrency(memory, [set | BaseOptions]), + test_table_counter_concurrency(memory, [ordered_set | BaseOptions]) + end, + [true, auto]) end. %% Tests that calling the ets:delete operation on a table T with @@ -5232,9 +5288,18 @@ test_decentralized_counters_setting(Config) when is_list(Config) -> do_test_decentralized_counters_setting(TableType) -> wait_for_memory_deallocations(), FlxCtrMemUsage = erts_debug:get_internal_state(flxctr_memory_usage), + FixOptsList = + fun(Opts) -> + case TableType of + ordered_set -> + replace_dbg_hash_fixed_nr_of_locks(Opts); + set -> + Opts + end + end, lists:foreach( fun(OptList) -> - T1 = ets:new(t1, [public, TableType] ++ OptList ++ [TableType]), + T1 = ets:new(t1, FixOptsList([public, TableType] ++ OptList ++ [TableType])), check_decentralized_counters(T1, false, FlxCtrMemUsage), ets:delete(T1) end, @@ -5242,21 +5307,22 @@ do_test_decentralized_counters_setting(TableType) -> case TableType of set -> [[{write_concurrency, true}, {decentralized_counters, false}], - [{write_concurrency, 1024}, {write_concurrency, true}]]; + [{write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}, {write_concurrency, true}]]; ordered_set -> [] end), lists:foreach( fun(OptList) -> - T1 = ets:new(t1, [public, - TableType, - {write_concurrency, true}] ++ OptList ++ [TableType]), + T1 = ets:new(t1, + FixOptsList([public, + TableType, + {write_concurrency, true}] ++ OptList ++ [TableType])), check_decentralized_counters(T1, true, FlxCtrMemUsage), ets:delete(T1), wait_for_memory_deallocations(), FlxCtrMemUsage = erts_debug:get_internal_state(flxctr_memory_usage) end, [[{decentralized_counters, true}], - [{write_concurrency, 1024}], + [{write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}], [{write_concurrency, auto}]]), ok. @@ -6049,7 +6115,8 @@ xfilltabstr(Tab,N) -> fill_sets_int(N) -> fill_sets_int(N,[]). fill_sets_int(N,Opts) -> - Tab1 = ets_new(xxx, [ordered_set|Opts]), + Tab1 = ets_new(xxx, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), filltabint(Tab1,N), Tab2 = ets_new(xxx, [set|Opts]), filltabint(Tab2,N), @@ -6060,7 +6127,8 @@ fill_sets_int(N,Opts) -> [Tab1,Tab2,Tab3,Tab4]. fill_sets_intup(N,Opts) -> - Tab1 = ets_new(xxx, [ordered_set|Opts]), + Tab1 = ets_new(xxx, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), filltabintup(Tab1,N), Tab2 = ets_new(xxx, [set|Opts]), filltabintup(Tab2,N), @@ -7703,7 +7771,7 @@ prefill_insert_map_loop(T, RS0, N, ObjFun, InsertMap, NrOfSchedulers) -> [set, public, {read_concurrency, true}], [set, public, {write_concurrency, true}, {read_concurrency, true}], [set, public, {write_concurrency, auto}, {read_concurrency, true}], - [set, public, {write_concurrency, 16384}] + [set, public, {write_concurrency, {debug_hash_fixed_number_of_locks, 16384}}] ], etsmem_fun = fun() -> ok end, verify_etsmem_fun = fun(_) -> true end, @@ -8072,7 +8140,7 @@ long_throughput_benchmark(Config) when is_list(Config) -> [ordered_set, public, {write_concurrency, true}, {read_concurrency, true}], [set, public, {write_concurrency, true}, {read_concurrency, true}], [set, public, {write_concurrency, auto}, {read_concurrency, true}], - [set, public, {write_concurrency, 16384}] + [set, public, {write_concurrency, {debug_hash_fixed_number_of_locks, 16384}}] ], etsmem_fun = fun etsmem/0, verify_etsmem_fun = fun verify_etsmem/1, @@ -9241,8 +9309,30 @@ make_unaligned_sub_binary(Bin0) when is_binary(Bin0) -> make_unaligned_sub_binary(List) -> make_unaligned_sub_binary(list_to_binary(List)). +replace_dbg_hash_fixed_nr_of_locks(Opts) -> + [case X of + {write_concurrency, {debug_hash_fixed_number_of_locks, _}} -> + {write_concurrency, true}; + _ -> X + end || X <- Opts]. + %% Repeat test function with different combination of table options -%% +%% +repeat_for_opts_extra_opt(F, Extra) -> + repeat_for_opts( + fun(Opts) -> + WithExtra = + case erlang:is_list(Extra) of + true -> Extra ++ Opts; + false ->[Extra | Opts] + end, + case is_invalid_opts_combo(WithExtra) of + true -> ok; + false -> F(WithExtra) + end + end, + [write_concurrency, read_concurrency, compressed]). + repeat_for_opts(F) -> repeat_for_opts(F, [write_concurrency, read_concurrency, compressed]). @@ -9303,21 +9393,35 @@ repeat_for_opts_atom2list(all_non_stim_types) -> [set,ordered_set,cat_ord_set,ba repeat_for_opts_atom2list(all_non_stim_set_types) -> [set,ordered_set,cat_ord_set]; repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false}, {write_concurrency,true}, - {write_concurrency,2}, - {write_concurrency,2048}, + {write_concurrency, {debug_hash_fixed_number_of_locks, 2048}}, {write_concurrency,auto}]; repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}]; repeat_for_opts_atom2list(compressed) -> [void,compressed]. +is_invalid_opts_combo(Opts) -> + FixedNumLocksOption = + lists:any( + fun({write_concurrency, {debug_hash_fixed_number_of_locks, _}}) -> + true; + (_) -> + false + end, + Opts), + OrderedSet = lists:member(ordered_set, Opts) orelse + lists:member(stim_cat_ord_set, Opts) orelse + lists:member(cat_ord_set, Opts), + OrderedSet andalso FixedNumLocksOption. + is_redundant_opts_combo(Opts) -> - ((lists:member(stim_cat_ord_set, Opts) orelse - lists:member(cat_ord_set, Opts)) - andalso - (lists:member({write_concurrency, 2}, Opts) orelse - lists:member({write_concurrency, 2048}, Opts) orelse - lists:member({write_concurrency, false}, Opts) orelse - lists:member(private, Opts) orelse - lists:member(protected, Opts))). + IsRed1 = + ((lists:member(stim_cat_ord_set, Opts) orelse + lists:member(cat_ord_set, Opts)) + andalso + (lists:member({write_concurrency, false}, Opts) orelse + lists:member(private, Opts) orelse + lists:member(protected, Opts))), + IsRed2 = is_invalid_opts_combo(Opts), + IsRed1 orelse IsRed2. %% Add fake table option with info about key range. %% Will be consumed by ets_new and used for stim_cat_ord_set. -- 2.31.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor