diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vespamalloc/src/tests |
Publish
Diffstat (limited to 'vespamalloc/src/tests')
58 files changed, 2204 insertions, 0 deletions
diff --git a/vespamalloc/src/tests/.gitignore b/vespamalloc/src/tests/.gitignore new file mode 100644 index 00000000000..fdebd8b7f2c --- /dev/null +++ b/vespamalloc/src/tests/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +test +vespamalloc_test_app diff --git a/vespamalloc/src/tests/CMakeLists.txt b/vespamalloc/src/tests/CMakeLists.txt new file mode 100644 index 00000000000..4d566371bd7 --- /dev/null +++ b/vespamalloc/src/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_test_app + SOURCES + test.cpp + DEPENDS +) diff --git a/vespamalloc/src/tests/allocfree/.gitignore b/vespamalloc/src/tests/allocfree/.gitignore new file mode 100644 index 00000000000..a80a52d808a --- /dev/null +++ b/vespamalloc/src/tests/allocfree/.gitignore @@ -0,0 +1,14 @@ +.depend +Makefile +allocfree_shared_test +allocfree_static_test +allocfree_static_testd +allocfree_test +linklist_test +realloc_test +realloc_testd +/creatingmanythreads_test +vespamalloc_allocfree_shared_test_app +vespamalloc_creatingmanythreads_test_app +vespamalloc_linklist_test_app +vespamalloc_realloc_test_app diff --git a/vespamalloc/src/tests/allocfree/CMakeLists.txt b/vespamalloc/src/tests/allocfree/CMakeLists.txt new file mode 100644 index 00000000000..1dc36f8dec7 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_creatingmanythreads_test_app + SOURCES + creatingmanythreads.cpp +) +vespa_add_executable(vespamalloc_allocfree_shared_test_app + SOURCES + allocfree.cpp + producerconsumer.cpp +) +vespa_add_test(NAME vespamalloc_allocfree_shared_test_app NO_VALGRIND COMMAND sh allocfree_test.sh BENCHMARK) +vespa_add_executable(vespamalloc_realloc_test_app + SOURCES + realloc.cpp +) +vespa_add_executable(vespamalloc_linklist_test_app + SOURCES + linklist.cpp + producerconsumer.cpp + ../../vespamalloc/malloc/allocchunk.cpp + ../../vespamalloc/malloc/common.cpp + $<TARGET_OBJECTS:vespamalloc_util> +) diff --git a/vespamalloc/src/tests/allocfree/DESC b/vespamalloc/src/tests/allocfree/DESC new file mode 100644 index 00000000000..4f3ca4d4d97 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/DESC @@ -0,0 +1 @@ +This is a unittest of vespamalloc. diff --git a/vespamalloc/src/tests/allocfree/FILES b/vespamalloc/src/tests/allocfree/FILES new file mode 100644 index 00000000000..4b14c586dd4 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/FILES @@ -0,0 +1 @@ +testatomic.cpp diff --git a/vespamalloc/src/tests/allocfree/allocfree.cpp b/vespamalloc/src/tests/allocfree/allocfree.cpp new file mode 100644 index 00000000000..0f7b4d53c6f --- /dev/null +++ b/vespamalloc/src/tests/allocfree/allocfree.cpp @@ -0,0 +1,115 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include "producerconsumer.h" +#include <map> + +using vespalib::Consumer; +using vespalib::Producer; +using vespalib::ProducerConsumer; + +LOG_SETUP("allocfree_test"); + +TEST_SETUP(Test); + +//----------------------------------------------------------------------------- + +class FreeWorker : public Consumer { +public: + FreeWorker(uint32_t maxQueue, bool inverse) + : Consumer (maxQueue, inverse) {} +private: + virtual void consume(void * p) { free(p); } +}; + +//----------------------------------------------------------------------------- + +class MallocWorker : public Producer { +public: + MallocWorker(uint32_t size, uint32_t cnt, FreeWorker &target) + : Producer(cnt, target), _size(size) {} +private: + uint32_t _size; + virtual void * produce() { return malloc(_size); } +}; + +//----------------------------------------------------------------------------- + +class MallocFreeWorker : public ProducerConsumer { +public: + MallocFreeWorker(uint32_t size, uint32_t cnt, bool inverse) + : ProducerConsumer(cnt, inverse), _size(size) { } +private: + uint32_t _size; + virtual void * produce() { return malloc(_size); } + virtual void consume(void * p) { free(p); } +}; + +//----------------------------------------------------------------------------- + +int Test::Main() { + int duration = 10; + int numCrossThreadAlloc(2); + int numSameThreadAlloc(2); + if (_argc > 1) { + duration = atoi(_argv[1]); + } + if (_argc > 2) { + numCrossThreadAlloc = atoi(_argv[2]); + } + if (_argc > 3) { + numSameThreadAlloc = atoi(_argv[3]); + } + TEST_INIT("allocfree_test"); + + FastOS_ThreadPool pool(128000); + + std::map<int, std::shared_ptr<FreeWorker> > freeWorkers; + std::map<int, std::shared_ptr<MallocWorker> > mallocWorkers; + std::map<int, std::shared_ptr<MallocFreeWorker> > mallocFreeWorkers; + for (int i(0); i < numCrossThreadAlloc; i++) { + freeWorkers[i] = std::shared_ptr<FreeWorker>(new FreeWorker(1024, (i%2) ? true : false)); + mallocWorkers[i] = std::shared_ptr<MallocWorker>(new MallocWorker(400, 256, *freeWorkers[i])); + } + for(int i(0); i < numSameThreadAlloc; i++) { + mallocFreeWorkers[i] = std::shared_ptr<MallocFreeWorker>(new MallocFreeWorker(200, 16, (i%2) ? true : false)); + } + + + for(std::map<int, std::shared_ptr<FreeWorker> >::iterator it(freeWorkers.begin()), mt(freeWorkers.end()); it != mt; it++) { + ASSERT_TRUE(pool.NewThread(it->second.get(), NULL) != NULL); + } + for(std::map<int, std::shared_ptr<MallocWorker> >::iterator it(mallocWorkers.begin()), mt(mallocWorkers.end()); it != mt; it++) { + ASSERT_TRUE(pool.NewThread(it->second.get(), NULL) != NULL); + } + for(std::map<int, std::shared_ptr<MallocFreeWorker> >::iterator it(mallocFreeWorkers.begin()), mt(mallocFreeWorkers.end()); it != mt; it++) { + ASSERT_TRUE(pool.NewThread(it->second.get(), NULL) != NULL); + } + + for (; duration > 0; --duration) { + LOG(info, "%d seconds left...", duration); + FastOS_Thread::Sleep(1000); + } + pool.Close(); + size_t numFreeOperations(0); + size_t numMallocOperations(0); + size_t numSameThreadMallocFreeOperations(0); + for(std::map<int, std::shared_ptr<FreeWorker> >::iterator it(freeWorkers.begin()), mt(freeWorkers.end()); it != mt; it++) { + numFreeOperations += it->second->operations(); + } + for(std::map<int, std::shared_ptr<MallocWorker> >::iterator it(mallocWorkers.begin()), mt(mallocWorkers.end()); it != mt; it++) { + numMallocOperations += it->second->operations(); + } + for(std::map<int, std::shared_ptr<MallocFreeWorker> >::iterator it(mallocFreeWorkers.begin()), mt(mallocFreeWorkers.end()); it != mt; it++) { + numSameThreadMallocFreeOperations += it->second->operationsConsumed(); + } + EXPECT_EQUAL(numFreeOperations, numMallocOperations); + const size_t numCrossThreadMallocFreeOperations(numMallocOperations); + + fprintf(stderr, "Did %" PRIu64 " Cross thread malloc/free operations\n", numCrossThreadMallocFreeOperations); + fprintf(stderr, "Did %" PRIu64 " Same thread malloc/free operations\n", numSameThreadMallocFreeOperations); + fprintf(stderr, "Did %" PRIu64 " Total operations\n", numCrossThreadMallocFreeOperations + numSameThreadMallocFreeOperations); + + TEST_DONE(); +} diff --git a/vespamalloc/src/tests/allocfree/allocfree_benchmark.sh b/vespamalloc/src/tests/allocfree/allocfree_benchmark.sh new file mode 100755 index 00000000000..51165dfce71 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/allocfree_benchmark.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +TIME=/usr/bin/time + +VESPA_MALLOC_SO=../../../src/vespamalloc/libvespamalloc.so +LIBDIR=$LIBDIR + +$TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +$TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +$TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +$TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +$TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +$TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +$TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +$TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +$TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +$TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +$TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +$TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +$TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +$TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +$TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +$TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +$TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +$TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$LIBDIR/libtcmalloc_minimal.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$LIBDIR/libjemalloc_mt.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$LIBDIR/libptmalloc3.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$LIBDIR/libnedmalloc.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$LIBDIR/libhoard.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 0 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 0 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 0 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 0 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 0 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 0 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 1 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 2 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 4 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 8 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 16 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 0 32 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 1 1 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 2 2 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 4 4 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 8 8 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 16 16 +LD_PRELOAD=$LIBDIR/libtlsf.so $TIME ./vespamalloc_allocfree_shared_test_app 5 32 32 diff --git a/vespamalloc/src/tests/allocfree/allocfree_test.sh b/vespamalloc/src/tests/allocfree/allocfree_test.sh new file mode 100755 index 00000000000..ac864dc891b --- /dev/null +++ b/vespamalloc/src/tests/allocfree/allocfree_test.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +TIME=/usr/bin/time + +VESPA_MALLOC_SO=../../../src/vespamalloc/libvespamalloc.so +VESPA_MALLOC_SO_D=../../../src/vespamalloc/libvespamalloc_vespamallocd.so + +LD_PRELOAD=$VESPA_MALLOC_SO ./vespamalloc_realloc_test_app +LD_PRELOAD=$VESPA_MALLOC_SO_D ./vespamalloc_realloc_test_app +$TIME ./vespamalloc_linklist_test_app 3 +LD_PRELOAD=$VESPA_MALLOC_SO $TIME ./vespamalloc_allocfree_shared_test_app 3 +LD_PRELOAD=$VESPA_MALLOC_SO_D $TIME ./vespamalloc_allocfree_shared_test_app 3 +$TIME ./vespamalloc_allocfree_shared_test_app 3 +VESPA_MALLOC_MADVISE_LIMIT=0x200000 LD_PRELOAD=$VESPA_MALLOC_SO_D $TIME ./vespamalloc_allocfree_shared_test_app 3 +LD_PRELOAD=$VESPA_MALLOC_SO_D $TIME ./vespamalloc_allocfree_shared_test_app 3 +VESPA_MALLOC_MADVISE_LIMIT=0x200000 VESPA_MALLOC_HUGEPAGES=on LD_PRELOAD=$VESPA_MALLOC_SO_D $TIME ./vespamalloc_allocfree_shared_test_app 3 +VESPA_MALLOC_HUGEPAGES=on LD_PRELOAD=$VESPA_MALLOC_SO_D $TIME ./vespamalloc_allocfree_shared_test_app 3 diff --git a/vespamalloc/src/tests/allocfree/creatingmanythreads.cpp b/vespamalloc/src/tests/allocfree/creatingmanythreads.cpp new file mode 100644 index 00000000000..53de3f274cc --- /dev/null +++ b/vespamalloc/src/tests/allocfree/creatingmanythreads.cpp @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> + +LOG_SETUP("creatingmanythreads_test"); + +TEST_SETUP(Test); + +void * thread_alloc(void * arg) +{ + char * v = new char [*static_cast<int *>(arg)]; + delete [] v; + return NULL; +} + +int Test::Main() { + int numThreads(10000); + int allocSize(256); + if (_argc > 1) { + numThreads = atoi(_argv[1]); + } + if (_argc > 2) { + allocSize = atoi(_argv[2]); + } + TEST_INIT("creatingmanythreads_test"); + + LOG(info, "Will create and run %d threads each allocating a single block of memory of %d size\n", numThreads, allocSize); + for (int i(0); i < numThreads; ) { + for (int j(0); (i < numThreads) && j < 10000; i++, j++) { + pthread_t thread; + ASSERT_EQUAL(0, pthread_create(&thread, NULL, thread_alloc, &allocSize)); + ASSERT_EQUAL(0, pthread_join(thread, NULL)); + } + LOG(info, "Completed %d tests", i); + } + + TEST_DONE(); +} diff --git a/vespamalloc/src/tests/allocfree/generate_testtable.sh b/vespamalloc/src/tests/allocfree/generate_testtable.sh new file mode 100755 index 00000000000..5763024c086 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/generate_testtable.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +base=$1 + +echo "No threads test. Test difference of static linkage, shared and debug versus glibc" +cat $base | ./timeusage.sh > t1 +cat $base | grep time | grep allocfree_ | cut -d'5' -f2 | awk '{print $1*2 + $2 ";"}' > t2 +cat $base | grep "Total" | awk '{print $2}' > t3 +paste testnames.all testtype.all t2 t1 t3 > t4 + +for t in "cross thread" "same thread" "same + cross" +do + echo $t + + for f in "glibc" "vespamallostatic" "vespamalloc" "tcmalloc" "jemalloc" "ptmalloc3" "nedmalloc" "hoard" "tlsf" + do + grep "$t" t4 | grep "$f" | cut -d';' -f7 | xargs echo $f | sed "s/ /;/g" + done +done + +cat t4 + diff --git a/vespamalloc/src/tests/allocfree/linklist.cpp b/vespamalloc/src/tests/allocfree/linklist.cpp new file mode 100644 index 00000000000..5ad31d481f9 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/linklist.cpp @@ -0,0 +1,188 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include "producerconsumer.h" +#include <vespamalloc/malloc/allocchunk.h> +#include <vespamalloc/util/callstack.h> + +using vespalib::Consumer; +using vespalib::Producer; +using vespalib::ProducerConsumer; + +LOG_SETUP("linklist_test"); + +TEST_SETUP(Test); + +//----------------------------------------------------------------------------- + +template <size_t MinSizeClassC, size_t MaxSizeClassMultiAllocC> +class MemBlockT : public vespamalloc::CommonT<MinSizeClassC> +{ +public: + typedef vespamalloc::StackEntry<vespamalloc::StackReturnEntry> Stack; + enum { + MaxSizeClassMultiAlloc = MaxSizeClassMultiAllocC, + SizeClassSpan = (MaxSizeClassMultiAllocC-MinSizeClassC) + }; + MemBlockT() : _ptr(NULL) { } + MemBlockT(void * p) : _ptr(p) { } + MemBlockT(void * p, size_t /*sz*/) : _ptr(p) { } + void *ptr() { return _ptr; } + const void *ptr() const { return _ptr; } + bool validAlloc() const { return _ptr != NULL; } + bool validFree() const { return _ptr != NULL; } + void setExact(size_t ) { } + void alloc(bool ) { } + void threadId(int ) { } + void free() { } + size_t size() const { return 0; } + bool allocated() const { return false; } + int threadId() const { return 0; } + void info(FILE *, unsigned level=0) const { level = 0; } + Stack * callStack() { return NULL; } + size_t callStackLen() const { return 0; } + + static size_t adjustSize(size_t sz) { return sz; } + static size_t unAdjustSize(size_t sz) { return sz; } + static void dumpInfo(size_t level); +private: + void * _ptr; +}; + +typedef MemBlockT<5, 20> DummyMemBlock; + +typedef vespamalloc::AFList<DummyMemBlock> List; + +const size_t NumBlocks((64*(32+2)+16)*2); + +List globalList[NumBlocks]; + +class LinkIn : public Consumer { +public: + LinkIn(List::HeadPtr & list, uint32_t maxQueue, bool inverse); +private: + List::HeadPtr & _head; + virtual void consume(void * p) { + List * l((List *) p); + if ( ! ((l >= &globalList[0]) && (l < &globalList[NumBlocks]))) { abort(); } + List::linkIn(_head, l, l); + } +}; + +LinkIn::LinkIn(List::HeadPtr & list, uint32_t maxQueue, bool inverse) : + Consumer (maxQueue, inverse), + _head(list) +{ +} + +//----------------------------------------------------------------------------- + +class LinkOut : public Producer { +public: + LinkOut(List::HeadPtr & list, uint32_t cnt, LinkIn &target) + : Producer(cnt, target), _head(list) {} +private: + List::HeadPtr & _head; + virtual void * produce() { + void *p = List::linkOut(_head); + List *l((List *)p); + if ( ! ((l >= &globalList[0]) && (l < &globalList[NumBlocks]))) { abort(); } + return p; + } +}; + +//----------------------------------------------------------------------------- + +class LinkInOutAndIn : public ProducerConsumer { +public: + LinkInOutAndIn(List::HeadPtr & list, uint32_t cnt, bool inverse) + : ProducerConsumer(cnt, inverse), _head(list) { } +private: + List::HeadPtr & _head; + virtual void * produce() { + void *p = List::linkOut(_head); + List *l((List *)p); + if ( !((l >= &globalList[0]) && (l < &globalList[NumBlocks]))) { abort(); } + return p; + } + virtual void consume(void * p) { + List * l((List *) p); + if ( !((l >= &globalList[0]) && (l < &globalList[NumBlocks]))) { abort(); } + List::linkIn(_head, l, l); + } +}; + +//----------------------------------------------------------------------------- + +int Test::Main() { + int duration = 10; + if (_argc > 1) { + duration = atoi(_argv[1]); + } + TEST_INIT("allocfree_test"); + + ASSERT_EQUAL(1024ul, sizeof(List)); + + FastOS_ThreadPool pool(128000); + List::HeadPtr sharedList; + sharedList._tag = 1; + List::init(); + List::enableThreadSupport(); + fprintf(stderr, "Start populating list\n"); + for (size_t i=0; i < NumBlocks; i++) { + List * l(&globalList[i]); + List::linkIn(sharedList, l, l); + } + fprintf(stderr, "Finished populating list with %ld elements\n", NumBlocks); + fprintf(stderr, "Start verifying result 1.\n"); + for (size_t i=0; i < NumBlocks; i++) { + List *l = List::linkOut(sharedList); + ASSERT_TRUE((l >= &globalList[0]) && (l < &globalList[NumBlocks])); + } + List *n = List::linkOut(sharedList); + ASSERT_TRUE(n == NULL); + + sharedList._tag = 1; + fprintf(stderr, "Start populating list\n"); + for (size_t i=0; i < NumBlocks; i++) { + List * l(&globalList[i]); + List::linkIn(sharedList, l, l); + } + fprintf(stderr, "Finished populating list with %ld elements\n", NumBlocks); + LinkIn c1(sharedList, 64, false); + LinkIn c2(sharedList, 64, true); + LinkOut p1(sharedList, 32, c1); + LinkOut p2(sharedList, 32, c2); + LinkInOutAndIn pc1(sharedList, 16, false); + LinkInOutAndIn pc2(sharedList, 16, true); + + ASSERT_TRUE(pool.NewThread(&c1, NULL) != NULL); + ASSERT_TRUE(pool.NewThread(&c2, NULL) != NULL); + ASSERT_TRUE(pool.NewThread(&p1, NULL) != NULL); + ASSERT_TRUE(pool.NewThread(&p2, NULL) != NULL); + ASSERT_TRUE(pool.NewThread(&pc1, NULL) != NULL); + ASSERT_TRUE(pool.NewThread(&pc2, NULL) != NULL); + + for (; duration > 0; --duration) { + LOG(info, "%d seconds left...", duration); + FastOS_Thread::Sleep(1000); + } + pool.Close(); + fprintf(stderr, "Did (%" PRIu64 " + %" PRIu64 ") = %" PRIu64 " linkIn operations\n", + c1.operations(), c2.operations(), c1.operations() + c2.operations()); + fprintf(stderr, "Did (%" PRIu64 " + %" PRIu64 ") = %" PRIu64 " linkOut operations\n", + p1.operations(), p2.operations(), p1.operations() + p2.operations()); + fprintf(stderr, "Did (%" PRIu64 " + %" PRIu64 ") = %" PRIu64 " linkInOut operations\n", + pc1.operationsConsumed(), pc2.operationsConsumed(), pc1.operationsConsumed() + pc2.operationsConsumed()); + fprintf(stderr, "Did %" PRIu64 " Total operations\n", + c1.operations() + c2.operations() + p1.operations() + p2.operations() + pc1.operationsConsumed() + pc2.operationsConsumed()); + fprintf(stderr, "Start verifying result 2.\n"); + for (size_t i=0; i < NumBlocks; i++) { + List *l = List::linkOut(sharedList); + ASSERT_TRUE((l >= &globalList[0]) && (l < &globalList[NumBlocks])); + } + n = List::linkOut(sharedList); + ASSERT_TRUE(n == NULL); + TEST_DONE(); +} diff --git a/vespamalloc/src/tests/allocfree/producerconsumer.cpp b/vespamalloc/src/tests/allocfree/producerconsumer.cpp new file mode 100644 index 00000000000..38c52993762 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/producerconsumer.cpp @@ -0,0 +1,95 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "producerconsumer.h" + +namespace vespalib { + +Consumer::Consumer(uint32_t maxQueue, bool inverse) : + _queue(NULL, maxQueue), + _inverse(inverse), + _operations(0) +{ +} + +Consumer::~Consumer() +{ +} + +Producer::Producer(uint32_t cnt, Consumer &target) : + _target(target), + _cnt(cnt), + _operations(0) +{ +} + +Producer::~Producer() +{ +} + +ProducerConsumer::ProducerConsumer(uint32_t cnt, bool inverse) : + _cnt(cnt), + _inverse(inverse), + _operationsConsumed(0), + _operationsProduced(0) +{ +} + +ProducerConsumer::~ProducerConsumer() +{ +} + + +void Consumer::Run(FastOS_ThreadInterface *, void *) { + for (;;) { + MemList ml = _queue.dequeue(); + if (ml == NULL) { + return; + } + if (_inverse) { + for (uint32_t i = ml->size(); i > 0; --i) { + consume((*ml)[i - 1]); + _operations++; + } + } else { + for (uint32_t i = 0; i < ml->size(); ++i) { + consume((*ml)[i]); + _operations++; + } + } + delete ml; + } +} + +void Producer::Run(FastOS_ThreadInterface *t, void *) { + while (!t->GetBreakFlag()) { + MemList ml = new MemListImpl(); + for (uint32_t i = 0; i < _cnt; ++i) { + ml->push_back(produce()); + _operations++; + } + _target.enqueue(ml); + } + _target.close(); +} + +void ProducerConsumer::Run(FastOS_ThreadInterface *t, void *) { + while (!t->GetBreakFlag()) { + MemListImpl ml; + for (uint32_t i = 0; i < _cnt; ++i) { + ml.push_back(produce()); + _operationsProduced++; + } + if (_inverse) { + for (uint32_t i = ml.size(); i > 0; --i) { + consume(ml[i - 1]); + _operationsConsumed++; + } + } else { + for (uint32_t i = 0; i < ml.size(); ++i) { + consume(ml[i]); + _operationsConsumed++; + } + } + } +} + +} diff --git a/vespamalloc/src/tests/allocfree/producerconsumer.h b/vespamalloc/src/tests/allocfree/producerconsumer.h new file mode 100644 index 00000000000..daa0173af98 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/producerconsumer.h @@ -0,0 +1,58 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <vector> +#include "queue.h" + +namespace vespalib { + +typedef std::vector<void *> MemListImpl; +typedef MemListImpl * MemList; +typedef vespalib::Queue<MemList> MemQueue; + +class Consumer : public FastOS_Runnable { +private: + MemQueue _queue; + bool _inverse; + uint64_t _operations; + virtual void consume(void *) = 0; +public: + Consumer(uint32_t maxQueue, bool inverse); + virtual ~Consumer(); + void enqueue(const MemList &mem) { _queue.enqueue(mem); } + void close() { _queue.close(); } + void Run(FastOS_ThreadInterface *t, void *); + uint64_t operations() const { return _operations; } +}; + +class Producer : public FastOS_Runnable { +private: + Consumer & _target; + uint32_t _cnt; + uint64_t _operations; + virtual void * produce() = 0; +public: + Producer(uint32_t cnt, Consumer &target); + virtual ~Producer(); + void Run(FastOS_ThreadInterface *t, void *); + uint64_t operations() const { return _operations; } +}; + +class ProducerConsumer : public FastOS_Runnable { +private: + uint32_t _cnt; + bool _inverse; + uint64_t _operationsConsumed; + uint64_t _operationsProduced; + virtual void * produce() = 0; + virtual void consume(void *) = 0; +public: + ProducerConsumer(uint32_t cnt, bool inverse); + virtual ~ProducerConsumer(); + void Run(FastOS_ThreadInterface *t, void *); + uint64_t operationsConsumed() const { return _operationsConsumed; } + uint64_t operationsProduced() const { return _operationsProduced; } +}; + +} + diff --git a/vespamalloc/src/tests/allocfree/queue.h b/vespamalloc/src/tests/allocfree/queue.h new file mode 100644 index 00000000000..ce5c18d33f2 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/queue.h @@ -0,0 +1,86 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <vespa/vespalib/util/guard.h> +#include <vespa/vespalib/util/sync.h> +#include <queue> + +namespace vespalib { + +template <typename T> +class Queue { +private: + std::queue<T> _q; + Monitor _cond; + int _waitRead; + int _waitWrite; + uint32_t _maxSize; + bool _closed; + T _nil; + Queue(const Queue &); + Queue &operator=(const Queue &); +public: + Queue(const T &nil, uint32_t maxSize); + ~Queue(); + void enqueue(const T &entry); + void close(); + T dequeue(); +}; + +template <typename T> +Queue<T>::Queue(const T &nil, uint32_t maxSize) : + _q(), + _cond(), + _waitRead(0), + _waitWrite(0), + _maxSize(maxSize), + _closed(false), + _nil(nil) +{ +} + +template <typename T> +Queue<T>::~Queue() +{ +} + +template <typename T> +void Queue<T>::enqueue(const T &entry) { + MonitorGuard guard(_cond); + while (_q.size() >= _maxSize) { + CounterGuard cntGuard(_waitWrite); + guard.wait(); + } + _q.push(entry); + if (_waitRead > 0) { + guard.signal(); + } +} +template <typename T> +void Queue<T>::close() { + MonitorGuard guard(_cond); + _closed = true; + if (_waitRead > 0) { + guard.signal(); + } +} +template <typename T> +T Queue<T>::dequeue() { + MonitorGuard guard(_cond); + while (_q.empty() && !_closed) { + CounterGuard cntGuard(_waitRead); + guard.wait(); + } + if (_q.empty()) { + return _nil; + } + T tmp = _q.front(); + _q.pop(); + if (_waitWrite > 0) { + guard.signal(); + } + return tmp; +} + +} + diff --git a/vespamalloc/src/tests/allocfree/realloc.cpp b/vespamalloc/src/tests/allocfree/realloc.cpp new file mode 100644 index 00000000000..8cfd50d0132 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/realloc.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> + +LOG_SETUP("realloc_test"); + +TEST_SETUP(Test); + +int Test::Main() { + char * v = static_cast<char *>(malloc(0x400001)); + char * nv = static_cast<char *>(realloc(v, 0x500001)); + ASSERT_TRUE(v == nv); + v = static_cast<char *>(realloc(nv, 0x600001)); + ASSERT_TRUE(v != nv); + free(v); + + char *t = static_cast<char *>(malloc(70)); + free (t+7); + t = static_cast<char *>(malloc(0x400001)); + free (t+7); + return 0; +} diff --git a/vespamalloc/src/tests/allocfree/testnames.all b/vespamalloc/src/tests/allocfree/testnames.all new file mode 100644 index 00000000000..eb51eeefa31 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/testnames.all @@ -0,0 +1,162 @@ +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +glibc; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamallostatic; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +vespamalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +tcmalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +jemalloc; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +ptmalloc3; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +nedmalloc; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +hoard; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; +tlsf; diff --git a/vespamalloc/src/tests/allocfree/testtype.all b/vespamalloc/src/tests/allocfree/testtype.all new file mode 100644 index 00000000000..a70eb05bde7 --- /dev/null +++ b/vespamalloc/src/tests/allocfree/testtype.all @@ -0,0 +1,162 @@ +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +cross thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same thread; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; +same + cross; diff --git a/vespamalloc/src/tests/allocfree/timeusage.sh b/vespamalloc/src/tests/allocfree/timeusage.sh new file mode 100755 index 00000000000..58fdc47104a --- /dev/null +++ b/vespamalloc/src/tests/allocfree/timeusage.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +grep "CPU" |grep "elapsed" | sed "s/user / user /g" | sed "s/system / system /g" | sed "s/elapsed / elapsed /g" | sed "s/CPU / CPU /g" | awk '{print $1 ";\t" $3 ";\t" $7 ";"}' diff --git a/vespamalloc/src/tests/allocfree/vespamalloc.conf b/vespamalloc/src/tests/allocfree/vespamalloc.conf new file mode 100644 index 00000000000..5c82d46d94b --- /dev/null +++ b/vespamalloc/src/tests/allocfree/vespamalloc.conf @@ -0,0 +1,13 @@ +#Config file for vespa malloc +#loglevel = 0 should mean no logging. Only level 1 is implemented. +# logfile vespamalloc.log # default(stderr) This is the file to where log is written (stderr, stdout, filename) +sigprof_loglevel 2 # default(0) Loglevel used at SIGPROF signal. +atend_loglevel 2 # default(1) Loglevel used when application stops. +atnomem_loglevel 2 # default(1) Loglevel used when datasegment is exhausted. +atdoubledelete_loglevel 2 # default(1) Loglevel used when vespa_malloc discovers a double delete. +atinvalid_loglevel 2 # default(1) Loglevel used when vespa_malloc discovers logical error. +bigsegment_loglevel 0 # default(1) Loglevel used when datasegment passes a boundary. +bigsegment_limit 0x80000000 # default(0x20000000) First level the datasegment must reach before logging is started +bigsegment_increment 0x10000000 # default(0x4000000) At what increment it will log next time. +bigblocklimit 0x800000 # default(0x800000) Limit for when to log new/deletes wuth stack trace. Only mallocdst.so +allocs2show 8 diff --git a/vespamalloc/src/tests/doubledelete/.gitignore b/vespamalloc/src/tests/doubledelete/.gitignore new file mode 100644 index 00000000000..0ac32be10fc --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/.gitignore @@ -0,0 +1,7 @@ +.depend +Makefile +doubledelete_test +doubledelete_testd +expectsignal +vespamalloc_doubledelete_test_app +vespamalloc_expectsignal_app diff --git a/vespamalloc/src/tests/doubledelete/CMakeLists.txt b/vespamalloc/src/tests/doubledelete/CMakeLists.txt new file mode 100644 index 00000000000..e38f163148a --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_doubledelete_test_app + SOURCES + doubledelete.cpp + DEPENDS +) +vespa_add_test(NAME vespamalloc_doubledelete_test_app NO_VALGRIND COMMAND sh doubledelete_test.sh) +vespa_add_executable(vespamalloc_expectsignal_app + SOURCES + expectsignal.cpp + DEPENDS +) diff --git a/vespamalloc/src/tests/doubledelete/DESC b/vespamalloc/src/tests/doubledelete/DESC new file mode 100644 index 00000000000..004492d6b82 --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/DESC @@ -0,0 +1 @@ +Test that double delete is detected by vespamallocdxxxx. diff --git a/vespamalloc/src/tests/doubledelete/FILES b/vespamalloc/src/tests/doubledelete/FILES new file mode 100644 index 00000000000..3beebbcb132 --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/FILES @@ -0,0 +1 @@ +doubledelete.cpp diff --git a/vespamalloc/src/tests/doubledelete/doubledelete.cpp b/vespamalloc/src/tests/doubledelete/doubledelete.cpp new file mode 100644 index 00000000000..954e2d90bd2 --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/doubledelete.cpp @@ -0,0 +1,11 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <stdlib.h> + +int main(int argc, char *argv[]) +{ + (void) argc; + (void) argv; + char * a = new char [100]; + delete a; + delete a; +} diff --git a/vespamalloc/src/tests/doubledelete/doubledelete_test.sh b/vespamalloc/src/tests/doubledelete/doubledelete_test.sh new file mode 100755 index 00000000000..a43b5e3a406 --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/doubledelete_test.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +LD_PRELOAD=../../../src/vespamalloc/libvespamalloc.so ./vespamalloc_doubledelete_test_app + +ulimit -c 0 +./vespamalloc_expectsignal_app 6 "LD_PRELOAD=../../../src/vespamalloc/libvespamalloc_vespamallocd.so ./vespamalloc_doubledelete_test_app" diff --git a/vespamalloc/src/tests/doubledelete/expectsignal.cpp b/vespamalloc/src/tests/doubledelete/expectsignal.cpp new file mode 100644 index 00000000000..0b2d5e154c4 --- /dev/null +++ b/vespamalloc/src/tests/doubledelete/expectsignal.cpp @@ -0,0 +1,57 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/slaveproc.h> + +LOG_SETUP("expectsignal_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); +private: + virtual bool useProcessStarter() const { return true; } +}; + +int Test::Main() +{ + TEST_INIT("expectsignal_test"); + + EXPECT_EQUAL(_argc, 3); + ASSERT_TRUE(_argc == 3); + + int retval = strtol(_argv[1], NULL, 0); + + fprintf(stderr, "argc=%d : Running '%s' expecting signal %d\n", _argc, _argv[2], retval); + + SlaveProc cmd(_argv[2]); + for(std::string line; cmd.readLine(line, 60000);) { + fprintf(stdout, "%s\n", line.c_str()); + } + + ASSERT_TRUE(cmd.wait(60000)); + + int exitCode = cmd.getExitCode(); + + if (exitCode == 65535) { + fprintf(stderr, "[ERROR] child killed (timeout)\n"); + } else if (WIFEXITED(exitCode)) { + fprintf(stderr, "child terminated normally with exit code %u\n", WEXITSTATUS(exitCode)); + } else if (WIFSIGNALED(exitCode)) { + fprintf(stderr, "child terminated by signal %u\n", WTERMSIG(exitCode)); + if (WCOREDUMP(exitCode)) { + fprintf(stderr, "[WARNING] child dumped core\n"); + } + } else { + fprintf(stderr, "[WARNING] strange exit code: %u\n", exitCode); + } + + EXPECT_EQUAL(exitCode & 0x7f, retval); + + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/vespamalloc/src/tests/overwrite/.gitignore b/vespamalloc/src/tests/overwrite/.gitignore new file mode 100644 index 00000000000..5a8760f913d --- /dev/null +++ b/vespamalloc/src/tests/overwrite/.gitignore @@ -0,0 +1,8 @@ +.depend +Makefile +expectsignal +overwrite_test +overwrite_testd +/expectsignal-overwrite +vespamalloc_overwrite_test_app +vespamalloc_expectsignal-overwrite_app diff --git a/vespamalloc/src/tests/overwrite/CMakeLists.txt b/vespamalloc/src/tests/overwrite/CMakeLists.txt new file mode 100644 index 00000000000..f3625bd396c --- /dev/null +++ b/vespamalloc/src/tests/overwrite/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_overwrite_test_app + SOURCES + overwrite.cpp + DEPENDS +) +vespa_add_test(NAME vespamalloc_overwrite_test_app NO_VALGRIND COMMAND sh overwrite_test.sh) +vespa_add_executable(vespamalloc_expectsignal-overwrite_app + SOURCES + expectsignal.cpp + DEPENDS +) diff --git a/vespamalloc/src/tests/overwrite/DESC b/vespamalloc/src/tests/overwrite/DESC new file mode 100644 index 00000000000..5d5e1d01ba4 --- /dev/null +++ b/vespamalloc/src/tests/overwrite/DESC @@ -0,0 +1 @@ +This is a test of using memory after delete detection. diff --git a/vespamalloc/src/tests/overwrite/FILES b/vespamalloc/src/tests/overwrite/FILES new file mode 100644 index 00000000000..d8b6a578e9d --- /dev/null +++ b/vespamalloc/src/tests/overwrite/FILES @@ -0,0 +1 @@ +overwrite.cpp diff --git a/vespamalloc/src/tests/overwrite/expectsignal.cpp b/vespamalloc/src/tests/overwrite/expectsignal.cpp new file mode 100644 index 00000000000..0b2d5e154c4 --- /dev/null +++ b/vespamalloc/src/tests/overwrite/expectsignal.cpp @@ -0,0 +1,57 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/slaveproc.h> + +LOG_SETUP("expectsignal_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); +private: + virtual bool useProcessStarter() const { return true; } +}; + +int Test::Main() +{ + TEST_INIT("expectsignal_test"); + + EXPECT_EQUAL(_argc, 3); + ASSERT_TRUE(_argc == 3); + + int retval = strtol(_argv[1], NULL, 0); + + fprintf(stderr, "argc=%d : Running '%s' expecting signal %d\n", _argc, _argv[2], retval); + + SlaveProc cmd(_argv[2]); + for(std::string line; cmd.readLine(line, 60000);) { + fprintf(stdout, "%s\n", line.c_str()); + } + + ASSERT_TRUE(cmd.wait(60000)); + + int exitCode = cmd.getExitCode(); + + if (exitCode == 65535) { + fprintf(stderr, "[ERROR] child killed (timeout)\n"); + } else if (WIFEXITED(exitCode)) { + fprintf(stderr, "child terminated normally with exit code %u\n", WEXITSTATUS(exitCode)); + } else if (WIFSIGNALED(exitCode)) { + fprintf(stderr, "child terminated by signal %u\n", WTERMSIG(exitCode)); + if (WCOREDUMP(exitCode)) { + fprintf(stderr, "[WARNING] child dumped core\n"); + } + } else { + fprintf(stderr, "[WARNING] strange exit code: %u\n", exitCode); + } + + EXPECT_EQUAL(exitCode & 0x7f, retval); + + TEST_DONE(); +} + +TEST_APPHOOK(Test) diff --git a/vespamalloc/src/tests/overwrite/overwrite.cpp b/vespamalloc/src/tests/overwrite/overwrite.cpp new file mode 100644 index 00000000000..d7057444505 --- /dev/null +++ b/vespamalloc/src/tests/overwrite/overwrite.cpp @@ -0,0 +1,135 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/log/log.h> +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> + +LOG_SETUP("overwrite_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + int Main(); + ~Test(); +private: + void testFillValue(char *a); + void verifyPreWriteDetection(); // Should abort + void verifyPostWriteDetection(); // Should abort + void verifyWriteAfterFreeDetection(); // Should abort +}; + +Test::~Test() +{ +} + +void Test::testFillValue(char *a) +{ + // Verify fillvalue + EXPECT_EQUAL((int)a[0], 0x66); + EXPECT_EQUAL((int)a[1], 0x66); + EXPECT_EQUAL((int)a[255], 0x66); + + // Make sure that enough blocks of memory is allocated and freed. + for (size_t i(0); i < 100; i++) { + char *d = new char[256]; + memset(d, 0x77, 256); + delete [] d; + EXPECT_EQUAL((int)d[0], 0x66); + EXPECT_EQUAL((int)d[1], 0x66); + EXPECT_EQUAL((int)d[255], 0x66); + } + + // Make sure we trigger vespamallocd detection of memory written after delete. + char *aa[1024]; + for (size_t i(0); i < sizeof(aa)/sizeof(aa[0]); i++) { + aa[i] = new char[256]; + } + + // Verify overwrite detection in place after cleaning up. + for (size_t i(0); i < sizeof(aa)/sizeof(aa[0]); i++) { + delete [] aa[i]; + EXPECT_EQUAL((int)a[0], 0x66); + EXPECT_EQUAL((int)a[1], 0x66); + EXPECT_EQUAL((int)a[255], 0x66); + } +} + +void Test::verifyPreWriteDetection() +{ + char * a = new char[8]; + *(a-1) = 0; + delete [] a; +} + +void Test::verifyPostWriteDetection() +{ + char * a = new char[8]; + a[8] = 0; + delete [] a; +} + +void Test::verifyWriteAfterFreeDetection() +{ + // Make sure that enough blocks of memory is allocated and freed. + char * a = new char[256]; + delete [] a; + for (size_t i(0); i < 100; i++) { + char *d = new char[256]; + delete [] d; + } + // Write freed memory. + a[0] = 0; + + // Make sure we trigger vespamallocd detection of memory written after delete. + char *aa[1024]; + for (size_t i(0); i < sizeof(aa)/sizeof(aa[0]); i++) { + aa[i] = new char[256]; + } + + // Clean up. + for (size_t i(0); i < sizeof(aa)/sizeof(aa[0]); i++) { + delete [] aa[i]; + } +} + +int Test::Main() +{ + TEST_INIT("overwrite_test"); + + char * a = new char[256]; + memset(a, 0x77, 256); + a[0] = 0; + EXPECT_EQUAL((int)a[0], 0); + EXPECT_EQUAL((int)a[1], 0x77); + EXPECT_EQUAL((int)a[255], 0x77); + char * b = a; + EXPECT_EQUAL(a, b); + delete [] a; + EXPECT_EQUAL(a, b); + + if (_argc > 1) { + testFillValue(a); + if (strcmp(_argv[1], "prewrite") == 0) { + verifyPreWriteDetection(); + return 0; + } else if (strcmp(_argv[1], "postwrite") == 0) { + verifyPostWriteDetection(); + return 0; + } else if (strcmp(_argv[1], "writeafterfree") == 0) { + verifyWriteAfterFreeDetection(); + return 0; + } + + } else { + // Verify that nothing is done when not expected too. + EXPECT_EQUAL((int)a[0], 0); + EXPECT_EQUAL((int)a[1], 0x77); + EXPECT_EQUAL((int)a[255], 0x77); + } + + TEST_DONE(); + return 42; +} + +TEST_APPHOOK(Test) diff --git a/vespamalloc/src/tests/overwrite/overwrite_test.sh b/vespamalloc/src/tests/overwrite/overwrite_test.sh new file mode 100755 index 00000000000..8ccac33aecc --- /dev/null +++ b/vespamalloc/src/tests/overwrite/overwrite_test.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +LD_PRELOAD=../../../src/vespamalloc/libvespamalloc.so ./vespamalloc_overwrite_test_app +LD_PRELOAD=../../../src/vespamalloc/libvespamalloc_vespamallocd.so ./vespamalloc_overwrite_test_app testmemoryfill +ulimit -c 0; +./vespamalloc_expectsignal-overwrite_app 6 "LD_PRELOAD=../../../src/vespamalloc/libvespamalloc_vespamallocd.so ./vespamalloc_overwrite_test_app prewrite" +./vespamalloc_expectsignal-overwrite_app 6 "LD_PRELOAD=../../../src/vespamalloc/libvespamalloc_vespamallocd.so ./vespamalloc_overwrite_test_app postwrite" +./vespamalloc_expectsignal-overwrite_app 6 "LD_PRELOAD=../../../src/vespamalloc/libvespamalloc_vespamallocd.so ./vespamalloc_overwrite_test_app writeafterfree" diff --git a/vespamalloc/src/tests/overwrite/vespamalloc.conf b/vespamalloc/src/tests/overwrite/vespamalloc.conf new file mode 100644 index 00000000000..f371e36204a --- /dev/null +++ b/vespamalloc/src/tests/overwrite/vespamalloc.conf @@ -0,0 +1,15 @@ +#Config file for vespa malloc +#loglevel = 0 should mean no logging. Only level 1 is implemented. +# logfile vespamalloc.log # default(stderr) This is the file to where log is written (stderr, stdout, filename) +sigprof_loglevel 0 # default(0) Loglevel used at SIGPROF signal. +atend_loglevel 2 # default(1) Loglevel used when application stops. +atnomem_loglevel 2 # default(1) Loglevel used when datasegment is exhausted. +pralloc_loglimit 1 # What to log pr alloc. default(0) except mallocdst(1). mallocdst_nl(0), but has effect og SIGHUP. +atdoubledelete_loglevel 2 # default(1) Loglevel used when vespa_malloc discovers a double delete. +atinvalid_loglevel 2 # default(1) Loglevel used when vespa_malloc discovers logical error. +bigsegment_loglevel 0 # default(1) Loglevel used when datasegment passes a boundary. +bigsegment_limit 0x80000000 # default(0x20000000) First level the datasegment must reach before logging is started +bigsegment_increment 0x10000000 # default(0x4000000) At what increment it will log next time. +bigblocklimit 0x800000 # default(0x800000) Limit for when to log new/deletes wuth stack trace. Only mallocdst.so +allocs2show 8 +fillvalue 0x66 diff --git a/vespamalloc/src/tests/stacktrace/.gitignore b/vespamalloc/src/tests/stacktrace/.gitignore new file mode 100644 index 00000000000..669d726db1e --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/.gitignore @@ -0,0 +1,3 @@ +*_test* +.depend +Makefile diff --git a/vespamalloc/src/tests/stacktrace/CMakeLists.txt b/vespamalloc/src/tests/stacktrace/CMakeLists.txt new file mode 100644 index 00000000000..6d8fbfcbaa1 --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_stacktrace_test_app + SOURCES + stacktrace.cpp + backtrace.c + DEPENDS +) +vespa_add_test( + NAME vespamalloc_stacktrace_test_app + NO_VALGRIND COMMAND vespamalloc_stacktrace_test_app + ENVIRONMENT "LD_PRELOAD=${CMAKE_CURRENT_BINARY_DIR}/../../vespamalloc/libvespamalloc_vespamallocdst16.so" + NO_VALGRIND) diff --git a/vespamalloc/src/tests/stacktrace/DESC b/vespamalloc/src/tests/stacktrace/DESC new file mode 100644 index 00000000000..5f30c916321 --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/DESC @@ -0,0 +1 @@ +Test that the stacktrace functionality works as expected. diff --git a/vespamalloc/src/tests/stacktrace/FILES b/vespamalloc/src/tests/stacktrace/FILES new file mode 100644 index 00000000000..24b43aa0f89 --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/FILES @@ -0,0 +1 @@ +stacktrace.cpp diff --git a/vespamalloc/src/tests/stacktrace/backtrace.c b/vespamalloc/src/tests/stacktrace/backtrace.c new file mode 100644 index 00000000000..d594caa3368 --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/backtrace.c @@ -0,0 +1,84 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "backtrace.h" + +#if defined(__i386__) +// use GLIBC version, hope it works +extern int backtrace(void **buffer, int size); +#define HAVE_BACKTRACE +#endif + +#if defined(__x86_64__) + +/** + Written by Arne H. J. based on docs: + + http://www.kernel.org/pub/linux/devel/gcc/unwind/ + http://www.codesourcery.com/public/cxx-abi/abi-eh.html + http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/libgcc-s-ddefs.html +**/ + +#include <unwind.h> + +struct trace_context { + void **array; + int size; + int index; +}; + +static _Unwind_Reason_Code +trace_fn(struct _Unwind_Context *ctxt, void *arg) +{ + struct trace_context *tp = (struct trace_context *)arg; + void *ip = (void *)_Unwind_GetIP(ctxt); + + if (ip == 0) { + return _URC_END_OF_STACK; + } + if (tp->index <= tp->size) { + // there's no point filling in the address of the backtrace() + // function itself, that doesn't provide any extra information, + // so skip one level + if (tp->index > 0) { + tp->array[tp->index - 1] = ip; + } + tp->index++; + } else { + return _URC_NORMAL_STOP; + } + return _URC_NO_REASON; // "This is not the destination frame" -> try next frame +} + +#define HAVE_BACKTRACE +int +backtrace (void **array, int size) +{ + struct trace_context t; + t.array = array; + t.size = size; + t.index = 0; + _Unwind_Backtrace(trace_fn, &t); + return t.index - 1; +} +#endif // x86_64 + + +#ifdef HAVE_BACKTRACE + +int +FastOS_backtrace (void **array, int size) +{ + return backtrace(array, size); +} + +#else + +# warning "backtrace not supported on this CPU" +int +FastOS_backtrace (void **array, int size) +{ + (void) array; + (void) size; + return 0; +} + +#endif diff --git a/vespamalloc/src/tests/stacktrace/backtrace.h b/vespamalloc/src/tests/stacktrace/backtrace.h new file mode 100644 index 00000000000..45c1ef1378d --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/backtrace.h @@ -0,0 +1,17 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int FastOS_backtrace (void **array, int size); + +#if defined(__x86_64__) +int backtrace (void **array, int size); +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/vespamalloc/src/tests/stacktrace/stacktrace.cpp b/vespamalloc/src/tests/stacktrace/stacktrace.cpp new file mode 100644 index 00000000000..0fb0c9759a2 --- /dev/null +++ b/vespamalloc/src/tests/stacktrace/stacktrace.cpp @@ -0,0 +1,35 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> + +void * run(void * arg) +{ + (void) arg; + char * a = new char [100]; // a should not remain in stacktrace + char * b = new char [1]; // but b should as it not deleted. + (void) b; + delete [] a; + return NULL; +} + +int main(int argc, char *argv[]) +{ + (void) argc; + (void) argv; + char * a = new char [100]; // a should not remain in stacktrace + char * b = new char [1]; // but b should as it not deleted. + (void) b; + delete [] a; + pthread_t tid; + int retval = pthread_create(&tid, NULL, run, NULL); + if (retval != 0) { + perror("pthread_create failed"); + abort(); + } + retval = pthread_join(tid, NULL); + if (retval != 0) { + perror("pthread_join failed"); + abort(); + } +} diff --git a/vespamalloc/src/tests/test.cpp b/vespamalloc/src/tests/test.cpp new file mode 100644 index 00000000000..24acb3368d8 --- /dev/null +++ b/vespamalloc/src/tests/test.cpp @@ -0,0 +1,62 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <stdio.h> +#include <stdlib.h> +#include <vespa/fastos/fastos.h> + +namespace vespamalloc { +void info(); +} + +void testbigblocks(size_t count, size_t sz) +{ + for (size_t i=0; i < count; i++) { + char * a = new char[sz]; + delete [] a; + a = new char [sz-1]; + delete [] a; + } +} + +void testdd() +{ + char * a = (char *)malloc(0x1003); + free(a); +} + +class Thread : public FastOS_Runnable +{ +private: + void Run(FastOS_ThreadInterface * ti, void * arg); +}; + +int main(int, char *[]) +{ + FastOS_ThreadPool threadPool(512*1024); + printf("Main stack(%p)\n", &threadPool); + Thread context; + + FastOS_ThreadInterface * th[4]; + for (size_t i=0; i<sizeof(th)/sizeof(th[0]); i++) { + th[i] = threadPool.NewThread(&context); + } + for (size_t i=0; i<sizeof(th)/sizeof(th[0]); i++) { + th[i]->Join(); + delete th[i]; + } + + return 0; +} + +void Thread::Run(FastOS_ThreadInterface *, void *) +{ + char * a = new char [100]; + delete [] a; + char * b; + + testbigblocks(1, 0x800003); + testbigblocks(64000, 0x200003); + for (size_t i=0; i<100;i++) a = new char[400]; + testdd(); + b = new char[200]; + (void)b; +} diff --git a/vespamalloc/src/tests/test1/.gitignore b/vespamalloc/src/tests/test1/.gitignore new file mode 100644 index 00000000000..b7fab5d205c --- /dev/null +++ b/vespamalloc/src/tests/test1/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +testatomic +vespamalloc_testatomic_app diff --git a/vespamalloc/src/tests/test1/CMakeLists.txt b/vespamalloc/src/tests/test1/CMakeLists.txt new file mode 100644 index 00000000000..dc0217b139a --- /dev/null +++ b/vespamalloc/src/tests/test1/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_testatomic_app + SOURCES + testatomic.cpp + DEPENDS +) +vespa_add_test(NAME vespamalloc_testatomic_app NO_VALGRIND COMMAND vespamalloc_testatomic_app) diff --git a/vespamalloc/src/tests/test1/DESC b/vespamalloc/src/tests/test1/DESC new file mode 100644 index 00000000000..4f3ca4d4d97 --- /dev/null +++ b/vespamalloc/src/tests/test1/DESC @@ -0,0 +1 @@ +This is a unittest of vespamalloc. diff --git a/vespamalloc/src/tests/test1/FILES b/vespamalloc/src/tests/test1/FILES new file mode 100644 index 00000000000..4b14c586dd4 --- /dev/null +++ b/vespamalloc/src/tests/test1/FILES @@ -0,0 +1 @@ +testatomic.cpp diff --git a/vespamalloc/src/tests/test1/testatomic.cpp b/vespamalloc/src/tests/test1/testatomic.cpp new file mode 100644 index 00000000000..1222493446c --- /dev/null +++ b/vespamalloc/src/tests/test1/testatomic.cpp @@ -0,0 +1,118 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/fastos/fastos.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/atomic.h> +#include <vector> + +using vespalib::Atomic; + +class Test : public vespalib::TestApp +{ +public: + int Main(); +private: + template<typename T> + void testSwap(T initial); + template<typename T> + void testSwapStress(T v, int numThreads); +}; + +template <typename T> +class Stress : public FastOS_Runnable +{ +private: + void Run(FastOS_ThreadInterface * ti, void * arg); + void stressSwap(T & value); +public: + Stress(T * value) : _value(value), _successCount(0), _failedCount(0) { } + void wait() { _wait.Lock(); _wait.Unlock(); } + FastOS_Mutex _wait; + T * _value; + size_t _successCount; + size_t _failedCount; +}; + +TEST_APPHOOK(Test); + +template<typename T> +void Test::testSwap(T initial) +{ + T value(initial); + + ASSERT_TRUE(Atomic::cmpSwap(&value, initial+1, initial)); + ASSERT_TRUE(value == initial+1); + + ASSERT_TRUE(!Atomic::cmpSwap(&value, initial+2, initial)); + ASSERT_TRUE(value == initial+1); +} + +template<typename T> +void Test::testSwapStress(T v, int numThreads) +{ + T old(v); + std::vector<Stress<T> *> contexts; + std::vector<FastOS_ThreadInterface *> threads; + FastOS_ThreadPool threadPool(512*1024); + + for(int i=0; i < numThreads; i++) { + contexts.push_back(new Stress<T>(&v)); + } + + for(size_t i = 0; i < contexts.size(); i++) { + threads.push_back(threadPool.NewThread(contexts[i])); + } + FastOS_Thread::Sleep(1000); + size_t succesCount(0); + size_t failedCount(0); + for(size_t i = 0; i < contexts.size(); i++) { + Stress<T> * s = contexts[i]; + s->wait(); + succesCount += s->_successCount; + failedCount += s->_failedCount; + } + ASSERT_TRUE(v == 0); + ASSERT_TRUE(old == succesCount); + fprintf(stderr, "%ld threads counting down from %" PRIu64 " had %ld succesfull and %ld unsuccessful attempts\n", + contexts.size(), uint64_t(old), succesCount, failedCount); + for(size_t i = 0; i < contexts.size(); i++) { + delete contexts[i]; + } +} + +template <typename T> +void Stress<T>::Run(FastOS_ThreadInterface *, void *) +{ + _wait.Lock(); + stressSwap(*_value); + _wait.Unlock(); +} + +template <typename T> +void Stress<T>::stressSwap(T & value) +{ + for (T old = value; old > 0; old = value) { + if (Atomic::cmpSwap(&value, old-1, old)) { + _successCount++; + } else { + _failedCount++; + } + } +} + +int Test::Main() +{ + TEST_INIT("atomic"); + + testSwap<uint32_t>(6); + testSwap<uint32_t>(7); + testSwap<uint32_t>(uint32_t(-6)); + testSwap<uint32_t>(uint32_t(-7)); + testSwap<uint64_t>(6); + testSwap<uint64_t>(7); + testSwap<uint64_t>(uint64_t(-6)); + testSwap<uint64_t>(uint64_t(-7)); + testSwapStress<uint64_t>(0x1000000, 4); + testSwapStress<uint32_t>(0x1000000, 4); + + TEST_DONE(); +} diff --git a/vespamalloc/src/tests/test2/.gitignore b/vespamalloc/src/tests/test2/.gitignore new file mode 100644 index 00000000000..1c719511e5b --- /dev/null +++ b/vespamalloc/src/tests/test2/.gitignore @@ -0,0 +1,4 @@ +.depend +Makefile +testgraph +vespamalloc_testgraph_app diff --git a/vespamalloc/src/tests/test2/CMakeLists.txt b/vespamalloc/src/tests/test2/CMakeLists.txt new file mode 100644 index 00000000000..668c09feb03 --- /dev/null +++ b/vespamalloc/src/tests/test2/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_testgraph_app + SOURCES + testgraph.cpp + ../../vespamalloc/util/stream.cpp + ../../vespamalloc/util/traceutil.cpp + ../../vespamalloc/util/callstack.cpp + DEPENDS +) +vespa_add_test(NAME vespamalloc_testgraph_app NO_VALGRIND COMMAND vespamalloc_testgraph_app) diff --git a/vespamalloc/src/tests/test2/DESC b/vespamalloc/src/tests/test2/DESC new file mode 100644 index 00000000000..4f3ca4d4d97 --- /dev/null +++ b/vespamalloc/src/tests/test2/DESC @@ -0,0 +1 @@ +This is a unittest of vespamalloc. diff --git a/vespamalloc/src/tests/test2/FILES b/vespamalloc/src/tests/test2/FILES new file mode 100644 index 00000000000..44b3d9f7c51 --- /dev/null +++ b/vespamalloc/src/tests/test2/FILES @@ -0,0 +1 @@ +testgraph.cpp diff --git a/vespamalloc/src/tests/test2/testgraph.cpp b/vespamalloc/src/tests/test2/testgraph.cpp new file mode 100644 index 00000000000..a9cf2c07b61 --- /dev/null +++ b/vespamalloc/src/tests/test2/testgraph.cpp @@ -0,0 +1,91 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespamalloc/util/index.h> +#include <vespamalloc/util/callgraph.h> +#include <vespamalloc/util/callstack.h> +#include <vespamalloc/util/traceutil.h> + +using namespace vespamalloc; + +//typedef StackEntry<StackFrameReturnEntry> StackElem; +typedef CallGraph<int, 0x1000, Index> CallGraphIntT; +typedef CallGraph<StackElem, 0x1000, Index> CallGraphStackEntryT; + +namespace vespalibtest { + +template <typename T> +class DumpGraph +{ +public: + DumpGraph(const char * s="") : _string(s) { } + void handle(const T & node) + { + asciistream os; + os << ' ' << node; + _string += os.c_str(); + if (node.callers() == NULL) { + printf("%s\n", _string.c_str()); + } + } + const std::string & str() const { return _string; } +private: + std::string _string; +}; + +} +void testint() { + CallGraphIntT callGraph; + vespalibtest::DumpGraph<CallGraphIntT::Node> dump("int: "); + int s1[3] = { 1, 2, 3 }; + int s2[3] = { 1, 2, 4 }; + int s3[1] = { 1 }; + int s4[3] = { 1, 3, 4 }; + callGraph.addStack(s1, 3); + callGraph.addStack(s2, 3); + callGraph.addStack(s3, 1); + callGraph.addStack(s4, 3); + callGraph.traverseDepth(dump); + printf("%s\n", dump.str().c_str()); +} + +void teststackentry() { + CallGraphStackEntryT callGraph; + vespalibtest::DumpGraph<CallGraphStackEntryT::Node> dump("callstack: "); + StackElem s1[3] = { StackElem((void *)1), StackElem((void *)2), StackElem((void *)3) }; + StackElem s2[3] = { StackElem((void *)1), StackElem((void *)2), StackElem((void *)4) }; + StackElem s3[1] = { StackElem((void *)1) }; + StackElem s4[3] = { StackElem((void *)1), StackElem((void *)3), StackElem((void *)4) }; + callGraph.addStack(s1, 3); + callGraph.addStack(s2, 3); + callGraph.addStack(s3, 1); + callGraph.addStack(s4, 3); + callGraph.traverseDepth(dump); + printf("%s\n", dump.str().c_str()); +} + +void testaggregator() { + CallGraphStackEntryT callGraph; + StackElem s1[3] = { StackElem((void *)1), StackElem((void *)2), StackElem((void *)3) }; + StackElem s2[3] = { StackElem((void *)1), StackElem((void *)2), StackElem((void *)4) }; + StackElem s3[1] = { StackElem((void *)1) }; + StackElem s4[3] = { StackElem((void *)1), StackElem((void *)3), StackElem((void *)4) }; + callGraph.addStack(s1, 3); + callGraph.addStack(s2, 3); + callGraph.addStack(s3, 1); + callGraph.addStack(s4, 3); + Aggregator agg; + DumpGraph<CallGraphT::Node> dump(&agg, "{ ", " }"); + callGraph.traverseDepth(dump);; + asciistream ost; + ost << agg; + printf("%s\n", ost.c_str()); +} +int main (int argc, char *argv[]) +{ + (void) argc; + (void) argv; + testint(); + teststackentry(); + testaggregator(); + return 0; +} + diff --git a/vespamalloc/src/tests/thread/.gitignore b/vespamalloc/src/tests/thread/.gitignore new file mode 100644 index 00000000000..e342e6aaea7 --- /dev/null +++ b/vespamalloc/src/tests/thread/.gitignore @@ -0,0 +1,3 @@ +/*_test +vespamalloc_racemanythreads_test_app +vespamalloc_thread_test_app diff --git a/vespamalloc/src/tests/thread/CMakeLists.txt b/vespamalloc/src/tests/thread/CMakeLists.txt new file mode 100644 index 00000000000..67539a68f77 --- /dev/null +++ b/vespamalloc/src/tests/thread/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespamalloc_thread_test_app + SOURCES + thread.cpp +) +vespa_add_test(NAME vespamalloc_thread_test_app NO_VALGRIND COMMAND sh thread_test.sh) +vespa_add_executable(vespamalloc_racemanythreads_test_app + SOURCES + racemanythreads.cpp +) diff --git a/vespamalloc/src/tests/thread/racemanythreads.cpp b/vespamalloc/src/tests/thread/racemanythreads.cpp new file mode 100644 index 00000000000..ba5cc8b7a1c --- /dev/null +++ b/vespamalloc/src/tests/thread/racemanythreads.cpp @@ -0,0 +1,82 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <stdint.h> +#include <errno.h> +#include <vespa/vespalib/util/atomic.h> +#include <sys/resource.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/log/log.h> + +LOG_SETUP("thread_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + ~Test(); + int Main(); +}; + +Test::~Test() +{ +} + +void * hammer(void * arg) +{ + usleep(4000000); + long seconds = * static_cast<const long *>(arg); + long stopTime(time(NULL) + seconds); + pthread_t id = pthread_self(); + while (time(NULL) < stopTime) { + std::vector<pthread_t *> allocations; + for (size_t i(0); i < 2000; i++) { + pthread_t *t = new pthread_t[20]; + allocations.push_back(t); + for (size_t j(0); j < 20; j++) { + t[j] = id; + } + } + + for (size_t i(0); i < allocations.size(); i++) { + for (size_t j(0); j < 20; j++) { + assert(allocations[i][j] == id); + } + delete [] allocations[i]; + } + } + return arg; +} + +int Test::Main() +{ + TEST_INIT("racemanythreads_test"); + size_t threadCount(1024); + long seconds(10); + if (_argc >= 2) { + threadCount = strtoul(_argv[1], NULL, 0); + if (_argc >= 3) { + seconds = strtoul(_argv[2], NULL, 0); + } + } + + pthread_attr_t attr; + EXPECT_EQUAL(pthread_attr_init(&attr), 0); + EXPECT_EQUAL(pthread_attr_setstacksize(&attr, 64*1024), 0); + std::vector<pthread_t> threads(threadCount); + for (size_t i(0); i < threadCount; i++) { + EXPECT_EQUAL( pthread_create(&threads[i], &attr, hammer, &seconds), 0); + } + for (size_t i(0); i < threadCount; i++) { + void *retval; + EXPECT_EQUAL(pthread_join(threads[i], &retval), 0); + } + + TEST_DONE(); +} + +TEST_APPHOOK(Test); diff --git a/vespamalloc/src/tests/thread/thread.cpp b/vespamalloc/src/tests/thread/thread.cpp new file mode 100644 index 00000000000..49631c0f7e5 --- /dev/null +++ b/vespamalloc/src/tests/thread/thread.cpp @@ -0,0 +1,131 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <stdint.h> +#include <errno.h> +#include <vespa/vespalib/util/atomic.h> +#include <sys/resource.h> +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/log/log.h> + +LOG_SETUP("thread_test"); + +using namespace vespalib; + +class Test : public TestApp +{ +public: + ~Test(); + int Main(); +private: + virtual bool useIPCHelper() const { return true; } +}; + +Test::~Test() +{ +} + +void * just_return(void * arg) +{ + return arg; +} + +void * just_exit(void * arg) +{ + pthread_exit(arg); +} + +void * just_cancel(void * arg) +{ + sleep(60); + return arg; +} + +struct wait_info { + wait_info() : + _count(0) + { + if (pthread_mutex_init(&_mutex, NULL) != 0) { abort(); } + if (pthread_cond_init(&_cond, NULL) != 0) { abort(); } + } + ~wait_info() { + if (pthread_mutex_destroy(&_mutex) != 0) { abort(); } + if (pthread_cond_destroy(&_cond) != 0) { abort(); } + } + pthread_cond_t _cond; + pthread_mutex_t _mutex; + volatile uint64_t _count; +}; + +void * just_wait(void * arg) +{ + wait_info * info = (wait_info *) arg; + pthread_mutex_lock(&info->_mutex); + vespalib::Atomic::postInc(&info->_count); + pthread_cond_wait(&info->_cond, &info->_mutex); + pthread_mutex_unlock(&info->_mutex); + pthread_cond_signal(&info->_cond); + vespalib::Atomic::postDec(&info->_count); + return arg; +} + +int Test::Main() +{ + TEST_INIT("thread_test"); + size_t threadCount(102400); + if (_argc >= 3) { + threadCount = strtoul(_argv[2], NULL, 0); + } + + const char * testType = _argv[1]; + + for (size_t i(0); i < threadCount; i++) { + pthread_t th; + void *retval; + if (strcmp(testType, "exit") == 0) { + EXPECT_EQUAL( pthread_create(&th, NULL, just_exit, NULL), 0); + } else if (strcmp(testType, "cancel") == 0) { + EXPECT_EQUAL( pthread_create(&th, NULL, just_cancel, NULL), 0); + EXPECT_EQUAL( pthread_cancel(th), 0); + } else { + EXPECT_EQUAL( pthread_create(&th, NULL, just_return, NULL), 0); + } + EXPECT_EQUAL(pthread_join(th, &retval), 0); + } + + wait_info info; + pthread_attr_t attr; + EXPECT_EQUAL(pthread_attr_init(&attr), 0); + EXPECT_EQUAL(pthread_attr_setstacksize(&attr, 64*1024), 0); + EXPECT_EQUAL(info._count, 0ul); + const size_t NUM_THREADS(16382); // +1 for main thread, +1 for testsystem = 16384 + pthread_t tl[NUM_THREADS]; + for (size_t j=0;j < NUM_THREADS;j++) { + int e = pthread_create(&tl[j], &attr, just_wait, &info); + if (e != 0) { + fprintf(stderr, "pthread_create failed at index '%ld'. with errno='%d'", j, e); + perror("pthread_create failed"); + abort(); + } + } + pthread_t th; + EXPECT_EQUAL( pthread_create(&th, &attr, just_wait, &info), EAGAIN); // Verify that you have reached upper limit of threads with vespamalloc. + while (info._count != NUM_THREADS) { + usleep(1); + } + pthread_mutex_lock(&info._mutex); + pthread_cond_signal(&info._cond); + pthread_mutex_unlock(&info._mutex); + for (size_t j=0;j < NUM_THREADS;j++) { + void *retval; + EXPECT_EQUAL(pthread_join(tl[j], &retval), 0); + } + EXPECT_EQUAL(pthread_attr_destroy(&attr), 0); + EXPECT_EQUAL(info._count, 0ul); + TEST_DONE(); +} + +TEST_APPHOOK(Test); diff --git a/vespamalloc/src/tests/thread/thread_test.sh b/vespamalloc/src/tests/thread/thread_test.sh new file mode 100755 index 00000000000..edcd7a41a17 --- /dev/null +++ b/vespamalloc/src/tests/thread/thread_test.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +VESPA_MALLOC_SO=../../../src/vespamalloc/libvespamalloc.so +VESPA_MALLOC_SO_D=../../../src/vespamalloc/libvespamalloc_vespamallocd.so + +LD_PRELOAD=$VESPA_MALLOC_SO ./vespamalloc_thread_test_app return 20 +LD_PRELOAD=$VESPA_MALLOC_SO ./vespamalloc_thread_test_app exit 20 +LD_PRELOAD=$VESPA_MALLOC_SO ./vespamalloc_thread_test_app cancel 20 +#LD_PRELOAD=$VESPA_MALLOC_SO ./vespamalloc_racemanythreads_test_app 4000 20 +#LD_PRELOAD=$VESPA_MALLOC_SO_D ./vespamalloc_racemanythreads_test_app 4000 20 |