aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/erl_alloc.c6
-rw-r--r--erts/emulator/test/alloc_SUITE.erl58
-rw-r--r--erts/emulator/test/alloc_SUITE_data/allocator_test.h5
-rw-r--r--erts/emulator/test/alloc_SUITE_data/migration.c112
4 files changed, 132 insertions, 49 deletions
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 214fb1f2af..b3522a9dbf 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -3722,7 +3722,9 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
case 0xf15: erts_free(ERTS_ALC_T_TEST, (void*)a1); return 0;
- case 0xf16: {
+ case 0xf16: return (UWord) erts_realloc(ERTS_ALC_T_TEST, (void*)a1, (Uint)a2);
+
+ case 0xf17: {
Uint extra_hdr_sz = UNIT_CEILING((Uint)a1);
ErtsAllocatorThrSpec_t* ts = &erts_allctr_thr_spec[ERTS_ALC_A_TEST];
Uint offset = ts->allctr[0]->mbc_header_size;
@@ -3749,7 +3751,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
*(void**)a3 = orig_destroying_mbc;
return offset;
}
- case 0xf17: {
+ case 0xf18: {
ErtsAllocatorThrSpec_t* ts = &erts_allctr_thr_spec[ERTS_ALC_A_TEST];
return ts->allctr[0]->largest_mbc_size;
}
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index 3a721095e2..518e0c974a 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -114,7 +114,7 @@ erts_mmap_do(Config, SCO, SCRPM, SCRFSD) ->
0 -> O1;
_ -> O1 ++ " +MMscrfsd"++integer_to_list(SCRFSD)
end,
- {ok, Node} = start_node(Config, Opts),
+ {ok, Node} = start_node(Config, Opts, []),
Self = self(),
Ref = make_ref(),
F = fun() ->
@@ -155,7 +155,9 @@ drv_case(Config) ->
drv_case(Config, Mode, NodeOpts) when is_list(Config) ->
case os:type() of
{Family, _} when Family == unix; Family == win32 ->
- {ok, Node} = start_node(Config, NodeOpts),
+ %%Prog = {prog,"/my/own/otp/bin/cerl -debug"},
+ Prog = [],
+ {ok, Node} = start_node(Config, NodeOpts, Prog),
Self = self(),
Ref = make_ref(),
spawn_link(Node,
@@ -221,19 +223,35 @@ wait_for_memory_deallocations() ->
end.
print_stats(migration) ->
- {Btot,Ctot} = lists:foldl(fun({instance,Inr,Istats}, {Bacc,Cacc}) ->
- {mbcs,MBCS} = lists:keyfind(mbcs, 1, Istats),
- Btup = lists:keyfind(blocks, 1, MBCS),
- Ctup = lists:keyfind(carriers, 1, MBCS),
- io:format("{instance,~p,~p,~p}\n", [Inr, Btup, Ctup]),
- {tuple_add(Bacc,Btup),tuple_add(Cacc,Ctup)};
- (_, Acc) -> Acc
- end,
- {{blocks,0,0,0},{carriers,0,0,0}},
- erlang:system_info({allocator,test_alloc})),
-
+ IFun = fun({instance,Inr,Istats}, {Bacc,Cacc,Pacc}) ->
+ {mbcs,MBCS} = lists:keyfind(mbcs, 1, Istats),
+ Btup = lists:keyfind(blocks, 1, MBCS),
+ Ctup = lists:keyfind(carriers, 1, MBCS),
+
+ Ptup = case lists:keyfind(mbcs_pool, 1, Istats) of
+ {mbcs_pool,POOL} ->
+ {blocks, Bpool} = lists:keyfind(blocks, 1, POOL),
+ {carriers, Cpool} = lists:keyfind(carriers, 1, POOL),
+ {pool, Bpool, Cpool};
+ false ->
+ {pool, 0, 0}
+ end,
+ io:format("{instance,~p,~p,~p,~p}}\n",
+ [Inr, Btup, Ctup, Ptup]),
+ {tuple_add(Bacc,Btup),tuple_add(Cacc,Ctup),
+ tuple_add(Pacc,Ptup)};
+ (_, Acc) -> Acc
+ end,
+
+ {Btot,Ctot,Ptot} = lists:foldl(IFun,
+ {{blocks,0,0,0},{carriers,0,0,0},{pool,0,0}},
+ erlang:system_info({allocator,test_alloc})),
+
+ {pool, PBtot, PCtot} = Ptot,
io:format("Number of blocks : ~p\n", [Btot]),
- io:format("Number of carriers: ~p\n", [Ctot]);
+ io:format("Number of carriers: ~p\n", [Ctot]),
+ io:format("Number of pooled blocks : ~p\n", [PBtot]),
+ io:format("Number of pooled carriers: ~p\n", [PCtot]);
print_stats(_) -> ok.
tuple_add(T1, T2) ->
@@ -330,13 +348,13 @@ handle_result(_State, Result0) ->
continue
end.
-start_node(Config, Opts) when is_list(Config), is_list(Opts) ->
+start_node(Config, Opts, Prog) when is_list(Config), is_list(Opts) ->
case proplists:get_value(debug,Config) of
true -> {ok, node()};
- _ -> start_node_1(Config, Opts)
+ _ -> start_node_1(Config, Opts, Prog)
end.
-start_node_1(Config, Opts) ->
+start_node_1(Config, Opts, Prog) ->
Pa = filename:dirname(code:which(?MODULE)),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
@@ -345,7 +363,11 @@ start_node_1(Config, Opts) ->
++ integer_to_list(erlang:system_time(second))
++ "-"
++ integer_to_list(erlang:unique_integer([positive]))),
- test_server:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]).
+ ErlArg = case Prog of
+ [] -> [];
+ _ -> [{erl,[Prog]}]
+ end,
+ test_server:start_node(Name, slave, [{args, Opts++" -pa "++Pa} | ErlArg]).
stop_node(Node) when Node =:= node() -> ok;
stop_node(Node) ->
diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
index 97ee58cdad..5272f86c98 100644
--- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h
+++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
@@ -156,7 +156,8 @@ typedef void* erts_cond;
#define IS_SMP_ENABLED ((int) ALC_TEST0(0xf13))
#define ALLOC_TEST(S) ((void*) ALC_TEST1(0xf14, (S)))
#define FREE_TEST(P) ((void) ALC_TEST1(0xf15, (P)))
-#define SET_TEST_MBC_USER_HEADER(SZ,CMBC,DMBC) ((int)ALC_TEST3(0xf16, (SZ), (CMBC), (DMBC)))
-#define GET_TEST_MBC_SIZE() ((int) ALC_TEST0(0xf17))
+#define REALLOC_TEST(P,S) ((void*) ALC_TEST2(0xf16, (P), (S)))
+#define SET_TEST_MBC_USER_HEADER(SZ,CMBC,DMBC) ((int)ALC_TEST3(0xf17, (SZ), (CMBC), (DMBC)))
+#define GET_TEST_MBC_SIZE() ((int) ALC_TEST0(0xf18))
#endif
diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c
index b9a4de03b3..1d974225fc 100644
--- a/erts/emulator/test/alloc_SUITE_data/migration.c
+++ b/erts/emulator/test/alloc_SUITE_data/migration.c
@@ -223,6 +223,42 @@ static int rand_int(MigrationState* state, int low, int high)
return low + (x % (high+1-low));
}
+enum Operation
+{
+ ALLOCATE_OP,
+ FREE_OP,
+ REALLOC_OP,
+ CLEANUP_OP
+};
+
+static enum Operation rand_op(MigrationState* state)
+{
+ int r = rand_int(state, 1, 100);
+ switch (state->phase) {
+ case GROWING:
+ FATAL_ASSERT(state->nblocks < state->max_nblocks);
+ if (r > 10 || state->nblocks == 0)
+ return ALLOCATE_OP;
+ else if (r > 5)
+ return FREE_OP;
+ else
+ return REALLOC_OP;
+
+ case SHRINKING:
+ FATAL_ASSERT(state->nblocks > 0);
+ if (r > 10 || state->nblocks == state->max_nblocks)
+ return FREE_OP;
+ else if (r > 5)
+ return ALLOCATE_OP;
+ else
+ return REALLOC_OP;
+
+ case CLEANUP:
+ return CLEANUP_OP;
+ default:
+ FATAL_ASSERT(!"Invalid op phase");
+ }
+}
static void do_cleanup(TestCaseState_t *tcs, MigrationState* state)
{
@@ -275,53 +311,75 @@ testcase_run(TestCaseState_t *tcs)
state->goal_nblocks = rand_int(state, 1, state->max_nblocks);
}
- switch (state->phase) {
- case GROWING: {
+ switch (rand_op(state)) {
+ case ALLOCATE_OP: {
MyBlock* p;
FATAL_ASSERT(!state->blockv[state->nblocks]);
- p = ALLOC_TEST(rand_int(state, state->block_size/2, state->block_size));
+ p = ALLOC_TEST(rand_int(state, state->block_size/2, state->block_size));
FATAL_ASSERT(p);
add_block(p, state);
- state->blockv[state->nblocks] = p;
- if (++state->nblocks >= state->goal_nblocks) {
- /*testcase_printf(tcs, "%d: Grown to %d blocks", tcs->thr_nr, state->nblocks);*/
- state->phase = SHRINKING;
- state->goal_nblocks = rand_int(state, 0, state->goal_nblocks-1);
- }
- else
- FATAL_ASSERT(!state->blockv[state->nblocks]);
+ state->blockv[state->nblocks++] = p;
break;
}
- case SHRINKING: {
+ case FREE_OP: {
int ix = rand_int(state, 0, state->nblocks-1);
FATAL_ASSERT(state->blockv[ix]);
remove_block(state->blockv[ix]);
FREE_TEST(state->blockv[ix]);
state->blockv[ix] = state->blockv[--state->nblocks];
state->blockv[state->nblocks] = NULL;
-
- if (state->nblocks <= state->goal_nblocks) {
- /*testcase_printf(tcs, "%d: Shrunk to %d blocks", tcs->thr_nr, state->nblocks);*/
- if (++state->round >= MAX_ROUNDS) {
- state->phase = CLEANUP;
- } else {
- state->phase = GROWING;
- state->goal_nblocks = rand_int(state, state->goal_nblocks+1, state->max_nblocks);
- }
- }
break;
}
+ case REALLOC_OP: {
+ int ix = rand_int(state, 0, state->nblocks-1);
+ MyBlock* p;
+ FATAL_ASSERT(state->blockv[ix]);
+ remove_block(state->blockv[ix]);
+ p = REALLOC_TEST(state->blockv[ix], rand_int(state, state->block_size/2, state->block_size));
+ FATAL_ASSERT(p);
+ add_block(p, state);
+ state->blockv[ix] = p;
+ break;
+ }
+ case CLEANUP_OP:
+ do_cleanup(tcs, state);
+ break;
+ default:
+ FATAL_ASSERT(!"Invalid operation");
+ }
+
+ switch (state->phase) {
+ case GROWING: {
+ if (state->nblocks >= state->goal_nblocks) {
+ /*testcase_printf(tcs, "%d: Grown to %d blocks", tcs->thr_nr, state->nblocks);*/
+ state->phase = SHRINKING;
+ state->goal_nblocks = rand_int(state, 0, state->goal_nblocks-1);
+ }
+ else
+ FATAL_ASSERT(!state->blockv[state->nblocks]);
+ break;
+ }
+ case SHRINKING: {
+ if (state->nblocks <= state->goal_nblocks) {
+ /*testcase_printf(tcs, "%d: Shrunk to %d blocks", tcs->thr_nr, state->nblocks);*/
+ if (++state->round >= MAX_ROUNDS) {
+ state->phase = CLEANUP;
+ } else {
+ state->phase = GROWING;
+ state->goal_nblocks = rand_int(state, state->goal_nblocks+1, state->max_nblocks);
+ }
+ }
+ break;
+ }
case CLEANUP:
- do_cleanup(tcs, state);
- break;
+ case DONE:
+ break;
default:
FATAL_ASSERT(!"Invalid phase");
}
- if (state->phase == DONE) {
- }
- else {
+ if (state->phase != DONE) {
testcase_continue(tcs);
}
}