2009-11-23 01:55:08 +01:00
|
|
|
/*
|
|
|
|
|
test-threadpool.c - test thread pool creation and usage
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2009, Michael Ploujnikov <ploujj@gmail.com>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
2010-12-17 23:28:49 +01:00
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
2009-11-23 01:55:08 +01:00
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "tests/test.h"
|
|
|
|
|
|
|
|
|
|
#include "backend/threadpool.h"
|
2010-02-01 02:28:25 +01:00
|
|
|
#include "include/logging.h"
|
2009-11-23 01:55:08 +01:00
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2009-12-23 19:10:31 +01:00
|
|
|
#include <math.h>
|
2009-12-24 01:55:24 +01:00
|
|
|
#include <unistd.h>
|
2009-12-23 19:10:31 +01:00
|
|
|
|
|
|
|
|
void is_prime(void * arg)
|
|
|
|
|
{
|
2010-01-18 18:43:28 +01:00
|
|
|
unsigned long long number = *(unsigned long long *)arg;
|
|
|
|
|
unsigned long long prime = 1;
|
2010-01-31 19:33:47 +01:00
|
|
|
usleep(1);
|
2010-01-20 13:54:26 +01:00
|
|
|
for (unsigned long long x = number-1; x >= sqrt(number); --x)
|
2009-12-23 19:10:31 +01:00
|
|
|
{
|
2010-01-20 13:54:26 +01:00
|
|
|
if ((number % x) == 0)
|
2010-03-04 16:23:57 +01:00
|
|
|
{
|
|
|
|
|
prime = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-12-23 19:10:31 +01:00
|
|
|
}
|
2010-01-18 18:43:28 +01:00
|
|
|
*(unsigned long long *)arg = prime;
|
2010-01-31 19:33:47 +01:00
|
|
|
usleep(1);
|
2009-12-23 19:10:31 +01:00
|
|
|
}
|
2009-11-23 01:55:08 +01:00
|
|
|
|
2010-01-30 04:12:09 +01:00
|
|
|
void sleep_fn(void * arg)
|
|
|
|
|
{
|
|
|
|
|
unsigned int usec = *(int *)arg;
|
|
|
|
|
|
|
|
|
|
unsigned int result = usleep (usec);
|
|
|
|
|
*(int *)arg = result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-01 23:02:24 +01:00
|
|
|
|
|
|
|
|
void other_fn(void * arg)
|
|
|
|
|
{
|
|
|
|
|
int input = *(int *)arg;
|
|
|
|
|
lumiera_thread_sync (); // the main thread can discard the argument storage
|
2010-02-11 02:47:13 +01:00
|
|
|
CHECK (input == 42, "input is not 42, but %d", input);
|
2010-02-01 23:02:24 +01:00
|
|
|
input -= 42;
|
|
|
|
|
ECHO ("result is %d", input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sleeping_worker_fn(void * arg)
|
|
|
|
|
{
|
|
|
|
|
int input = *(int *)arg;
|
|
|
|
|
int delay = rand () % 100000;
|
|
|
|
|
usleep (delay);
|
|
|
|
|
lumiera_thread_sync (); // the main thread can discard the argument storage
|
2010-02-10 13:55:47 +01:00
|
|
|
input -= 81;
|
|
|
|
|
CHECK (input == 42, "result is not 42, but %d", input);
|
2010-02-01 23:02:24 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-11 00:09:16 +01:00
|
|
|
// subtracts 13 from the value
|
2010-02-03 14:02:41 +01:00
|
|
|
void joinable_worker_fn(void * arg)
|
|
|
|
|
{
|
|
|
|
|
int input = *(int *)arg;
|
2010-02-11 00:09:16 +01:00
|
|
|
lumiera_thread_sync (); // signal that arguments have been received
|
|
|
|
|
*(int *)arg = input - 13;
|
2010-02-03 14:02:41 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-11 00:09:16 +01:00
|
|
|
// adds 42 to the value
|
2010-02-03 14:02:41 +01:00
|
|
|
void joinable_master_fn(void * arg)
|
|
|
|
|
{
|
|
|
|
|
int input = *(int *)arg;
|
|
|
|
|
lumiera_thread_sync ();
|
2010-02-11 00:09:16 +01:00
|
|
|
CHECK (input == 42, "input is not 42, but %d", input);
|
2010-02-03 14:02:41 +01:00
|
|
|
LumieraThread worker = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE
|
2010-03-04 16:23:57 +01:00
|
|
|
| LUMIERA_THREAD_JOINABLE,
|
|
|
|
|
&joinable_worker_fn,
|
|
|
|
|
(void *)&input,
|
|
|
|
|
"joinable worker thread",
|
|
|
|
|
&NOBUG_FLAG (NOBUG_ON));
|
|
|
|
|
lumiera_thread_sync_other (worker);
|
|
|
|
|
lumiera_thread_join (worker);
|
2010-02-11 00:09:16 +01:00
|
|
|
lumiera_thread_sync_other (worker); // wait until the arguments are sent
|
2010-02-12 13:20:32 +01:00
|
|
|
lumiera_thread_join (worker); // wait until the result has been calculated
|
2010-02-11 00:09:16 +01:00
|
|
|
CHECK (input == 42-13, "result is not 42-13=29, but %d", input);
|
|
|
|
|
input += 42;
|
|
|
|
|
*(int *)arg = input;
|
2010-02-03 14:02:41 +01:00
|
|
|
}
|
|
|
|
|
|
2009-11-23 01:55:08 +01:00
|
|
|
TESTS_BEGIN
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (threadpool-basic)
|
2009-12-23 19:10:31 +01:00
|
|
|
{
|
2010-01-08 00:36:51 +01:00
|
|
|
lumiera_threadpool_init();
|
2009-12-23 19:10:31 +01:00
|
|
|
lumiera_threadpool_destroy();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (threadpool1)
|
2009-12-23 19:10:31 +01:00
|
|
|
{
|
|
|
|
|
ECHO("start by initializing the threadpool");
|
2010-01-08 00:36:51 +01:00
|
|
|
lumiera_threadpool_init();
|
2009-12-23 19:10:31 +01:00
|
|
|
LumieraThread t1 =
|
|
|
|
|
lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE,
|
2010-03-04 16:23:57 +01:00
|
|
|
"test purpose",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
2009-12-23 19:10:31 +01:00
|
|
|
// lumiera_threadpool_release_thread(t1);
|
|
|
|
|
ECHO("acquired thread 1 %p",t1);
|
|
|
|
|
lumiera_threadpool_destroy();
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 01:55:08 +01:00
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (two-thread-acquire)
|
2009-11-23 01:55:08 +01:00
|
|
|
{
|
2009-11-24 01:05:57 +01:00
|
|
|
ECHO("start by initializing the threadpool");
|
2010-01-08 00:36:51 +01:00
|
|
|
lumiera_threadpool_init();
|
2009-11-24 01:05:57 +01:00
|
|
|
ECHO("acquiring thread 1");
|
2010-01-30 02:57:57 +01:00
|
|
|
|
2009-11-23 22:40:31 +01:00
|
|
|
LumieraThread t1 =
|
2009-11-26 17:21:31 +01:00
|
|
|
lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE,
|
2010-03-04 16:23:57 +01:00
|
|
|
"test purpose",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
2010-01-30 02:57:57 +01:00
|
|
|
|
2009-11-24 01:05:57 +01:00
|
|
|
ECHO("acquiring thread 2");
|
2009-11-23 22:40:31 +01:00
|
|
|
LumieraThread t2 =
|
2009-11-26 17:21:31 +01:00
|
|
|
lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_IDLE,
|
2010-03-04 16:23:57 +01:00
|
|
|
"test purpose",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
2009-11-23 22:40:31 +01:00
|
|
|
|
2010-01-30 03:30:08 +01:00
|
|
|
ECHO("thread 1 state=%s", lumiera_threadstate_names[t1->state]);
|
|
|
|
|
CHECK(LUMIERA_THREADSTATE_IDLE == t1->state);
|
2009-11-23 22:40:31 +01:00
|
|
|
|
2010-01-30 03:30:08 +01:00
|
|
|
ECHO("thread 2 state=%s", lumiera_threadstate_names[t2->state]);
|
|
|
|
|
CHECK(LUMIERA_THREADSTATE_IDLE == t2->state);
|
2009-11-25 04:25:00 +01:00
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
LUMIERA_CONDITION_SECTION(NOBUG_ON, &t1->signal)
|
2010-01-30 02:57:57 +01:00
|
|
|
{
|
|
|
|
|
t1->state = LUMIERA_THREADSTATE_WAKEUP;
|
|
|
|
|
LUMIERA_CONDITION_SIGNAL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
LUMIERA_CONDITION_SECTION(NOBUG_ON, &t2->signal)
|
2010-01-30 02:57:57 +01:00
|
|
|
{
|
|
|
|
|
t2->state = LUMIERA_THREADSTATE_WAKEUP;
|
|
|
|
|
LUMIERA_CONDITION_SIGNAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ECHO("cleaning up");
|
2009-11-25 04:25:00 +01:00
|
|
|
lumiera_threadpool_destroy();
|
2009-11-23 01:55:08 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (many-sleepy-threads)
|
2009-11-25 23:43:22 +01:00
|
|
|
{
|
|
|
|
|
|
2009-11-27 17:39:23 +01:00
|
|
|
const int threads_per_pool_count = 10;
|
2010-02-01 01:46:48 +01:00
|
|
|
unsigned int delay = 10000;
|
2009-11-25 23:43:22 +01:00
|
|
|
|
2010-01-30 04:12:09 +01:00
|
|
|
lumiera_threadpool_init();
|
2009-11-26 03:46:03 +01:00
|
|
|
LumieraThread threads[threads_per_pool_count*LUMIERA_THREADCLASS_COUNT];
|
|
|
|
|
|
|
|
|
|
for (int kind = 0; kind < LUMIERA_THREADCLASS_COUNT; ++kind)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < threads_per_pool_count; ++i)
|
2010-03-04 16:23:57 +01:00
|
|
|
{
|
|
|
|
|
threads[i+kind*threads_per_pool_count] =
|
|
|
|
|
lumiera_thread_run(kind,
|
|
|
|
|
&sleep_fn,
|
|
|
|
|
(void *) &delay,
|
|
|
|
|
"just sleep a bit",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
|
|
|
|
}
|
2009-11-26 03:46:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lumiera_threadpool_destroy();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (toomany-random-sleepy-threads (compiletest only))
|
2009-11-26 03:46:03 +01:00
|
|
|
{
|
2010-02-01 02:05:05 +01:00
|
|
|
const int threads_per_pool_count = 500;
|
|
|
|
|
unsigned int delay[threads_per_pool_count*LUMIERA_THREADCLASS_COUNT];
|
|
|
|
|
lumiera_threadpool_init();
|
2009-11-25 23:43:22 +01:00
|
|
|
LumieraThread threads[threads_per_pool_count*LUMIERA_THREADCLASS_COUNT];
|
2010-02-01 02:05:05 +01:00
|
|
|
|
2009-11-25 23:43:22 +01:00
|
|
|
for (int kind = 0; kind < LUMIERA_THREADCLASS_COUNT; ++kind)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < threads_per_pool_count; ++i)
|
2010-03-04 16:23:57 +01:00
|
|
|
{
|
|
|
|
|
delay[i] = rand() % 1000000;
|
|
|
|
|
threads[i+kind*threads_per_pool_count] =
|
|
|
|
|
lumiera_thread_run(kind,
|
|
|
|
|
&sleep_fn,
|
|
|
|
|
(void *) &delay[i],
|
|
|
|
|
"just sleep a bit",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
|
|
|
|
}
|
2009-11-25 23:43:22 +01:00
|
|
|
}
|
|
|
|
|
lumiera_threadpool_destroy();
|
|
|
|
|
}
|
2009-12-23 19:10:31 +01:00
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (no-function)
|
2009-12-24 01:55:24 +01:00
|
|
|
{
|
|
|
|
|
LumieraThread t;
|
|
|
|
|
|
2010-01-08 00:36:51 +01:00
|
|
|
lumiera_threadpool_init();
|
2009-12-24 01:55:24 +01:00
|
|
|
|
|
|
|
|
t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE,
|
2010-03-04 16:23:57 +01:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
"process my test function",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
2009-12-24 01:55:24 +01:00
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
|
ECHO("finished waiting");
|
|
|
|
|
lumiera_threadpool_destroy();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (process-function)
|
2009-12-23 19:10:31 +01:00
|
|
|
{
|
|
|
|
|
// this is what the scheduler would do once it figures out what function a job needs to run
|
|
|
|
|
LumieraThread t;
|
2010-01-30 04:26:37 +01:00
|
|
|
unsigned long long number = 1307;
|
2009-12-23 19:10:31 +01:00
|
|
|
|
2010-01-08 00:36:51 +01:00
|
|
|
lumiera_threadpool_init();
|
2009-12-23 19:10:31 +01:00
|
|
|
|
2010-01-18 18:43:28 +01:00
|
|
|
ECHO ("the input to the function is %llu", number);
|
2009-12-23 19:10:31 +01:00
|
|
|
|
|
|
|
|
t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE,
|
2010-03-04 16:23:57 +01:00
|
|
|
&is_prime,
|
|
|
|
|
(void *)&number, //void * arg,
|
|
|
|
|
"process my test function",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag)
|
2009-12-23 19:10:31 +01:00
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
|
lumiera_threadpool_destroy();
|
2010-01-20 13:54:26 +01:00
|
|
|
ECHO("the result is %llu", number);
|
|
|
|
|
|
2009-12-23 19:10:31 +01:00
|
|
|
}
|
2009-11-25 23:43:22 +01:00
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (many-random-sleepy-threads (compiletest only))
|
2010-01-30 04:41:41 +01:00
|
|
|
{
|
|
|
|
|
const int threads_per_pool_count = 10;
|
|
|
|
|
unsigned int delay[threads_per_pool_count*LUMIERA_THREADCLASS_COUNT];
|
|
|
|
|
lumiera_threadpool_init();
|
|
|
|
|
LumieraThread threads[threads_per_pool_count*LUMIERA_THREADCLASS_COUNT];
|
|
|
|
|
|
|
|
|
|
for (int kind = 0; kind < LUMIERA_THREADCLASS_COUNT; ++kind)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < threads_per_pool_count; ++i)
|
2010-03-04 16:23:57 +01:00
|
|
|
{
|
|
|
|
|
delay[i] = rand() % 1000000;
|
|
|
|
|
threads[i+kind*threads_per_pool_count] =
|
|
|
|
|
lumiera_thread_run(kind,
|
|
|
|
|
&sleep_fn,
|
|
|
|
|
(void *) &delay[i],
|
|
|
|
|
"just sleep a bit",
|
|
|
|
|
&NOBUG_FLAG(NOBUG_ON));
|
|
|
|
|
}
|
2010-01-30 04:41:41 +01:00
|
|
|
}
|
|
|
|
|
lumiera_threadpool_destroy();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (simple-sync)
|
2010-02-01 23:02:24 +01:00
|
|
|
{
|
|
|
|
|
lumiera_threadpool_init ();
|
|
|
|
|
|
|
|
|
|
int value = 42;
|
|
|
|
|
|
|
|
|
|
LumieraThread other = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE,
|
2010-03-04 16:23:57 +01:00
|
|
|
&other_fn,
|
|
|
|
|
(void *)&value,
|
|
|
|
|
"other thread",
|
|
|
|
|
&NOBUG_FLAG (NOBUG_ON));
|
2010-02-01 23:02:24 +01:00
|
|
|
|
|
|
|
|
ECHO ("syncing with the other thread");
|
|
|
|
|
lumiera_thread_sync_other (other);
|
|
|
|
|
value += 42;
|
2010-02-11 02:47:13 +01:00
|
|
|
CHECK (value == 42*2, "value is not equal to 42*2=84, but %d", value);
|
2010-02-01 23:02:24 +01:00
|
|
|
|
|
|
|
|
lumiera_threadpool_destroy ();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (sync-many)
|
2010-02-01 23:02:24 +01:00
|
|
|
{
|
|
|
|
|
lumiera_threadpool_init ();
|
|
|
|
|
|
2010-02-10 13:55:47 +01:00
|
|
|
int value = 1337;
|
2010-02-01 23:02:24 +01:00
|
|
|
int workers = 100;
|
|
|
|
|
LumieraThread threads[workers];
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < workers; i++)
|
|
|
|
|
{
|
2010-02-10 13:55:47 +01:00
|
|
|
value = 123;
|
2010-02-01 23:02:24 +01:00
|
|
|
threads[i] = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE,
|
2010-03-04 16:23:57 +01:00
|
|
|
&sleeping_worker_fn,
|
|
|
|
|
(void *)&value,
|
|
|
|
|
"worker thread",
|
|
|
|
|
&NOBUG_FLAG (NOBUG_ON));
|
2010-02-01 23:02:24 +01:00
|
|
|
lumiera_thread_sync_other (threads[i]);
|
2010-02-10 13:55:47 +01:00
|
|
|
value -= 123;
|
2010-02-01 23:02:24 +01:00
|
|
|
}
|
2010-02-10 13:55:47 +01:00
|
|
|
CHECK (value == 0, "final value is not 0, but %d", value);
|
2010-02-01 23:02:24 +01:00
|
|
|
lumiera_threadpool_destroy ();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (joinable-thread)
|
2010-02-03 23:06:27 +01:00
|
|
|
{
|
|
|
|
|
int delay = 10000;
|
|
|
|
|
lumiera_threadpool_init ();
|
|
|
|
|
LumieraThread t = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE
|
2010-03-04 16:23:57 +01:00
|
|
|
| LUMIERA_THREAD_JOINABLE,
|
|
|
|
|
&sleep_fn,
|
|
|
|
|
(void *)&delay,
|
|
|
|
|
"joinable idle thread",
|
|
|
|
|
&NOBUG_FLAG (NOBUG_ON));
|
2010-02-03 23:06:27 +01:00
|
|
|
lumiera_thread_join(t);
|
|
|
|
|
lumiera_threadpool_destroy ();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 16:23:57 +01:00
|
|
|
TEST (sync-joinable)
|
2010-02-03 14:02:41 +01:00
|
|
|
{
|
2010-02-11 00:09:16 +01:00
|
|
|
// NOTE: this test essentially avoids concurrency with _sync() calls
|
2010-02-03 14:02:41 +01:00
|
|
|
lumiera_threadpool_init ();
|
|
|
|
|
|
2010-02-11 00:09:16 +01:00
|
|
|
int value = 42;
|
2010-02-03 14:02:41 +01:00
|
|
|
|
|
|
|
|
LumieraThread master = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE
|
2010-03-04 16:23:57 +01:00
|
|
|
| LUMIERA_THREAD_JOINABLE,
|
|
|
|
|
&joinable_master_fn,
|
|
|
|
|
(void *)&value,
|
|
|
|
|
"joinable master thread",
|
|
|
|
|
&NOBUG_FLAG (NOBUG_ON));
|
2010-02-03 14:02:41 +01:00
|
|
|
|
|
|
|
|
lumiera_thread_sync_other (master);
|
2010-02-11 00:09:16 +01:00
|
|
|
value = 7732;
|
|
|
|
|
|
2011-05-20 19:42:29 +02:00
|
|
|
lumiera_thread_join (master); //////////////////////////////TICKET #803 deadlock here
|
2010-02-11 00:09:16 +01:00
|
|
|
CHECK (value == 42*2-13, "result is not 42*2-12=71, but %d", value);
|
2010-02-03 14:02:41 +01:00
|
|
|
|
|
|
|
|
lumiera_threadpool_destroy ();
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 01:55:08 +01:00
|
|
|
TESTS_END
|