aboutsummaryrefslogtreecommitdiffstats
path: root/vespamalloc/src/tests/thread
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/thread
Publish
Diffstat (limited to 'vespamalloc/src/tests/thread')
-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
5 files changed, 236 insertions, 0 deletions
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