|
@@ -2,6 +2,7 @@
|
|
|
*
|
|
|
* Copyright (C) 2011 Université de Bordeaux 1
|
|
|
* Copyright (C) 2011 Télécom-SudParis
|
|
|
+ * Copyright (C) 2012 Inria
|
|
|
*
|
|
|
* StarPU is free software; you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
@@ -30,6 +31,8 @@ void starpu_task_bundle_create(starpu_task_bundle_t *bundle)
|
|
|
STARPU_ASSERT(*bundle);
|
|
|
|
|
|
_STARPU_PTHREAD_MUTEX_INIT(&(*bundle)->mutex, NULL);
|
|
|
+ /* Of course at the beginning a bundle is open,
|
|
|
+ * user can insert and remove tasks from it */
|
|
|
(*bundle)->closed = 0;
|
|
|
|
|
|
/* Start with an empty list */
|
|
@@ -37,38 +40,20 @@ void starpu_task_bundle_create(starpu_task_bundle_t *bundle)
|
|
|
|
|
|
}
|
|
|
|
|
|
-/* Deinitialize a bundle. In case the destroy flag is set, the bundle structure
|
|
|
- * is freed too. */
|
|
|
-void starpu_task_bundle_destroy(starpu_task_bundle_t bundle)
|
|
|
-{
|
|
|
- /* Remove all entries from the bundle (which is likely to be empty) */
|
|
|
- while (bundle->list)
|
|
|
- {
|
|
|
- struct _starpu_task_bundle_entry *entry = bundle->list;
|
|
|
- bundle->list = bundle->list->next;
|
|
|
- free(entry);
|
|
|
- }
|
|
|
-
|
|
|
- _STARPU_PTHREAD_MUTEX_DESTROY(&bundle->mutex);
|
|
|
-
|
|
|
- free(bundle);
|
|
|
-}
|
|
|
-
|
|
|
-/* Insert a task into a bundle. */
|
|
|
int starpu_task_bundle_insert(starpu_task_bundle_t bundle, struct starpu_task *task)
|
|
|
{
|
|
|
_STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
|
|
|
|
|
|
if (bundle->closed)
|
|
|
{
|
|
|
- /* The bundle is closed, we cannot add tasks anymore */
|
|
|
+ /* The bundle is closed, we cannot add task anymore */
|
|
|
_STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
return -EPERM;
|
|
|
}
|
|
|
|
|
|
if (task->status != STARPU_TASK_INVALID)
|
|
|
{
|
|
|
- /* the task has already been submitted, it's too late to put it
|
|
|
+ /* The task has already been submitted, it's too late to put it
|
|
|
* into a bundle now. */
|
|
|
_STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
return -EINVAL;
|
|
@@ -95,16 +80,13 @@ int starpu_task_bundle_insert(starpu_task_bundle_t bundle, struct starpu_task *t
|
|
|
item->next = entry;
|
|
|
}
|
|
|
|
|
|
+ /* Mark the task as belonging the bundle */
|
|
|
task->bundle = bundle;
|
|
|
|
|
|
_STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* Remove a task from a bundle. This method must be called with bundle->mutex
|
|
|
- * hold. This function returns 0 if the task was found, -ENOENT if the element
|
|
|
- * was not found, 1 if the element is found and if the list was deinitialized
|
|
|
- * because it was locked and became empty. */
|
|
|
int starpu_task_bundle_remove(starpu_task_bundle_t bundle, struct starpu_task *task)
|
|
|
{
|
|
|
struct _starpu_task_bundle_entry *item;
|
|
@@ -113,6 +95,8 @@ int starpu_task_bundle_remove(starpu_task_bundle_t bundle, struct starpu_task *t
|
|
|
|
|
|
item = bundle->list;
|
|
|
|
|
|
+ /* List is empty, there is no way the task
|
|
|
+ * belong to it */
|
|
|
if (!item)
|
|
|
{
|
|
|
_STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
@@ -132,7 +116,7 @@ int starpu_task_bundle_remove(starpu_task_bundle_t bundle, struct starpu_task *t
|
|
|
if (bundle->closed && bundle->list == NULL)
|
|
|
{
|
|
|
_STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
- starpu_task_bundle_destroy(bundle);
|
|
|
+ _starpu_task_bundle_destroy(bundle);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -140,6 +124,8 @@ int starpu_task_bundle_remove(starpu_task_bundle_t bundle, struct starpu_task *t
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ /* Go through the list until we find the right task,
|
|
|
+ * then we delete it */
|
|
|
while (item->next)
|
|
|
{
|
|
|
struct _starpu_task_bundle_entry *next;
|
|
@@ -170,11 +156,12 @@ void starpu_task_bundle_close(starpu_task_bundle_t bundle)
|
|
|
{
|
|
|
_STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
|
|
|
|
|
|
- /* If the bundle is already empty, we deinitialize it now. */
|
|
|
+ /* If the bundle is already empty, we deinitialize it now as the
|
|
|
+ * user closed it and thus don't intend to insert new tasks in it. */
|
|
|
if (bundle->list == NULL)
|
|
|
{
|
|
|
_STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
- starpu_task_bundle_destroy(bundle);
|
|
|
+ _starpu_task_bundle_destroy(bundle);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -185,79 +172,32 @@ void starpu_task_bundle_close(starpu_task_bundle_t bundle)
|
|
|
|
|
|
}
|
|
|
|
|
|
-/* Return the expected duration of the entire task bundle in µs */
|
|
|
-double starpu_task_bundle_expected_length(starpu_task_bundle_t bundle, enum starpu_perf_archtype arch, unsigned nimpl)
|
|
|
-{
|
|
|
- double expected_length = 0.0;
|
|
|
-
|
|
|
- /* We expect the length of the bundle the be the sum of the different tasks length. */
|
|
|
- _STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
|
|
|
-
|
|
|
- struct _starpu_task_bundle_entry *entry;
|
|
|
- entry = bundle->list;
|
|
|
-
|
|
|
- while (entry)
|
|
|
- {
|
|
|
- double task_length = starpu_task_expected_length(entry->task, arch, nimpl);
|
|
|
-
|
|
|
- /* In case the task is not calibrated, we consider the task
|
|
|
- * ends immediately. */
|
|
|
- if (task_length > 0.0)
|
|
|
- expected_length += task_length;
|
|
|
-
|
|
|
- entry = entry->next;
|
|
|
- }
|
|
|
-
|
|
|
- _STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
-
|
|
|
- return expected_length;
|
|
|
-}
|
|
|
-
|
|
|
-/* Return the expected power consumption of the entire task bundle in J */
|
|
|
-double starpu_task_bundle_expected_power(starpu_task_bundle_t bundle, enum starpu_perf_archtype arch, unsigned nimpl)
|
|
|
+void _starpu_task_bundle_destroy(starpu_task_bundle_t bundle)
|
|
|
{
|
|
|
- double expected_power = 0.0;
|
|
|
-
|
|
|
- /* We expect total consumption of the bundle the be the sum of the different tasks consumption. */
|
|
|
- _STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
|
|
|
-
|
|
|
- struct _starpu_task_bundle_entry *entry;
|
|
|
- entry = bundle->list;
|
|
|
-
|
|
|
- while (entry)
|
|
|
+ /* Remove all entries from the bundle (which is likely to be empty) */
|
|
|
+ while (bundle->list)
|
|
|
{
|
|
|
- double task_power = starpu_task_expected_power(entry->task, arch, nimpl);
|
|
|
-
|
|
|
- /* In case the task is not calibrated, we consider the task
|
|
|
- * ends immediately. */
|
|
|
- if (task_power > 0.0)
|
|
|
- expected_power += task_power;
|
|
|
-
|
|
|
- entry = entry->next;
|
|
|
+ struct _starpu_task_bundle_entry *entry = bundle->list;
|
|
|
+ bundle->list = bundle->list->next;
|
|
|
+ free(entry);
|
|
|
}
|
|
|
|
|
|
- _STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
+ _STARPU_PTHREAD_MUTEX_DESTROY(&bundle->mutex);
|
|
|
|
|
|
- return expected_power;
|
|
|
+ free(bundle);
|
|
|
}
|
|
|
|
|
|
-struct handle_list
|
|
|
-{
|
|
|
- starpu_data_handle_t handle;
|
|
|
- enum starpu_access_mode mode;
|
|
|
- struct handle_list *next;
|
|
|
-};
|
|
|
-
|
|
|
-static void insertion_handle_sorted(struct handle_list **listp, starpu_data_handle_t handle, enum starpu_access_mode mode)
|
|
|
+void _insertion_handle_sorted(struct _starpu_handle_list **listp, starpu_data_handle_t handle, enum starpu_access_mode mode)
|
|
|
{
|
|
|
STARPU_ASSERT(listp);
|
|
|
|
|
|
- struct handle_list *list = *listp;
|
|
|
+ struct _starpu_handle_list *list = *listp;
|
|
|
|
|
|
+ /* If the list is empty or the handle's address the smallest among the
|
|
|
+ * list, we insert it as first element */
|
|
|
if (!list || list->handle > handle)
|
|
|
{
|
|
|
- /* We insert the first element of the list */
|
|
|
- struct handle_list *link = (struct handle_list *) malloc(sizeof(struct handle_list));
|
|
|
+ struct _starpu_handle_list *link = (struct _starpu_handle_list *) malloc(sizeof(struct _starpu_handle_list));
|
|
|
STARPU_ASSERT(link);
|
|
|
link->handle = handle;
|
|
|
link->mode = mode;
|
|
@@ -266,26 +206,26 @@ static void insertion_handle_sorted(struct handle_list **listp, starpu_data_hand
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Look for the element or a place to insert it. */
|
|
|
- struct handle_list *prev = list;
|
|
|
+ struct _starpu_handle_list *prev = list;
|
|
|
|
|
|
+ /* Look for the same handle if already present in the list.
|
|
|
+ * Else place it right before the smallest following handle */
|
|
|
while (list && (handle >= list->handle))
|
|
|
{
|
|
|
prev = list;
|
|
|
list = list->next;
|
|
|
}
|
|
|
|
|
|
- /* The element should be in prev or not in the list */
|
|
|
-
|
|
|
if (prev->handle == handle)
|
|
|
{
|
|
|
- /* The handle is already in the list */
|
|
|
+ /* The handle is already in the list, the merge both the access modes */
|
|
|
prev->mode = (enum starpu_access_mode) ((int) prev->mode | (int) mode);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- /* The handle was not in the list, we insert it after prev */
|
|
|
- struct handle_list *link = (struct handle_list *) malloc(sizeof(struct handle_list));
|
|
|
+ /* The handle was not in the list, we insert it after 'prev', thus right before
|
|
|
+ * 'list' which is the smallest following handle */
|
|
|
+ struct _starpu_handle_list *link = (struct _starpu_handle_list *) malloc(sizeof(struct _starpu_handle_list));
|
|
|
STARPU_ASSERT(link);
|
|
|
link->handle = handle;
|
|
|
link->mode = mode;
|
|
@@ -293,60 +233,3 @@ static void insertion_handle_sorted(struct handle_list **listp, starpu_data_hand
|
|
|
prev->next = link;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-/* Return the time (in µs) expected to transfer all data used within the bundle */
|
|
|
-double starpu_task_bundle_expected_data_transfer_time(starpu_task_bundle_t bundle, unsigned memory_node)
|
|
|
-{
|
|
|
- _STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
|
|
|
-
|
|
|
- struct handle_list *handles = NULL;
|
|
|
-
|
|
|
- /* We list all the handle that are accessed within the bundle. */
|
|
|
-
|
|
|
- /* For each task in the bundle */
|
|
|
- struct _starpu_task_bundle_entry *entry = bundle->list;
|
|
|
- while (entry)
|
|
|
- {
|
|
|
- struct starpu_task *task = entry->task;
|
|
|
-
|
|
|
- if (task->cl)
|
|
|
- {
|
|
|
- unsigned b;
|
|
|
- for (b = 0; b < task->cl->nbuffers; b++)
|
|
|
- {
|
|
|
- starpu_data_handle_t handle = task->handles[b];
|
|
|
- enum starpu_access_mode mode = task->cl->modes[b];
|
|
|
-
|
|
|
- if (!(mode & STARPU_R))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* Insert the handle in the sorted list in case
|
|
|
- * it's not already in that list. */
|
|
|
- insertion_handle_sorted(&handles, handle, mode);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- entry = entry->next;
|
|
|
- }
|
|
|
-
|
|
|
- _STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
|
|
|
-
|
|
|
- /* Compute the sum of data transfer time, and destroy the list */
|
|
|
-
|
|
|
- double total_exp = 0.0;
|
|
|
-
|
|
|
- while (handles)
|
|
|
- {
|
|
|
- struct handle_list *current = handles;
|
|
|
- handles = handles->next;
|
|
|
-
|
|
|
- double exp;
|
|
|
- exp = starpu_data_expected_transfer_time(current->handle, memory_node, current->mode);
|
|
|
-
|
|
|
- total_exp += exp;
|
|
|
-
|
|
|
- free(current);
|
|
|
- }
|
|
|
-
|
|
|
- return total_exp;
|
|
|
-}
|