summaryrefslogtreecommitdiffstats
path: root/fastos/src/tests/thread_stats_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fastos/src/tests/thread_stats_test.cpp')
-rw-r--r--fastos/src/tests/thread_stats_test.cpp422
1 files changed, 422 insertions, 0 deletions
diff --git a/fastos/src/tests/thread_stats_test.cpp b/fastos/src/tests/thread_stats_test.cpp
new file mode 100644
index 00000000000..e38fb49a787
--- /dev/null
+++ b/fastos/src/tests/thread_stats_test.cpp
@@ -0,0 +1,422 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <stdlib.h>
+
+#include <vespa/fastos/fastos.h>
+#include "tests.h"
+
+#define PRI_TIME_COUNT 4096
+
+enum JobCode
+{
+ PRINT_MESSAGE_AND_WAIT3SEC,
+ INCREASE_NUMBER,
+ PRIORITY_TEST,
+ WAIT_FOR_BREAK_FLAG,
+ WAIT_FOR_THREAD_TO_FINISH,
+ WAIT_FOR_CONDITION,
+ BOUNCE_CONDITIONS,
+ TEST_ID,
+ WAIT2SEC_AND_SIGNALCOND,
+ HOLD_MUTEX_FOR2SEC,
+ WAIT_2_SEC,
+ SILENTNOP,
+ NOP
+};
+
+class Job
+{
+private:
+ Job(const Job &);
+ Job &operator=(const Job&);
+
+public:
+ JobCode code;
+ char *message;
+ FastOS_Mutex *mutex;
+ FastOS_Cond *condition;
+ FastOS_BoolCond *boolcondition;
+ FastOS_ThreadInterface *otherThread, *ownThread;
+ double *timebuf;
+ double average;
+ int result;
+ FastOS_ThreadId _threadId;
+ Job *otherjob;
+ int bouncewakeupcnt;
+ bool bouncewakeup;
+
+ Job()
+ : code(NOP),
+ message(NULL),
+ mutex(NULL),
+ condition(NULL),
+ boolcondition(NULL),
+ otherThread(NULL),
+ ownThread(NULL),
+ timebuf(NULL),
+ average(0.0),
+ result(-1),
+ _threadId(),
+ otherjob(NULL),
+ bouncewakeupcnt(0),
+ bouncewakeup(false)
+ {
+ }
+
+ ~Job()
+ {
+ if(message != NULL)
+ free(message);
+ }
+};
+
+static volatile int64_t number;
+#define INCREASE_NUMBER_AMOUNT 10000
+
+#define MUTEX_TEST_THREADS 6
+#define MAX_THREADS 7
+
+
+class ThreadTest : public BaseTest, public FastOS_Runnable
+{
+private:
+ FastOS_Mutex printMutex;
+
+public:
+ ThreadTest(void)
+ : printMutex()
+ {
+ }
+ virtual ~ThreadTest() {};
+
+ void PrintProgress (char *string)
+ {
+ printMutex.Lock();
+ BaseTest::PrintProgress(string);
+ printMutex.Unlock();
+ }
+
+ void Run (FastOS_ThreadInterface *thread, void *arg);
+
+ void WaitForThreadsToFinish (Job *jobs, int count)
+ {
+ int i;
+
+ Progress(true, "Waiting for threads to finish...");
+ for(;;)
+ {
+ bool threadsFinished=true;
+
+ for(i=0; i<count; i++)
+ {
+ if(jobs[i].result == -1)
+ {
+ threadsFinished = false;
+ break;
+ }
+ }
+
+ FastOS_Thread::Sleep(500);
+
+ if(threadsFinished)
+ break;
+ }
+
+ Progress(true, "Threads finished");
+ }
+
+
+ void ThreadStatsTest ()
+ {
+ int inactiveThreads;
+ int activeThreads;
+ int startedThreads;
+
+ TestHeader("Thread Statistics Test");
+
+ FastOS_ThreadPool pool(128*1024);
+ Job job[2];
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 0, "Initial inactive threads = %d",
+ inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 0, "Initial active threads = %d",
+ activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 0, "Initial started threads = %d",
+ startedThreads);
+
+ job[0].code = WAIT_FOR_BREAK_FLAG;
+ job[0].ownThread = pool.NewThread(this,
+ static_cast<void *>(&job[0]));
+
+ FastOS_Thread::Sleep(1000);
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 0, "Inactive threads = %d", inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 1, "Active threads = %d", activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 1, "Started threads = %d", startedThreads);
+
+ job[1].code = WAIT_FOR_BREAK_FLAG;
+ job[1].ownThread = pool.NewThread(this,
+ static_cast<void *>(&job[1]));
+
+ FastOS_Thread::Sleep(1000);
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 0, "Inactive threads = %d", inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 2, "Active threads = %d", activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 2, "Started threads = %d", startedThreads);
+
+ Progress(true, "Setting breakflag on threads...");
+ job[0].ownThread->SetBreakFlag();
+ job[1].ownThread->SetBreakFlag();
+
+ FastOS_Thread::Sleep(3000);
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 2, "Inactive threads = %d", inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 0, "Active threads = %d", activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 2, "Started threads = %d", startedThreads);
+
+
+ Progress(true, "Repeating process in the same pool...");
+
+ job[0].code = WAIT_FOR_BREAK_FLAG;
+ job[0].ownThread = pool.NewThread(this, static_cast<void *>(&job[0]));
+
+ FastOS_Thread::Sleep(1000);
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 1, "Inactive threads = %d", inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 1, "Active threads = %d", activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 3, "Started threads = %d", startedThreads);
+
+ job[1].code = WAIT_FOR_BREAK_FLAG;
+ job[1].ownThread = pool.NewThread(this, static_cast<void *>(&job[1]));
+
+ FastOS_Thread::Sleep(1000);
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 0, "Inactive threads = %d", inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 2, "Active threads = %d", activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 4, "Started threads = %d", startedThreads);
+
+ Progress(true, "Setting breakflag on threads...");
+ job[0].ownThread->SetBreakFlag();
+ job[1].ownThread->SetBreakFlag();
+
+ FastOS_Thread::Sleep(3000);
+
+ inactiveThreads = pool.GetNumInactiveThreads();
+ Progress(inactiveThreads == 2, "Inactive threads = %d", inactiveThreads);
+ activeThreads = pool.GetNumActiveThreads();
+ Progress(activeThreads == 0, "Active threads = %d", activeThreads);
+ startedThreads = pool.GetNumStartedThreads();
+ Progress(startedThreads == 4, "Started threads = %d", startedThreads);
+
+
+ pool.Close();
+ Progress(true, "Pool closed.");
+
+ PrintSeparator();
+ }
+
+ int Main ();
+};
+
+int ThreadTest::Main ()
+{
+ printf("grep for the string '%s' to detect failures.\n\n", failString);
+ time_t before = time(0);
+
+ ThreadStatsTest();
+ { time_t now = time(0); printf("[%ld seconds]\n", now-before); before = now; }
+
+ printf("END OF TEST (%s)\n", _argv[0]);
+
+ return 0;
+}
+
+volatile int busyCnt;
+
+void ThreadTest::Run (FastOS_ThreadInterface *thread, void *arg)
+{
+ if(arg == NULL)
+ return;
+
+ Job *job = static_cast<Job *>(arg);
+ char someStack[15*1024];
+
+ memset(someStack, 0, 15*1024);
+
+ switch(job->code)
+ {
+ case SILENTNOP:
+ {
+ job->result = 1;
+ break;
+ }
+
+ case NOP:
+ {
+ Progress(true, "Doing NOP");
+ job->result = 1;
+ break;
+ }
+
+ case PRINT_MESSAGE_AND_WAIT3SEC:
+ {
+ Progress(true, "Thread printing message: [%s]", job->message);
+ job->result = strlen(job->message);
+
+ FastOS_Thread::Sleep(3000);
+ break;
+ }
+
+ case INCREASE_NUMBER:
+ {
+ int result;
+
+ if(job->mutex != NULL)
+ job->mutex->Lock();
+
+ result = static_cast<int>(number);
+
+ int sleepOn = (INCREASE_NUMBER_AMOUNT/2) * 321/10000;
+ for(int i=0; i<(INCREASE_NUMBER_AMOUNT/2); i++)
+ {
+ number = number + 2;
+
+ if(i == sleepOn)
+ FastOS_Thread::Sleep(1000);
+ }
+
+ if(job->mutex != NULL)
+ job->mutex->Unlock();
+
+ job->result = result; // This marks the end of the thread
+
+ break;
+ }
+
+ case WAIT_FOR_BREAK_FLAG:
+ {
+ for(;;)
+ {
+ FastOS_Thread::Sleep(1000);
+
+ if(thread->GetBreakFlag())
+ {
+ Progress(true, "Thread %p got breakflag", thread);
+ break;
+ }
+ }
+ break;
+ }
+
+ case WAIT_FOR_THREAD_TO_FINISH:
+ {
+ if(job->mutex)
+ job->mutex->Lock();
+
+ if(job->otherThread != NULL)
+ job->otherThread->Join();
+
+ if(job->mutex)
+ job->mutex->Unlock();
+ break;
+ }
+
+ case WAIT_FOR_CONDITION:
+ {
+ job->condition->Lock();
+
+ job->result = 1;
+
+ job->condition->Wait();
+ job->condition->Unlock();
+
+ job->result = 0;
+
+ break;
+ }
+
+ case BOUNCE_CONDITIONS:
+ {
+ while (!thread->GetBreakFlag()) {
+ job->otherjob->condition->Lock();
+ job->otherjob->bouncewakeupcnt++;
+ job->otherjob->bouncewakeup = true;
+ job->otherjob->condition->Signal();
+ job->otherjob->condition->Unlock();
+
+ job->condition->Lock();
+ while (!job->bouncewakeup)
+ job->condition->TimedWait(1);
+ job->bouncewakeup = false;
+ job->condition->Unlock();
+ }
+ break;
+ }
+
+ case TEST_ID:
+ {
+ job->mutex->Lock(); // Initially the parent threads owns the lock
+ job->mutex->Unlock(); // It is unlocked when we should start
+
+ FastOS_ThreadId currentId = FastOS_Thread::GetCurrentThreadId();
+
+ if(currentId == job->_threadId)
+ job->result = 1;
+ else
+ job->result = -1;
+ break;
+ }
+
+ case WAIT2SEC_AND_SIGNALCOND:
+ {
+ FastOS_Thread::Sleep(2000);
+ job->condition->Signal();
+ job->result = 1;
+ break;
+ }
+
+ case HOLD_MUTEX_FOR2SEC:
+ {
+ job->mutex->Lock();
+ FastOS_Thread::Sleep(2000);
+ job->mutex->Unlock();
+ job->result = 1;
+ break;
+ }
+
+ case WAIT_2_SEC:
+ {
+ FastOS_Thread::Sleep(2000);
+ job->result = 1;
+ break;
+ }
+
+ default:
+ Progress(false, "Unknown jobcode");
+ break;
+ }
+}
+
+int main (int argc, char **argv)
+{
+ ThreadTest app;
+ setvbuf(stdout, NULL, _IOLBF, 8192);
+ return app.Entry(argc, argv);
+}