lumiera_/tests/backend/test-threadpool.c
Ichthyostega ada5cefaaf re-arrange tests according to layer structure
the buildsystem will now pick up and link
all test cases according to the layer, e.g.
backend tests will automatically be linked
against the backend + library solely.
2013-01-07 05:43:01 +01:00

360 lines
10 KiB
C

/*
TEST-THREADPOOL - 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
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
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 "lib/test/test.h"
#include "backend/threadpool.h"
#include "include/logging.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
void is_prime(void * arg)
{
unsigned long long number = *(unsigned long long *)arg;
unsigned long long prime = 1;
usleep(1);
for (unsigned long long x = number-1; x >= sqrt(number); --x)
{
if ((number % x) == 0)
{
prime = 0;
break;
}
}
*(unsigned long long *)arg = prime;
usleep(1);
}
void sleep_fn(void * arg)
{
unsigned int usec = *(int *)arg;
unsigned int result = usleep (usec);
*(int *)arg = result;
}
void other_fn(void * arg)
{
int input = *(int *)arg;
lumiera_thread_sync (); // the main thread can discard the argument storage
CHECK (input == 42, "input is not 42, but %d", input);
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
input -= 81;
CHECK (input == 42, "result is not 42, but %d", input);
}
// subtracts 13 from the value
void joinable_worker_fn(void * arg)
{
int input = *(int *)arg;
lumiera_thread_sync (); // signal that arguments have been received
*(int *)arg = input - 13;
}
// adds 42 to the value
void joinable_master_fn(void * arg)
{
int input = *(int *)arg;
lumiera_thread_sync ();
CHECK (input == 42, "input is not 42, but %d", input);
LumieraThread worker = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE
| LUMIERA_THREAD_JOINABLE,
&joinable_worker_fn,
(void *)&input,
"joinable worker thread",
&NOBUG_FLAG (NOBUG_ON));
lumiera_thread_sync_other (worker);
lumiera_thread_join (worker);
lumiera_thread_sync_other (worker); // wait until the arguments are sent
lumiera_thread_join (worker); // wait until the result has been calculated
CHECK (input == 42-13, "result is not 42-13=29, but %d", input);
input += 42;
*(int *)arg = input;
}
TESTS_BEGIN
TEST (threadpool-basic)
{
lumiera_threadpool_init();
lumiera_threadpool_destroy();
}
TEST (threadpool1)
{
ECHO("start by initializing the threadpool");
lumiera_threadpool_init();
LumieraThread t1 =
lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE,
"test purpose",
&NOBUG_FLAG(NOBUG_ON));
// lumiera_threadpool_release_thread(t1);
ECHO("acquired thread 1 %p",t1);
lumiera_threadpool_destroy();
}
TEST (two-thread-acquire)
{
ECHO("start by initializing the threadpool");
lumiera_threadpool_init();
ECHO("acquiring thread 1");
LumieraThread t1 =
lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_INTERACTIVE,
"test purpose",
&NOBUG_FLAG(NOBUG_ON));
ECHO("acquiring thread 2");
LumieraThread t2 =
lumiera_threadpool_acquire_thread(LUMIERA_THREADCLASS_IDLE,
"test purpose",
&NOBUG_FLAG(NOBUG_ON));
ECHO("thread 1 state=%s", lumiera_threadstate_names[t1->state]);
CHECK(LUMIERA_THREADSTATE_IDLE == t1->state);
ECHO("thread 2 state=%s", lumiera_threadstate_names[t2->state]);
CHECK(LUMIERA_THREADSTATE_IDLE == t2->state);
LUMIERA_CONDITION_SECTION(NOBUG_ON, &t1->signal)
{
t1->state = LUMIERA_THREADSTATE_WAKEUP;
LUMIERA_CONDITION_SIGNAL;
}
LUMIERA_CONDITION_SECTION(NOBUG_ON, &t2->signal)
{
t2->state = LUMIERA_THREADSTATE_WAKEUP;
LUMIERA_CONDITION_SIGNAL;
}
ECHO("cleaning up");
lumiera_threadpool_destroy();
}
TEST (many-sleepy-threads)
{
const int threads_per_pool_count = 10;
unsigned int delay = 10000;
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)
{
threads[i+kind*threads_per_pool_count] =
lumiera_thread_run(kind,
&sleep_fn,
(void *) &delay,
"just sleep a bit",
&NOBUG_FLAG(NOBUG_ON));
}
}
lumiera_threadpool_destroy();
}
TEST (toomany-random-sleepy-threads (compiletest only))
{
const int threads_per_pool_count = 500;
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)
{
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));
}
}
lumiera_threadpool_destroy();
}
TEST (no-function)
{
LumieraThread t;
lumiera_threadpool_init();
t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE,
NULL,
NULL,
"process my test function",
&NOBUG_FLAG(NOBUG_ON));
// cleanup
ECHO("finished waiting");
lumiera_threadpool_destroy();
}
TEST (process-function)
{
// this is what the scheduler would do once it figures out what function a job needs to run
LumieraThread t;
unsigned long long number = 1307;
lumiera_threadpool_init();
ECHO ("the input to the function is %llu", number);
t = lumiera_thread_run (LUMIERA_THREADCLASS_INTERACTIVE,
&is_prime,
(void *)&number, //void * arg,
"process my test function",
&NOBUG_FLAG(NOBUG_ON)); // struct nobug_flag* flag)
// cleanup
lumiera_threadpool_destroy();
ECHO("the result is %llu", number);
}
TEST (many-random-sleepy-threads (compiletest only))
{
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)
{
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));
}
}
lumiera_threadpool_destroy();
}
TEST (simple-sync)
{
lumiera_threadpool_init ();
int value = 42;
LumieraThread other = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE,
&other_fn,
(void *)&value,
"other thread",
&NOBUG_FLAG (NOBUG_ON));
ECHO ("syncing with the other thread");
lumiera_thread_sync_other (other);
value += 42;
CHECK (value == 42*2, "value is not equal to 42*2=84, but %d", value);
lumiera_threadpool_destroy ();
}
TEST (sync-many)
{
lumiera_threadpool_init ();
int value = 1337;
int workers = 100;
LumieraThread threads[workers];
for (int i = 0; i < workers; i++)
{
value = 123;
threads[i] = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE,
&sleeping_worker_fn,
(void *)&value,
"worker thread",
&NOBUG_FLAG (NOBUG_ON));
lumiera_thread_sync_other (threads[i]);
value -= 123;
}
CHECK (value == 0, "final value is not 0, but %d", value);
lumiera_threadpool_destroy ();
}
TEST (joinable-thread)
{
int delay = 10000;
lumiera_threadpool_init ();
LumieraThread t = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE
| LUMIERA_THREAD_JOINABLE,
&sleep_fn,
(void *)&delay,
"joinable idle thread",
&NOBUG_FLAG (NOBUG_ON));
lumiera_thread_join(t);
lumiera_threadpool_destroy ();
}
TEST (sync-joinable)
{
// NOTE: this test essentially avoids concurrency with _sync() calls
lumiera_threadpool_init ();
int value = 42;
LumieraThread master = lumiera_thread_run (LUMIERA_THREADCLASS_IDLE
| LUMIERA_THREAD_JOINABLE,
&joinable_master_fn,
(void *)&value,
"joinable master thread",
&NOBUG_FLAG (NOBUG_ON));
lumiera_thread_sync_other (master);
value = 7732;
lumiera_thread_join (master); //////////////////////////////TICKET #803 deadlock here
CHECK (value == 42*2-13, "result is not 42*2-12=71, but %d", value);
lumiera_threadpool_destroy ();
}
TESTS_END