tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Bad threading performance
On Mon, 7 Mar 2011 18:39:39 +0000
Sad Clouds <cryintothebluesky%googlemail.com@localhost> wrote:
> Below are test results. Any ideas why concurrency on NetBSD is so bad
> compared to Solaris? It seems as if on NetBSD threads are stuck on a
> wait list for much longer.
OK this is a follow up on the issue I've raised previously. I have
attached a test program, which has good concurrency on Linux and
Solaris, however on NetBSD concurrency is very poor, i.e. CPU sits idle
a lot of the time.
I'd be interested to hear from NetBSD developers as to what causes
this, or at least if this is a known issue...
/*
Build with:
gcc -O1 test_ptask.c -lpthread
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#define NTHREADS 4
/* Function call structure */
struct fcall
{
/* Function pointers */
void *(*fptr)(void *arg);
/* Pointer to function arguments structure */
void *arg;
};
/* Function arguments */
struct farg
{
uint32_t n1;
uint32_t n2;
/* Pad to 64-byte boundary */
uint8_t pad[64 - (sizeof(uint32_t) * 2)];
};
/* Parallel task */
struct ptask
{
pthread_mutex_t mutex;
pthread_cond_t cond;
uint8_t pad0[64];
/* Array of function call parameters */
struct fcall fcalls[NTHREADS];
uint8_t pad1[64];
/* Array of function arguments */
struct farg args[NTHREADS];
uint32_t task_run_cnt; /* Counter of tasks to run */
};
/* Thread instance */
struct thread
{
pthread_mutex_t mutex;
pthread_cond_t cond;
struct fcall *fcall_ptr;
struct ptask *ptask_ptr;
uint8_t pad[64];
};
/* Thread pool */
struct tpool
{
struct thread threads_array[NTHREADS];
};
/* Thread function passed to pthread_create() */
void *thread_func(void *arg)
{
struct thread *tptr = (struct thread *)arg;
struct fcall *fcall;
struct ptask *ptask;
while (1)
{
if (pthread_mutex_lock(&(tptr->mutex)) != 0)
abort();
/* Sleep on a condition variable */
while (tptr->fcall_ptr == NULL)
{
if (pthread_cond_wait(&(tptr->cond), &(tptr->mutex)) !=
0)
abort();
}
/* Copy pointers to local variables */
fcall = tptr->fcall_ptr;
ptask = tptr->ptask_ptr;
/* Reset to null values */
tptr->fcall_ptr = NULL;
tptr->ptask_ptr = NULL;
if (pthread_mutex_unlock(&(tptr->mutex)) != 0)
abort();
/* Run current task */
fcall->fptr(fcall->arg);
if (pthread_mutex_lock(&(ptask->mutex)) != 0)
abort();
/* If this is last task, signal to waiting main thread */
if (--(ptask->task_run_cnt) == 0)
{
if (pthread_cond_signal(&(ptask->cond)) != 0)
abort();
}
if (pthread_mutex_unlock(&(ptask->mutex)) != 0)
abort();
} /* while (1) */
}
void *test_func(void *arg)
{
struct farg *farg = (struct farg *)arg;
int i;
for (i = 0; i < 1000000; i++)
{
farg->n1++;
farg->n2++;
}
return NULL;
}
static struct tpool tpool;
int main(void)
{
int i, j;
struct ptask ptask;
pthread_t tid;
/* Initialize ptask */
if (pthread_mutex_init(&(ptask.mutex), NULL) != 0)
abort();
if (pthread_cond_init(&(ptask.cond), NULL) != 0)
abort();
/* Initialize threads */
for (j = 0; j < NTHREADS; j++)
{
if (pthread_mutex_init(&(tpool.threads_array[j].mutex), NULL)
!= 0)
abort();
if (pthread_cond_init(&(tpool.threads_array[j].cond), NULL) !=
0)
abort();
tpool.threads_array[j].fcall_ptr = NULL;
tpool.threads_array[j].ptask_ptr = NULL;
if (pthread_create(
&tid, NULL, &thread_func, &(tpool.threads_array[j])) !=
0)
{
abort();
}
}
for (i = 0; i < 100000; i++)
{
/* Set function arguments */
for (j = 0; j < NTHREADS; j++)
{
ptask.fcalls[j].fptr = &test_func;
ptask.fcalls[j].arg = &(ptask.args[j]);
ptask.args[j].n1 = j;
ptask.args[j].n2 = j;
}
ptask.task_run_cnt = NTHREADS;
/* Tell threads to execute functions */
for (j = 0; j < NTHREADS; j++)
{
if (pthread_mutex_lock(&(tpool.threads_array[j].mutex))
!= 0)
abort();
tpool.threads_array[j].fcall_ptr = &(ptask.fcalls[j]);
tpool.threads_array[j].ptask_ptr = &ptask;
if (pthread_cond_signal(&(tpool.threads_array[j].cond))
!= 0)
abort();
if
(pthread_mutex_unlock(&(tpool.threads_array[j].mutex)) != 0)
abort();
}
/* Wait for all threads to finish */
if (pthread_mutex_lock(&(ptask.mutex)) != 0)
abort();
while (ptask.task_run_cnt != 0)
{
if (pthread_cond_wait(&(ptask.cond), &(ptask.mutex)) !=
0)
abort();
}
if (pthread_mutex_unlock(&(ptask.mutex)) != 0)
abort();
}
return 0;
}
Home |
Main Index |
Thread Index |
Old Index