|
@@ -146,6 +146,15 @@ int _starpu_test_job_termination(struct _starpu_job *j)
|
|
STARPU_ASSERT(!j->task->detach);
|
|
STARPU_ASSERT(!j->task->detach);
|
|
return (j->terminated == 2);
|
|
return (j->terminated == 2);
|
|
}
|
|
}
|
|
|
|
+/* Prepare a currently running job for accepting a new set of
|
|
|
|
+ * dependencies in anticipation of becoming a continuation. */
|
|
|
|
+void _starpu_job_prepare_for_continuation(struct _starpu_job *j)
|
|
|
|
+{
|
|
|
|
+ STARPU_ASSERT(!j->continuation);
|
|
|
|
+ /* continuation are not supported for parallel tasks for now */
|
|
|
|
+ STARPU_ASSERT(j->task_size == 1);
|
|
|
|
+ j->continuation = 1;
|
|
|
|
+}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
@@ -153,15 +162,31 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
struct starpu_task *task = j->task;
|
|
struct starpu_task *task = j->task;
|
|
unsigned sched_ctx = task->sched_ctx;
|
|
unsigned sched_ctx = task->sched_ctx;
|
|
double flops = task->flops;
|
|
double flops = task->flops;
|
|
- STARPU_PTHREAD_MUTEX_LOCK(&j->sync_mutex);
|
|
|
|
|
|
+ const unsigned continuation =
|
|
|
|
+#ifdef STARPU_OPENMP
|
|
|
|
+ j->continuation
|
|
|
|
+#else
|
|
|
|
+ 0
|
|
|
|
+#endif
|
|
|
|
+ ;
|
|
|
|
|
|
- task->status = STARPU_TASK_FINISHED;
|
|
|
|
|
|
+ STARPU_PTHREAD_MUTEX_LOCK(&j->sync_mutex);
|
|
|
|
+#ifdef STARPU_OPENMP
|
|
|
|
+ if (continuation)
|
|
|
|
+ {
|
|
|
|
+ task->status = STARPU_TASK_STOPPED;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+#endif
|
|
|
|
+ {
|
|
|
|
+ task->status = STARPU_TASK_FINISHED;
|
|
|
|
|
|
- /* We must have set the j->terminated flag early, so that it is
|
|
|
|
- * possible to express task dependencies within the callback
|
|
|
|
- * function. A value of 1 means that the codelet was executed but that
|
|
|
|
- * the callback is not done yet. */
|
|
|
|
- j->terminated = 1;
|
|
|
|
|
|
+ /* We must have set the j->terminated flag early, so that it is
|
|
|
|
+ * possible to express task dependencies within the callback
|
|
|
|
+ * function. A value of 1 means that the codelet was executed but that
|
|
|
|
+ * the callback is not done yet. */
|
|
|
|
+ j->terminated = 1;
|
|
|
|
+ }
|
|
|
|
|
|
STARPU_PTHREAD_MUTEX_UNLOCK(&j->sync_mutex);
|
|
STARPU_PTHREAD_MUTEX_UNLOCK(&j->sync_mutex);
|
|
|
|
|
|
@@ -178,7 +203,7 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
#endif //STARPU_USE_SC_HYPERVISOR
|
|
#endif //STARPU_USE_SC_HYPERVISOR
|
|
|
|
|
|
/* We release handle reference count */
|
|
/* We release handle reference count */
|
|
- if (task->cl)
|
|
|
|
|
|
+ if (task->cl && !continuation)
|
|
{
|
|
{
|
|
unsigned i;
|
|
unsigned i;
|
|
for (i=0; i<task->cl->nbuffers; i++)
|
|
for (i=0; i<task->cl->nbuffers; i++)
|
|
@@ -190,14 +215,23 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
_starpu_spin_unlock(&handle->header_lock);
|
|
_starpu_spin_unlock(&handle->header_lock);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- /* Tell other tasks that we don't exist any more, thus no need for
|
|
|
|
- * implicit dependencies any more. */
|
|
|
|
- _starpu_release_task_enforce_sequential_consistency(j);
|
|
|
|
|
|
+ /* If this is a continuation, we do not release task dependencies now.
|
|
|
|
+ * Task dependencies will be released only when the continued task
|
|
|
|
+ * fully completes */
|
|
|
|
+ if (!continuation)
|
|
|
|
+ {
|
|
|
|
+ /* Tell other tasks that we don't exist any more, thus no need for
|
|
|
|
+ * implicit dependencies any more. */
|
|
|
|
+ _starpu_release_task_enforce_sequential_consistency(j);
|
|
|
|
+ }
|
|
/* Task does not have a cl, but has explicit data dependencies, we need
|
|
/* Task does not have a cl, but has explicit data dependencies, we need
|
|
* to tell them that we will not exist any more before notifying the
|
|
* to tell them that we will not exist any more before notifying the
|
|
- * tasks waiting for us */
|
|
|
|
- if (j->implicit_dep_handle) {
|
|
|
|
|
|
+ * tasks waiting for us
|
|
|
|
+ *
|
|
|
|
+ * For continuations, implicit dependency handles are only released
|
|
|
|
+ * when the task fully completes */
|
|
|
|
+ if (j->implicit_dep_handle && !continuation)
|
|
|
|
+ {
|
|
starpu_data_handle_t handle = j->implicit_dep_handle;
|
|
starpu_data_handle_t handle = j->implicit_dep_handle;
|
|
_starpu_release_data_enforce_sequential_consistency(j->task, handle);
|
|
_starpu_release_data_enforce_sequential_consistency(j->task, handle);
|
|
/* Release reference taken while setting implicit_dep_handle */
|
|
/* Release reference taken while setting implicit_dep_handle */
|
|
@@ -207,46 +241,68 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
_starpu_spin_unlock(&handle->header_lock);
|
|
_starpu_spin_unlock(&handle->header_lock);
|
|
}
|
|
}
|
|
|
|
|
|
- /* in case there are dependencies, wake up the proper tasks */
|
|
|
|
- _starpu_notify_dependencies(j);
|
|
|
|
|
|
+ /* If this is a continuation, we do not notify task/tag dependencies
|
|
|
|
+ * now. Task/tag dependencies will be notified only when the continued
|
|
|
|
+ * task fully completes */
|
|
|
|
+ if (!continuation)
|
|
|
|
+ {
|
|
|
|
+ /* in case there are dependencies, wake up the proper tasks */
|
|
|
|
+ _starpu_notify_dependencies(j);
|
|
|
|
+ }
|
|
|
|
|
|
- /* the callback is executed after the dependencies so that we may remove the tag
|
|
|
|
- * of the task itself */
|
|
|
|
- if (task->callback_func)
|
|
|
|
|
|
+ /* If this is a continuation, we do not execute the callback
|
|
|
|
+ * now. The callback will be executed only when the continued
|
|
|
|
+ * task fully completes */
|
|
|
|
+ if (!continuation)
|
|
{
|
|
{
|
|
- int profiling = starpu_profiling_status_get();
|
|
|
|
- if (profiling && task->profiling_info)
|
|
|
|
- _starpu_clock_gettime(&task->profiling_info->callback_start_time);
|
|
|
|
|
|
+ /* the callback is executed after the dependencies so that we may remove the tag
|
|
|
|
+ * of the task itself */
|
|
|
|
+ if (task->callback_func)
|
|
|
|
+ {
|
|
|
|
+ int profiling = starpu_profiling_status_get();
|
|
|
|
+ if (profiling && task->profiling_info)
|
|
|
|
+ _starpu_clock_gettime(&task->profiling_info->callback_start_time);
|
|
|
|
|
|
- /* so that we can check whether we are doing blocking calls
|
|
|
|
- * within the callback */
|
|
|
|
- _starpu_set_local_worker_status(STATUS_CALLBACK);
|
|
|
|
|
|
+ /* so that we can check whether we are doing blocking calls
|
|
|
|
+ * within the callback */
|
|
|
|
+ _starpu_set_local_worker_status(STATUS_CALLBACK);
|
|
|
|
|
|
|
|
|
|
- /* Perhaps we have nested callbacks (eg. with chains of empty
|
|
|
|
- * tasks). So we store the current task and we will restore it
|
|
|
|
- * later. */
|
|
|
|
- struct starpu_task *current_task = starpu_task_get_current();
|
|
|
|
|
|
+ /* Perhaps we have nested callbacks (eg. with chains of empty
|
|
|
|
+ * tasks). So we store the current task and we will restore it
|
|
|
|
+ * later. */
|
|
|
|
+ struct starpu_task *current_task = starpu_task_get_current();
|
|
|
|
|
|
- _starpu_set_current_task(task);
|
|
|
|
|
|
+ _starpu_set_current_task(task);
|
|
|
|
|
|
- _STARPU_TRACE_START_CALLBACK(j);
|
|
|
|
- task->callback_func(task->callback_arg);
|
|
|
|
- _STARPU_TRACE_END_CALLBACK(j);
|
|
|
|
|
|
+ _STARPU_TRACE_START_CALLBACK(j);
|
|
|
|
+ task->callback_func(task->callback_arg);
|
|
|
|
+ _STARPU_TRACE_END_CALLBACK(j);
|
|
|
|
|
|
- _starpu_set_current_task(current_task);
|
|
|
|
|
|
+ _starpu_set_current_task(current_task);
|
|
|
|
|
|
- _starpu_set_local_worker_status(STATUS_UNKNOWN);
|
|
|
|
|
|
+ _starpu_set_local_worker_status(STATUS_UNKNOWN);
|
|
|
|
|
|
- if (profiling && task->profiling_info)
|
|
|
|
- _starpu_clock_gettime(&task->profiling_info->callback_end_time);
|
|
|
|
|
|
+ if (profiling && task->profiling_info)
|
|
|
|
+ _starpu_clock_gettime(&task->profiling_info->callback_end_time);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* If the job was executed on a combined worker there is no need for the
|
|
/* If the job was executed on a combined worker there is no need for the
|
|
* scheduler to process it : the task structure doesn't contain any valuable
|
|
* scheduler to process it : the task structure doesn't contain any valuable
|
|
* data as it's not linked to an actual worker */
|
|
* data as it's not linked to an actual worker */
|
|
/* control task should not execute post_exec_hook */
|
|
/* control task should not execute post_exec_hook */
|
|
- if(j->task_size == 1 && task->cl != NULL && !j->internal)
|
|
|
|
|
|
+ if(j->task_size == 1 && task->cl != NULL && !j->internal
|
|
|
|
+#ifdef STARPU_OPENMP
|
|
|
|
+ /* If this is a continuation, we do not execute the post_exec_hook. The
|
|
|
|
+ * post_exec_hook will be run only when the continued task fully
|
|
|
|
+ * completes.
|
|
|
|
+ *
|
|
|
|
+ * Note: If needed, a specific hook could be added to handle stopped
|
|
|
|
+ * tasks */
|
|
|
|
+ && !continuation
|
|
|
|
+#endif
|
|
|
|
+ )
|
|
{
|
|
{
|
|
_starpu_sched_post_exec_hook(task);
|
|
_starpu_sched_post_exec_hook(task);
|
|
#ifdef STARPU_USE_SC_HYPERVISOR
|
|
#ifdef STARPU_USE_SC_HYPERVISOR
|
|
@@ -255,6 +311,9 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Note: For now, we keep the TASK_DONE trace event for continuation,
|
|
|
|
+ * however we could add a specific event for stopped tasks if needed.
|
|
|
|
+ */
|
|
_STARPU_TRACE_TASK_DONE(j);
|
|
_STARPU_TRACE_TASK_DONE(j);
|
|
|
|
|
|
/* NB: we do not save those values before the callback, in case the
|
|
/* NB: we do not save those values before the callback, in case the
|
|
@@ -267,9 +326,12 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
/* we do not desallocate the job structure if some is going to
|
|
/* we do not desallocate the job structure if some is going to
|
|
* wait after the task */
|
|
* wait after the task */
|
|
STARPU_PTHREAD_MUTEX_LOCK(&j->sync_mutex);
|
|
STARPU_PTHREAD_MUTEX_LOCK(&j->sync_mutex);
|
|
- /* A value of 2 is put to specify that not only the codelet but
|
|
|
|
- * also the callback were executed. */
|
|
|
|
- j->terminated = 2;
|
|
|
|
|
|
+ if (!continuation)
|
|
|
|
+ {
|
|
|
|
+ /* A value of 2 is put to specify that not only the codelet but
|
|
|
|
+ * also the callback were executed. */
|
|
|
|
+ j->terminated = 2;
|
|
|
|
+ }
|
|
STARPU_PTHREAD_COND_BROADCAST(&j->sync_cond);
|
|
STARPU_PTHREAD_COND_BROADCAST(&j->sync_cond);
|
|
|
|
|
|
#ifdef HAVE_AYUDAME_H
|
|
#ifdef HAVE_AYUDAME_H
|
|
@@ -278,7 +340,7 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
|
|
|
|
STARPU_PTHREAD_MUTEX_UNLOCK(&j->sync_mutex);
|
|
STARPU_PTHREAD_MUTEX_UNLOCK(&j->sync_mutex);
|
|
|
|
|
|
- if (detach)
|
|
|
|
|
|
+ if (detach && !continuation)
|
|
{
|
|
{
|
|
/* no one is going to synchronize with that task so we release
|
|
/* no one is going to synchronize with that task so we release
|
|
* the data structures now. In case the job was already locked
|
|
* the data structures now. In case the job was already locked
|
|
@@ -288,9 +350,12 @@ void _starpu_handle_job_termination(struct _starpu_job *j)
|
|
_starpu_task_destroy(task);
|
|
_starpu_task_destroy(task);
|
|
}
|
|
}
|
|
|
|
|
|
- if (regenerate)
|
|
|
|
|
|
+ /* A continuation is not much different from a regenerated task. */
|
|
|
|
+ if (regenerate || continuation)
|
|
{
|
|
{
|
|
- STARPU_ASSERT_MSG(detach && !destroy && !task->synchronous, "Regenerated task must be detached (was %d), and not have detroy=1 (was %d) or synchronous=1 (was %d)", detach, destroy, task->synchronous);
|
|
|
|
|
|
+ STARPU_ASSERT_MSG((detach && !destroy && !task->synchronous)
|
|
|
|
+ || continuation
|
|
|
|
+ , "Regenerated task must be detached (was %d), and not have detroy=1 (was %d) or synchronous=1 (was %d)", detach, destroy, task->synchronous);
|
|
|
|
|
|
#ifdef HAVE_AYUDAME_H
|
|
#ifdef HAVE_AYUDAME_H
|
|
if (AYU_event)
|
|
if (AYU_event)
|
|
@@ -450,6 +515,29 @@ unsigned _starpu_enforce_deps_starting_from_task(struct _starpu_job *j)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef STARPU_OPENMP
|
|
|
|
+/* When waking up a continuation, we only enforce new task dependencies */
|
|
|
|
+unsigned _starpu_reenforce_task_deps_and_schedule(struct _starpu_job *j)
|
|
|
|
+{
|
|
|
|
+ unsigned ret;
|
|
|
|
+ _STARPU_LOG_IN();
|
|
|
|
+ STARPU_ASSERT(j->discontinuous);
|
|
|
|
+
|
|
|
|
+ /* enfore task dependencies */
|
|
|
|
+ if (_starpu_not_all_task_deps_are_fulfilled(j))
|
|
|
|
+ {
|
|
|
|
+ STARPU_PTHREAD_MUTEX_UNLOCK(&j->sync_mutex);
|
|
|
|
+ _STARPU_LOG_OUT_TAG("not_all_task_deps_are_fulfilled");
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ STARPU_PTHREAD_MUTEX_UNLOCK(&j->sync_mutex);
|
|
|
|
+ ret = _starpu_push_task(j);
|
|
|
|
+
|
|
|
|
+ _STARPU_LOG_OUT();
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
/* This function must be called with worker->sched_mutex taken */
|
|
/* This function must be called with worker->sched_mutex taken */
|
|
struct starpu_task *_starpu_pop_local_task(struct _starpu_worker *worker)
|
|
struct starpu_task *_starpu_pop_local_task(struct _starpu_worker *worker)
|
|
{
|
|
{
|