From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- erts/emulator/test/alloc_SUITE_data/Makefile.src | 41 ++ .../test/alloc_SUITE_data/allocator_test.h | 131 ++++++ erts/emulator/test/alloc_SUITE_data/basic.c | 61 +++ erts/emulator/test/alloc_SUITE_data/bucket_index.c | 114 ++++++ erts/emulator/test/alloc_SUITE_data/bucket_mask.c | 147 +++++++ erts/emulator/test/alloc_SUITE_data/coalesce.c | 318 +++++++++++++++ .../test/alloc_SUITE_data/mseg_clear_cache.c | 102 +++++ erts/emulator/test/alloc_SUITE_data/rbtree.c | 386 ++++++++++++++++++ erts/emulator/test/alloc_SUITE_data/realloc_copy.c | 279 +++++++++++++ .../test/alloc_SUITE_data/testcase_driver.c | 260 ++++++++++++ .../test/alloc_SUITE_data/testcase_driver.h | 51 +++ erts/emulator/test/alloc_SUITE_data/threads.c | 447 +++++++++++++++++++++ 12 files changed, 2337 insertions(+) create mode 100644 erts/emulator/test/alloc_SUITE_data/Makefile.src create mode 100644 erts/emulator/test/alloc_SUITE_data/allocator_test.h create mode 100644 erts/emulator/test/alloc_SUITE_data/basic.c create mode 100644 erts/emulator/test/alloc_SUITE_data/bucket_index.c create mode 100644 erts/emulator/test/alloc_SUITE_data/bucket_mask.c create mode 100644 erts/emulator/test/alloc_SUITE_data/coalesce.c create mode 100644 erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c create mode 100644 erts/emulator/test/alloc_SUITE_data/rbtree.c create mode 100644 erts/emulator/test/alloc_SUITE_data/realloc_copy.c create mode 100644 erts/emulator/test/alloc_SUITE_data/testcase_driver.c create mode 100644 erts/emulator/test/alloc_SUITE_data/testcase_driver.h create mode 100644 erts/emulator/test/alloc_SUITE_data/threads.c (limited to 'erts/emulator/test/alloc_SUITE_data') diff --git a/erts/emulator/test/alloc_SUITE_data/Makefile.src b/erts/emulator/test/alloc_SUITE_data/Makefile.src new file mode 100644 index 0000000000..035415d73e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/Makefile.src @@ -0,0 +1,41 @@ +# ``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 via the world wide web 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. +# +# The Initial Developer of the Original Code is Ericsson Utvecklings AB. +# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +# AB. All Rights Reserved.'' +# +# $Id$ +# + +TEST_DRVS = basic@dll@ \ + coalesce@dll@ \ + threads@dll@ \ + realloc_copy@dll@ \ + bucket_index@dll@ \ + bucket_mask@dll@ \ + rbtree@dll@ \ + mseg_clear_cache@dll@ + +CC = @CC@ +LD = @LD@ +CFLAGS = @SHLIB_CFLAGS@ -I@erl_include@ @DEFS@ +SHLIB_EXTRA_LDLIBS = testcase_driver@obj@ + +all: $(TEST_DRVS) + +@SHLIB_RULES@ + +testcase_driver@obj@: testcase_driver.c testcase_driver.h +$(TEST_DRVS): testcase_driver@obj@ allocator_test.h + + + diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h new file mode 100644 index 0000000000..b869a4079c --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -0,0 +1,131 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#ifndef ALLOCATOR_TEST_H__ +#define ALLOCATOR_TEST_H__ + +typedef unsigned long Ulong; + +#ifndef __WIN32__ +Ulong erts_alc_test(Ulong, Ulong, Ulong, Ulong); +#endif + +#define UNDEF__ ~((Ulong) 0) + +#define ALC_TEST0(OP) \ + erts_alc_test((Ulong) (OP), UNDEF__, UNDEF__, UNDEF__) +#define ALC_TEST1(OP, A1) \ + erts_alc_test((Ulong) (OP), (Ulong) (A1), UNDEF__, UNDEF__) +#define ALC_TEST2(OP, A1, A2) \ + erts_alc_test((Ulong) (OP), (Ulong) (A1), (Ulong) (A2), UNDEF__) +#define ALC_TEST3(OP, A1, A2, A3) \ + erts_alc_test((Ulong) (OP), (Ulong) (A1), (Ulong) (A2), (Ulong) (A3)) + +typedef Ulong Block_t; +typedef Ulong Carrier_t; +typedef Ulong Allctr_t; +typedef Ulong RBT_t; +typedef Ulong RBTL_t; +typedef void* erts_thread; +typedef void* erts_mutex; +typedef void* erts_cond; + +/* From erl_alloc_util.c */ + +#define BLK_SZ(B) ((Ulong) ALC_TEST1(0x000, (B))) +#define UMEM_SZ(B) ((Ulong) ALC_TEST1(0x001, (B))) +#define IS_PREV_FREE_BLK(B) ((Ulong) ALC_TEST1(0x002, (B))) +#define IS_FREE_BLK(B) ((Ulong) ALC_TEST1(0x003, (B))) +#define IS_LAST_BLK(B) ((Ulong) ALC_TEST1(0x004, (B))) +#define UMEM2BLK(U) ((Block_t *) ALC_TEST1(0x005, (U))) +#define BLK2UMEM(B) ((void *) ALC_TEST1(0x006, (B))) +#define IS_SBC(C) ((Ulong) ALC_TEST1(0x007, (C))) +#define IS_SBC_BLK(B) ((Ulong) ALC_TEST1(0x008, (B))) +#define IS_MBC(C) ((Ulong) ALC_TEST1(0x009, (C))) +#define IS_MMAP_C(C) ((Ulong) ALC_TEST1(0x00a, (C))) +#define C_SZ(C) ((Ulong) ALC_TEST1(0x00b, (C))) +#define SBC2BLK(A, C) ((Block_t *) ALC_TEST2(0x00c, (A), (C))) +#define BLK2SBC(A, B) ((Carrier_t *) ALC_TEST2(0x00d, (A), (B))) +#define MBC2FBLK(A, C) ((Block_t *) ALC_TEST2(0x00e, (A), (C))) +#define FBLK2MBC(A, B) ((Carrier_t *) ALC_TEST2(0x00f, (A), (B))) +#define FIRST_MBC(A) ((Carrier_t *) ALC_TEST1(0x010, (A))) +#define LAST_MBC(A) ((Carrier_t *) ALC_TEST1(0x011, (A))) +#define FIRST_SBC(A) ((Carrier_t *) ALC_TEST1(0x012, (A))) +#define LAST_SBC(A) ((Carrier_t *) ALC_TEST1(0x013, (A))) +#define NEXT_C(C) ((Carrier_t *) ALC_TEST1(0x014, (C))) +#define PREV_C(C) ((Carrier_t *) ALC_TEST1(0x015, (C))) +#define ABLK_HDR_SZ ((Ulong) ALC_TEST0(0x016)) +#define MIN_BLK_SZ(A) ((Ulong) ALC_TEST1(0x017, (A))) +#define NXT_BLK(B) ((Block_t *) ALC_TEST1(0x018, (B))) +#define PREV_BLK(B) ((Block_t *) ALC_TEST1(0x019, (B))) +#define IS_FIRST_BLK(B) ((Ulong) ALC_TEST1(0x01a, (B))) +#define UNIT_SZ ((Ulong) ALC_TEST0(0x01b)) + +/* From erl_goodfit_alloc.c */ +#define BKT_IX(A, S) ((Ulong) ALC_TEST2(0x100, (A), (S))) +#define BKT_MIN_SZ(A, I) ((Ulong) ALC_TEST2(0x101, (A), (I))) +#define NO_OF_BKTS ((Ulong) ALC_TEST0(0x102)) +#define FIND_BKT(A, I) ((int) ALC_TEST2(0x103, (A), (I))) + +/* From erl_bestfit_alloc.c */ +#define IS_AOBF(A) ((Ulong) ALC_TEST1(0x200, (A))) +#define RBT_ROOT(A) ((RBT_t *) ALC_TEST1(0x201, (A))) +#define RBT_PARENT(T) ((RBT_t *) ALC_TEST1(0x202, (T))) +#define RBT_LEFT(T) ((RBT_t *) ALC_TEST1(0x203, (T))) +#define RBT_RIGHT(T) ((RBT_t *) ALC_TEST1(0x204, (T))) +#define RBT_NEXT(T) ((RBTL_t *) ALC_TEST1(0x205, (T))) +#define RBT_IS_BLACK(T) ((Ulong) ALC_TEST1(0x206, (T))) +#define RBT_IS_TREE(T) ((Ulong) ALC_TEST1(0x207, (T))) + +/* From erl_mseg.c */ +#define HAVE_MSEG() ((int) ALC_TEST0(0x400)) +#define MSEG_ALLOC(SP) ((void *) ALC_TEST1(0x401, (SP))) +#define MSEG_DEALLOC(P, S) ((void) ALC_TEST2(0x402, (P), (S))) +#define MSEG_REALLOC(P, OS, SP) ((void *) ALC_TEST3(0x403, (P), (OS), \ + (SP))) +#define MSEG_CLEAR_CACHE() ((void) ALC_TEST0(0x404)) +#define MSEG_NO() ((Ulong) ALC_TEST0(0x405)) +#define MSEG_CACHE_SIZE() ((Ulong) ALC_TEST0(0x406)) + +/* From erl_alloc.c */ + +#undef ALLOC +#undef REALLOC +#undef FREE + +#define ALLOC(A, S) ((void *) ALC_TEST2(0xf00, (A), (S))) +#define REALLOC(A, P, S) ((void *) ALC_TEST3(0xf01, (A), (P), (S))) +#define FREE(A, P) ((void) ALC_TEST2(0xf02, (A), (P))) +#define START_ALC(N, T, A) ((Allctr_t *) ALC_TEST3(0xf03, (N), (T), (A))) +#define STOP_ALC(A) ((void) ALC_TEST1(0xf04, (A))) +#define IS_THREADS_ENABLED ((int) ALC_TEST0(0xf05)) +#define IS_ALLOC_THREAD_SAFE(A) ((int) ALC_TEST1(0xf06, (A))) +#define IS_ALLOC_FORK_SAFE(A) ((int) ALC_TEST1(0xf07, (A))) +#define THR_MTX_CREATE() ((erts_mutex) ALC_TEST0(0xf08)) +#define THR_MTX_DESTROY(M) ((void) ALC_TEST1(0xf09, (M))) +#define THR_MTX_LOCK(M) ((void) ALC_TEST1(0xf0a, (M))) +#define THR_MTX_UNLOCK(M) ((void) ALC_TEST1(0xf0b, (M))) +#define THR_COND_CREATE() ((erts_cond) ALC_TEST0(0xf0c)) +#define THR_COND_DESTROY(C) ((void) ALC_TEST1(0xf0d, (C))) +#define THR_COND_BCAST(C) ((void) ALC_TEST1(0xf0e, (C))) +#define THR_COND_WAIT(C, M) ((void) ALC_TEST2(0xf0f, (C), (M))) +#define THR_CREATE(F, A) ((erts_thread) ALC_TEST2(0xf10, (F), (A))) +#define THR_JOIN(T) ((void) ALC_TEST1(0xf11, (T))) +#define THR_EXIT(R) ((void) ALC_TEST1(0xf12, (R))) + +#endif diff --git a/erts/emulator/test/alloc_SUITE_data/basic.c b/erts/emulator/test/alloc_SUITE_data/basic.c new file mode 100644 index 0000000000..4a5e888161 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/basic.c @@ -0,0 +1,61 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" + +char * +testcase_name(void) +{ + return "basic"; +} + +void +testcase_run(TestCaseState_t *tcs) +{ + Carrier_t *c; + Block_t *blk; + void *p; + Allctr_t *a = START_ALC("basic_", 0, NULL); + tcs->extra = (void *) a; + + ASSERT(tcs, a); + + p = ALLOC(a, 10); + ASSERT(tcs, p); + p = REALLOC(a, p, 15); + ASSERT(tcs, p); + FREE(a, p); + + c = FIRST_MBC(a); + ASSERT(tcs, !NEXT_C(c)); + blk = MBC2FBLK(a, c); + ASSERT(tcs, IS_LAST_BLK(blk)); + ASSERT(tcs, IS_FREE_BLK(blk)); + + STOP_ALC((Allctr_t *) a); + tcs->extra = NULL; + +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) + STOP_ALC((Allctr_t *) tcs->extra); +} diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_index.c b/erts/emulator/test/alloc_SUITE_data/bucket_index.c new file mode 100644 index 0000000000..32fd16fc10 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/bucket_index.c @@ -0,0 +1,114 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" +#include + +#define MAX_TEST_SIZE 100000000 + +char * +testcase_name(void) +{ + return "bucket_index"; +} + +void test_it(TestCaseState_t *tcs, unsigned sbct); + +void +testcase_run(TestCaseState_t *tcs) +{ + testcase_printf(tcs, "No of buckets = %lu:\n\n", NO_OF_BKTS); + + test_it(tcs, 1); + test_it(tcs, 0); + test_it(tcs, 1024); + test_it(tcs, 10240); +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) { + STOP_ALC(tcs->extra); + tcs->extra = NULL; + } +} + +void +test_it(TestCaseState_t *tcs, unsigned sbct) +{ + Ulong max_cont_test_sz; + char sbct_buf[21]; + char *argv[] = {"-tas", "gf", "-tsbct", NULL, NULL}; + int no_changes; + Ulong bi; + Ulong min_sz; + Ulong prev_bi; + Ulong sz; + Allctr_t *a; + + no_changes = 0; + prev_bi = -1; + + if (sbct) { + sprintf(sbct_buf, "%d", sbct); + argv[3] = sbct_buf; + } + else + argv[2] = NULL; + + max_cont_test_sz = 2*sbct*1024; + if (max_cont_test_sz < 1000000) + max_cont_test_sz = 1000000; + + testcase_printf(tcs, "Testing with sbct = %s\n", + sbct ? sbct_buf : "default"); + a = START_ALC("bkt_ix_", 0, argv); + tcs->extra = (void *) a; + ASSERT(tcs, a); + + sz = MIN_BLK_SZ(a); + while(sz < ((((Ulong)1) << 31) - 1)) { + bi = BKT_IX(a, sz); + if (prev_bi != bi) { + ASSERT(tcs, prev_bi + 1 == bi); + + min_sz = BKT_MIN_SZ(a, bi); + + ASSERT(tcs, sz == min_sz); + + testcase_printf(tcs, "sz=%d->ix=%d ", sz, bi); + no_changes++; + } + prev_bi = bi; + if (sz < max_cont_test_sz) + sz++; + else + sz += 100000000; + } + testcase_printf(tcs, "\n\n"); + ASSERT(tcs, no_changes == NO_OF_BKTS); + + STOP_ALC(a); + tcs->extra = NULL; + + testcase_printf(tcs, "Test with sbct=%s succeeded\n", + sbct ? sbct_buf : "default"); +} + diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c new file mode 100644 index 0000000000..13af7d861a --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c @@ -0,0 +1,147 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" +#include + +#define SBCT (512*1024) + +char * +testcase_name(void) +{ + return "bucket_mask"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) { + STOP_ALC(tcs->extra); + tcs->extra = NULL; + } +} + +void +testcase_run(TestCaseState_t *tcs) +{ + void *tmp; + void **fence; + void **blk; + Ulong sz; + Ulong smbcs; + int i; + int bi; + int bi_tests; + Ulong sbct = (SBCT/1024)*1024; + Ulong min_blk_sz; + Ulong ablk_hdr_sz = ABLK_HDR_SZ; + char smbcs_buf[30]; + char sbct_buf[30]; + int no_bkts = (int) NO_OF_BKTS; + char *argv1[] = {"-tasgf", "-tmmbcs0", sbct_buf, NULL}; + char *argv2[] = {"-tasgf", "-tmmbcs0", sbct_buf, NULL, NULL}; + Allctr_t *a; + + sprintf(sbct_buf, "-tsbct%lu", sbct/1024); + + a = START_ALC("bkt_mask_1_", 0, argv1); + tcs->extra = (void *) a; + ASSERT(tcs, a); + + min_blk_sz = MIN_BLK_SZ(a); + smbcs = 2*(no_bkts*sizeof(void *) + min_blk_sz) + min_blk_sz; + for (i = 0; i < no_bkts; i++) { + sz = BKT_MIN_SZ(a, i); + if (sz >= sbct) + break; + smbcs += sz + min_blk_sz; + } + + bi_tests = i; + testcase_printf(tcs, "Will test %d buckets\n", bi_tests); + + STOP_ALC(a); + tcs->extra = NULL; + + smbcs /= 1024; + smbcs++; + + testcase_printf(tcs, "smbcs = %lu\n", smbcs); + sprintf(smbcs_buf, "-tsmbcs%lu", smbcs); + argv2[3] = smbcs_buf; + + a = START_ALC("bkt_mask_2_", 0, argv2); + tcs->extra = (void *) a; + ASSERT(tcs, a); + + blk = (void **) ALLOC(a, no_bkts*sizeof(void *)); + fence = (void **) ALLOC(a, no_bkts*sizeof(void *)); + + ASSERT(tcs, blk && fence); + + testcase_printf(tcs, "Allocating blocks and fences\n"); + for (i = 0; i < bi_tests; i++) { + sz = BKT_MIN_SZ(a, i); + blk[i] = ALLOC(a, sz - ablk_hdr_sz); + fence[i] = ALLOC(a, 1); + ASSERT(tcs, blk[i] && fence[i]); + } + + tmp = (void *) UMEM2BLK(fence[bi_tests - 1]); + tmp = (void *) NXT_BLK((Block_t *) tmp); + ASSERT(tcs, IS_LAST_BLK(tmp)); + sz = BLK_SZ((Block_t *) tmp); + testcase_printf(tcs, "Allocating leftover size = %lu\n", sz); + tmp = ALLOC(a, sz - ablk_hdr_sz); + ASSERT(tcs, tmp); + + bi = FIND_BKT(a, 0); + ASSERT(tcs, bi < 0); + + for (i = 0; i < bi_tests; i++) { + sz = BKT_MIN_SZ(a, i); + testcase_printf(tcs, "Testing bucket %d\n", i); + FREE(a, blk[i]); + bi = FIND_BKT(a, i); + ASSERT(tcs, bi == i); + blk[i] = ALLOC(a, sz - ablk_hdr_sz); + bi = FIND_BKT(a, i); + ASSERT(tcs, bi != i); + } + + for (i = 0; i < bi_tests; i++) { + FREE(a, blk[i]); + FREE(a, fence[i]); + } + + FREE(a, (void *) blk); + FREE(a, (void *) fence); + + bi = FIND_BKT(a, 0); + ASSERT(tcs, bi == no_bkts - 1); + + FREE(a, tmp); + + bi = FIND_BKT(a, 0); + ASSERT(tcs, bi < 0); + + STOP_ALC(a); + tcs->extra = NULL; +} + diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c new file mode 100644 index 0000000000..c84da97d35 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c @@ -0,0 +1,318 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" +#include + +#define CEILING(X, U) ((((X)+(U)-1)/(U))*(U)) + +void +check_ablk(TestCaseState_t *tcs, Allctr_t *a, void *ptr, Ulong umem_sz) +{ + Ulong unit_sz = UNIT_SZ; + Block_t *blk = UMEM2BLK(ptr); + Block_t *nxt_blk = NXT_BLK(blk); + Ulong real_sz = ((Ulong) nxt_blk) - ((Ulong) (blk)); + ASSERT(tcs, real_sz == BLK_SZ(blk)); + ASSERT(tcs, !IS_FREE_BLK(blk)); + ASSERT(tcs, real_sz >= CEILING(ABLK_HDR_SZ + umem_sz, unit_sz)); + if (real_sz > MIN_BLK_SZ(a) + && real_sz > CEILING(ABLK_HDR_SZ+umem_sz, unit_sz)) { + ASSERT(tcs, + real_sz <= CEILING(MIN_BLK_SZ(a)+ABLK_HDR_SZ+umem_sz, + unit_sz)); + ASSERT(tcs, IS_LAST_BLK(blk) || !IS_FREE_BLK(nxt_blk)); + } +} + +void +setup_sequence(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz, int no, + void *res[]) +{ + Carrier_t *c; + Block_t *blk; + int i; + + testcase_printf(tcs, + "Setting up a sequence of %d blocks of size %lu\n", + no, bsz); + c = FIRST_MBC(a); + ASSERT(tcs, !NEXT_C(c)); + blk = MBC2FBLK(a, c); + ASSERT(tcs, IS_LAST_BLK(blk)); + + for (i = 0; i < no; i++) + res[i] = ALLOC(a, bsz); + for (i = 0; i < no; i++) + ASSERT(tcs, res[i]); + + testcase_printf(tcs, "Checking that sequence was set up as expected\n"); + + for (i = 1; i < no; i++) + ASSERT(tcs, NXT_BLK(UMEM2BLK(res[i-1])) == UMEM2BLK(res[i])); + + blk = NXT_BLK(UMEM2BLK(res[no-1])); + ASSERT(tcs, IS_LAST_BLK(blk)); + + testcase_printf(tcs, "Sequence ok\n"); + + /* If we fail in setup_sequence(), it doesn't mean that something is + wrong. It is just a faulty assumption in setup_sequence() about + how blocks are going to be placed. + Fix setup_sequence()... */ +} + +static void +test_free(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz) +{ + Block_t *blk; + void *p[7]; + + testcase_printf(tcs," --- Testing free() with block size %lu ---\n",bsz); + + setup_sequence(tcs, a, bsz, 7, p); + + check_ablk(tcs, a, p[0], bsz); + check_ablk(tcs, a, p[1], bsz); + check_ablk(tcs, a, p[2], bsz); + check_ablk(tcs, a, p[3], bsz); + check_ablk(tcs, a, p[4], bsz); + check_ablk(tcs, a, p[5], bsz); + check_ablk(tcs, a, p[6], bsz); + + /* Coalescing with previous block */ + FREE(a, p[2]); + FREE(a, p[3]); + + blk = NXT_BLK(UMEM2BLK(p[1])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[4])); + + /* Coalescing with next block */ + + FREE(a, p[1]); + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[4])); + + /* Coalescing with next and previous block */ + + FREE(a, p[5]); + FREE(a, p[4]); + + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[6])); + + /* Cleanup */ + + FREE(a, p[0]); + FREE(a, p[6]); + + testcase_printf(tcs," --- free() with block size %lu succeded ---\n",bsz); +} + +static void +test_realloc(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz) +{ + Block_t *blk; + void *ptr; + void *p[3]; + Ulong nbsz; + + testcase_printf(tcs," --- Testing realloc() with block size %lu ---\n", + bsz); + + setup_sequence(tcs, a, bsz, 3, p); + + check_ablk(tcs, a, p[0], bsz); + check_ablk(tcs, a, p[1], bsz); + check_ablk(tcs, a, p[2], bsz); + + /* Grow to the end of the carrier */ + blk = NXT_BLK(UMEM2BLK(p[2])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, IS_LAST_BLK(blk)); + nbsz = bsz + BLK_SZ(blk); + ptr = REALLOC(a, p[2], nbsz); + ASSERT(tcs, p[2] == ptr); + check_ablk(tcs, a, p[2], nbsz); + blk = UMEM2BLK(p[2]); + ASSERT(tcs, IS_LAST_BLK(blk)); + + /* Shrink from the end of the carrier */ + ptr = REALLOC(a, p[2], bsz); + ASSERT(tcs, p[2] == ptr); + blk = UMEM2BLK(p[2]); + ASSERT(tcs, !IS_LAST_BLK(blk)); + blk = NXT_BLK(blk); + ASSERT(tcs, IS_LAST_BLK(blk)); + check_ablk(tcs, a, p[2], bsz); + + /* Shrink and coalecse with next free */ + + FREE(a, p[1]); + + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, IS_FREE_BLK(blk)); + + nbsz = bsz/2; + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + + check_ablk(tcs, a, p[0], nbsz); + + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2])); + + /* Grow into next free; but leave free block at end */ + + nbsz *= 3; + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + + check_ablk(tcs, a, p[0], nbsz); + blk = NXT_BLK(UMEM2BLK(p[0])); + + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2])); + + /* Grow upto next alloced block by allocating just enough so that no + free block fits between them */ + nbsz = BLK_SZ(blk) + UMEM_SZ(UMEM2BLK(p[0])); + nbsz -= MIN_BLK_SZ(a) - 1; + + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + check_ablk(tcs, a, p[0], nbsz); + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, !IS_FREE_BLK(blk)); + ASSERT(tcs, blk == UMEM2BLK(p[2])); + + /* Grow into unused part at end */ + nbsz += MIN_BLK_SZ(a) - 1; + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + check_ablk(tcs, a, p[0], nbsz); + ASSERT(tcs, !IS_FREE_BLK(blk)); + ASSERT(tcs, blk == UMEM2BLK(p[2])); + + /* Shrink *almost* as much so that a free block would fit between the + allocated blocks, and make sure that we don't get a free block + in between */ + nbsz -= MIN_BLK_SZ(a) - 1; + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + check_ablk(tcs, a, p[0], nbsz); + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, !IS_FREE_BLK(blk)); + ASSERT(tcs, blk == UMEM2BLK(p[2])); + + /* Shrink just as much so that a free block can fit between + the alloced blocks */ + nbsz -= 1; + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + check_ablk(tcs, a, p[0], nbsz); + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, blk < UMEM2BLK(p[2])); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2])); + + /* Shrink so little that no free block would fit between allocated + blocks, and make sure that we shrink the allocated block and + coalesce the extra free part with the next free block. */ + nbsz -= MIN_BLK_SZ(a) - 1; + ptr = REALLOC(a, p[0], nbsz); + ASSERT(tcs, p[0] == ptr); + check_ablk(tcs, a, p[0], nbsz); + blk = NXT_BLK(UMEM2BLK(p[0])); + ASSERT(tcs, IS_FREE_BLK(blk)); + ASSERT(tcs, blk < UMEM2BLK(p[2])); + ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2])); + + /* Cleanup */ + FREE(a, p[0]); + FREE(a, p[2]); + + testcase_printf(tcs, " --- realloc() with block size %lu succeded ---\n", + bsz); + +} + +char * +testcase_name(void) +{ + return "coalesce"; +} + +void +testcase_run(TestCaseState_t *tcs) +{ + char *argv_org[] = {"-tmmbcs1024", "-tsbct2048", "-trmbcmt100", "-tas", NULL, NULL}; + char *alg[] = {"af", "gf", "bf", "aobf", NULL}; + int i; + + for (i = 0; alg[i]; i++) { + Ulong sz; + Allctr_t *a; + char *argv[sizeof(argv_org)/sizeof(argv_org[0])]; + memcpy((void *) argv, (void *) argv_org, sizeof(argv_org)); + + argv[4] = alg[i]; + testcase_printf(tcs, " *** Starting \"%s\" allocator *** \n", alg[i]); + a = START_ALC("coalesce_", 0, argv); + ASSERT(tcs, a); + tcs->extra = (void *) a; + + sz = MIN_BLK_SZ(a) - ABLK_HDR_SZ; + test_free(tcs, a, sz); + sz += 1; + test_free(tcs, a, sz); + sz *= 4; + test_free(tcs, a, sz); + sz += 1; + test_free(tcs, a, sz); + sz *= 10; + test_free(tcs, a, sz); + + sz = MIN_BLK_SZ(a)*4 - ABLK_HDR_SZ; + test_realloc(tcs, a, sz); + sz += 1; + test_realloc(tcs, a, sz); + sz *= 4; + test_realloc(tcs, a, sz); + sz += 1; + test_realloc(tcs, a, sz); + sz *= 10; + test_realloc(tcs, a, sz); + + testcase_printf(tcs, " *** Stopping \"%s\" allocator *** \n", alg[i]); + STOP_ALC(a); + tcs->extra = NULL; + } +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) + STOP_ALC((Allctr_t *) tcs->extra); +} diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c new file mode 100644 index 0000000000..0277616bd0 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c @@ -0,0 +1,102 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" + +#define MAX_SEGS 10 + +typedef struct { + void *ptr; + Ulong size; +} seg_t; + +char * +testcase_name(void) +{ + return "mseg_clear_cache"; +} + +void +testcase_run(TestCaseState_t *tcs) +{ + int i; + Ulong n; + seg_t *seg; + + if (!HAVE_MSEG()) + testcase_skipped(tcs, "No mseg_alloc; nothing to test"); + + seg = (seg_t *) testcase_alloc(sizeof(seg_t)*(MAX_SEGS+1)); + + ASSERT(tcs, seg); + + for (i = 0; i <= MAX_SEGS; i++) + seg[i].ptr = NULL; + + tcs->extra = &seg[0]; + + for (i = 0; i < MAX_SEGS; i++) { + seg[i].size = 1000; + seg[i].ptr = MSEG_ALLOC(&seg[i].size); + ASSERT(tcs, seg[i].ptr); + ASSERT(tcs, seg[i].size >= 1000); + } + + n = MSEG_NO(); + testcase_printf(tcs, "MSEG_NO() = %lu\n", n); + + ASSERT(tcs, n >= MAX_SEGS); + + testcase_printf(tcs, "Deallocating half of the segments\n"); + for (i = MAX_SEGS-1; i >= MAX_SEGS/2; i--) { + MSEG_DEALLOC(seg[i].ptr, seg[i].size); + seg[i].ptr = NULL; + } + + n = MSEG_NO(); + testcase_printf(tcs, "MSEG_NO() = %lu\n", n); + + ASSERT(tcs, n >= MAX_SEGS/2); + + n = MSEG_CACHE_SIZE(); + testcase_printf(tcs, "MSEG_CACHE_SIZE() = %lu\n", n); + ASSERT(tcs, n > 0); + + testcase_printf(tcs, "MSEG_CLEAR_CACHE()\n"); + MSEG_CLEAR_CACHE(); + + n = MSEG_CACHE_SIZE(); + testcase_printf(tcs, "MSEG_CACHE_SIZE() = %lu\n", n); + + ASSERT(tcs, n == 0); + +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) { + seg_t *seg = (seg_t *) tcs->extra; + int i; + for (i = 0; seg[i].ptr; i++) + MSEG_DEALLOC(seg[i].ptr, seg[i].size); + testcase_free((void *) seg); + tcs->extra = NULL; + } +} diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.c b/erts/emulator/test/alloc_SUITE_data/rbtree.c new file mode 100644 index 0000000000..c97e0aac1a --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/rbtree.c @@ -0,0 +1,386 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" + +#define NO_BLOCKS 100000 + +#define RIGHT_VISITED (1 << 0) +#define LEFT_VISITED (1 << 1) + +typedef struct { + Allctr_t *allocator; + void **blk; + void **fence; +} rbtree_test_data; + +#if 0 +#define PRINT_TREE +#endif + +#ifdef PRINT_TREE + +#define INDENT_STEP 5 + +#include +static void +print_tree_aux(TestCaseState_t *tcs, RBT_t *x, int indent) +{ + if (!x) { + char frmt[20]; + sprintf(frmt, "%%%ds%%s\n", indent); + testcase_printf(tcs, frmt, "", "BLACK: nil"); + } + else { + print_tree_aux(tcs, RBT_RIGHT(x), indent + INDENT_STEP); + { + char frmt[40]; + sprintf(frmt, "%%%ds%%s: sz=%%lu addr=0x%%lx\n", indent); + testcase_printf(tcs, + frmt, + "", + RBT_IS_BLACK(x) ? "BLACK" : "RED", + BLK_SZ(x), + (Ulong) x); + } + print_tree_aux(tcs, RBT_LEFT(x), indent + INDENT_STEP); + } +} + + +static void +print_tree(TestCaseState_t *tcs, RBT_t *root, int aobf) +{ + char *type = aobf ? "Size-Adress" : "Size"; + testcase_printf(tcs, " --- %s tree begin ---\r\n", type); + print_tree_aux(tcs, root, 0); + testcase_printf(tcs, " --- %s tree end ---\r\n", type); +} + +#endif + +static RBT_t * +check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size) +{ + int i, max_i, address_order; + char stk[128]; + RBT_t *root, *x, *y, *res; + Ulong x_sz, y_sz, is_x_black; + long blacks, curr_blacks; + + res = NULL; + + address_order = IS_AOBF(alc); + root = RBT_ROOT(alc); + +#ifdef PRINT_TREE + print_tree(tcs, root, address_order); +#endif + + max_i = i = -1; + curr_blacks = 0; + blacks = -1; + + if (!root) + goto done; + + stk[++i] = 0; + + ASSERT(tcs, RBT_IS_BLACK(root)); + ASSERT(tcs, !RBT_PARENT(root)); + x = root; + curr_blacks++; + + while (x) { + + ASSERT(tcs, i <= 128); + + if (!(stk[i] & LEFT_VISITED)) { + stk[i] |= LEFT_VISITED; + y = RBT_LEFT(x); + if (RBT_IS_BLACK(y)) + curr_blacks++; + if (y) { + x = y; + stk[++i] = 0; + continue; + } + else { + if (blacks < 0) + blacks = curr_blacks; + ASSERT(tcs, blacks == curr_blacks); + curr_blacks--; + } + } + + if (!(stk[i] & RIGHT_VISITED)) { + stk[i] |= RIGHT_VISITED; + y = RBT_RIGHT(x); + if (RBT_IS_BLACK(y)) + curr_blacks++; + if (y) { + x = y; + stk[++i] = 0; + continue; + } + else { + if (blacks < 0) + blacks = curr_blacks; + ASSERT(tcs, blacks == curr_blacks); + curr_blacks--; + } + } + + + /* Check x ... */ + + is_x_black = RBT_IS_BLACK(x); + x_sz = BLK_SZ(x); + + + if (!is_x_black) { + ASSERT(tcs, RBT_IS_BLACK(RBT_RIGHT(x))); + ASSERT(tcs, RBT_IS_BLACK(RBT_LEFT(x))); + } + + ASSERT(tcs, RBT_PARENT(x) || x == root); + + y = RBT_LEFT(x); + if (y) { + y_sz = BLK_SZ(y); + ASSERT(tcs, RBT_PARENT(y) == x); + if (address_order) { + ASSERT(tcs, y_sz < x_sz || (y_sz == x_sz && y < x)); + } + else { + ASSERT(tcs, RBT_IS_TREE(y)); + ASSERT(tcs, y_sz < x_sz); + } + } + + y = RBT_RIGHT(x); + if (y) { + y_sz = BLK_SZ(y); + ASSERT(tcs, RBT_PARENT(y) == x); + if (address_order) { + ASSERT(tcs, y_sz > x_sz || (y_sz == x_sz && y > x)); + } + else { + ASSERT(tcs, RBT_IS_TREE(y)); + ASSERT(tcs, y_sz > x_sz); + } + } + + if (!address_order) { + Ulong l_sz; + RBTL_t *l = RBT_NEXT(x); + for (l = RBT_NEXT(x); l; l = RBT_NEXT(l)) { + l_sz = BLK_SZ(l); + ASSERT(tcs, l_sz == x_sz); + ASSERT(tcs, !RBT_IS_TREE(l)); + } + } + + if (size && x_sz >= size) { + if (!res) + res = x; + else { + y_sz = BLK_SZ(res); + if (address_order) { + if (x_sz < y_sz || (x_sz == y_sz && x < res)) + res = x; + } + else { + if (!res || x_sz < y_sz) + res = x; + } + } + } + + if (max_i < i) + max_i = i; + if (is_x_black) + curr_blacks--; + x = RBT_PARENT(x); + i--; + } + + done: + 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; + +} + +static void +do_check(TestCaseState_t *tcs, Allctr_t *a, Ulong size) +{ + Ulong sz = ((size + 7) / 8)*8; + void *tmp; + Block_t *x, *y; + + x = (Block_t *) check_tree(tcs, a, sz); + tmp = ALLOC(a, sz - ABLK_HDR_SZ); + ASSERT(tcs, tmp); + y = UMEM2BLK(tmp); + if (IS_AOBF(a)) { + ASSERT(tcs, x == y); + } + else { + ASSERT(tcs, BLK_SZ(x) == BLK_SZ(y)); + } + FREE(a, tmp); +} + + +static void +test_it(TestCaseState_t *tcs) +{ + int i; + Allctr_t a = ((rbtree_test_data *) tcs->extra)->allocator; + void **blk = ((rbtree_test_data *) tcs->extra)->blk; + void **fence = ((rbtree_test_data *) tcs->extra)->fence; + Ulong min_blk_sz; + + min_blk_sz = MIN_BLK_SZ(a); + + for (i = 0; i < NO_BLOCKS; i++) { + blk[i] = ALLOC(a, min_blk_sz + i % 500); + fence[i] = ALLOC(a, 1); + ASSERT(tcs, blk[i] && fence[i]); + } + + for (i = 0; i < NO_BLOCKS; i++) { + if (i % 3 == 0) { + FREE(a, blk[i]); + blk[i] = NULL; + } + if (i % (NO_BLOCKS/2) == 0) + do_check(tcs, a, 50); + } + + for (i = 0; i < NO_BLOCKS; i++) { + if (i % 5 == 0 && blk[i]) { + FREE(a, blk[i]); + blk[i] = NULL; + } + if (i % (NO_BLOCKS/2) == 0) + do_check(tcs, a, 200); + } + + for (i = 0; i < NO_BLOCKS; i++) { + if (blk[i]) { + FREE(a, blk[i]); + blk[i] = NULL; + } + if (i % (NO_BLOCKS/2) == 0) + do_check(tcs, a, 100); + } + + do_check(tcs, a, 250); + + for (i = 0; i < NO_BLOCKS; i++) { + FREE(a, fence[i]); + if (i % (NO_BLOCKS/3) == 0) + do_check(tcs, a, 300); + } + + ASSERT(tcs, RBT_ROOT(a)); + ASSERT(tcs, !RBT_LEFT(RBT_ROOT(a))); + ASSERT(tcs, !RBT_RIGHT(RBT_ROOT(a))); +} + + +char * +testcase_name(void) +{ + return "rbtree"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) { + rbtree_test_data *td = tcs->extra; + tcs->extra = NULL; + if (td->allocator) + STOP_ALC(td->allocator); + if (td->blk) + testcase_free((void *) td->blk); + if (td->fence) + testcase_free((void *) td->fence); + testcase_free((void *) td); + } +} + +void +testcase_run(TestCaseState_t *tcs) +{ + char *argv1[] = {"-tasbf", NULL}; + char *argv2[] = {"-tasaobf", NULL}; + Allctr_t *a; + rbtree_test_data *td; + + /* Best fit... */ + + testcase_printf(tcs, "Setup...\n"); + + td = (rbtree_test_data *) testcase_alloc(sizeof(rbtree_test_data)); + ASSERT(tcs, td); + tcs->extra = (void *) td; + td->allocator = NULL; + td->blk = (void **) testcase_alloc(sizeof(void *)*NO_BLOCKS); + td->fence = (void **) testcase_alloc(sizeof(void *)*NO_BLOCKS); + ASSERT(tcs, td->blk && td->fence); + + testcase_printf(tcs, "Starting test of best fit...\n"); + + td->allocator = a = START_ALC("rbtree_bf_", 0, argv1); + + ASSERT(tcs, a); + ASSERT(tcs, !IS_AOBF(a)); + + test_it(tcs); + + STOP_ALC(a); + td->allocator = NULL; + + testcase_printf(tcs, "Best fit test succeeded!\n"); + + /* Address order best fit... */ + + testcase_printf(tcs, "Starting test of address order best fit...\n"); + + td->allocator = a = START_ALC("rbtree_aobf_", 0, argv2); + + ASSERT(tcs, a); + ASSERT(tcs, IS_AOBF(a)); + + test_it(tcs); + + STOP_ALC(a); + td->allocator = NULL; + + testcase_printf(tcs, "Address order best fit test succeeded!\n"); + +} diff --git a/erts/emulator/test/alloc_SUITE_data/realloc_copy.c b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c new file mode 100644 index 0000000000..12454c75e4 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c @@ -0,0 +1,279 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include "allocator_test.h" +#include +#include + +#if 1 +#define PRINT_ALLOC_OPS +#endif + +#define SBC_THRESHOLD 8192 +#define NO_OF_BLOCKS 7 +#define NO_OF_ALLOC_OPS_PER_BLOCK 700 + +typedef struct { + unsigned char *p; + Ulong s; + int i; + Ulong *as; +} block; + +Ulong alloc_seq_1[] = { + SBC_THRESHOLD, /* mmap */ + SBC_THRESHOLD*4, /* mmap to new mmap */ + SBC_THRESHOLD/50, /* mmap to malloc */ + SBC_THRESHOLD, /* malloc to mmap */ + 0 +}; + + +Ulong alloc_seq_2[] = { + 1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/9, + SBC_THRESHOLD/8, + SBC_THRESHOLD/7, + SBC_THRESHOLD/6, + SBC_THRESHOLD/5, + SBC_THRESHOLD/4, + SBC_THRESHOLD/3, + SBC_THRESHOLD/2, + SBC_THRESHOLD*1, + SBC_THRESHOLD*2, + SBC_THRESHOLD*3, + SBC_THRESHOLD*4, + SBC_THRESHOLD*5, + SBC_THRESHOLD*6, + SBC_THRESHOLD*7, + SBC_THRESHOLD*8, + SBC_THRESHOLD*9, + SBC_THRESHOLD*10, + SBC_THRESHOLD*9, + SBC_THRESHOLD*8, + SBC_THRESHOLD*7, + SBC_THRESHOLD*6, + SBC_THRESHOLD*5, + SBC_THRESHOLD*4, + SBC_THRESHOLD*3, + SBC_THRESHOLD*2, + SBC_THRESHOLD*1, + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/4, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/9, + SBC_THRESHOLD/10, + 1, + 0 +}; + +Ulong alloc_seq_3[] = { + SBC_THRESHOLD*11, + SBC_THRESHOLD*10, + SBC_THRESHOLD*9, + SBC_THRESHOLD*8, + SBC_THRESHOLD*7, + SBC_THRESHOLD*6, + SBC_THRESHOLD*5, + SBC_THRESHOLD*4, + SBC_THRESHOLD*3, + SBC_THRESHOLD*2, + SBC_THRESHOLD*1, + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/4, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/9, + SBC_THRESHOLD/10, + 1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/9, + SBC_THRESHOLD/8, + SBC_THRESHOLD/7, + SBC_THRESHOLD/6, + SBC_THRESHOLD/5, + SBC_THRESHOLD/4, + SBC_THRESHOLD/3, + SBC_THRESHOLD/2, + SBC_THRESHOLD*1, + SBC_THRESHOLD*2, + SBC_THRESHOLD*3, + SBC_THRESHOLD*4, + SBC_THRESHOLD*5, + SBC_THRESHOLD*6, + SBC_THRESHOLD*7, + SBC_THRESHOLD*8, + SBC_THRESHOLD*9, + SBC_THRESHOLD*10, + 0 +}; + +Ulong alloc_seq_4[] = { + SBC_THRESHOLD*1, + SBC_THRESHOLD*10, + SBC_THRESHOLD*1, + 0 +}; + +Ulong alloc_seq_5[] = { + SBC_THRESHOLD/50, + SBC_THRESHOLD*10, + SBC_THRESHOLD/50, + 0 +}; + +Ulong alloc_seq_6[] = { + SBC_THRESHOLD/50, + SBC_THRESHOLD*10, + SBC_THRESHOLD/50, + SBC_THRESHOLD*10, + 0 +}; + +Ulong alloc_seq_7[] = { + 1, + SBC_THRESHOLD/50, + SBC_THRESHOLD*10, + SBC_THRESHOLD/50, + 0 +}; + + +block blocks[NO_OF_BLOCKS] = {{NULL, 0, 0, alloc_seq_1}, + {NULL, 0, 0, alloc_seq_2}, + {NULL, 0, 0, alloc_seq_3}, + {NULL, 0, 0, alloc_seq_4}, + {NULL, 0, 0, alloc_seq_5}, + {NULL, 0, 0, alloc_seq_6}, + {NULL, 0, 0, alloc_seq_7}}; + +#define CHECK_BLOCK_DATA(T, P, S, D) \ + check_block_data(__FILE__, __LINE__, (T), (P), (S), (D)) + +static void +check_block_data(char *file, int line, + TestCaseState_t *tcs, unsigned char *p, Ulong sz, int d) +{ + Ulong i; + for (i = 0; i < sz; i++) + if (p[i] != (unsigned char) d) + testcase_failed(tcs, "%s:%d: Data clobbered! found id=%d; " + "expected id=%d\n", file, line, (int) p[i], d); +} + + +static void +alloc_op(TestCaseState_t *tcs, Allctr_t *a, block *bp, int id, int clean_up) +{ + if(bp->p) + CHECK_BLOCK_DATA(tcs, bp->p, bp->s, id); + + if(bp->as[bp->i] == 0 || clean_up) { + FREE(a, bp->p); +#ifdef PRINT_ALLOC_OPS + testcase_printf(tcs, "FREE(0x%lx) [id=%d]\n", (Ulong) bp->p, id); +#endif + bp->p = NULL; + bp->s = 0; + bp->i = 0; /* start from the beginning again */ + return; + } + + if(!bp->p) { + bp->s = bp->as[bp->i]; + bp->p = (unsigned char *) ALLOC(a, bp->s); +#ifdef PRINT_ALLOC_OPS + testcase_printf(tcs, "0x%lx = ALLOC(%lu) [id=%d]\n", + (Ulong) bp->p, bp->s, id); +#endif + if(!bp->p) + testcase_failed(tcs, "ALLOC(%lu) failed [id=%d])\n", bp->s, id); + memset((void *) bp->p, id, (size_t) bp->s); + } + else { + unsigned char *p = (unsigned char *) REALLOC(a, bp->p, bp->as[bp->i]); +#ifdef PRINT_ALLOC_OPS + testcase_printf(tcs, "0x%lx = REALLOC(0x%lx, %lu) [id=%d]\n", + (Ulong) p, (Ulong) bp->p, bp->as[bp->i], id); +#endif + if(!p) { + testcase_failed(tcs, "REALLOC(0x%lx, %lu) failed [id=%d]\n", + (Ulong) bp->p, bp->as[bp->i], id); + } + + if(bp->s < bp->as[bp->i]) { + CHECK_BLOCK_DATA(tcs, p, bp->s, id); + memset((void *) p, id, (size_t) bp->as[bp->i]); + } + else + CHECK_BLOCK_DATA(tcs, p, bp->as[bp->i], id); + + bp->s = bp->as[bp->i]; + bp->p = p; + } + + bp->i++; +} + +char * +testcase_name(void) +{ + return "realloc_copy"; +} + +void +testcase_run(TestCaseState_t *tcs) +{ + int i, j; + char sbct_buf[20]; + char *argv[] = {"-tmmsbc", "5000", "-tsbct", &sbct_buf[0], NULL}; + Allctr_t *a; + + sprintf(sbct_buf, "%d", SBC_THRESHOLD/1024); + + a = START_ALC("realloc_copy_", 0, argv); + ASSERT(tcs, a); + tcs->extra = (void *) a; + + for(i = 0; i < NO_OF_ALLOC_OPS_PER_BLOCK; i++) + for(j = 0; j < NO_OF_BLOCKS; j++) + alloc_op(tcs, a, &blocks[j], j + 1, 0); + + for(j = 0; j < NO_OF_BLOCKS; j++) + alloc_op(tcs, a, &blocks[j], j + 1, 1); + + STOP_ALC((Allctr_t *) tcs->extra); + tcs->extra = NULL; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + if (tcs->extra) + STOP_ALC((Allctr_t *) tcs->extra); +} + diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c new file mode 100644 index 0000000000..1e98844838 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -0,0 +1,260 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "testcase_driver.h" +#include +#include +#include +#include +#include + +#ifdef __WIN32__ +#undef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 1 +#define vsnprintf _vsnprintf +#endif + +#ifndef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 0 +#endif + +#define COMMENT_BUF_SZ 4096 + +#define TESTCASE_FAILED 0 +#define TESTCASE_SKIPPED 1 +#define TESTCASE_SUCCEEDED 2 + +typedef struct { + TestCaseState_t visible; + ErlDrvPort port; + 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, int len); + +static ErlDrvEntry testcase_drv_entry = { + NULL, + testcase_drv_start, + testcase_drv_stop, + testcase_drv_run +}; + + +DRIVER_INIT(testcase_drv) +{ + testcase_drv_entry.driver_name = testcase_name(); + return &testcase_drv_entry; +} + +ErlDrvData +testcase_drv_start(ErlDrvPort port, char *command) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) + driver_alloc(sizeof(InternalTestCaseState_t)); + if (!itcs) { + return ERL_DRV_ERROR_GENERAL; + } + + itcs->visible.testcase_name = testcase_name(); + itcs->visible.extra = NULL; + itcs->port = port; + itcs->result = TESTCASE_FAILED; + itcs->comment = ""; + + return (ErlDrvData) itcs; +} + +void +testcase_drv_stop(ErlDrvData drv_data) +{ + testcase_cleanup((TestCaseState_t *) drv_data); + driver_free((void *) drv_data); +} + +void +testcase_drv_run(ErlDrvData drv_data, char *buf, int len) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data; + ErlDrvTermData result_atom; + ErlDrvTermData msg[12]; + + itcs->visible.command = buf; + itcs->visible.command_len = len; + + if (setjmp(itcs->done_jmp_buf) == 0) { + testcase_run((TestCaseState_t *) itcs); + itcs->result = TESTCASE_SUCCEEDED; + } + + switch (itcs->result) { + 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] = driver_mk_port(itcs->port); + + 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; + + driver_output_term(itcs->port, msg, 11); +} + +int +testcase_assertion_failed(TestCaseState_t *tcs, + char *file, int line, char *assertion) +{ + testcase_failed(tcs, "%s:%d: Assertion failed: \"%s\"", + file, line, assertion); + return 0; +} + +void +testcase_printf(TestCaseState_t *tcs, char *frmt, ...) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + ErlDrvTermData msg[12]; + 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 + va_end(va); + + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) driver_mk_atom("print"); + + msg[2] = ERL_DRV_PORT; + msg[3] = driver_mk_port(itcs->port); + + 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[9] = ERL_DRV_TUPLE; + msg[10] = (ErlDrvTermData) 4; + + driver_output_term(itcs->port, msg, 11); +} + + +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 + va_end(va); + + itcs->result = TESTCASE_SUCCEEDED; + itcs->comment = itcs->comment_buf; + + longjmp(itcs->done_jmp_buf, 1); +} + +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 + va_end(va); + + itcs->result = TESTCASE_SKIPPED; + itcs->comment = itcs->comment_buf; + + longjmp(itcs->done_jmp_buf, 1); +} + +void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + char buf[10]; + 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 + va_end(va); + + itcs->result = TESTCASE_FAILED; + itcs->comment = itcs->comment_buf; + + if (erl_drv_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); + abort(); + } + + longjmp(itcs->done_jmp_buf, 1); +} + +void *testcase_alloc(size_t size) +{ + return driver_alloc(size); +} + +void *testcase_realloc(void *ptr, size_t size) +{ + return driver_realloc(ptr, size); +} + +void testcase_free(void *ptr) +{ + driver_free(ptr); +} diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h new file mode 100644 index 0000000000..66d567cb44 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h @@ -0,0 +1,51 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#ifndef TESTCASE_DRIVER_H__ +#define TESTCASE_DRIVER_H__ + +#include "erl_driver.h" +#include + +typedef struct { + char *testcase_name; + char *command; + int command_len; + void *extra; +} TestCaseState_t; + +#define ASSERT(TCS, B) \ + ((void) ((B) ? 1 : testcase_assertion_failed((TCS), __FILE__, __LINE__, #B))) + + +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_failed(TestCaseState_t *tcs, char *frmt, ...); +int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line, + char *assertion); +void *testcase_alloc(size_t size); +void *testcase_realloc(void *ptr, size_t size); +void testcase_free(void *ptr); + + +char *testcase_name(void); +void testcase_run(TestCaseState_t *tcs); +void testcase_cleanup(TestCaseState_t *tcs); + +#endif diff --git a/erts/emulator/test/alloc_SUITE_data/threads.c b/erts/emulator/test/alloc_SUITE_data/threads.c new file mode 100644 index 0000000000..1247e5d7dd --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/threads.c @@ -0,0 +1,447 @@ +/* ``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 via the world wide web 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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + + +#ifndef __WIN32__ +#include +#include +#include +#endif +#include +#include +#include +#include "testcase_driver.h" +#include "allocator_test.h" + +#ifdef __WIN32__ +#undef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 1 +#define vsnprintf _vsnprintf +#endif + +#ifndef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 0 +#endif + +#define NO_OF_ALLOC_SEQS 6 +#define NO_OF_THREADS (18) +#define NO_OF_BLOCKS 10 +#define NO_OF_OPS_PER_BL 200 +#define SBC_THRESHOLD 8192 + +#define BLOCK_ID(TN, BN) ((TN) << 4 | (BN)) + +#define ERR_BUF_SZ 4096 +static char err_buf[ERR_BUF_SZ]; +static volatile int tc_failed; +static int dead_thread_no; +static erts_mutex tc_mutex; +static erts_cond tc_cond; + +static void exit_thread(int t_no, int do_lock) +{ + if (do_lock) + THR_MTX_LOCK(tc_mutex); + + while (dead_thread_no >= 0) + THR_COND_WAIT(tc_cond, tc_mutex); + dead_thread_no = t_no; + + THR_COND_BCAST(tc_cond); + THR_MTX_UNLOCK(tc_mutex); + THR_EXIT(NULL); +} + +static void fail(int t_no, char *frmt, ...) +{ + char buf[10]; + size_t bufsz = sizeof(buf); + va_list va; + + THR_MTX_LOCK(tc_mutex); + + va_start(va, frmt); +#if HAVE_VSNPRINTF + vsnprintf(err_buf, ERR_BUF_SZ, frmt, va); +#else + vsprintf(err_buf, frmt, va); +#endif + va_end(va); + + tc_failed = 1; + + if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + && strcmp("true", buf) == 0) { + fprintf(stderr, "Testcase \"%s\" failed: %s\n", + testcase_name(), err_buf); + abort(); + } + + exit_thread(t_no, 0); +} + +static Allctr_t *alloc_not_ts = NULL; +static Allctr_t *alloc_ts_1 = NULL; +static Allctr_t *alloc_ts_2 = NULL; + +static void stop_allocators(void) +{ + if (alloc_not_ts) { + STOP_ALC(alloc_not_ts); + alloc_not_ts = NULL; + } + if (alloc_ts_1) { + STOP_ALC(alloc_ts_1); + alloc_ts_1 = NULL; + } + if (alloc_ts_2) { + STOP_ALC(alloc_ts_2); + alloc_ts_2 = NULL; + } +} + + +void *thread_func(void *arg); + +typedef struct { + Allctr_t *a; + int t_no; + int no_ops_per_bl; +} ThreadData; + + +char * +testcase_name(void) +{ + return "threads"; +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + stop_allocators(); +} + +void +testcase_run(TestCaseState_t *tcs) +{ + struct { + erts_thread tid; + ThreadData arg; + } threads[NO_OF_THREADS+1] = {{0}}; + int no_threads; + int i; + char sbct_buf[10]; + char *argv_org[] = {"-tasaobf", "-tmmsbc5000", "-tmmmbc5000", "-tsbct", + &sbct_buf[0], NULL}; + char *argv[sizeof(argv_org)/sizeof(argv_org[0])]; + + if (!IS_THREADS_ENABLED) + testcase_skipped(tcs, "Threads not enabled"); + + alloc_not_ts = NULL; + alloc_ts_1 = NULL; + alloc_ts_2 = NULL; + + err_buf[0] = '\0'; + + sprintf(sbct_buf, "%d", SBC_THRESHOLD/1024); + + memcpy((void *) argv, argv_org, sizeof(argv_org)); + alloc_not_ts = START_ALC("threads_not_ts", 0, argv); + ASSERT(tcs, alloc_not_ts); + memcpy((void *) argv, argv_org, sizeof(argv_org)); + alloc_ts_1 = START_ALC("threads_ts_1", 1, argv); + ASSERT(tcs, alloc_ts_1); + memcpy((void *) argv, argv_org, sizeof(argv_org)); + alloc_ts_2 = START_ALC("threads_ts_2", 1, argv); + ASSERT(tcs, alloc_ts_2); + + ASSERT(tcs, !IS_ALLOC_THREAD_SAFE(alloc_not_ts)); + ASSERT(tcs, IS_ALLOC_THREAD_SAFE(alloc_ts_1)); + ASSERT(tcs, IS_ALLOC_THREAD_SAFE(alloc_ts_2)); + + tc_mutex = THR_MTX_CREATE(); + tc_cond = THR_COND_CREATE(); + + THR_MTX_LOCK(tc_mutex); + + dead_thread_no = -1; + no_threads = 0; + + for(i = 1; i <= NO_OF_THREADS; i++) { + char *alc; + int res; + + threads[i].arg.no_ops_per_bl = NO_OF_OPS_PER_BL; + + if (i == 1) { + alc = "threads_not_ts"; + threads[i].arg.no_ops_per_bl *= 2; + threads[i].arg.a = alloc_not_ts; + } + else if (i % 2 == 0) { + alc = "threads_ts_1"; + threads[i].arg.a = alloc_ts_1; + } + else { + alc = "threads_ts_2"; + threads[i].arg.a = alloc_ts_2; + } + threads[i].arg.t_no = i; + + threads[i].tid = THR_CREATE(thread_func, (void *) &threads[i].arg); + if (threads[i].tid) { + testcase_printf(tcs, "Successfully created thread %d " + "using %s_alloc\n", i, alc); + no_threads++; + } + else { + tc_failed = 1; + sprintf(err_buf, "Failed to create thread %d\n", i); + break; + } + + } + + while (no_threads) { + THR_COND_WAIT(tc_cond, tc_mutex); + if (dead_thread_no >= 0) { + no_threads--; + THR_JOIN(threads[dead_thread_no].tid); + testcase_printf(tcs, "Thread %d died\n", dead_thread_no); + dead_thread_no = -1; + THR_COND_BCAST(tc_cond); + } + } + + THR_MTX_UNLOCK(tc_mutex); + THR_MTX_DESTROY(tc_mutex); + THR_COND_DESTROY(tc_cond); + + stop_allocators(); + + if (tc_failed) + testcase_failed(tcs, "%s", err_buf); +} + +Ulong alloc_seq_1[] = { + 17, + SBC_THRESHOLD*2, + SBC_THRESHOLD*20, + SBC_THRESHOLD*2, + 17, + 0 +}; + +Ulong alloc_seq_2[] = { + SBC_THRESHOLD*20, + SBC_THRESHOLD*2, + 17, + SBC_THRESHOLD*2, + SBC_THRESHOLD*20, + 0 +}; + +Ulong alloc_seq_3[] = { + 1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/9, + SBC_THRESHOLD/8, + SBC_THRESHOLD/7, + SBC_THRESHOLD/6, + SBC_THRESHOLD/5, + SBC_THRESHOLD/4, + SBC_THRESHOLD/3, + SBC_THRESHOLD/2, + SBC_THRESHOLD/1, + SBC_THRESHOLD*1, + SBC_THRESHOLD*2, + SBC_THRESHOLD*3, + SBC_THRESHOLD*4, + SBC_THRESHOLD*5, + SBC_THRESHOLD*6, + SBC_THRESHOLD*7, + SBC_THRESHOLD*8, + SBC_THRESHOLD*9, + SBC_THRESHOLD*10, + SBC_THRESHOLD*9, + SBC_THRESHOLD*8, + SBC_THRESHOLD*7, + SBC_THRESHOLD*6, + SBC_THRESHOLD*5, + SBC_THRESHOLD*4, + SBC_THRESHOLD*3, + SBC_THRESHOLD*2, + SBC_THRESHOLD*1, + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/4, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/9, + SBC_THRESHOLD/10, + 1, + 0 +}; + +Ulong alloc_seq_4[] = { + SBC_THRESHOLD*2, + SBC_THRESHOLD*3, + SBC_THRESHOLD*7, + SBC_THRESHOLD*8, + SBC_THRESHOLD*5, + SBC_THRESHOLD*6, + SBC_THRESHOLD*1, + SBC_THRESHOLD*10, + SBC_THRESHOLD*4, + SBC_THRESHOLD*2, + 0 +}; + +Ulong alloc_seq_5[] = { + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/4, + SBC_THRESHOLD/2, + SBC_THRESHOLD/3, + SBC_THRESHOLD/7, + SBC_THRESHOLD/8, + SBC_THRESHOLD/5, + SBC_THRESHOLD/6, + SBC_THRESHOLD/1, + SBC_THRESHOLD/10, + SBC_THRESHOLD/4, + SBC_THRESHOLD/2, + 0 +}; + +Ulong alloc_seq_6[] = { + 1, 50, 100, 50, 23, 46, 2345, 23, 54, 2, 0 +}; + +Ulong *alloc_seqs[NO_OF_ALLOC_SEQS] = { + alloc_seq_1, + alloc_seq_2, + alloc_seq_3, + alloc_seq_4, + alloc_seq_5, + alloc_seq_6 +}; + +typedef struct { + unsigned char *p; + Ulong s; + int i; + Ulong *as; +} block; + +#define CHECK_BLOCK_DATA(T, P, S, D) \ + check_block_data(__FILE__, __LINE__, (T), (P), (S), (D)) + +static void +check_block_data(char *file, int line, int t_no, + unsigned char *p, Ulong sz, int d) +{ + Ulong i; + for (i = 0; i < sz; i++) + if (p[i] != (unsigned char) d) + fail(t_no, "%s:%d: Thread no %d found clobbered data! " + "found id=%d; expected id=%d\n", + file, line, t_no, (int) p[i], d); +} + +static void +alloc_op(int t_no, Allctr_t *a, block *bp, int id, int clean_up) +{ + if (tc_failed) + exit_thread(t_no, 1); + + if(bp->p) + CHECK_BLOCK_DATA(t_no, bp->p, bp->s, id); + + if(bp->as[bp->i] == 0 || clean_up) { + FREE(a, bp->p); + bp->p = NULL; + bp->s = 0; + bp->i = 0; /* start from the beginning again */ + return; + } + + if(!bp->p) { + bp->s = bp->as[bp->i]; + bp->p = (unsigned char *) ALLOC(a, bp->s); + if(!bp->p) + fail(t_no, "ALLOC(%lu) failed [id=%d])\n", bp->s, id); + memset((void *) bp->p, id, (size_t) bp->s); + } + else { + unsigned char *p = (unsigned char *) REALLOC(a, bp->p, bp->as[bp->i]); + if(!p) + fail(t_no, "REALLOC(0x%lx, %lu) failed [id=%d]\n", + (Ulong) bp->p, bp->as[bp->i], id); + + if(bp->s < bp->as[bp->i]) { + CHECK_BLOCK_DATA(t_no, p, bp->s, id); + memset((void *) p, id, (size_t) bp->as[bp->i]); + } + else + CHECK_BLOCK_DATA(t_no, p, bp->as[bp->i], id); + + bp->s = bp->as[bp->i]; + bp->p = p; + } + + bp->i++; +} + + +void * +thread_func(void *arg) +{ + int i, j; + ThreadData *td = ((ThreadData *) arg); + block bs[NO_OF_BLOCKS]; + + for(i = 0; i < NO_OF_BLOCKS; i++) { + bs[i].p = NULL; + bs[i].s = 0; + bs[i].i = 0; + bs[i].as = alloc_seqs[i % NO_OF_ALLOC_SEQS]; + } + + for(i = 0; i < td->no_ops_per_bl; i++) { + + for(j = 0; j < NO_OF_BLOCKS; j++) + alloc_op(td->t_no, td->a, &bs[j], BLOCK_ID(td->t_no, j), 0); + } + + for(j = 0; j < NO_OF_BLOCKS; j++) + alloc_op(td->t_no, td->a, &bs[j], BLOCK_ID(td->t_no, j), 1); + + exit_thread(td->t_no, 1); + return NULL; +} -- cgit v1.2.3