summaryrefslogtreecommitdiffstats
path: root/vespamalloc/src/tests
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vespamalloc/src/tests
Publish
Diffstat (limited to 'vespamalloc/src/tests')
-rw-r--r--vespamalloc/src/tests/.gitignore4
-rw-r--r--vespamalloc/src/tests/CMakeLists.txt6
-rw-r--r--vespamalloc/src/tests/allocfree/.gitignore14
-rw-r--r--vespamalloc/src/tests/allocfree/CMakeLists.txt23
-rw-r--r--vespamalloc/src/tests/allocfree/DESC1
-rw-r--r--vespamalloc/src/tests/allocfree/FILES1
-rw-r--r--vespamalloc/src/tests/allocfree/allocfree.cpp115
-rwxr-xr-xvespamalloc/src/tests/allocfree/allocfree_benchmark.sh151
-rwxr-xr-xvespamalloc/src/tests/allocfree/allocfree_test.sh17
-rw-r--r--vespamalloc/src/tests/allocfree/creatingmanythreads.cpp39
-rwxr-xr-xvespamalloc/src/tests/allocfree/generate_testtable.sh22
-rw-r--r--vespamalloc/src/tests/allocfree/linklist.cpp188
-rw-r--r--vespamalloc/src/tests/allocfree/producerconsumer.cpp95
-rw-r--r--vespamalloc/src/tests/allocfree/producerconsumer.h58
-rw-r--r--vespamalloc/src/tests/allocfree/queue.h86
-rw-r--r--vespamalloc/src/tests/allocfree/realloc.cpp23
-rw-r--r--vespamalloc/src/tests/allocfree/testnames.all162
-rw-r--r--vespamalloc/src/tests/allocfree/testtype.all162
-rwxr-xr-xvespamalloc/src/tests/allocfree/timeusage.sh3
-rw-r--r--vespamalloc/src/tests/allocfree/vespamalloc.conf13
-rw-r--r--vespamalloc/src/tests/doubledelete/.gitignore7
-rw-r--r--vespamalloc/src/tests/doubledelete/CMakeLists.txt12
-rw-r--r--vespamalloc/src/tests/doubledelete/DESC1
-rw-r--r--vespamalloc/src/tests/doubledelete/FILES1
-rw-r--r--vespamalloc/src/tests/doubledelete/doubledelete.cpp11
-rwxr-xr-xvespamalloc/src/tests/doubledelete/doubledelete_test.sh6
-rw-r--r--vespamalloc/src/tests/doubledelete/expectsignal.cpp57
-rw-r--r--vespamalloc/src/tests/overwrite/.gitignore8
-rw-r--r--vespamalloc/src/tests/overwrite/CMakeLists.txt12
-rw-r--r--vespamalloc/src/tests/overwrite/DESC1
-rw-r--r--vespamalloc/src/tests/overwrite/FILES1
-rw-r--r--vespamalloc/src/tests/overwrite/expectsignal.cpp57
-rw-r--r--vespamalloc/src/tests/overwrite/overwrite.cpp135
-rwxr-xr-xvespamalloc/src/tests/overwrite/overwrite_test.sh8
-rw-r--r--vespamalloc/src/tests/overwrite/vespamalloc.conf15
-rw-r--r--vespamalloc/src/tests/stacktrace/.gitignore3
-rw-r--r--vespamalloc/src/tests/stacktrace/CMakeLists.txt12
-rw-r--r--vespamalloc/src/tests/stacktrace/DESC1
-rw-r--r--vespamalloc/src/tests/stacktrace/FILES1
-rw-r--r--vespamalloc/src/tests/stacktrace/backtrace.c84
-rw-r--r--vespamalloc/src/tests/stacktrace/backtrace.h17
-rw-r--r--vespamalloc/src/tests/stacktrace/stacktrace.cpp35
-rw-r--r--vespamalloc/src/tests/test.cpp62
-rw-r--r--vespamalloc/src/tests/test1/.gitignore4
-rw-r--r--vespamalloc/src/tests/test1/CMakeLists.txt7
-rw-r--r--vespamalloc/src/tests/test1/DESC1
-rw-r--r--vespamalloc/src/tests/test1/FILES1
-rw-r--r--vespamalloc/src/tests/test1/testatomic.cpp118
-rw-r--r--vespamalloc/src/tests/test2/.gitignore4
-rw-r--r--vespamalloc/src/tests/test2/CMakeLists.txt10
-rw-r--r--vespamalloc/src/tests/test2/DESC1
-rw-r--r--vespamalloc/src/tests/test2/FILES1
-rw-r--r--vespamalloc/src/tests/test2/testgraph.cpp91
-rw-r--r--vespamalloc/src/tests/thread/.gitignore3
-rw-r--r--vespamalloc/src/tests/thread/CMakeLists.txt10
-rw-r--r--vespamalloc/src/tests/thread/racemanythreads.cpp82
-rw-r--r--vespamalloc/src/tests/thread/thread.cpp131
-rwxr-xr-xvespamalloc/src/tests/thread/thread_test.sh10
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