Commit a4597f03 authored by Pedro Gonnet's avatar Pedro Gonnet
Browse files

minor bug fixes and make space_rebuild parallel (kind of).


Former-commit-id: 00d92b2b60c7d1041482fb0eea49b5c98831c4de
parent 9505d699
......@@ -38,7 +38,7 @@
/* Error macro. */
#define error(s) { printf( "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/* The timers. */
......
......@@ -45,7 +45,7 @@
#include "runner_iact.h"
/* Error macro. */
#define error(s) { printf( "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/* Convert cell location to ID. */
#define cell_getid( cdim , i , j , k ) ( (int)(k) + (cdim)[2]*( (int)(j) + (cdim)[1]*(int)(i) ) )
......@@ -206,7 +206,6 @@ void engine_run ( struct engine *e , int sort_queues ) {
/* Run throught the tasks and get all the waits right. */
for ( k = 0 ; k < s->nr_tasks ; k++ ) {
s->tasks[k].done = 0;
for ( j = 0 ; j < s->tasks[k].nr_unlock_tasks ; j++ )
s->tasks[k].unlock_tasks[j]->wait += 1;
for ( j = 0 ; j < s->tasks[k].nr_unlock_cells ; j++ )
......
......@@ -32,13 +32,13 @@
#include <hdf5.h>
#include "task.h"
#include "lock.h"
#include "task.h"
#include "part.h"
#include "space.h"
/* Error macro. */
#define error(s) { printf( "%s:%s():%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s():%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/**
......
......@@ -35,6 +35,7 @@
#define lock_lock( l ) ( pthread_spin_lock( l ) != 0 )
#define lock_trylock( l ) ( pthread_spin_lock( l ) != 0 )
#define lock_unlock( l ) ( pthread_spin_unlock( l ) != 0 )
#define lock_unlock_blind( l ) pthread_spin_unlock( l )
#else
#define lock_type volatile int
#define lock_init( l ) ( *l = 0 )
......@@ -46,4 +47,5 @@
}
#define lock_trylock( l ) ( ( *(l) ) ? 1 : __sync_val_compare_and_swap( l , 0 , 1 ) )
#define lock_unlock( l ) ( __sync_val_compare_and_swap( l , 1 , 0 ) != 1 )
#define lock_unlock_blind( l ) __sync_val_compare_and_swap( l , 1 , 0 )
#endif
......@@ -39,7 +39,7 @@
#include "queue.h"
/* Error macro. */
#define error(s) { printf( "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/* Define the timer macros. */
#ifdef TIMER_VERBOSE
......@@ -147,7 +147,7 @@ void queue_init ( struct queue *q , int size , struct task *tasks ) {
* @param keep Remove the returned task from this queue.
*/
struct task *queue_gettask ( struct queue *q , int blocking , int keep ) {
struct task *queue_gettask_old ( struct queue *q , int blocking , int keep ) {
int k, tid = -1, qcount, *qtid = q->tid;
lock_type *qlock = &q->lock;
......@@ -267,7 +267,7 @@ struct task *queue_gettask ( struct queue *q , int blocking , int keep ) {
}
struct task *queue_gettask_new ( struct queue *q , int rid , int blocking , int keep ) {
struct task *queue_gettask ( struct queue *q , int rid , int blocking , int keep ) {
int k, tid = -1, qcount, *qtid = q->tid;
lock_type *qlock = &q->lock;
......
......@@ -59,8 +59,8 @@ struct queue {
/* Function prototypes. */
struct task *queue_gettask ( struct queue *q , int blocking , int keep );
struct task *queue_gettask_new ( struct queue *q , int rid , int blocking , int keep );
struct task *queue_gettask_old ( struct queue *q , int blocking , int keep );
struct task *queue_gettask ( struct queue *q , int rid , int blocking , int keep );
void queue_init ( struct queue *q , int size , struct task *tasks );
void queue_insert ( struct queue *q , struct task *t );
void queue_sort ( struct queue *q );
......@@ -45,7 +45,7 @@
#include "runner_iact.h"
/* Error macro. */
#define error(s) { printf( "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/* Convert cell location to ID. */
#define cell_getid( cdim , i , j , k ) ( (int)(k) + (cdim)[2]*( (int)(j) + (cdim)[1]*(int)(i) ) )
......@@ -508,11 +508,11 @@ void *runner_main ( void *data ) {
TIMER_TIC
t = NULL;
if ( e->nr_queues == 1 ) {
t = queue_gettask( &e->queues[0] , 1 , 0 );
t = queue_gettask_old( &e->queues[0] , 1 , 0 );
}
else if ( e->policy & engine_policy_steal ) {
if ( ( myq->next == myq->count ) ||
( t = queue_gettask_new( myq , r->id , 0 , 0 ) ) == NULL ) {
( t = queue_gettask( myq , r->id , 0 , 0 ) ) == NULL ) {
TIMER_TIC2
qid = rand_r( &myseed ) % naq;
keep = ( e->policy & engine_policy_keep ) &&
......@@ -521,7 +521,7 @@ void *runner_main ( void *data ) {
COUNT(runner_counter_steal_empty);
else
COUNT(runner_counter_steal_stall);
t = queue_gettask_new( queues[qid] , r->id , 0 , keep );
t = queue_gettask( queues[qid] , r->id , 0 , keep );
if ( t != NULL && keep )
queue_insert( myq , t );
TIMER_TOC2(runner_timer_steal);
......@@ -529,10 +529,10 @@ void *runner_main ( void *data ) {
}
else if ( e->policy & engine_policy_rand ) {
qid = rand_r( &myseed ) % naq;
t = queue_gettask( queues[qid] , e->policy & engine_policy_block , 0 );
t = queue_gettask( queues[qid] , r->id , e->policy & engine_policy_block , 0 );
}
else {
t = queue_gettask( &e->queues[threadID] , e->policy & engine_policy_block , 0 );
t = queue_gettask( &e->queues[threadID] , r->id , e->policy & engine_policy_block , 0 );
}
TIMER_TOC(runner_timer_getpair);
......@@ -602,8 +602,6 @@ void *runner_main ( void *data ) {
error( "Unknown task type." );
}
t->done = 1;
/* Resolve any dependencies. */
for ( k = 0 ; k < t->nr_unlock_tasks ; k++ )
if ( __sync_fetch_and_sub( &t->unlock_tasks[k]->wait , 1 ) == 0 )
......
......@@ -39,7 +39,7 @@
#include "runner.h"
/* Error macro. */
#define error(s) { printf( "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/* Split size. */
int space_splitsize = space_splitsize_default;
......@@ -288,6 +288,7 @@ int space_rebuild ( struct space *s , int force , double cell_max ) {
/* At this point, we have the upper-level cells, old or new. Now make
sure that the parts in each cell are ok. */
#pragma omp parallel for shared(s) reduction(+:changes)
for ( k = 0 ; k < s->nr_cells ; k++ )
changes += space_rebuild_recurse( s , &s->cells[k] );
......@@ -344,6 +345,9 @@ void parts_sort ( struct part *parts , int *ind , int N , int min , int max ) {
error( "Sorting failed (>pivot)." );
}
/* Try to recurse in parallel. */
if ( N < 100 ) {
/* Recurse on the left? */
if ( j > 0 && pivot > min )
parts_sort( parts , ind , j+1 , min , pivot );
......@@ -354,6 +358,24 @@ void parts_sort ( struct part *parts , int *ind , int N , int min , int max ) {
}
else
#pragma omp parallel sections
{
/* Recurse on the left? */
#pragma omp section
if ( j > 0 && pivot > min )
parts_sort( parts , ind , j+1 , min , pivot );
/* Recurse on the right? */
#pragma omp section
if ( i < N && pivot+1 < max )
parts_sort( &parts[i], &ind[i], N-i , pivot+1 , max );
}
}
/**
* @brief Mapping function to free the sorted indices buffers.
......@@ -413,101 +435,6 @@ void space_map_clearnrtasks ( struct cell *c , void *data ) {
}
/**
* @brief Get a task free of dependencies and conflicts.
*
* @param s The #space.
*/
struct task *space_gettask ( struct space *s ) {
int k, tid = -1;
struct task *res = NULL;
struct cell *c;
/* Main loop, while there are tasks... */
while ( s->next_task < s->nr_tasks ) {
/* Grab the task lock. */
if ( lock_lock( &s->task_lock ) != 0 )
error( "Locking the task_lock failed.\n" );
/* Loop over the remaining task IDs. */
for ( k = s->next_task ; k < s->nr_tasks ; k++ ) {
/* Put a finger on the task. */
res = &s->tasks[ s->tasks_ind[k] ];
/* Is this task blocked? */
if ( res->wait )
continue;
/* Different criteria for different types. */
switch ( res->type ) {
case task_type_self:
if ( res->ci->lock || res->ci->wait > 0 )
continue;
break;
case task_type_pair:
if ( res->ci->lock || res->cj->lock || res->ci->wait || res->cj->wait )
continue;
break;
case task_type_sort:
if ( res->ci->lock )
continue;
break;
}
/* If we made it this far, we're safe. */
break;
} /* loop over the task IDs. */
/* Did we get a task? */
if ( k < s->nr_tasks ) {
// /* Swap to front. */
// tid = s->tasks_ind[k];
// s->tasks_ind[k] = s->tasks_ind[ s->next_task ];
// s->tasks_ind[ s->next_task ] = tid;
/* Bubble-down the task. */
tid = s->tasks_ind[k];
while ( k > s->next_task ) {
s->tasks_ind[ k ] = s->tasks_ind[ k-1 ];
k -= 1;
}
s->tasks_ind[ s->next_task ] = tid;
/* Lock the cells, if needed. */
if ( s->tasks[tid].type != task_type_sort ) {
for ( c = res->ci ; c != NULL ; c = c->parent )
__sync_fetch_and_add( &c->lock , 1 );
for ( c = res->cj ; c != NULL ; c = c->parent )
__sync_fetch_and_add( &c->lock , 1 );
}
/* up the counter. */
s->next_task += 1;
}
/* Release the task lock. */
if ( lock_unlock( &s->task_lock ) != 0 )
error( "Locking the task_lock failed.\n" );
/* Leave? */
if ( tid >= 0 )
return &s->tasks[tid];
} /* while there are tasks. */
/* No beef. */
return NULL;
}
/**
* @brief Map a function to all particles in a aspace.
*
......@@ -584,7 +511,13 @@ void space_map_cells ( struct space *s , int full , void (*fun)( struct cell *c
struct task *space_addtask ( struct space *s , int type , int subtype , int flags , int wait , struct cell *ci , struct cell *cj , struct task *unlock_tasks[] , int nr_unlock_tasks , struct cell *unlock_cells[] , int nr_unlock_cells ) {
struct task *t = &s->tasks[ s->nr_tasks ];
struct task *t;
/* Lock the space. */
lock_lock( &s->lock );
/* Get the next free task. */
t = &s->tasks[ s->nr_tasks ];
/* Copy the data. */
t->type = type;
......@@ -603,6 +536,9 @@ struct task *space_addtask ( struct space *s , int type , int subtype , int flag
/* Increase the task counter. */
s->nr_tasks += 1;
/* Unock the space. */
lock_unlock_blind( &s->lock );
/* Return a pointer to the new task. */
return t;
......@@ -1344,9 +1280,6 @@ void space_maketasks ( struct space *s , int do_sort ) {
printf( " %s=%i" , taskID_names[k] , counts[k] );
printf( " ]\n" );
/* Re-set the next task pointer. */
s->next_task = 0;
}
......@@ -1444,6 +1377,9 @@ void space_split ( struct space *s , struct cell *c ) {
void space_recycle ( struct space *s , struct cell *c ) {
/* Lock the space. */
lock_lock( &s->lock );
/* Clear the cell. */
if ( lock_destroy( &c->lock ) != 0 )
error( "Failed to destroy spinlock." );
......@@ -1457,6 +1393,9 @@ void space_recycle ( struct space *s , struct cell *c ) {
s->cells_new = c;
s->tot_cells -= 1;
/* Unlock the space. */
lock_unlock_blind( &s->lock );
}
......@@ -1471,6 +1410,9 @@ struct cell *space_getcell ( struct space *s ) {
struct cell *c;
int k;
/* Lock the space. */
lock_lock( &s->lock );
/* Is the buffer empty? */
if ( s->cells_new == NULL ) {
if ( posix_memalign( (void *)&s->cells_new , 64 , space_cellallocchunk * sizeof(struct cell) ) != 0 )
......@@ -1491,6 +1433,9 @@ struct cell *space_getcell ( struct space *s ) {
if ( lock_init( &c->lock ) != 0 )
error( "Failed to initialize cell spinlock." );
/* Unlock the space. */
lock_unlock_blind( &s->lock );
return c;
}
......@@ -1519,8 +1464,10 @@ void space_init ( struct space *s , double dim[3] , struct part *parts , int N ,
s->periodic = periodic;
s->nr_parts = N;
s->parts = parts;
if ( lock_init( &s->task_lock ) != 0 )
error( "Failed to create task spin-lock." );
/* Init the space lock. */
if ( lock_init( &s->lock ) != 0 )
error( "Failed to create space spin-lock." );
/* Build the cells and the tasks. */
space_rebuild( s , 1 , h_max );
......
......@@ -87,9 +87,11 @@ struct space {
/* The list of tasks. */
struct task *tasks;
int nr_tasks, next_task, tasks_size;
int nr_tasks, tasks_size;
int *tasks_ind;
lock_type task_lock;
/* General-purpose lock for this space. */
lock_type lock;
};
......
......@@ -41,7 +41,7 @@
const char *taskID_names[task_type_count] = { "none" , "sort" , "self" , "pair" , "sub" , "ghost" };
/* Error macro. */
#define error(s) { printf( "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
#define error(s) { fprintf( stderr , "%s:%s:%i: %s\n" , __FILE__ , __FUNCTION__ , __LINE__ , s ); abort(); }
/**
......@@ -55,10 +55,13 @@ void task_rmunlock( struct task *ta , struct task *tb ) {
int k;
lock_lock( &ta->lock );
for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
if ( ta->unlock_tasks[k] == tb ) {
ta->nr_unlock_tasks -= 1;
ta->unlock_tasks[k] = ta->unlock_tasks[ ta->nr_unlock_tasks ];
lock_unlock_blind( &ta->lock );
return;
}
error( "Task not found." );
......@@ -80,13 +83,17 @@ void task_rmunlock_blind( struct task *ta , struct task *tb ) {
int k;
lock_lock( &ta->lock );
for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
if ( ta->unlock_tasks[k] == tb ) {
ta->nr_unlock_tasks -= 1;
ta->unlock_tasks[k] = ta->unlock_tasks[ ta->nr_unlock_tasks ];
return;
break;
}
lock_unlock_blind( &ta->lock );
}
......@@ -105,10 +112,14 @@ void task_addunlock( struct task *ta , struct task *tb ) {
if ( ta == NULL || tb == NULL )
return;
lock_lock( &ta->lock );
/* Check if ta already unlocks tb. */
for ( k = 0 ; k < ta->nr_unlock_tasks ; k++ )
if ( ta->unlock_tasks[k] == tb )
if ( ta->unlock_tasks[k] == tb ) {
lock_unlock_blind( &ta->lock );
return;
}
if ( ta->nr_unlock_tasks == task_maxunlock )
error( "Too many unlock_tasks in task." );
......@@ -116,6 +127,8 @@ void task_addunlock( struct task *ta , struct task *tb ) {
ta->unlock_tasks[ ta->nr_unlock_tasks] = tb;
ta->nr_unlock_tasks += 1;
lock_unlock_blind( &ta->lock );
}
......@@ -49,7 +49,9 @@ extern const char *taskID_names[];
/* Data of a task. */
struct task {
int type, subtype, flags, wait, rank, done;
int type, subtype, flags, wait, rank;
lock_type lock;
int nr_unlock_tasks;
struct task *unlock_tasks[ task_maxunlock ];
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment