From b72ad981e96fcc14c245ef2bd10c5c98c6a239f6 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 5 Dec 2014 15:13:07 +0100 Subject: erts: Add TEST allocator --- erts/emulator/test/alloc_SUITE_data/allocator_test.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h index 1d6b2f4907..a7f12c6ca8 100644 --- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -142,5 +142,7 @@ typedef void* erts_cond; #define THR_JOIN(T) ((void) ALC_TEST1(0xf11, (T))) #define THR_EXIT(R) ((void) ALC_TEST1(0xf12, (R))) #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))) #endif -- cgit v1.2.3 From 38ddf72b48377bd6b2fb8c4b6981360ae7d44d79 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 8 Dec 2014 15:38:04 +0100 Subject: erts: Add alloc_SUITE:migration --- erts/emulator/test/alloc_SUITE.erl | 78 +++++-- erts/emulator/test/alloc_SUITE_data/Makefile.src | 3 +- .../test/alloc_SUITE_data/allocator_test.h | 2 + erts/emulator/test/alloc_SUITE_data/migration.c | 229 +++++++++++++++++++++ .../test/alloc_SUITE_data/testcase_driver.c | 14 ++ .../test/alloc_SUITE_data/testcase_driver.h | 1 + 6 files changed, 313 insertions(+), 14 deletions(-) create mode 100644 erts/emulator/test/alloc_SUITE_data/migration.c (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 7c7ddde5d4..9b0d4737b1 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -31,7 +31,8 @@ rbtree/1, mseg_clear_cache/1, erts_mmap/1, - cpool/1]). + cpool/1, + migration/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -43,7 +44,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, coalesce, threads, realloc_copy, bucket_index, - bucket_mask, rbtree, mseg_clear_cache, erts_mmap, cpool]. + bucket_mask, rbtree, mseg_clear_cache, erts_mmap, cpool, migration]. groups() -> []. @@ -112,6 +113,8 @@ cpool(suite) -> []; cpool(doc) -> []; cpool(Cfg) -> ?line drv_case(Cfg). +migration(Cfg) -> drv_case(Cfg, concurrent, "+MZe true"). + erts_mmap(Config) when is_list(Config) -> case {?t:os_type(), is_halfword_vm()} of {{unix, _}, false} -> @@ -176,18 +179,17 @@ erts_mmap_do(Config, SCO, SCRPM, SCRFSD) -> %% %% drv_case(Config) -> - drv_case(Config, ""). + drv_case(Config, one_shot, ""). -drv_case(Config, Command) when is_list(Config), - is_list(Command) -> +drv_case(Config, Mode, NodeOpts) when is_list(Config) -> case ?t:os_type() of {Family, _} when Family == unix; Family == win32 -> - ?line {ok, Node} = start_node(Config), + ?line {ok, Node} = start_node(Config, NodeOpts), ?line Self = self(), ?line Ref = make_ref(), ?line spawn_link(Node, fun () -> - Res = run_drv_case(Config, Command), + Res = run_drv_case(Config, Mode), Self ! {Ref, Res} end), ?line Result = receive {Ref, Rslt} -> Rslt end, @@ -199,7 +201,7 @@ drv_case(Config, Command) when is_list(Config), | io_lib:format("~p",[SkipOs])])} end. -run_drv_case(Config, Command) -> +run_drv_case(Config, Mode) -> ?line DataDir = ?config(data_dir,Config), ?line CaseName = ?config(testcase,Config), case erl_ddll:load_driver(DataDir, CaseName) of @@ -208,6 +210,19 @@ run_drv_case(Config, Command) -> io:format("~s\n", [erl_ddll:format_error(Error)]), ?line ?t:fail() end, + + case Mode of + one_shot -> + Result = one_shot(CaseName, ""); + + concurrent -> + Result = concurrent(CaseName) + end, + + ?line ok = erl_ddll:unload_driver(CaseName), + ?line Result. + +one_shot(CaseName, Command) -> ?line Port = open_port({spawn, atom_to_list(CaseName)}, []), ?line true = is_port(Port), ?line Port ! {self(), {command, Command}}, @@ -217,8 +232,45 @@ run_drv_case(Config, Command) -> {Port, closed} -> ok end, - ?line ok = erl_ddll:unload_driver(CaseName), - ?line Result. + Result. + + +many_shot(CaseName, Command) -> + ?line Port = open_port({spawn, atom_to_list(CaseName)}, []), + ?line true = is_port(Port), + Result = repeat_while(fun() -> + ?line Port ! {self(), {command, Command}}, + receive_drv_result(Port, CaseName) =:= continue + end), + ?line Port ! {self(), close}, + ?line receive + {Port, closed} -> + ok + end, + Result. + +concurrent(CaseName) -> + one_shot(CaseName, "init"), + PRs = lists:map(fun(I) -> spawn_opt(fun() -> + many_shot(CaseName, "") + end, + [monitor, {scheduler,I}]) + end, + lists:seq(1, erlang:system_info(schedulers))), + lists:foreach(fun({Pid,Ref}) -> + receive {'DOWN', Ref, process, Pid, Reason} -> + Reason + end + end, + PRs), + ok. + +repeat_while(Fun) -> + io:format("~p calls fun\n", [self()]), + case Fun() of + true -> repeat_while(Fun); + false -> ok + end. receive_drv_result(Port, CaseName) -> ?line receive @@ -236,11 +288,11 @@ receive_drv_result(Port, CaseName) -> {succeeded, Port, CaseName, ""} -> ?line succeeded; {succeeded, Port, CaseName, Comment} -> - ?line {comment, Comment} + ?line {comment, Comment}; + continue -> + continue end. -start_node(Config) -> - start_node(Config, []). start_node(Config, Opts) when is_list(Config), is_list(Opts) -> Pa = filename:dirname(code:which(?MODULE)), Name = list_to_atom(atom_to_list(?MODULE) diff --git a/erts/emulator/test/alloc_SUITE_data/Makefile.src b/erts/emulator/test/alloc_SUITE_data/Makefile.src index a441fe946b..e31de54e1b 100644 --- a/erts/emulator/test/alloc_SUITE_data/Makefile.src +++ b/erts/emulator/test/alloc_SUITE_data/Makefile.src @@ -25,7 +25,8 @@ TEST_DRVS = basic@dll@ \ bucket_mask@dll@ \ rbtree@dll@ \ mseg_clear_cache@dll@ \ - cpool@dll@ + cpool@dll@ \ + migration@dll@ CC = @CC@ LD = @LD@ diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h index a7f12c6ca8..bfd0bb3094 100644 --- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -85,6 +85,7 @@ typedef void* erts_cond; #define CPOOL_DELETE(A,B) ((Carrier_t *) ALC_TEST2(0x022, (A), (B))) #define CPOOL_IS_EMPTY(A) ((int) ALC_TEST1(0x023, (A))) #define CPOOL_IS_IN_POOL(A,B) ((int) ALC_TEST2(0x024, (A), (B))) +#define UMEM2BLK_TEST(P) ((Block_t*) ALC_TEST1(0x025, (P))) /* From erl_goodfit_alloc.c */ #define BKT_IX(A, S) ((Ulong) ALC_TEST2(0x100, (A), (S))) @@ -144,5 +145,6 @@ 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))) #endif diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c new file mode 100644 index 0000000000..dd58a0d3dd --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/migration.c @@ -0,0 +1,229 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2014. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Test the carrier migration logic + */ + +#ifndef __WIN32__ +#include +#include +#include +#endif +#include +#include +#include +#include "testcase_driver.h" +#include "allocator_test.h" + +#define FATAL_ASSERT(A) \ + ((void) ((A) \ + ? 1 \ + : (fatal_assert_failed(#A, \ + (char *) __FILE__, \ + __LINE__), \ + 0))) + +static void +fatal_assert_failed(char* expr, char* file, int line) +{ + fflush(stdout); + fprintf(stderr, "%s:%d: Assertion failed: %s\n", + file, line, expr); + fflush(stderr); + abort(); +} + + +char * +testcase_name(void) +{ + return "migration"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ +} + +#define MAX_BLOCK_PER_THR 100 +#define MAX_ROUNDS 10 + +typedef struct MyBlock_ { + struct MyBlock_* next; + struct MyBlock_** prevp; +} MyBlock; + +typedef struct { + MyBlock* blockv[MAX_BLOCK_PER_THR]; + enum { GROWING, SHRINKING, CLEANUP, DONE } phase; + int ix; + int round; +} MigrationState; + +typedef struct { + ErlDrvMutex* mtx; + int nblocks; + MyBlock* first; +} MyCrrInfo; + + +static int crr_info_offset = -1; +static void (*orig_create_mbc_fn)(Allctr_t *allctr, Carrier_t *carrier); +static void (*orig_destroying_mbc_fn)(Allctr_t *allctr, Carrier_t *carrier); + +static void my_creating_mbc(Allctr_t *allctr, Carrier_t *carrier) +{ + MyCrrInfo* mci = (MyCrrInfo*) ((char*)carrier + crr_info_offset); + if (orig_create_mbc_fn) + orig_create_mbc_fn(allctr, carrier); + + mci->mtx = erl_drv_mutex_create("alloc_SUITE.migration"); + mci->nblocks = 0; + mci->first = NULL; +} + +static void my_destroying_mbc(Allctr_t *allctr, Carrier_t *carrier) +{ + MyCrrInfo* mci = (MyCrrInfo*) ((char*)carrier + crr_info_offset); + + FATAL_ASSERT(mci->nblocks == 0); + FATAL_ASSERT(mci->first == NULL); + erl_drv_mutex_destroy(mci->mtx); + + if (orig_destroying_mbc_fn) + orig_destroying_mbc_fn(allctr, carrier); +} + + +static void setup(TestCaseState_t* tcs) +{ + void* creating_mbc_arg = (void*)my_creating_mbc; + void* destroying_mbc_arg = (void*)my_destroying_mbc; + crr_info_offset = SET_TEST_MBC_USER_HEADER(sizeof(MyCrrInfo), + &creating_mbc_arg, + &destroying_mbc_arg); + ASSERT(tcs, crr_info_offset >= 0); + orig_create_mbc_fn = creating_mbc_arg; + orig_destroying_mbc_fn = destroying_mbc_arg; +} + +static void add_block(MyBlock* p) +{ + MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); + + erl_drv_mutex_lock(mci->mtx); + mci->nblocks++; + p->next = mci->first; + p->prevp = &mci->first; + mci->first = p; + if (p->next) + p->next->prevp = &p->next; + erl_drv_mutex_unlock(mci->mtx); +} + +static void remove_block(MyBlock* p) +{ + MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); + + erl_drv_mutex_lock(mci->mtx); + mci->nblocks--; + if (p->next) + p->next->prevp = p->prevp; + *p->prevp = p->next; + erl_drv_mutex_unlock(mci->mtx); +} + +void +testcase_run(TestCaseState_t *tcs) +{ + MigrationState* state = (MigrationState*) tcs->extra; + + if (tcs->command_len == 4 + && memcmp(tcs->command, "init", tcs->command_len) == 0) { + setup(tcs); + return; + } + + if (!tcs->extra) { + if (!IS_SMP_ENABLED) + testcase_skipped(tcs, "No SMP support"); + + tcs->extra = driver_alloc(sizeof(MigrationState)); + state = (MigrationState*) tcs->extra; + memset(state->blockv, 0, sizeof(state->blockv)); + state->phase = GROWING; + state->ix = 0; + state->round = 0; + } + + switch (state->phase) { + case GROWING: { + MyBlock* p; + FATAL_ASSERT(!state->blockv[state->ix]); + p = ALLOC_TEST((1 << 18) / 5); + FATAL_ASSERT(p); + add_block(p); + state->blockv[state->ix] = p; + do { + if (++state->ix >= MAX_BLOCK_PER_THR) { + state->phase = SHRINKING; + state->ix = 0; + break; + } + } while (state->blockv[state->ix] != NULL); + break; + } + case SHRINKING: + FATAL_ASSERT(state->blockv[state->ix]); + remove_block(state->blockv[state->ix]); + FREE_TEST(state->blockv[state->ix]); + state->blockv[state->ix] = NULL; + + state->ix += 1 + ((state->ix % 3) == 0); + if (state->ix >= MAX_BLOCK_PER_THR) { + if (++state->round >= MAX_ROUNDS) { + state->phase = CLEANUP; + } else { + state->phase = GROWING; + } + state->ix = 0; + } + break; + + case CLEANUP: + if (state->blockv[state->ix]) { + remove_block(state->blockv[state->ix]); + FREE_TEST(state->blockv[state->ix]); + } + if (++state->ix >= MAX_BLOCK_PER_THR) + state->phase = DONE; + break; + + default: + FATAL_ASSERT(!"Invalid phase"); + } + + if (state->phase == DONE) { + driver_free(tcs->extra); + tcs->extra = NULL; + } + else + testcase_continue(tcs); +} diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index bc674c56b7..d04eb1bcb0 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -39,6 +39,7 @@ #define TESTCASE_FAILED 0 #define TESTCASE_SKIPPED 1 #define TESTCASE_SUCCEEDED 2 +#define TESTCASE_CONTINUE 3 typedef struct { TestCaseState_t visible; @@ -129,6 +130,12 @@ testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) } switch (itcs->result) { + case TESTCASE_CONTINUE: + msg[0] = ERL_DRV_ATOM; + msg[1] = driver_mk_atom("continue"); + erl_drv_output_term(itcs->port_id, msg, 2); + return; + case TESTCASE_SUCCEEDED: result_atom = driver_mk_atom("succeeded"); break; @@ -239,6 +246,13 @@ void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) longjmp(itcs->done_jmp_buf, 1); } +void testcase_continue(TestCaseState_t *tcs) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + itcs->result = TESTCASE_CONTINUE; + longjmp(itcs->done_jmp_buf, 1); +} + void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) { InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h index 5d17eaec64..5d439735b7 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h @@ -37,6 +37,7 @@ typedef struct { void testcase_printf(TestCaseState_t *tcs, char *frmt, ...); void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...); void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...); +void testcase_continue(TestCaseState_t *tcs); void testcase_failed(TestCaseState_t *tcs, char *frmt, ...); int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line, char *assertion); -- cgit v1.2.3 From 41e0c6e584d392ed0d5fbbc51a84418c4f7abcf5 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 9 Dec 2014 11:53:16 +0100 Subject: erts: Refactor alloc_SUITE to use NIFs instead of drivers --- erts/emulator/test/alloc_SUITE.erl | 109 +++++++------ .../test/alloc_SUITE_data/allocator_test.h | 15 +- erts/emulator/test/alloc_SUITE_data/basic.c | 3 + erts/emulator/test/alloc_SUITE_data/basic.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/bucket_index.c | 2 + .../test/alloc_SUITE_data/bucket_index.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/bucket_mask.c | 2 + .../emulator/test/alloc_SUITE_data/bucket_mask.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/coalesce.c | 3 + erts/emulator/test/alloc_SUITE_data/coalesce.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/cpool.c | 9 +- erts/emulator/test/alloc_SUITE_data/cpool.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/migration.c | 44 +++--- erts/emulator/test/alloc_SUITE_data/migration.erl | 10 ++ .../test/alloc_SUITE_data/mseg_clear_cache.c | 3 + .../test/alloc_SUITE_data/mseg_clear_cache.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/rbtree.c | 3 + erts/emulator/test/alloc_SUITE_data/rbtree.erl | 10 ++ erts/emulator/test/alloc_SUITE_data/realloc_copy.c | 2 + .../test/alloc_SUITE_data/realloc_copy.erl | 10 ++ .../test/alloc_SUITE_data/testcase_driver.c | 171 ++++++++------------- .../test/alloc_SUITE_data/testcase_driver.h | 11 +- erts/emulator/test/alloc_SUITE_data/threads.c | 6 +- erts/emulator/test/alloc_SUITE_data/threads.erl | 10 ++ 24 files changed, 287 insertions(+), 196 deletions(-) create mode 100644 erts/emulator/test/alloc_SUITE_data/basic.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/bucket_index.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/bucket_mask.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/coalesce.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/cpool.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/migration.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/rbtree.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/realloc_copy.erl create mode 100644 erts/emulator/test/alloc_SUITE_data/threads.erl (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 9b0d4737b1..0dd68b778b 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -204,55 +204,43 @@ drv_case(Config, Mode, NodeOpts) when is_list(Config) -> run_drv_case(Config, Mode) -> ?line DataDir = ?config(data_dir,Config), ?line CaseName = ?config(testcase,Config), - case erl_ddll:load_driver(DataDir, CaseName) of - ok -> ok; - {error, Error} -> - io:format("~s\n", [erl_ddll:format_error(Error)]), - ?line ?t:fail() - end, + File = filename:join(DataDir, CaseName), + {ok,CaseName,Bin} = compile:file(File, [binary,return_errors]), + ?line {module,CaseName} = erlang:load_module(CaseName,Bin), + ok = CaseName:init(File), case Mode of one_shot -> - Result = one_shot(CaseName, ""); + Result = one_shot(CaseName); concurrent -> Result = concurrent(CaseName) end, - ?line ok = erl_ddll:unload_driver(CaseName), + ?line true = erlang:delete_module(CaseName), ?line Result. -one_shot(CaseName, Command) -> - ?line Port = open_port({spawn, atom_to_list(CaseName)}, []), - ?line true = is_port(Port), - ?line Port ! {self(), {command, Command}}, - ?line Result = receive_drv_result(Port, CaseName), - ?line Port ! {self(), close}, - ?line receive - {Port, closed} -> - ok - end, - Result. +one_shot(CaseName) -> + State = CaseName:start(1), + Result0 = CaseName:run(State), + false = (Result0 =:= continue), + Result1 = handle_result(State, Result0), + CaseName:stop(State), + Result1. -many_shot(CaseName, Command) -> - ?line Port = open_port({spawn, atom_to_list(CaseName)}, []), - ?line true = is_port(Port), - Result = repeat_while(fun() -> - ?line Port ! {self(), {command, Command}}, - receive_drv_result(Port, CaseName) =:= continue - end), - ?line Port ! {self(), close}, - ?line receive - {Port, closed} -> - ok - end, - Result. +many_shot(CaseName, I) -> + State = CaseName:start(I), + Result1 = repeat_while(fun() -> + Result0 = CaseName:run(State), + handle_result(State, Result0) + end), + CaseName:stop(State), + Result1. concurrent(CaseName) -> - one_shot(CaseName, "init"), PRs = lists:map(fun(I) -> spawn_opt(fun() -> - many_shot(CaseName, "") + many_shot(CaseName, I) end, [monitor, {scheduler,I}]) end, @@ -266,32 +254,39 @@ concurrent(CaseName) -> ok. repeat_while(Fun) -> - io:format("~p calls fun\n", [self()]), + %%io:format("~p calls fun\n", [self()]), case Fun() of - true -> repeat_while(Fun); - false -> ok + continue -> repeat_while(Fun); + R -> R end. -receive_drv_result(Port, CaseName) -> - ?line receive - {print, Port, CaseName, Str} -> - ?line ?t:format("~s", [Str]), - ?line receive_drv_result(Port, CaseName); - {'EXIT', Port, Error} -> - ?line ?t:fail(Error); - {'EXIT', error, Error} -> - ?line ?t:fail(Error); - {failed, Port, CaseName, Comment} -> - ?line ?t:fail(Comment); - {skipped, Port, CaseName, Comment} -> - ?line {skipped, Comment}; - {succeeded, Port, CaseName, ""} -> - ?line succeeded; - {succeeded, Port, CaseName, Comment} -> - ?line {comment, Comment}; - continue -> - continue - end. +flush_log() -> + receive + {print, Str} -> + ?t:format("~s", [Str]), + flush_log() + after 0 -> + ok + end. + +handle_result(_State, Result0) -> + flush_log(), + case Result0 of + {'EXIT', Error} -> + ?line ?t:fail(Error); + {'EXIT', error, Error} -> + ?line ?t:fail(Error); + {failed, Comment} -> + ?line ?t:fail(Comment); + {skipped, Comment} -> + ?line {skipped, Comment}; + {succeeded, ""} -> + ?line succeeded; + {succeeded, Comment} -> + ?line {comment, Comment}; + continue -> + continue + end. start_node(Config, Opts) when is_list(Config), is_list(Opts) -> Pa = filename:dirname(code:which(?MODULE)), diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h index bfd0bb3094..dd0227e725 100644 --- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -20,9 +20,20 @@ #ifndef ALLOCATOR_TEST_H__ #define ALLOCATOR_TEST_H__ -typedef ErlDrvUInt Ulong; +#if SIZEOF_VOID_P == SIZEOF_INT +typedef unsigned int Ulong; +#elif SIZEOF_VOID_P == SIZEOF_LONG +typedef unsigned long Ulong; +#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG +typedef unsigned long long Ulong; +#else +# error No pointer sized integer type found ??? +#endif -#ifndef __WIN32__ +#ifdef __WIN32__ +typedef Ulong erts_alc_test_Fn(Ulong, Ulong, Ulong, Ulong); +# define erts_alc_test ((erts_alc_test_Fn*)WinDynNifCallbacks.erts_alc_test) +#else Ulong erts_alc_test(Ulong, Ulong, Ulong, Ulong); #endif diff --git a/erts/emulator/test/alloc_SUITE_data/basic.c b/erts/emulator/test/alloc_SUITE_data/basic.c index 323a24a11f..debb3d7ebe 100644 --- a/erts/emulator/test/alloc_SUITE_data/basic.c +++ b/erts/emulator/test/alloc_SUITE_data/basic.c @@ -60,3 +60,6 @@ testcase_cleanup(TestCaseState_t *tcs) if (tcs->extra) STOP_ALC((Allctr_t *) tcs->extra); } + +ERL_NIF_INIT(basic, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/basic.erl b/erts/emulator/test/alloc_SUITE_data/basic.erl new file mode 100644 index 0000000000..a018fd5582 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/basic.erl @@ -0,0 +1,10 @@ +-module(basic). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_index.c b/erts/emulator/test/alloc_SUITE_data/bucket_index.c index c13f229049..45cb53fbf7 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_index.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_index.c @@ -113,3 +113,5 @@ test_it(TestCaseState_t *tcs, unsigned sbct) sbct ? sbct_buf : "default"); } +ERL_NIF_INIT(bucket_index, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_index.erl b/erts/emulator/test/alloc_SUITE_data/bucket_index.erl new file mode 100644 index 0000000000..c54f54e2f5 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/bucket_index.erl @@ -0,0 +1,10 @@ +-module(bucket_index). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c index 8d6166771e..d474c80343 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c @@ -183,3 +183,5 @@ testcase_run(TestCaseState_t *tcs) tcs->extra = NULL; } +ERL_NIF_INIT(bucket_mask, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.erl b/erts/emulator/test/alloc_SUITE_data/bucket_mask.erl new file mode 100644 index 0000000000..589a50e1fa --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.erl @@ -0,0 +1,10 @@ +-module(bucket_mask). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c index 0a5e0c5b0e..7791409a34 100644 --- a/erts/emulator/test/alloc_SUITE_data/coalesce.c +++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c @@ -317,3 +317,6 @@ testcase_cleanup(TestCaseState_t *tcs) if (tcs->extra) STOP_ALC((Allctr_t *) tcs->extra); } + +ERL_NIF_INIT(coalesce, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.erl b/erts/emulator/test/alloc_SUITE_data/coalesce.erl new file mode 100644 index 0000000000..453c726c4e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/coalesce.erl @@ -0,0 +1,10 @@ +-module(coalesce). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/cpool.c b/erts/emulator/test/alloc_SUITE_data/cpool.c index 75c2bc13ae..73026cc758 100644 --- a/erts/emulator/test/alloc_SUITE_data/cpool.c +++ b/erts/emulator/test/alloc_SUITE_data/cpool.c @@ -86,13 +86,13 @@ thread_func(void *arg) for (i = 0; i < (TEST_NO_CARRIERS_PER_THREAD+TEST_CARRIERS_OFFSET); i++) { int d; if (i < TEST_NO_CARRIERS_PER_THREAD) { - CPOOL_INSERT(alloc, crr[i]); + (void) CPOOL_INSERT(alloc, crr[i]); if ((i & 0x7) == 0) FATAL_ASSERT(CPOOL_IS_IN_POOL(alloc, crr[i])); } d = i-TEST_CARRIERS_OFFSET; if (d >= 0) { - CPOOL_DELETE(alloc, crr[d]); + (void) CPOOL_DELETE(alloc, crr[d]); if ((d & 0x7) == 0) FATAL_ASSERT(!CPOOL_IS_IN_POOL(alloc, crr[d])); } @@ -129,7 +129,7 @@ testcase_run(TestCaseState_t *tcs) for (c = 0; c < TEST_NO_CARRIERS_PER_THREAD; c++) { Carrier_t *crr = (Carrier_t *) p; p += zcrr_sz; - ZERO_CRR_INIT(alloc, crr); + (void) ZERO_CRR_INIT(alloc, crr); threads[t].crr[c] = crr; } } @@ -156,3 +156,6 @@ testcase_run(TestCaseState_t *tcs) ASSERT(tcs, no_threads == TEST_NO_THREADS); } + +ERL_NIF_INIT(cpool, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/cpool.erl b/erts/emulator/test/alloc_SUITE_data/cpool.erl new file mode 100644 index 0000000000..89053471fa --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/cpool.erl @@ -0,0 +1,10 @@ +-module(cpool). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c index dd58a0d3dd..9f6535c834 100644 --- a/erts/emulator/test/alloc_SUITE_data/migration.c +++ b/erts/emulator/test/alloc_SUITE_data/migration.c @@ -60,6 +60,8 @@ testcase_name(void) void testcase_cleanup(TestCaseState_t *tcs) { + enif_free(tcs->extra); + tcs->extra = NULL; } #define MAX_BLOCK_PER_THR 100 @@ -78,7 +80,7 @@ typedef struct { } MigrationState; typedef struct { - ErlDrvMutex* mtx; + ErlNifMutex* mtx; int nblocks; MyBlock* first; } MyCrrInfo; @@ -94,7 +96,7 @@ static void my_creating_mbc(Allctr_t *allctr, Carrier_t *carrier) if (orig_create_mbc_fn) orig_create_mbc_fn(allctr, carrier); - mci->mtx = erl_drv_mutex_create("alloc_SUITE.migration"); + mci->mtx = enif_mutex_create("alloc_SUITE.migration"); mci->nblocks = 0; mci->first = NULL; } @@ -105,49 +107,54 @@ static void my_destroying_mbc(Allctr_t *allctr, Carrier_t *carrier) FATAL_ASSERT(mci->nblocks == 0); FATAL_ASSERT(mci->first == NULL); - erl_drv_mutex_destroy(mci->mtx); + enif_mutex_destroy(mci->mtx); if (orig_destroying_mbc_fn) orig_destroying_mbc_fn(allctr, carrier); } - -static void setup(TestCaseState_t* tcs) +static int migration_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { void* creating_mbc_arg = (void*)my_creating_mbc; void* destroying_mbc_arg = (void*)my_destroying_mbc; + + if (testcase_nif_init(env, priv_data, load_info)) + return -1; + crr_info_offset = SET_TEST_MBC_USER_HEADER(sizeof(MyCrrInfo), &creating_mbc_arg, &destroying_mbc_arg); - ASSERT(tcs, crr_info_offset >= 0); + FATAL_ASSERT(crr_info_offset >= 0); orig_create_mbc_fn = creating_mbc_arg; orig_destroying_mbc_fn = destroying_mbc_arg; + + return 0; } static void add_block(MyBlock* p) { MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); - erl_drv_mutex_lock(mci->mtx); + enif_mutex_lock(mci->mtx); mci->nblocks++; p->next = mci->first; p->prevp = &mci->first; mci->first = p; if (p->next) p->next->prevp = &p->next; - erl_drv_mutex_unlock(mci->mtx); + enif_mutex_unlock(mci->mtx); } static void remove_block(MyBlock* p) { MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); - erl_drv_mutex_lock(mci->mtx); + enif_mutex_lock(mci->mtx); mci->nblocks--; if (p->next) p->next->prevp = p->prevp; *p->prevp = p->next; - erl_drv_mutex_unlock(mci->mtx); + enif_mutex_unlock(mci->mtx); } void @@ -155,17 +162,11 @@ testcase_run(TestCaseState_t *tcs) { MigrationState* state = (MigrationState*) tcs->extra; - if (tcs->command_len == 4 - && memcmp(tcs->command, "init", tcs->command_len) == 0) { - setup(tcs); - return; - } - if (!tcs->extra) { if (!IS_SMP_ENABLED) testcase_skipped(tcs, "No SMP support"); - tcs->extra = driver_alloc(sizeof(MigrationState)); + tcs->extra = enif_alloc(sizeof(MigrationState)); state = (MigrationState*) tcs->extra; memset(state->blockv, 0, sizeof(state->blockv)); state->phase = GROWING; @@ -220,10 +221,9 @@ testcase_run(TestCaseState_t *tcs) FATAL_ASSERT(!"Invalid phase"); } - if (state->phase == DONE) { - driver_free(tcs->extra); - tcs->extra = NULL; - } - else + if (state->phase != DONE) testcase_continue(tcs); } + +ERL_NIF_INIT(migration, testcase_nif_funcs, migration_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/migration.erl b/erts/emulator/test/alloc_SUITE_data/migration.erl new file mode 100644 index 0000000000..440a99becd --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/migration.erl @@ -0,0 +1,10 @@ +-module(migration). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c index 9c03f3a331..e5df3d647f 100644 --- a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c +++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c @@ -101,3 +101,6 @@ testcase_cleanup(TestCaseState_t *tcs) tcs->extra = NULL; } } + +ERL_NIF_INIT(mseg_clear_cache, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl new file mode 100644 index 0000000000..befd6c2e8e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl @@ -0,0 +1,10 @@ +-module(mseg_clear_cache). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.c b/erts/emulator/test/alloc_SUITE_data/rbtree.c index 8d4d5535a8..eb7b36984e 100644 --- a/erts/emulator/test/alloc_SUITE_data/rbtree.c +++ b/erts/emulator/test/alloc_SUITE_data/rbtree.c @@ -577,3 +577,6 @@ testcase_run(TestCaseState_t *tcs) testcase_printf(tcs, "aoffcaobf test succeeded!\n"); } + +ERL_NIF_INIT(rbtree, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.erl b/erts/emulator/test/alloc_SUITE_data/rbtree.erl new file mode 100644 index 0000000000..f5b7120ff2 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/rbtree.erl @@ -0,0 +1,10 @@ +-module(rbtree). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/realloc_copy.c b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c index e405f06225..c4147eb00d 100644 --- a/erts/emulator/test/alloc_SUITE_data/realloc_copy.c +++ b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c @@ -278,3 +278,5 @@ testcase_cleanup(TestCaseState_t *tcs) STOP_ALC((Allctr_t *) tcs->extra); } +ERL_NIF_INIT(realloc_copy, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/realloc_copy.erl b/erts/emulator/test/alloc_SUITE_data/realloc_copy.erl new file mode 100644 index 0000000000..cc6617bf64 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/realloc_copy.erl @@ -0,0 +1,10 @@ +-module(realloc_copy). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index d04eb1bcb0..83ee1b67ca 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -43,128 +43,95 @@ typedef struct { TestCaseState_t visible; - ErlDrvPort port; - ErlDrvTermData port_id; + ErlNifEnv* curr_env; int result; jmp_buf done_jmp_buf; char *comment; char comment_buf[COMMENT_BUF_SZ]; } InternalTestCaseState_t; -ErlDrvData testcase_drv_start(ErlDrvPort port, char *command); -void testcase_drv_stop(ErlDrvData drv_data); -void testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); - -static ErlDrvEntry testcase_drv_entry = { - NULL, - testcase_drv_start, - testcase_drv_stop, - testcase_drv_run, - NULL, - NULL, - "testcase_drv", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, - NULL, - NULL, - NULL +ERL_NIF_TERM testcase_nif_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM testcase_nif_stop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +ErlNifFunc testcase_nif_funcs[] = +{ + {"start", 1, testcase_nif_start}, + {"run", 1, testcase_nif_run}, + {"stop", 1, testcase_nif_stop} }; +static ErlNifResourceType* testcase_rt; +static ERL_NIF_TERM print_atom; -DRIVER_INIT(testcase_drv) +int testcase_nif_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { - testcase_drv_entry.driver_name = testcase_name(); - return &testcase_drv_entry; + testcase_rt = enif_open_resource_type(env, NULL, "testcase_rt", NULL, + ERL_NIF_RT_CREATE, NULL); + + print_atom = enif_make_atom(env, "print"); + return 0; } -ErlDrvData -testcase_drv_start(ErlDrvPort port, char *command) +ERL_NIF_TERM +testcase_nif_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + ERL_NIF_TERM ret; InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) - driver_alloc(sizeof(InternalTestCaseState_t)); - if (!itcs) { - return ERL_DRV_ERROR_GENERAL; + enif_alloc_resource(testcase_rt, sizeof(InternalTestCaseState_t)); + + if (!itcs || !enif_get_int(env, argv[0], &itcs->visible.thr_nr)) { + enif_make_badarg(env); } itcs->visible.testcase_name = testcase_name(); + itcs->visible.extra = NULL; - itcs->port = port; - itcs->port_id = driver_mk_port(port); itcs->result = TESTCASE_FAILED; itcs->comment = ""; - return (ErlDrvData) itcs; + ret = enif_make_resource(env, itcs); + enif_release_resource(itcs); + return ret; } -void -testcase_drv_stop(ErlDrvData drv_data) +ERL_NIF_TERM +testcase_nif_stop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - testcase_cleanup((TestCaseState_t *) drv_data); - driver_free((void *) drv_data); + InternalTestCaseState_t *itcs; + if (!enif_get_resource(env, argv[0], testcase_rt, (void**)&itcs)) + return enif_make_badarg(env); + testcase_cleanup(&itcs->visible); + return enif_make_atom(env,"ok"); } -void -testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) +ERL_NIF_TERM +testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data; - ErlDrvTermData result_atom; - ErlDrvTermData msg[12]; + InternalTestCaseState_t *itcs; + const char* result_atom; + + if (!enif_get_resource(env, argv[0], testcase_rt, (void**)&itcs)) + return enif_make_badarg(env); - itcs->visible.command = buf; - itcs->visible.command_len = len; + itcs->curr_env = env; if (setjmp(itcs->done_jmp_buf) == 0) { - testcase_run((TestCaseState_t *) itcs); + testcase_run(&itcs->visible); itcs->result = TESTCASE_SUCCEEDED; } switch (itcs->result) { case TESTCASE_CONTINUE: - msg[0] = ERL_DRV_ATOM; - msg[1] = driver_mk_atom("continue"); - erl_drv_output_term(itcs->port_id, msg, 2); - return; - - case TESTCASE_SUCCEEDED: - result_atom = driver_mk_atom("succeeded"); - break; - case TESTCASE_SKIPPED: - result_atom = driver_mk_atom("skipped"); - break; - case TESTCASE_FAILED: - default: - result_atom = driver_mk_atom("failed"); - break; - } - - msg[0] = ERL_DRV_ATOM; - msg[1] = (ErlDrvTermData) result_atom; - - msg[2] = ERL_DRV_PORT; - msg[3] = itcs->port_id; + return enif_make_atom(env, "continue"); - msg[4] = ERL_DRV_ATOM; - msg[5] = driver_mk_atom(itcs->visible.testcase_name); - - msg[6] = ERL_DRV_STRING; - msg[7] = (ErlDrvTermData) itcs->comment; - msg[8] = (ErlDrvTermData) strlen(itcs->comment); - - msg[9] = ERL_DRV_TUPLE; - msg[10] = (ErlDrvTermData) 4; + case TESTCASE_SUCCEEDED: result_atom = "succeeded"; break; + case TESTCASE_SKIPPED: result_atom = "skipped"; break; + case TESTCASE_FAILED: result_atom = "failed"; break; + } - erl_drv_output_term(itcs->port_id, msg, 11); + return enif_make_tuple2(env, enif_make_atom(env, result_atom), + enif_make_string(env, itcs->comment, ERL_NIF_LATIN1)); } int @@ -179,8 +146,10 @@ testcase_assertion_failed(TestCaseState_t *tcs, void testcase_printf(TestCaseState_t *tcs, char *frmt, ...) { - InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; - ErlDrvTermData msg[12]; + InternalTestCaseState_t* itcs = (InternalTestCaseState_t*)tcs; + ErlNifPid pid; + ErlNifEnv* msg_env = enif_alloc_env(); + ERL_NIF_TERM msg; va_list va; va_start(va, frmt); #if HAVE_VSNPRINTF @@ -190,23 +159,13 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) #endif va_end(va); - msg[0] = ERL_DRV_ATOM; - msg[1] = (ErlDrvTermData) driver_mk_atom("print"); - - msg[2] = ERL_DRV_PORT; - msg[3] = itcs->port_id; - - msg[4] = ERL_DRV_ATOM; - msg[5] = driver_mk_atom(itcs->visible.testcase_name); - - msg[6] = ERL_DRV_STRING; - msg[7] = (ErlDrvTermData) itcs->comment_buf; - msg[8] = (ErlDrvTermData) strlen(itcs->comment_buf); + msg = enif_make_tuple2(msg_env, print_atom, + enif_make_string(msg_env, itcs->comment_buf, ERL_NIF_LATIN1)); - msg[9] = ERL_DRV_TUPLE; - msg[10] = (ErlDrvTermData) 4; + enif_send(itcs->curr_env, enif_self(itcs->curr_env, &pid), + msg_env, msg); - erl_drv_output_term(itcs->port_id, msg, 11); + enif_free_env(msg_env); } @@ -270,7 +229,7 @@ void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) itcs->result = TESTCASE_FAILED; itcs->comment = itcs->comment_buf; - if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + if (enif_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 && strcmp("true", buf) == 0) { fprintf(stderr, "Testcase \"%s\" failed: %s\n", itcs->visible.testcase_name, itcs->comment); @@ -282,15 +241,15 @@ void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) void *testcase_alloc(size_t size) { - return driver_alloc(size); + return enif_alloc(size); } void *testcase_realloc(void *ptr, size_t size) { - return driver_realloc(ptr, size); + return enif_realloc(ptr, size); } void testcase_free(void *ptr) { - driver_free(ptr); + enif_free(ptr); } diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h index 5d439735b7..698ae66fac 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h @@ -20,13 +20,12 @@ #ifndef TESTCASE_DRIVER_H__ #define TESTCASE_DRIVER_H__ -#include "erl_driver.h" +#include "erl_nif.h" #include typedef struct { char *testcase_name; - char *command; - int command_len; + int thr_nr; void *extra; } TestCaseState_t; @@ -34,6 +33,7 @@ typedef struct { ((void) ((B) ? 1 : testcase_assertion_failed((TCS), __FILE__, __LINE__, #B))) +int testcase_nif_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); void testcase_printf(TestCaseState_t *tcs, char *frmt, ...); void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...); void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...); @@ -46,8 +46,11 @@ void *testcase_realloc(void *ptr, size_t size); void testcase_free(void *ptr); +/* Implemented by testcase: */ char *testcase_name(void); void testcase_run(TestCaseState_t *tcs); void testcase_cleanup(TestCaseState_t *tcs); -#endif +extern ErlNifFunc testcase_nif_funcs[3]; + +#endif /* TESTCASE_DRIVER_H__ */ diff --git a/erts/emulator/test/alloc_SUITE_data/threads.c b/erts/emulator/test/alloc_SUITE_data/threads.c index edad24ee6b..a8a6a23695 100644 --- a/erts/emulator/test/alloc_SUITE_data/threads.c +++ b/erts/emulator/test/alloc_SUITE_data/threads.c @@ -86,7 +86,7 @@ static void fail(int t_no, char *frmt, ...) tc_failed = 1; - if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + if (enif_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 && strcmp("true", buf) == 0) { fprintf(stderr, "Testcase \"%s\" failed: %s\n", testcase_name(), err_buf); @@ -187,7 +187,6 @@ testcase_run(TestCaseState_t *tcs) for(i = 1; i <= NO_OF_THREADS; i++) { char *alc; - int res; threads[i].arg.no_ops_per_bl = NO_OF_OPS_PER_BL; @@ -446,3 +445,6 @@ thread_func(void *arg) exit_thread(td->t_no, 1); return NULL; } + +ERL_NIF_INIT(threads, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/threads.erl b/erts/emulator/test/alloc_SUITE_data/threads.erl new file mode 100644 index 0000000000..a7b4965f5e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/threads.erl @@ -0,0 +1,10 @@ +-module(threads). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). -- cgit v1.2.3 From 3198ed17179f35b86f7f8ab5c0b9c165d44c1ba6 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 10 Dec 2014 20:03:02 +0100 Subject: erts: Workaround for strange crash on win64 in alloc_SUITE test code For some reason setjmp() crash when having jmp_buf heap allocated but works when stack allocated. --- erts/emulator/test/alloc_SUITE_data/testcase_driver.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index 83ee1b67ca..5b35f581ea 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -45,7 +45,7 @@ typedef struct { TestCaseState_t visible; ErlNifEnv* curr_env; int result; - jmp_buf done_jmp_buf; + jmp_buf* done_jmp_buf; char *comment; char comment_buf[COMMENT_BUF_SZ]; } InternalTestCaseState_t; @@ -110,13 +110,20 @@ testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { InternalTestCaseState_t *itcs; const char* result_atom; + jmp_buf the_jmp_buf; if (!enif_get_resource(env, argv[0], testcase_rt, (void**)&itcs)) return enif_make_badarg(env); itcs->curr_env = env; - if (setjmp(itcs->done_jmp_buf) == 0) { + /* For some unknown reason, first call to setjmp crashes on win64 + * when jmp_buf is allocated as part of the resource. But it works when + * allocated on stack. It used to work when this was a driver. + */ + itcs->done_jmp_buf = &the_jmp_buf; + + if (setjmp(the_jmp_buf) == 0) { testcase_run(&itcs->visible); itcs->result = TESTCASE_SUCCEEDED; } @@ -184,7 +191,7 @@ void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...) itcs->result = TESTCASE_SUCCEEDED; itcs->comment = itcs->comment_buf; - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); } void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) @@ -202,14 +209,14 @@ void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) itcs->result = TESTCASE_SKIPPED; itcs->comment = itcs->comment_buf; - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); } void testcase_continue(TestCaseState_t *tcs) { InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; itcs->result = TESTCASE_CONTINUE; - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); } void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) @@ -236,7 +243,7 @@ void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) abort(); } - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); } void *testcase_alloc(size_t size) -- cgit v1.2.3 From 8421d318090ca59406ef6e04a43af16e1a467d9b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 12 Oct 2015 17:00:07 +0200 Subject: erts: Fix snprintf in alloc_SUITE for windows --- .../test/alloc_SUITE_data/testcase_driver.c | 47 ++++++++++------------ 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index 5b35f581ea..1503fea4cb 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -25,14 +25,25 @@ #include #ifdef __WIN32__ -#undef HAVE_VSNPRINTF -#define HAVE_VSNPRINTF 1 -#define vsnprintf _vsnprintf +static void my_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + _vsnprintf(outBuf, size, format, ap); + outBuf[size-1] = 0; /* be sure string is terminated */ +} +#elif defined(HAVE_VSNPRINTF) +# define my_vsnprintf(B,S,F,A) (void)vsnprintf(B,S,F,A) +#else +# warning Using unsafe 'vsprintf' without buffer overflow protection +# define my_vsnprintf(B,S,F,A) (void)vsprintf(B,F,A) #endif -#ifndef HAVE_VSNPRINTF -#define HAVE_VSNPRINTF 0 -#endif +static void my_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + my_vsnprintf(outBuf, size, format, ap); + va_end(ap); +} #define COMMENT_BUF_SZ 4096 @@ -159,11 +170,7 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) ERL_NIF_TERM msg; va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); msg = enif_make_tuple2(msg_env, print_atom, @@ -181,11 +188,7 @@ void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...) InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); itcs->result = TESTCASE_SUCCEEDED; @@ -199,11 +202,7 @@ void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); itcs->result = TESTCASE_SKIPPED; @@ -226,11 +225,7 @@ void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) size_t bufsz = sizeof(buf); va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); itcs->result = TESTCASE_FAILED; -- cgit v1.2.3 From d1464746f9e2c24e7bc645a4fdb543d63a8e3e87 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 12 Oct 2015 17:06:27 +0200 Subject: erts: Pass free mem and build type to alloc_SUITE tests --- erts/emulator/test/alloc_SUITE.erl | 59 ++++++++++++++++++---- erts/emulator/test/alloc_SUITE_data/bucket_mask.c | 2 +- .../test/alloc_SUITE_data/testcase_driver.c | 30 ++++++++--- .../test/alloc_SUITE_data/testcase_driver.h | 3 ++ 4 files changed, 75 insertions(+), 19 deletions(-) (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 0dd68b778b..866008e3e0 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -202,13 +202,14 @@ drv_case(Config, Mode, NodeOpts) when is_list(Config) -> end. run_drv_case(Config, Mode) -> - ?line DataDir = ?config(data_dir,Config), - ?line CaseName = ?config(testcase,Config), + DataDir = ?config(data_dir,Config), + CaseName = ?config(testcase,Config), File = filename:join(DataDir, CaseName), {ok,CaseName,Bin} = compile:file(File, [binary,return_errors]), - ?line {module,CaseName} = erlang:load_module(CaseName,Bin), + {module,CaseName} = erlang:load_module(CaseName,Bin), ok = CaseName:init(File), + SlaveState = slave_init(CaseName), case Mode of one_shot -> Result = one_shot(CaseName); @@ -217,11 +218,26 @@ run_drv_case(Config, Mode) -> Result = concurrent(CaseName) end, - ?line true = erlang:delete_module(CaseName), - ?line Result. + true = erlang:delete_module(CaseName), + slave_end(SlaveState), + Result. + +slave_init(migration) -> + A0 = case application:start(sasl) of + ok -> [sasl]; + _ -> [] + end, + case application:start(os_mon) of + ok -> [os_mon|A0]; + _ -> A0 + end; +slave_init(_) -> []. + +slave_end(Apps) -> + lists:foreach(fun (A) -> application:stop(A) end, Apps). one_shot(CaseName) -> - State = CaseName:start(1), + State = CaseName:start({1, 0, erlang:system_info(build_type)}), Result0 = CaseName:run(State), false = (Result0 =:= continue), Result1 = handle_result(State, Result0), @@ -229,8 +245,8 @@ one_shot(CaseName) -> Result1. -many_shot(CaseName, I) -> - State = CaseName:start(I), +many_shot(CaseName, I, Mem) -> + State = CaseName:start({I, Mem, erlang:system_info(build_type)}), Result1 = repeat_while(fun() -> Result0 = CaseName:run(State), handle_result(State, Result0) @@ -239,12 +255,15 @@ many_shot(CaseName, I) -> Result1. concurrent(CaseName) -> + NSched = erlang:system_info(schedulers), + Mem = (free_memory() * 3) div 4, PRs = lists:map(fun(I) -> spawn_opt(fun() -> - many_shot(CaseName, I) + many_shot(CaseName, I, + Mem div NSched) end, [monitor, {scheduler,I}]) end, - lists:seq(1, erlang:system_info(schedulers))), + lists:seq(1, NSched)), lists:foreach(fun({Pid,Ref}) -> receive {'DOWN', Ref, process, Pid, Reason} -> Reason @@ -308,3 +327,23 @@ is_halfword_vm() -> {4, 8} -> true; {WS, WS} -> false end. + +free_memory() -> + %% Free memory in MB. + try + SMD = memsup:get_system_memory_data(), + {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD), + TotFree = (Free + + case lists:keysearch(cached_memory, 1, SMD) of + {value, {cached_memory, Cached}} -> Cached; + false -> 0 + end + + case lists:keysearch(buffered_memory, 1, SMD) of + {value, {buffered_memory, Buffed}} -> Buffed; + false -> 0 + end), + TotFree div (1024*1024) + catch + error : undef -> + ?t:fail({"os_mon not built"}) + end. diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c index d474c80343..c94c265f4e 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c @@ -52,7 +52,7 @@ testcase_run(TestCaseState_t *tcs) typedef struct linked_block { struct linked_block* next; }Linked; - Linked* link; + Linked* link = NULL; Linked* fence_list; Linked* pad_list; void* tmp; diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index 1503fea4cb..7dcca544e5 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __WIN32__ static void my_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) @@ -54,7 +55,6 @@ static void my_snprintf(char *outBuf, size_t size, const char *format, ...) typedef struct { TestCaseState_t visible; - ErlNifEnv* curr_env; int result; jmp_buf* done_jmp_buf; char *comment; @@ -86,17 +86,26 @@ int testcase_nif_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) ERL_NIF_TERM testcase_nif_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ +{ /* (ThrNr, FreeMeg, BuildType) */ ERL_NIF_TERM ret; InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) enif_alloc_resource(testcase_rt, sizeof(InternalTestCaseState_t)); - - if (!itcs || !enif_get_int(env, argv[0], &itcs->visible.thr_nr)) { + int free_megabyte; + const int max_megabyte = INT_MAX / (1024*1024); + const ERL_NIF_TERM* tpl; + int tpl_arity; + + if (!itcs + || !enif_get_tuple(env, argv[0], &tpl_arity, &tpl) + || tpl_arity != 3 + || !enif_get_int(env, tpl[0], &itcs->visible.thr_nr) + || !enif_get_int(env, tpl[1], &free_megabyte)) { enif_make_badarg(env); } - + itcs->visible.free_mem = (free_megabyte < max_megabyte ? + free_megabyte : max_megabyte) * (1024*1024); itcs->visible.testcase_name = testcase_name(); - + itcs->visible.build_type = tpl[2]; itcs->visible.extra = NULL; itcs->result = TESTCASE_FAILED; itcs->comment = ""; @@ -126,7 +135,7 @@ testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) if (!enif_get_resource(env, argv[0], testcase_rt, (void**)&itcs)) return enif_make_badarg(env); - itcs->curr_env = env; + itcs->visible.curr_env = env; /* For some unknown reason, first call to setjmp crashes on win64 * when jmp_buf is allocated as part of the resource. But it works when @@ -146,6 +155,11 @@ testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) case TESTCASE_SUCCEEDED: result_atom = "succeeded"; break; case TESTCASE_SKIPPED: result_atom = "skipped"; break; case TESTCASE_FAILED: result_atom = "failed"; break; + default: + result_atom = "failed"; + my_snprintf(itcs->comment_buf, sizeof(itcs->comment_buf), + "Unexpected test result code %d.", itcs->result); + itcs->comment = itcs->comment_buf; } return enif_make_tuple2(env, enif_make_atom(env, result_atom), @@ -176,7 +190,7 @@ testcase_printf(TestCaseState_t *tcs, char *frmt, ...) msg = enif_make_tuple2(msg_env, print_atom, enif_make_string(msg_env, itcs->comment_buf, ERL_NIF_LATIN1)); - enif_send(itcs->curr_env, enif_self(itcs->curr_env, &pid), + enif_send(itcs->visible.curr_env, enif_self(itcs->visible.curr_env, &pid), msg_env, msg); enif_free_env(msg_env); diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h index 698ae66fac..f0ca91bd06 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h @@ -24,8 +24,11 @@ #include typedef struct { + ErlNifEnv* curr_env; char *testcase_name; int thr_nr; + int free_mem; /* in bytes */ + ERL_NIF_TERM build_type; /* opt, debug, valgrind, ... */ void *extra; } TestCaseState_t; -- cgit v1.2.3 From 5c9557a814ac993a72d7b045ee374745d6dcab79 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 2 Oct 2015 18:14:28 +0200 Subject: erts: Improve alloc_SUITE:migration test In the quest to improve code coverage in cpool_fetch --- erts/emulator/test/alloc_SUITE.erl | 82 ++++++++- .../test/alloc_SUITE_data/allocator_test.h | 1 + erts/emulator/test/alloc_SUITE_data/migration.c | 190 ++++++++++++++++----- 3 files changed, 227 insertions(+), 46 deletions(-) (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 866008e3e0..aa6a1fbcdc 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -65,7 +65,7 @@ end_per_group(_GroupName, Config) -> init_per_testcase(Case, Config) when is_list(Config) -> Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)), - [{watchdog, Dog},{testcase, Case}|Config]. + [{watchdog, Dog}, {testcase, Case}, {debug,false} | Config]. end_per_testcase(_Case, Config) when is_list(Config) -> Dog = ?config(watchdog, Config), @@ -113,7 +113,13 @@ cpool(suite) -> []; cpool(doc) -> []; cpool(Cfg) -> ?line drv_case(Cfg). -migration(Cfg) -> drv_case(Cfg, concurrent, "+MZe true"). +migration(Cfg) -> + case erlang:system_info(smp_support) of + true -> + drv_case(Cfg, concurrent, "+MZe true"); + false -> + {skipped, "No smp"} + end. erts_mmap(Config) when is_list(Config) -> case {?t:os_type(), is_halfword_vm()} of @@ -207,6 +213,7 @@ run_drv_case(Config, Mode) -> File = filename:join(DataDir, CaseName), {ok,CaseName,Bin} = compile:file(File, [binary,return_errors]), {module,CaseName} = erlang:load_module(CaseName,Bin), + print_stats(CaseName), ok = CaseName:init(File), SlaveState = slave_init(CaseName), @@ -218,6 +225,9 @@ run_drv_case(Config, Mode) -> Result = concurrent(CaseName) end, + wait_for_memory_deallocations(), + print_stats(CaseName), + true = erlang:delete_module(CaseName), slave_end(SlaveState), Result. @@ -236,6 +246,41 @@ slave_init(_) -> []. slave_end(Apps) -> lists:foreach(fun (A) -> application:stop(A) end, Apps). +wait_for_memory_deallocations() -> + try + erts_debug:set_internal_state(wait, deallocations) + catch + error:undef -> + erts_debug:set_internal_state(available_internal_state, true), + 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})), + + io:format("Number of blocks : ~p\n", [Btot]), + io:format("Number of carriers: ~p\n", [Ctot]); + +print_stats(_) -> ok. + +tuple_add(T1, T2) -> + list_to_tuple(lists:zipwith(fun(E1,E2) when is_number(E1), is_number(E2) -> + E1 + E2; + (A,A) -> + A + end, + tuple_to_list(T1), tuple_to_list(T2))). + + one_shot(CaseName) -> State = CaseName:start({1, 0, erlang:system_info(build_type)}), Result0 = CaseName:run(State), @@ -250,8 +295,10 @@ many_shot(CaseName, I, Mem) -> Result1 = repeat_while(fun() -> Result0 = CaseName:run(State), handle_result(State, Result0) - end), + end, + 10*1000, I), CaseName:stop(State), + flush_log(), Result1. concurrent(CaseName) -> @@ -272,11 +319,23 @@ concurrent(CaseName) -> PRs), ok. -repeat_while(Fun) -> - %%io:format("~p calls fun\n", [self()]), - case Fun() of - continue -> repeat_while(Fun); - R -> R +repeat_while(Fun, Timeout, I) -> + TRef = erlang:start_timer(Timeout, self(), timeout), + R = repeat_while_loop(Fun, TRef, I), + erlang:cancel_timer(TRef, [{async,true},{info,false}]), + R. + +repeat_while_loop(Fun, TRef, I) -> + receive + {timeout, TRef, timeout} -> + io:format("~p: Timeout, enough is enough.",[I]), + succeeded + after 0 -> + %%io:format("~p calls fun\n", [self()]), + case Fun() of + continue -> repeat_while_loop(Fun, TRef, I); + R -> R + end end. flush_log() -> @@ -308,6 +367,12 @@ handle_result(_State, Result0) -> end. start_node(Config, Opts) when is_list(Config), is_list(Opts) -> + case ?config(debug,Config) of + true -> {ok, node()}; + _ -> start_node_1(Config, Opts) + end. + +start_node_1(Config, Opts) -> Pa = filename:dirname(code:which(?MODULE)), Name = list_to_atom(atom_to_list(?MODULE) ++ "-" @@ -318,6 +383,7 @@ start_node(Config, Opts) when is_list(Config), is_list(Opts) -> ++ integer_to_list(erlang:unique_integer([positive]))), ?t:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]). +stop_node(Node) when Node =:= node() -> ok; stop_node(Node) -> ?t: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 dd0227e725..97ee58cdad 100644 --- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -157,5 +157,6 @@ typedef void* erts_cond; #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)) #endif diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c index 9f6535c834..b006360043 100644 --- a/erts/emulator/test/alloc_SUITE_data/migration.c +++ b/erts/emulator/test/alloc_SUITE_data/migration.c @@ -27,6 +27,7 @@ #include #endif #include +#include #include #include #include "testcase_driver.h" @@ -57,15 +58,52 @@ testcase_name(void) return "migration"; } -void -testcase_cleanup(TestCaseState_t *tcs) +/* Turns out random_r() is a nonstandard glibc extension. +#define HAVE_RANDOM_R +*/ +#ifdef HAVE_RANDOM_R + +typedef struct { struct random_data rnd; char rndbuf[32]; } MyRandState; + +static void myrand_init(MyRandState* mrs, unsigned int seed) { - enif_free(tcs->extra); - tcs->extra = NULL; + int res; + memset(&mrs->rnd, 0, sizeof(mrs->rnd)); + res = initstate_r(seed, mrs->rndbuf, sizeof(mrs->rndbuf), &mrs->rnd); + FATAL_ASSERT(res == 0); +} + +static int myrand(MyRandState* mrs) +{ + int32_t x; + int res = random_r(&mrs->rnd, &x); + FATAL_ASSERT(res == 0); + return (int)x; +} + +#else /* !HAVE_RANDOM_R */ + +typedef unsigned int MyRandState; + +static void myrand_init(MyRandState* mrs, unsigned int seed) +{ + *mrs = seed; +} + +static int myrand(MyRandState* mrs) +{ + /* Taken from rand(3) man page. + * Modified to return a full 31-bit value by using low half of *mrs as well. + */ + *mrs = (*mrs) * 1103515245 + 12345; + return (int) (((*mrs >> 16) | (*mrs << 16)) & ~(1 << 31)); } -#define MAX_BLOCK_PER_THR 100 -#define MAX_ROUNDS 10 +#endif /* !HAVE_RANDOM_R */ + +#define MAX_BLOCK_PER_THR 200 +#define BLOCKS_PER_MBC 10 +#define MAX_ROUNDS 10000 typedef struct MyBlock_ { struct MyBlock_* next; @@ -74,15 +112,23 @@ typedef struct MyBlock_ { typedef struct { MyBlock* blockv[MAX_BLOCK_PER_THR]; + MyRandState rand_state; enum { GROWING, SHRINKING, CLEANUP, DONE } phase; - int ix; + int nblocks; + int goal_nblocks; int round; + int nr_of_migrations; + int nr_of_carriers; + int max_blocks_in_mbc; + int block_size; + int max_nblocks; } MigrationState; typedef struct { ErlNifMutex* mtx; int nblocks; MyBlock* first; + MigrationState* employer; } MyCrrInfo; @@ -99,6 +145,7 @@ static void my_creating_mbc(Allctr_t *allctr, Carrier_t *carrier) mci->mtx = enif_mutex_create("alloc_SUITE.migration"); mci->nblocks = 0; mci->first = NULL; + mci->employer = NULL; } static void my_destroying_mbc(Allctr_t *allctr, Carrier_t *carrier) @@ -131,17 +178,28 @@ static int migration_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_in return 0; } -static void add_block(MyBlock* p) +static void add_block(MyBlock* p, MigrationState* state) { MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); enif_mutex_lock(mci->mtx); - mci->nblocks++; + if (++mci->nblocks > state->max_blocks_in_mbc) + state->max_blocks_in_mbc = mci->nblocks; p->next = mci->first; p->prevp = &mci->first; mci->first = p; if (p->next) p->next->prevp = &p->next; + if (mci->employer != state) { + if (!mci->employer) { + FATAL_ASSERT(mci->nblocks == 1); + state->nr_of_carriers++; + } + else { + state->nr_of_migrations++; + } + mci->employer = state; + } enif_mutex_unlock(mci->mtx); } @@ -157,6 +215,38 @@ static void remove_block(MyBlock* p) enif_mutex_unlock(mci->mtx); } +static int rand_int(MigrationState* state, int low, int high) +{ + int x; + FATAL_ASSERT(high >= low); + x = myrand(&state->rand_state); + return low + (x % (high+1-low)); +} + + +static void do_cleanup(TestCaseState_t *tcs, MigrationState* state) +{ + if (state->nblocks == 0) { + state->phase = DONE; + testcase_printf(tcs, "%d: Done %d rounds", tcs->thr_nr, state->round); + testcase_printf(tcs, "%d: Cleanup all blocks", tcs->thr_nr); + testcase_printf(tcs, "%d: Empty carriers detected = %d", tcs->thr_nr, + state->nr_of_carriers); + testcase_printf(tcs, "%d: Migrations detected = %d", tcs->thr_nr, + state->nr_of_migrations); + testcase_printf(tcs, "%d: Max blocks in carrier = %d", tcs->thr_nr, + state->max_blocks_in_mbc); + } + else { + state->nblocks--; + if (state->blockv[state->nblocks]) { + remove_block(state->blockv[state->nblocks]); + FREE_TEST(state->blockv[state->nblocks]); + } + } +} + + void testcase_run(TestCaseState_t *tcs) { @@ -169,61 +259,85 @@ testcase_run(TestCaseState_t *tcs) tcs->extra = enif_alloc(sizeof(MigrationState)); state = (MigrationState*) tcs->extra; memset(state->blockv, 0, sizeof(state->blockv)); + myrand_init(&state->rand_state, tcs->thr_nr); state->phase = GROWING; - state->ix = 0; + state->nblocks = 0; state->round = 0; + state->nr_of_migrations = 0; + state->nr_of_carriers = 0; + state->max_blocks_in_mbc = 0; + state->block_size = GET_TEST_MBC_SIZE() / (BLOCKS_PER_MBC+1); + if (MAX_BLOCK_PER_THR * state->block_size < tcs->free_mem) { + state->max_nblocks = MAX_BLOCK_PER_THR; + } else { + state->max_nblocks = tcs->free_mem / state->block_size; + } + state->goal_nblocks = rand_int(state, 1, state->max_nblocks); } switch (state->phase) { case GROWING: { MyBlock* p; - FATAL_ASSERT(!state->blockv[state->ix]); - p = ALLOC_TEST((1 << 18) / 5); + FATAL_ASSERT(!state->blockv[state->nblocks]); + p = ALLOC_TEST(rand_int(state, state->block_size/2, state->block_size)); FATAL_ASSERT(p); - add_block(p); - state->blockv[state->ix] = p; - do { - if (++state->ix >= MAX_BLOCK_PER_THR) { - state->phase = SHRINKING; - state->ix = 0; - break; - } - } while (state->blockv[state->ix] != NULL); + 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]); break; } - case SHRINKING: - FATAL_ASSERT(state->blockv[state->ix]); - remove_block(state->blockv[state->ix]); - FREE_TEST(state->blockv[state->ix]); - state->blockv[state->ix] = NULL; - - state->ix += 1 + ((state->ix % 3) == 0); - if (state->ix >= MAX_BLOCK_PER_THR) { + case SHRINKING: { + 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); } - state->ix = 0; } break; - + } case CLEANUP: - if (state->blockv[state->ix]) { - remove_block(state->blockv[state->ix]); - FREE_TEST(state->blockv[state->ix]); - } - if (++state->ix >= MAX_BLOCK_PER_THR) - state->phase = DONE; + do_cleanup(tcs, state); break; default: FATAL_ASSERT(!"Invalid phase"); } - if (state->phase != DONE) + if (state->phase == DONE) { + } + else { testcase_continue(tcs); + } } +void +testcase_cleanup(TestCaseState_t *tcs) +{ + MigrationState* state = (MigrationState*) tcs->extra; + + while (state->phase != DONE) + do_cleanup(tcs, state); + + enif_free(tcs->extra); + tcs->extra = NULL; +} + + ERL_NIF_INIT(migration, testcase_nif_funcs, migration_init, NULL, NULL, NULL); -- cgit v1.2.3 From 64d1a7397c53d6cca32c49af9f833cdf6d26fc6e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 Nov 2015 17:55:49 +0100 Subject: erts: Reduce alloc_SUITE:rbtree runtime for valgrind --- erts/emulator/test/alloc_SUITE_data/rbtree.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'erts/emulator/test') diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.c b/erts/emulator/test/alloc_SUITE_data/rbtree.c index eb7b36984e..38bbbdf90c 100644 --- a/erts/emulator/test/alloc_SUITE_data/rbtree.c +++ b/erts/emulator/test/alloc_SUITE_data/rbtree.c @@ -20,7 +20,7 @@ #include "testcase_driver.h" #include "allocator_test.h" -#define NO_BLOCKS 100000 +int NO_BLOCKS; #define RIGHT_VISITED (1 << 0) #define LEFT_VISITED (1 << 1) @@ -265,9 +265,10 @@ check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size) ASSERT(tcs, curr_blacks == 0); ASSERT(tcs, i == -1); + /* testcase_printf(tcs, "Red-Black Tree OK! Max depth = %d; " "Black depth = %d\n", max_i+1, blacks < 0 ? 0 : blacks); - + */ return res; } @@ -468,6 +469,12 @@ testcase_run(TestCaseState_t *tcs) Allctr_t *a; rbtree_test_data *td; + NO_BLOCKS = 100*1000; + if (enif_is_identical(tcs->build_type, + enif_make_atom(tcs->curr_env,"valgrind"))) { + NO_BLOCKS /= 10; + } + /* Best fit... */ testcase_printf(tcs, "Setup...\n"); -- cgit v1.2.3