aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2018-11-23 17:36:59 +0100
committerSverker Eriksson <[email protected]>2018-11-23 17:36:59 +0100
commitceeb321ca0e86a436c87eab2c38eae2380f78d1a (patch)
tree50d4998f8842dd45c3fc94ada5bc8c4924cbb5b2
parent3d4ecf2f722dfb952bba57daaaef617500133fb9 (diff)
downloadotp-ceeb321ca0e86a436c87eab2c38eae2380f78d1a.tar.gz
otp-ceeb321ca0e86a436c87eab2c38eae2380f78d1a.tar.bz2
otp-ceeb321ca0e86a436c87eab2c38eae2380f78d1a.zip
erts: Fix bug in counters
Wow, that could have been embarrassing.
-rw-r--r--erts/emulator/beam/erl_bif_counters.c2
-rw-r--r--erts/emulator/test/counters_SUITE.erl61
2 files changed, 60 insertions, 3 deletions
diff --git a/erts/emulator/beam/erl_bif_counters.c b/erts/emulator/beam/erl_bif_counters.c
index 84496e83ef..7c8884ba32 100644
--- a/erts/emulator/beam/erl_bif_counters.c
+++ b/erts/emulator/beam/erl_bif_counters.c
@@ -130,7 +130,7 @@ static ERTS_INLINE int get_ref_cnt(Eterm ref, Eterm index,
UWord ix, ui, vi;
if (!get_ref(ref, &p) || !term_to_UWord(index, &ix) || --ix >= p->arity)
return 0;
- ui = (ix / ATOMICS_PER_CACHE_LINE) * ATOMICS_PER_COUNTER;
+ ui = (ix / ATOMICS_PER_CACHE_LINE) * ATOMICS_PER_COUNTER + sched_ix;
vi = ix % ATOMICS_PER_CACHE_LINE;
ASSERT(ui < p->ulen);
*pp = p;
diff --git a/erts/emulator/test/counters_SUITE.erl b/erts/emulator/test/counters_SUITE.erl
index 8cc963e3b9..b3f0358c1e 100644
--- a/erts/emulator/test/counters_SUITE.erl
+++ b/erts/emulator/test/counters_SUITE.erl
@@ -22,12 +22,12 @@
-include_lib("common_test/include/ct.hrl").
-export([suite/0, all/0]).
--export([basic/1, bad/1, limits/1, indep/1]).
+-export([basic/1, bad/1, limits/1, indep/1, write_concurrency/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [basic, bad, limits, indep].
+ [basic, bad, limits, indep, write_concurrency].
basic(Config) when is_list(Config) ->
Size = 10,
@@ -175,3 +175,60 @@ indep_subber(Ref, I, Val) when Val > -(1 bsl 62) ->
indep_subber(Ref, I, Res);
indep_subber(_Ref, _I, Val) ->
Val.
+
+
+
+%% Verify write_concurrency yields correct results.
+write_concurrency(Config) when is_list(Config) ->
+ rand:seed(exs1024s),
+ io:format("*** SEED: ~p ***\n", [rand:export_seed()]),
+ NScheds = erlang:system_info(schedulers),
+ Size = 100,
+ Ref = counters:new(Size,[write_concurrency]),
+ Rounds = 1000,
+ Papa = self(),
+ Pids = [spawn_opt(fun Worker() ->
+ receive
+ {go, Ix, Incr} ->
+ wc_looper(Rounds, Ref, Ix, Incr),
+ Papa ! {self(), done, Rounds*Incr},
+ Worker();
+ stop ->
+ ok
+ end
+ end,
+ [link, {scheduler, N}])
+ || N <- lists:seq(1, NScheds)],
+ [begin
+ Base = rand_log64(),
+ counters:put(Ref, Index, Base),
+ SendList = [{P,{go, Index, rand_log64()}} || P <- Pids],
+ [P ! Msg || {P,Msg} <- SendList],
+ Added = lists:sum([receive {P,done,Contrib} -> Contrib end || P <- Pids]),
+ Result = mask_sint64(Base+Added),
+ {_,Result} = {Result, counters:get(Ref, Index)}
+ end
+ || Index <- lists:seq(1, Size)],
+
+ [begin unlink(P), P ! stop end || P <- Pids],
+ ok.
+
+wc_looper(0, _, _, _) ->
+ ok;
+wc_looper(N, Ref, Ix, Incr) ->
+ counters:add(Ref, Ix, Incr),
+ wc_looper(N-1, Ref, Ix, Incr).
+
+mask_sint64(X) ->
+ SMask = 1 bsl 63,
+ UMask = SMask - 1,
+ (X band UMask) - (X band SMask).
+
+%% A random signed 64-bit integer
+%% with a uniformly distributed number of significant bits.
+rand_log64() ->
+ Uint = round(math:pow(2, rand:uniform()*63)),
+ case rand:uniform(2) of
+ 1 -> -Uint;
+ 2 -> Uint
+ end.