PLASMA  2.4.5
PLASMA - Parallel Linear Algebra for Scalable Multi-core Architectures
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
QUARK: QUeuing And Runtime for Kernels

Functions

int QUARK_Thread_Rank (Quark *quark)
void * QUARK_Args_List (Quark *quark)
int QUARK_Get_RankInTask (Quark *quark)
void * QUARK_Args_Pop (void *args_list, void **last_arg)
QuarkQUARK_Setup (int num_threads)
QuarkQUARK_New (int num_threads)
void QUARK_Barrier (Quark *quark)
void QUARK_Waitall (Quark *quark)
void QUARK_Free (Quark *quark)
void QUARK_Delete (Quark *quark)
TaskQUARK_Task_Init (Quark *quark, void(*function)(Quark *), Quark_Task_Flags *task_flags)
void QUARK_Task_Pack_Arg (Quark *quark, Task *task, int arg_size, void *arg_ptr, int arg_flags)
unsigned long long QUARK_Insert_Task_Packed (Quark *quark, Task *task)
unsigned long long QUARK_Insert_Task (Quark *quark, void(*function)(Quark *), Quark_Task_Flags *task_flags,...)
int QUARK_Cancel_Task (Quark *quark, unsigned long long taskid)
void QUARK_Worker_Loop (Quark *quark, int thread_rank)
Quark_SequenceQUARK_Sequence_Create (Quark *quark)
int QUARK_Sequence_Cancel (Quark *quark, Quark_Sequence *sequence)
Quark_SequenceQUARK_Sequence_Destroy (Quark *quark, Quark_Sequence *sequence)
int QUARK_Sequence_Wait (Quark *quark, Quark_Sequence *sequence)
Quark_SequenceQUARK_Get_Sequence (Quark *quark)
Quark_Task_FlagsQUARK_Task_Flag_Set (Quark_Task_Flags *task_flags, int flag, intptr_t val)
intptr_t QUARK_Task_Flag_Get (Quark *quark, int flag)
void QUARK_DOT_DAG_Enable (Quark *quark, int enable)

Detailed Description

These functions are available from the QUARK library for the scheduling of kernel routines.


Function Documentation

void* QUARK_Args_List ( Quark quark)

Return a pointer to the argument list being processed by the current task and worker.

Parameters:
[in]quarkThe scheduler's main data structure.
Returns:
Pointer to the current argument list (icl_list_t *)

Definition at line 525 of file quark.c.

References quark_task_s::args_list, worker_s::current_task_ptr, QUARK_Thread_Rank(), and quark_s::worker.

{
Task *curr_task = quark->worker[QUARK_Thread_Rank(quark)]->current_task_ptr;
return (void *)curr_task->args_list;
}

Here is the call graph for this function:

void* QUARK_Args_Pop ( void *  args_list,
void **  last_arg 
)

Return a pointer to the next argument. The variable last_arg should be NULL on the first call, then each subsequent call will use last_arg to get the the next argument. The argument list is not actually popped, it is preserved intact.

Parameters:
[in]args_listPointer to the current arguments
[in,out]last_argPointer to the last argument; should be NULL on the first call
Returns:
Pointer to the next argument

Definition at line 573 of file quark.c.

References icl_list_s::data, icl_list_first(), and icl_list_next().

{
icl_list_t *args = (icl_list_t *)args_list;
icl_list_t *node = (icl_list_t *)*last_arg;
void *arg = NULL;
if ( node == NULL ) {
node = icl_list_first( args );
if (node!=NULL) arg = node->data;
} else {
node = icl_list_next( args, node );
if (node!=NULL) arg = node->data;
}
*last_arg = node;
return arg;
}

Here is the call graph for this function:

void QUARK_Barrier ( Quark quark)

Called by the master thread. Wait for all the tasks to be completed, then return. The worker tasks will NOT exit from their work loop.

Parameters:
[in,out]quarkThe scheduler's main data structure.

Definition at line 908 of file quark.c.

References quark_s::address_set, quark_s::all_tasks_queued, quark_s::dot_dag_enable, FALSE, icl_hash_create(), icl_hash_destroy(), icl_hash_foreach, address_set_node_s::last_reader_or_writer_tasklevel, address_set_node_s::last_writer_tasklevel, quark_s::queue_before_computing, quark_s::tasklevel_width, tasklevel_width_max_level, TRUE, and quark_s::worker.

{
long long num_tasks = 1;
/* Force queue_before_computing to be OFF!! */
do {
quark_process_completed_tasks(quark);
num_tasks = quark_work_main_loop( quark->worker[0] );
#ifdef QUARK_WITH_VALGRIND
/* Asim: maybe you can have a signal right here ? */
pthread_yield();
#endif
} while ( num_tasks > 0 );
/* FIXME Since address_set_nodes are not cleaned as the code progresses, they are freed here */
if ( quark->dot_dag_enable ) {
/* If dag generation is enabled, reset level counters */
unsigned long long tasklevel = 0;
for ( tasklevel=1; tasklevel<tasklevel_width_max_level; tasklevel++ )
if ( quark->tasklevel_width[tasklevel] == 0 )
break;
tasklevel = tasklevel -1;
int tmpint; icl_entry_t* tmpent; void *kp, *dp;
icl_hash_foreach(quark->address_set, tmpint, tmpent, kp, dp) {
Address_Set_Node *address_set_node = (Address_Set_Node *)dp;
address_set_node->last_writer_tasklevel = tasklevel;
address_set_node->last_reader_or_writer_tasklevel = tasklevel;
}
fprintf(dot_dag_file, "// QUARK_Barrier reached: level=%llu \n", tasklevel );
} else {
/* If NO dag generation, cleanup memory */
icl_hash_destroy( quark->address_set, NULL, quark_address_set_node_free );
quark->address_set = icl_hash_create( 0x01<<12, address_hash_function, address_key_compare);
}
}

Here is the call graph for this function:

Here is the caller graph for this function:

int QUARK_Cancel_Task ( Quark quark,
unsigned long long  taskid 
)

Called by any thread. Cancel a task that is in the scheduler. This works by simply making the task a NULL task. The scheduler still processes all the standard dependencies for this task, but when it is time to run the actual function, the scheduler does nothing.

Parameters:
[in,out]quarkThe scheduler's main data structure.
[in]taskidThe taskid returned by a QUARK_Insert_Task
Returns:
1 on success.
-1 if the task cannot be found (may already be done and removed).
-2 if the task is aready running, done, or cancelled.

Definition at line 1373 of file quark.c.

References CANCELLED, DONE, quark_task_s::function, icl_hash_find(), RUNNING, quark_task_s::status, quark_task_s::task_mutex, quark_s::task_set, and quark_s::task_set_mutex.

{
pthread_mutex_lock_wrap( &quark->task_set_mutex );
Task *task = icl_hash_find( quark->task_set, &taskid );
if ( task == NULL ) {
pthread_mutex_unlock_wrap( &quark->task_set_mutex );
return -1;
}
pthread_mutex_lock_task( &task->task_mutex );
if ( task->status==RUNNING || task->status==DONE || task->status==CANCELLED ) {
pthread_mutex_unlock_task( &task->task_mutex );
pthread_mutex_unlock_wrap( &quark->task_set_mutex );
return -2;
}
task->function = NULL;
pthread_mutex_unlock_task( &task->task_mutex );
pthread_mutex_unlock_wrap( &quark->task_set_mutex );
return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void QUARK_Delete ( Quark quark)

Called by the master thread. Wait for all tasks to complete, then join/end the worker threads, and clean up all the data structures.

Parameters:
[in,out]quarkThe scheduler's main data structure.

Definition at line 1009 of file quark.c.

References quark_s::coresbind, quark_s::num_threads, pthread_attr_destroy(), pthread_join(), QUARK_Free(), quark_topology_finalize(), QUARK_Waitall(), quark_s::thread_attr, worker_s::thread_id, and quark_s::worker.

{
void *exitcodep = NULL;
int i;
/* Wait for all tasks to complete */
QUARK_Waitall( quark );
/* Wait for workers to quit and join threads */
for (i = 1; i < quark->num_threads; i++)
pthread_join(quark->worker[i]->thread_id, &exitcodep);
/* Destroy specific structures */
if (quark->coresbind) free(quark->coresbind);
/* Destroy hash tables, workers and other data structures */
QUARK_Free( quark );
}

Here is the call graph for this function:

void QUARK_DOT_DAG_Enable ( Quark quark,
int  enable 
)

Enable and disable DAG generation in QUARK. Only to be called at the task insertion level by the master thread. Can be called multiple times to enable and disable DAG generation during the runtime. For the output to make sense, this MUST be preceeded by a sync operation such as QUARK_Barrier.

Parameters:
[in,out]quarkPointer to the scheduler data structure
[in]enableInteger: 1 = enable DAG generation; otherwise disable

Definition at line 2589 of file quark.c.

References quark_s::address_set, quark_s::dot_dag_enable, DOT_DAG_FILENAME, quark_s::dot_dag_mutex, quark_s::dot_dag_was_setup, fopen, quark_s::high_water_mark, icl_hash_foreach, address_set_node_s::last_reader_or_writer_taskid, address_set_node_s::last_reader_or_writer_tasklevel, address_set_node_s::last_writer_taskid, address_set_node_s::last_writer_tasklevel, quark_s::low_water_mark, pthread_mutex_destroy(), pthread_mutex_init(), quark_s::tasklevel_width, and tasklevel_width_max_level.

{
int i;
if ( enable==1 ) {
if ( !quark->dot_dag_was_setup ) {
quark->high_water_mark = (int)(INT_MAX - 1);
quark->low_water_mark = (int)(quark->high_water_mark);
/* global FILE variable */
if ( dot_dag_file == NULL ) fopen( &dot_dag_file, DOT_DAG_FILENAME, "w" );
fprintf(dot_dag_file, "digraph G { size=\"10,7.5\"; center=1; orientation=portrait; \n");
fprintf(dot_dag_file, "%d [style=\"invis\"]\n", 0);
/* Reset tasklevel information */
for (i=0; i<tasklevel_width_max_level; i++ )
quark->tasklevel_width[i] = 0;
/* Reset the address set nodes information */
int tmpint;
icl_entry_t* tmpent;
void *kp, *dp;
icl_hash_foreach(quark->address_set, tmpint, tmpent, kp, dp) {
Address_Set_Node *address_set_node = (Address_Set_Node *)dp;
address_set_node->last_writer_taskid = 0;
address_set_node->last_writer_tasklevel = 0;
address_set_node->last_reader_or_writer_taskid = 0;
address_set_node->last_reader_or_writer_tasklevel = 0;
}
/* quark->dot_dag_was_setup is used to indicate that the
* dot_dag_file needs to be finalized */
quark->dot_dag_was_setup = 1;
quark->dot_dag_enable = 1;
}
} else {
if ( quark->dot_dag_was_setup ) {
for (i=1; i<tasklevel_width_max_level && quark->tasklevel_width[i]!=0; i++ ) {
fprintf(dot_dag_file, "%d [label=\"%d:%d\"]\n", i, i, quark->tasklevel_width[i] );
fprintf(dot_dag_file, "%d->%d [style=\"invis\"];\n", i-1, i );
}
fprintf(dot_dag_file, "} // close graph\n");
fprintf(dot_dag_file, "// ---------------------- \n");
fprintf(dot_dag_file, "\n\n");
fclose( dot_dag_file );
quark->dot_dag_was_setup = 0;
}
quark->dot_dag_enable = 0;
}
}

Here is the call graph for this function:

Here is the caller graph for this function:

void QUARK_Free ( Quark quark)

Called by the master thread. Free all QUARK data structures, this assumes that all usage of QUARK is completed. This interface does not manage, delete or close down the worker threads.

Parameters:
[in,out]quarkThe scheduler's main data structure.

Definition at line 981 of file quark.c.

References quark_s::address_set, quark_s::address_set_mutex, quark_s::completed_tasks, icl_hash_destroy(), quark_s::num_threads, pthread_mutex_destroy(), QUARK_DOT_DAG_Enable(), quark_s::quark_mutex, QUARK_Waitall(), quark_s::task_set, and quark_s::worker.

{
int i;
QUARK_Waitall(quark);
/* Write the level matching/forcing information */
QUARK_DOT_DAG_Enable( quark, 0 );
/* Destroy hash tables, workers and other data structures */
for (i = 1; i < quark->num_threads; i++)
quark_worker_delete( quark->worker[i] );
quark_worker_delete( quark->worker[0] );
if (quark->worker) free(quark->worker);
if (quark->completed_tasks) free(quark->completed_tasks);
icl_hash_destroy( quark->address_set, NULL, quark_address_set_node_free );
icl_hash_destroy( quark->task_set, NULL, NULL );
free(quark);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int QUARK_Get_RankInTask ( Quark quark)

Return the rank of a thread inside a parallel task.

Parameters:
[in]quarkThe scheduler's main data structure.
Returns:
Pointer to the current argument list (icl_list_t *)

Definition at line 544 of file quark.c.

References worker_s::current_task_ptr, QUARK_Thread_Rank(), quark_task_s::task_mutex, quark_task_s::threadid, and quark_s::worker.

{
int local_rank = 0;
int global_rank = QUARK_Thread_Rank(quark);
Task *curr_task = quark->worker[global_rank]->current_task_ptr;
pthread_mutex_lock_wrap( &curr_task->task_mutex );
local_rank = curr_task->threadid;
curr_task->threadid++;
pthread_mutex_unlock_wrap( &curr_task->task_mutex );
return local_rank;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Quark_Sequence* QUARK_Get_Sequence ( Quark quark)

For the current thread, in the current task being executed, return the task's sequence value. This is the value provided when the task was Task_Inserted into a sequence.

Parameters:
[in,out]quarkPointer to the scheduler data structure
Returns:
Pointer to sequence data structure

Definition at line 2238 of file quark.c.

References worker_s::current_task_ptr, QUARK_Thread_Rank(), quark_task_s::sequence, and quark_s::worker.

{
Task *curr_task = quark->worker[QUARK_Thread_Rank(quark)]->current_task_ptr;
return (Quark_Sequence *)curr_task->sequence;
}

Here is the call graph for this function:

unsigned long long QUARK_Insert_Task ( Quark quark,
void(*)(Quark *)  function,
Quark_Task_Flags task_flags,
  ... 
)

Called by the master thread. Add a new task to the scheduler, providing the data pointers, sizes, and dependency information. This function provides the main user interface for the user to write data-dependent algorithms.

Parameters:
[in,out]quarkThe scheduler's main data structure.
[in]functionThe function (task) to be executed by the scheduler
[in]task_flagsFlags to specify task behavior
[in]...Triplets of the form, ending with 0 for arg_size. arg_size, arg_ptr, arg_flags where arg_size: int: Size of the argument in bytes (0 cannot be used here) arg_ptr: pointer: Pointer to data or argument arg_flags: int: Flags indicating argument usage and various decorators INPUT, OUTPUT, INOUT, VALUE, NODEP, SCRATCH LOCALITY, ACCUMULATOR, GATHERV TASK_COLOR, TASK_LABEL (special decorators for VALUE) e.g., arg_flags INPUT | LOCALITY | ACCUMULATOR e.g., arg_flags VALUE | TASK_COLOR
Returns:
A long, long integer which can be used to refer to this task (e.g. for cancellation)

Definition at line 1264 of file quark.c.

References QUARK_Insert_Task_Packed(), QUARK_Task_Init(), and QUARK_Task_Pack_Arg().

{
va_list varg_list;
int arg_size;
unsigned long long taskid;
Task *task = QUARK_Task_Init(quark, function, task_flags);
/* For each argument */
va_start(varg_list, task_flags);
while( (arg_size = va_arg(varg_list, int)) != 0) {
void *arg_ptr = va_arg(varg_list, void *);
int arg_flags = va_arg(varg_list, int);
QUARK_Task_Pack_Arg( quark, task, arg_size, arg_ptr, arg_flags );
}
va_end(varg_list);
taskid = QUARK_Insert_Task_Packed( quark, task );
return taskid;
}

Here is the call graph for this function:

unsigned long long QUARK_Insert_Task_Packed ( Quark quark,
Task task 
)

Called by the master thread. Add a new task to the scheduler, providing the data pointers, sizes, and dependency information. This function provides the main user interface for the user to write data-dependent algorithms.

Parameters:
[in,out]quarkThe scheduler's main data structure.
[in,out]taskThe packed task structure that already has all the arguments associated with the function
Returns:
A long, long integer which can be used to refer to this task (e.g. for cancellation)

Definition at line 1181 of file quark.c.

References quark_s::all_tasks_queued, DBGPRINTF, FALSE, quark_task_s::function, quark_s::high_water_mark, icl_hash_insert(), LIST_INSERT_HEAD, NOTREADY, quark_s::num_tasks, quark_task_s::priority, quark_task_s::ptr_to_task_in_sequence, QUARK_ERR, QUARK_Thread_Rank(), quark_trace_addtask, worker_s::ready_list_size, quark_task_s::sequence, Quark_sequence_s::sequence_mutex, Quark_sequence_s::status, quark_task_s::status, quark_task_s::task_mutex, quark_s::task_set, quark_s::task_set_mutex, quark_task_s::task_thread_count, quark_task_s::task_thread_count_outstanding, quark_task_s::taskid, Quark_sequence_s::tasks_in_sequence, ll_list_node_s::val, and quark_s::worker.

{
long long num_tasks = -1;
unsigned long long taskid = task->taskid;
Quark_Sequence *sequence;
/* Track sequence information if it is provided */
if ( task->sequence ) {
sequence = task->sequence;
pthread_mutex_lock_wrap( &sequence->sequence_mutex );
if ( task->sequence->status == QUARK_ERR ) {
/* If the sequence is cancelled or has error, return at once */
task->function = NULL;
pthread_mutex_unlock_wrap( &sequence->sequence_mutex );
quark_task_delete( quark, task );
return QUARK_ERR;
} else {
/* Otherwise insert this task into sequence */
ll_list_node_t *entry = quark_malloc(sizeof(ll_list_node_t));
entry->val = task->taskid;
LIST_INSERT_HEAD( headp, entry, ll_entries );
pthread_mutex_unlock_wrap( &task->sequence->sequence_mutex );
/* Keep pointer to task in sequence so it can be deleted when task completes */
task->ptr_to_task_in_sequence = entry;
}
}
task->status = NOTREADY;
/* Save the task in task_set, indexed by its taskid */
pthread_mutex_lock_wrap( &quark->task_set_mutex );
icl_hash_insert( quark->task_set, &task->taskid, task );
num_tasks = quark->num_tasks++;
pthread_mutex_unlock_wrap( &quark->task_set_mutex );
DBGPRINTF("Wkr %d [ %d ] Inserted %lld [ %d %d ] into task set [ %lld ]\n", QUARK_Thread_Rank(quark), quark->worker[0]->ready_list_size, task->taskid, task->priority, task->task_thread_count, quark->num_tasks );
/* Insert the task in the address hash, locking access to the address set hash */
quark_insert_task_dependencies( quark, task );
/* Check and see if task is ready for execution */
pthread_mutex_lock_task( &task->task_mutex );
quark_check_and_queue_ready_task( quark, task, -1 );
pthread_mutex_unlock_task( &task->task_mutex );
/* If conditions are right, task insertion blocks and master
* works; this will return when num_tasks becomes less than
* low_water_mark */
quark_process_completed_tasks(quark);
while ( (quark->high_water_mark>0) && (num_tasks>=quark->high_water_mark) ) {
num_tasks = quark_work_main_loop(quark->worker[0]);
quark_process_completed_tasks(quark);
}
return taskid ;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Quark* QUARK_New ( int  num_threads)

Called by the master thread. Allocate and initialize the scheduler data stuctures and spawn worker threads. Used when this scheduler is to do all the thread management.

Parameters:
[in]num_threadsNumber of threads to be used (1 master and rest compute workers). If num_threads < 1, first try environment variable QUARK_NUM_THREADS or use use num_threads = number of cores
Returns:
Pointer to the QUARK data structure.

Definition at line 869 of file quark.c.

References quark_s::coresbind, pthread_attr_init(), pthread_attr_setscope(), pthread_create(), PTHREAD_SCOPE_SYSTEM, quark_get_affthreads(), quark_get_numthreads(), quark_setaffinity(), QUARK_Setup(), quark_topology_init(), quark_s::thread_attr, worker_s::thread_id, and quark_s::worker.

{
int i, nthrd;
/* Init number of cores and topology */
/* Get number of threads */
if ( num_threads < 1 ) {
if ( nthrd == -1 ) nthrd = 1;
} else {
nthrd = num_threads;
}
/* Create scheduler data structures for master and workers */
Quark *quark = QUARK_Setup(nthrd);
/* Get binding informations */
/* Setup thread attributes */
/* pthread_setconcurrency(quark->num_threads); */
/* Then start the threads, so that workers can scan the structures easily */
for(i = 1; i < nthrd; i++) {
int rc = pthread_create(&quark->worker[i]->thread_id, &quark->thread_attr, (void *(*)(void *))quark_work_set_affinity_and_call_main_loop, quark->worker[i]);
if ( rc != 0 ) quark_fatal_error ( " QUARK_New", "Could not create threads properly" );
}
return quark;
}

Here is the call graph for this function:

int QUARK_Sequence_Cancel ( Quark quark,
Quark_Sequence sequence 
)

Can be called by any thread. Cancels all the remaining tasks in a sequence using QUARK_Cancel_Task and changes the state so that future tasks belonging to that sequence are ignored.

Parameters:
[in,out]quarkPointer to the scheduler data structure
[in,out]sequencePointer to a sequence data structure
Returns:
0 (QUARK_SUCCESS) on success
-1 (QUARK_ERR) on failure

Definition at line 2150 of file quark.c.

References LIST_FOREACH, QUARK_Cancel_Task(), QUARK_ERR, QUARK_SUCCESS, Quark_sequence_s::sequence_mutex, Quark_sequence_s::status, Quark_sequence_s::tasks_in_sequence, and ll_list_node_s::val.

{
int retval;
if ( quark==NULL || sequence==NULL ) return QUARK_ERR;
pthread_mutex_lock_wrap( &sequence->sequence_mutex );
if ( sequence->status != QUARK_SUCCESS ) {
/* sequence already cancelled */
retval = QUARK_SUCCESS;
} else {
sequence->status = QUARK_ERR;
LIST_FOREACH( np, sequence->tasks_in_sequence, ll_entries ) {
long long int taskid = np->val;
/* Find taskid, make function NULL */
QUARK_Cancel_Task( quark, taskid );
/* Task node is removed from sequence when it finishes and is
* deleted; or when sequence is destroyed */
}
retval = QUARK_SUCCESS;
}
pthread_mutex_unlock_wrap( &sequence->sequence_mutex );
return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Quark_Sequence* QUARK_Sequence_Create ( Quark quark)

Called by the control program. Creates a new sequence data structure and returns it. This can be used to put a sequence of tasks into a group and cancel that group if an error condition occurs.

Parameters:
[in]outquark Pointer to the scheduler data structure
Returns:
Pointer to the newly created sequence structure.

Definition at line 2124 of file quark.c.

References DBGPRINTF, LIST_INIT, pthread_mutex_init(), QUARK_SUCCESS, QUARK_Thread_Rank(), worker_s::ready_list_size, Quark_sequence_s::sequence_mutex, Quark_sequence_s::status, Quark_sequence_s::tasks_in_sequence, and quark_s::worker.

{
Quark_Sequence *sequence = quark_malloc(sizeof(Quark_Sequence));
DBGPRINTF("Wkr %d [ %d ] In seq create\n", QUARK_Thread_Rank(quark), quark->worker[0]->ready_list_size );
sequence->status = QUARK_SUCCESS;
pthread_mutex_init( &sequence->sequence_mutex, NULL );
ll_list_head_t *head = quark_malloc(sizeof(ll_list_head_t));
LIST_INIT(head);
sequence->tasks_in_sequence = head;
return sequence;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Quark_Sequence* QUARK_Sequence_Destroy ( Quark quark,
Quark_Sequence sequence 
)

Called by the control program. Cancels all the remaining tasks in a sequence using QUARK_Cancel_Task and deletes the sequence data structure.

Parameters:
[in,out]quarkPointer to the scheduler data structure
[in,out]sequencePointer to a sequence data structure
Returns:
A NULL pointer; which can be used to reset the sequence structure

Definition at line 2187 of file quark.c.

References DBGPRINTF, LIST_EMPTY, pthread_mutex_destroy(), QUARK_Sequence_Cancel(), QUARK_Sequence_Wait(), QUARK_SUCCESS, QUARK_Thread_Rank(), worker_s::ready_list_size, Quark_sequence_s::sequence_mutex, Quark_sequence_s::tasks_in_sequence, and quark_s::worker.

{
DBGPRINTF("Wkr %d [ %d ] In seq destroy \n", QUARK_Thread_Rank(quark), quark->worker[0]->ready_list_size );
if ( quark==NULL || sequence==NULL ) return NULL;
if ( !LIST_EMPTY( sequence->tasks_in_sequence )) {
if ( QUARK_Sequence_Cancel( quark, sequence ) != QUARK_SUCCESS ) return NULL;
if ( QUARK_Sequence_Wait( quark, sequence ) != QUARK_SUCCESS ) return NULL;
}
/* Dont need to remove tasks in sequence, should have been removed by sequence_wait */
free( sequence->tasks_in_sequence );
sequence->tasks_in_sequence = NULL;
free( sequence );
return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int QUARK_Sequence_Wait ( Quark quark,
Quark_Sequence sequence 
)

Called by the control program. Returns when all the tasks in a sequence have completed.

Parameters:
[in,out]quarkPointer to the scheduler data structure
[in,out]sequencePointer to a sequence structure
Returns:
0 on success
-1 on failure

Definition at line 2216 of file quark.c.

References LIST_EMPTY, QUARK_ERR, QUARK_SUCCESS, QUARK_Thread_Rank(), Quark_sequence_s::tasks_in_sequence, and quark_s::worker.

{
if ( quark==NULL || sequence==NULL) return QUARK_ERR;
int myrank = QUARK_Thread_Rank( quark );
while ( !LIST_EMPTY( sequence->tasks_in_sequence ) ) {
quark_process_completed_tasks( quark );
quark_work_main_loop( quark->worker[myrank] );
}
return QUARK_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Quark* QUARK_Setup ( int  num_threads)

Called by the master thread. This routine does not do thread management, so it can be used with a larger libarary. Allocate and initialize the scheduler data stuctures for the master and num_threads worker threads.

Parameters:
[in]num_threadsNumber of threads to be used (1 master and rest compute workers).
Returns:
Pointer to the QUARK scheduler data structure.

Definition at line 803 of file quark.c.

References quark_s::address_set, quark_s::address_set_mutex, quark_s::all_tasks_queued, quark_s::completed_tasks, quark_s::completed_tasks_mutex, quark_s::completed_tasks_size, quark_s::dot_dag_enable, quark_s::dot_dag_was_setup, FALSE, quark_s::high_water_mark, icl_hash_create(), quark_s::list_robin, quark_s::low_water_mark, quark_s::num_queued_tasks, quark_s::num_queued_tasks_cond, quark_s::num_queued_tasks_mutex, quark_s::num_tasks, quark_s::num_threads, pthread_cond_init(), pthread_mutex_init(), pthread_self(), QUARK_DOT_DAG_Enable(), quark_getenv_int(), quark_s::quark_mutex, quark_s::queue_before_computing, quark_s::start, TAILQ_INIT, quark_s::task_set, quark_s::task_set_mutex, worker_s::thread_id, TRUE, quark_s::war_dependencies_enable, and quark_s::worker.

{
int i = 0;
Quark *quark = (Quark *) quark_malloc(sizeof(Quark));
/* Used to tell master when to act as worker */
int quark_unroll_tasks_per_thread = quark_getenv_int("QUARK_UNROLL_TASKS_PER_THREAD", 50);
int quark_unroll_tasks = quark_getenv_int("QUARK_UNROLL_TASKS", quark_unroll_tasks_per_thread * num_threads);
quark->war_dependencies_enable = quark_getenv_int("QUARK_WAR_DEPENDENCIES_ENABLE", 0);
quark->queue_before_computing = quark_getenv_int("QUARK_QUEUE_BEFORE_COMPUTING", 0);
quark->dot_dag_enable = quark_getenv_int("QUARK_DOT_DAG_ENABLE", 0);
//if ( quark->dot_dag_enable ) quark->queue_before_computing = 1;
if ( quark->queue_before_computing==1 || quark_unroll_tasks==0 ) {
quark->high_water_mark = (int)(INT_MAX - 1);
quark->low_water_mark = (int)(quark->high_water_mark);
} else {
quark->low_water_mark = (int)(quark_unroll_tasks);
quark->high_water_mark = (int)(quark->low_water_mark + quark->low_water_mark*0.25);
}
quark->num_queued_tasks = 0;
quark->num_threads = num_threads;
quark->list_robin = 0;
pthread_mutex_init( &quark->quark_mutex, NULL );
quark->start = FALSE;
quark->num_tasks = 0;
quark->task_set = icl_hash_create( 0x1<<12, ullong_hash_function, ullong_key_compare );
/* Create hash table to hold addresses */
quark->address_set = icl_hash_create( 0x01<<12, address_hash_function, address_key_compare);
/* To handle completed tasks */
quark->completed_tasks = quark_malloc(sizeof(completed_tasks_head_t));
/* Setup workers */
quark->worker = (Worker **) quark_malloc(num_threads * sizeof(Worker *));
/* The structure for the 0th worker will be used by the master */
quark->worker[0] = quark_worker_new(quark, 0);
quark->worker[0]->thread_id = pthread_self();
quark->dot_dag_was_setup = 0;
if ( quark->dot_dag_enable ) QUARK_DOT_DAG_Enable( quark, 1 );
/* Launch workers; first create the structures */
for(i = 1; i < num_threads; i++)
quark->worker[i] = quark_worker_new(quark, i);
/* Threads can start as soon as they want */
quark->start = TRUE;
return quark;
}

Here is the call graph for this function:

Here is the caller graph for this function:

intptr_t QUARK_Task_Flag_Get ( Quark quark,
int  flag 
)

Get the value of various task level flags. Each returned value can be either an integer or a pointer (intptr type).

     Select from one of the flags:
     TASK_PRIORITY : an integer (0-MAX_INT)
     TASK_LOCK_TO_THREAD : an integer for the thread number
     TASK_LOCK_TO_THREAD_MASK : a pointer to a bitmask where task can run
     TASK_LABEL : a string pointer (NULL terminated) for the label
     TASK_COLOR :  a string pointer (NULL terminated) for the color.
     TASK_SEQUENCE : pointer to a Quark_Sequence structure
     THREAD_SET_TO_MANUAL_SCHEDULING: boolean integer {0,1} setting thread to manual (1) or automatic (0) scheduling
Parameters:
[in]flagOne of the flags shown above.
Returns:
Intptr type giving the value of the flag; -9 on error

Definition at line 2541 of file quark.c.

References worker_s::current_task_ptr, quark_task_s::lock_to_thread, quark_task_s::lock_to_thread_mask, quark_task_s::priority, QUARK_Thread_Rank(), quark_task_s::sequence, TASK_COLOR, quark_task_s::task_color, TASK_LABEL, quark_task_s::task_label, TASK_LOCK_TO_THREAD, TASK_LOCK_TO_THREAD_MASK, TASK_PRIORITY, TASK_SEQUENCE, TASK_THREAD_COUNT, quark_task_s::task_thread_count, THREAD_SET_TO_MANUAL_SCHEDULING, quark_task_s::thread_set_to_manual_scheduling, and quark_s::worker.

{
Task *task = quark->worker[QUARK_Thread_Rank(quark)]->current_task_ptr;
switch (flag) {
return (intptr_t)task->priority;
break;
return (intptr_t)task->lock_to_thread;
break;
return (intptr_t)task->lock_to_thread_mask;
break;
case TASK_LABEL:
return (intptr_t)task->task_label;
break;
case TASK_COLOR:
return (intptr_t)task->task_color;
break;
return (intptr_t)task->sequence;
break;
return (intptr_t)task->task_thread_count;
break;
return (intptr_t)task->thread_set_to_manual_scheduling;
break;
default:
return -9;
break;
}
}

Here is the call graph for this function:

Quark_Task_Flags* QUARK_Task_Flag_Set ( Quark_Task_Flags task_flags,
int  flag,
intptr_t  val 
)

Set various task level flags. This flag data structure is then provided when the task is created/inserted. Each flag can take a value which is either an integer or a pointer.

     Select from one of the flags:
     TASK_PRIORITY : an integer (0-MAX_INT)
     TASK_LOCK_TO_THREAD : an integer for the thread number
     TASK_LOCK_TO_THREAD_MASK : a pointer to a bitmask where task can run
     TASK_LABEL : a string pointer (NULL terminated) for the label
     TASK_COLOR :  a string pointer (NULL terminated) for the color.
     TASK_SEQUENCE : takes pointer to a Quark_Sequence structure
     THREAD_SET_TO_MANUAL_SCHEDULING: boolean integer {0,1} setting thread to manual (1) or automatic (0) scheduling
Parameters:
[in,out]flagsPointer to a Quark_Task_Flags structure
[in]flagOne of the flags listed above
[in]valA integer or a pointer value for the flag ( uses the intptr_t )
Returns:
Pointer to the updated Quark_Task_Flags structure

Definition at line 2491 of file quark.c.

References TASK_COLOR, quark_task_flags_s::task_color, TASK_LABEL, quark_task_flags_s::task_label, TASK_LOCK_TO_THREAD, quark_task_flags_s::task_lock_to_thread, TASK_LOCK_TO_THREAD_MASK, quark_task_flags_s::task_lock_to_thread_mask, TASK_PRIORITY, quark_task_flags_s::task_priority, TASK_SEQUENCE, quark_task_flags_s::task_sequence, TASK_THREAD_COUNT, quark_task_flags_s::task_thread_count, THREAD_SET_TO_MANUAL_SCHEDULING, and quark_task_flags_s::thread_set_to_manual_scheduling.

{
switch (flag) {
task_flags->task_priority = (int)val;
break;
task_flags->task_lock_to_thread = (int)val;
break;
task_flags->task_lock_to_thread_mask = (unsigned char *)val;
break;
case TASK_LABEL:
task_flags->task_label = (char *)val;
break;
case TASK_COLOR:
task_flags->task_color = (char *)val;
break;
task_flags->task_sequence = (Quark_Sequence *)val;
break;
task_flags->task_thread_count = (int)val;
break;
task_flags->thread_set_to_manual_scheduling = (int)val;
break;
}
return task_flags;
}
Task* QUARK_Task_Init ( Quark quark,
void(*)(Quark *)  function,
Quark_Task_Flags task_flags 
)

Called by the master thread. This is used in argument packing, to create an initial task data structure. Arguments can be packed into this structure, and it can be submitted later.

Parameters:
[in,out]quarkThe scheduler's main data structure.
[in]functionThe function (task) to be executed by the scheduler
[in]task_flagsFlags to specify task behavior

Definition at line 1060 of file quark.c.

References quark_task_s::function, and quark_set_task_flags_in_task_structure().

{
Task *task = quark_task_new();
task->function = function;
quark_set_task_flags_in_task_structure( quark, task, task_flags );
return task;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void QUARK_Task_Pack_Arg ( Quark quark,
Task task,
int  arg_size,
void *  arg_ptr,
int  arg_flags 
)

Called by the master thread. This is used in argument packing, to pack/add arguments to a task data structure.

Parameters:
[in,out]quarkThe scheduler's main data structure.
[in,out]taskThe task data struture to hold the arguments
[in]arg_sizeSize of the argument in bytes (0 cannot be used here)
[in]arg_ptrPointer to data or argument
[in]arg_flagsFlags indicating argument usage and various decorators INPUT, OUTPUT, INOUT, VALUE, NODEP, SCRATCH LOCALITY, ACCUMULATOR, GATHERV TASK_COLOR, TASK_LABEL (special decorators for VALUE) e.g., arg_flags INPUT | LOCALITY | ACCUMULATOR e.g., arg_flags VALUE | TASK_COLOR

Definition at line 1090 of file quark.c.

References ACCUMULATOR, dependency_s::address, quark_task_s::args_list, icl_list_s::data, quark_task_s::dependency_list, quark_s::dot_dag_enable, GATHERV, icl_list_append(), icl_list_insert(), icl_list_last(), icl_list_prev(), INOUT, INPUT, LOCALITY, quark_task_s::lock_to_thread, NODEP, quark_task_s::num_dependencies_remaining, OUTPUT, quark_task_s::priority, QUARK_DIRECTION_BITMASK, QUARK_REGION_ALL, QUARK_REGION_BITMASK, QUARK_VALUE_FLAGS_BITMASK, SCRATCH, quark_task_s::scratch_list, quark_task_s::sequence, TASK_COLOR, quark_task_s::task_color, dependency_s::task_dependency_list_node_ptr, TASK_LABEL, quark_task_s::task_label, TASK_LOCK_TO_THREAD, TASK_PRIORITY, TASK_SEQUENCE, TASK_THREAD_COUNT, quark_task_s::task_thread_count, THREAD_SET_TO_MANUAL_SCHEDULING, quark_task_s::thread_set_to_manual_scheduling, and VALUE.

{
int value_mask;
bool arg_locality, accumulator, gatherv;
int data_region;
icl_list_t *task_args_list_node_ptr;
Scratch *scratcharg;
// extract information from the flags
switch ( arg_direction ) {
case VALUE:
/* If argument is a value; Copy the contents to the argument buffer */
value_mask = ( arg_flags & QUARK_VALUE_FLAGS_BITMASK );
if ( value_mask==0 ) {
icl_list_append(task->args_list, arg_dup(arg_ptr, arg_size));
} else if ( (arg_flags & TASK_PRIORITY) != 0 ) {
task->priority = *((int *)arg_ptr);
} else if ( (arg_flags & TASK_LOCK_TO_THREAD) != 0 ) {
task->lock_to_thread = *((int *)arg_ptr);
} else if ( (arg_flags & TASK_THREAD_COUNT) != 0 ) {
task->task_thread_count = *((int *)arg_ptr);
} else if ( (arg_flags & TASK_SEQUENCE) != 0 ) {
task->sequence = *((Quark_Sequence **)arg_ptr);
} else if ( (arg_flags & THREAD_SET_TO_MANUAL_SCHEDULING) != 0 ) {
task->thread_set_to_manual_scheduling = *((int *)arg_ptr);
} else if ( (arg_flags & TASK_COLOR) != 0 ) {
if ( quark->dot_dag_enable ) {
task->task_color = arg_dup(arg_ptr, arg_size);
}
} else if ( (arg_flags & TASK_LABEL) != 0 ) {
if ( quark->dot_dag_enable ) {
task->task_label = arg_dup(arg_ptr, arg_size) ;
}
}
break;
case NODEP:
icl_list_append(task->args_list, arg_dup((char *) &arg_ptr, sizeof(char *)));
break;
case SCRATCH:
task_args_list_node_ptr = icl_list_append(task->args_list, arg_dup((char *) &arg_ptr, sizeof(char *)));
scratcharg = quark_scratch_new( arg_ptr, arg_size, task_args_list_node_ptr);
icl_list_append( task->scratch_list, scratcharg );
break;
case INPUT:
case OUTPUT:
case INOUT:
default:
task_args_list_node_ptr = icl_list_append(task->args_list, arg_dup((char *) &arg_ptr, sizeof(char *)));
arg_locality = (bool) ((arg_flags & LOCALITY) != 0 );
accumulator = (bool) ((arg_flags & ACCUMULATOR) != 0 );
gatherv = (bool) ((arg_flags & GATHERV) != 0 );
if ( (arg_flags & QUARK_REGION_BITMASK) != 0 )
data_region = (arg_flags & QUARK_REGION_BITMASK);
else
data_region = QUARK_REGION_ALL;
// DBGPRINTF("Adding dependency arg_flags %x arg_direction %d data_region %x\n", arg_flags, arg_direction, data_region);
Dependency *dep = dependency_new(arg_ptr, arg_size, arg_direction, arg_locality, task, accumulator, gatherv, data_region, task_args_list_node_ptr);
/* Insert dependency in order of address; uses simple resource ordering to avoid deadlock situations */
icl_list_t *ptr = NULL;
icl_list_t *task_dependency_list_node_ptr = NULL;
for (ptr = icl_list_last(task->dependency_list); ptr != NULL; ptr = icl_list_prev(task->dependency_list, ptr)) {
Dependency *ptrdep = (Dependency *)ptr->data;
if (ptrdep->address > dep->address ) {
task_dependency_list_node_ptr = icl_list_insert( task->dependency_list, ptr, dep );
break;
}
}
if ( ptr==NULL) task_dependency_list_node_ptr = icl_list_append( task->dependency_list, dep );
dep->task_dependency_list_node_ptr = task_dependency_list_node_ptr;
break;
}
}

Here is the call graph for this function:

Here is the caller graph for this function:

int QUARK_Thread_Rank ( Quark quark)

Return the rank of a thread.

Parameters:
[in]quarkThe scheduler's main data structure.
Returns:
The rank of the calling thread

Definition at line 504 of file quark.c.

References quark_s::num_threads, pthread_equal(), pthread_self(), worker_s::thread_id, and quark_s::worker.

{
pthread_t self_id = pthread_self();
int i;
for (i=0; i<quark->num_threads; i++)
if (pthread_equal(quark->worker[i]->thread_id, self_id))
return i;
return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void QUARK_Waitall ( Quark quark)

Called by the master thread. Wait for all the tasks to be completed, then return. The worker tasks will also exit from their work loop at this time.

Parameters:
[in,out]quarkThe scheduler's main data structure.

Definition at line 954 of file quark.c.

References DBGPRINTF, worker_s::finalize, quark_s::num_queued_tasks_mutex, quark_s::num_threads, quark_atomic_set, QUARK_Barrier(), worker_s::rank, worker_s::ready_list_size, TRUE, quark_s::worker, worker_s::worker_must_awake_cond, and worker_s::worker_mutex.

{
int i;
Worker *worker;
QUARK_Barrier( quark );
/* Tell each worker to exit the work_loop; master handles himself */
for (i=1; i<quark->num_threads; i++) {
worker = quark->worker[i];
DBGPRINTF("Wkr %d [ %d ] setting finalize\n", worker->rank, worker->ready_list_size );
quark_atomic_set( worker->finalize, TRUE, &worker->worker_mutex );
}
pthread_mutex_lock_wrap( &quark->num_queued_tasks_mutex );
for (i=0; i<quark->num_threads; i++)
pthread_cond_signal( &quark->worker[i]->worker_must_awake_cond );
pthread_mutex_unlock_wrap( &quark->num_queued_tasks_mutex );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void QUARK_Worker_Loop ( Quark quark,
int  thread_rank 
)

This function is called by a thread when it wants to start working. This is used in a system that does its own thread management, so each worker thread in that system must call this routine to get the worker to participate in computation.

Parameters:
[in,out]quarkThe main data structure.
[in]thread_rankThe rank of the thread.

Definition at line 1898 of file quark.c.

References pthread_self(), worker_s::thread_id, and quark_s::worker.

{
quark->worker[thread_rank]->thread_id = pthread_self();
quark_work_main_loop( quark->worker[thread_rank] );
}

Here is the call graph for this function:

Here is the caller graph for this function: