+/* Copyright (c) 2007-2009 Da SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
#include "private.h"
#include "simdag/simdag.h"
#include "xbt/sysdep.h"
/* general information */
task->data = data; /* user data */
- if (name != NULL)
- task->name = xbt_strdup(name);
- else
- task->name = NULL;
-
+ task->name = xbt_strdup(name);
+ task->kind = 0;
task->state_hookup.prev = NULL;
task->state_hookup.next = NULL;
task->state_set = sd_global->not_scheduled_task_set;
return task->name;
}
+/** @brief Returns the dynar of the parents of a task
+ *
+ * \param task a task
+ * \return a newly allocated dynar comprising the parents of this task
+ */
+
+xbt_dynar_t SD_task_get_parents(SD_task_t task)
+{
+ unsigned int i;
+ xbt_dynar_t parents;
+ SD_dependency_t dep;
+ SD_CHECK_INIT_DONE();
+ xbt_assert0(task != NULL, "Invalid parameter");
+
+ parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
+ xbt_dynar_foreach(task->tasks_before, i, dep){
+ xbt_dynar_push(parents, &(dep->src));
+ }
+ return parents;
+}
+
+/** @brief Returns the dynar of the parents of a task
+ *
+ * \param task a task
+ * \return a newly allocated dynar comprising the parents of this task
+ */
+xbt_dynar_t SD_task_get_children(SD_task_t task)
+{
+ unsigned int i;
+ xbt_dynar_t children;
+ SD_dependency_t dep;
+ SD_CHECK_INIT_DONE();
+ xbt_assert0(task != NULL, "Invalid parameter");
+
+ children = xbt_dynar_new(sizeof(SD_task_t), NULL);
+ xbt_dynar_foreach(task->tasks_after, i, dep){
+ xbt_dynar_push(children, &(dep->dst));
+ }
+ return children;
+}
+
+/**
+ * \brief Returns the amount of workstations involved in a task
+ *
+ * Only call this on already scheduled tasks!
+ * \param task a task
+ */
+int SD_task_get_workstation_count(SD_task_t task)
+{
+ SD_CHECK_INIT_DONE();
+ xbt_assert0(task != NULL, "Invalid parameter");
+ // xbt_assert1( task->state_set != sd_global->scheduled_task_set,
+ // "Unscheduled task %s", task->name);
+ return task->workstation_nb;
+}
+
+/**
+ * \brief Returns the list of workstations involved in a task
+ *
+ * Only call this on already scheduled tasks!
+ * \param task a task
+ */
+SD_workstation_t* SD_task_get_workstation_list(SD_task_t task)
+{
+ SD_CHECK_INIT_DONE();
+ xbt_assert0(task != NULL, "Invalid parameter");
+ //xbt_assert1( task->state_set != sd_global->scheduled_task_set,
+ // "Unscheduled task %s", task->name);
+ return task->workstation_list;
+}
+
/**
* \brief Returns the total amount of a task
*
}
/* temporary function for debbuging */
-static void __SD_print_dependencies(SD_task_t task)
+void SD_task_dump(SD_task_t task)
{
- xbt_dynar_t dynar;
- int length;
- int i;
+ unsigned int counter;
SD_dependency_t dependency;
- INFO1("The following tasks must be executed before %s:",
- SD_task_get_name(task));
- dynar = task->tasks_before;
- length = xbt_dynar_length(dynar);
-
-
- for (i = 0; i < length; i++) {
- xbt_dynar_get_cpy(dynar, i, &dependency);
- INFO1(" %s", SD_task_get_name(dependency->src));
+ INFO1("Displaying task %s",SD_task_get_name(task));
+ INFO1(" - amount: %.0f",SD_task_get_amount(task));
+ if (task->kind!=0) {
+ switch(task->kind){
+ case SD_TASK_COMM_E2E:
+ INFO0(" - kind: end-to-end communication");
+ break;
+ case SD_TASK_COMP_SEQ:
+ INFO0(" - kind: sequential computation");
+ break;
+ default:
+ INFO1(" - (unknown kind %d)",task->kind);
+ }
}
-
- INFO1("The following tasks must be executed after %s:",
- SD_task_get_name(task));
-
- dynar = task->tasks_after;
- length = xbt_dynar_length(dynar);
- for (i = 0; i < length; i++) {
- xbt_dynar_get_cpy(dynar, i, &dependency);
- INFO1(" %s", SD_task_get_name(dependency->dst));
+ if (xbt_dynar_length(task->tasks_before)) {
+ INFO0(" - pre-dependencies:");
+ xbt_dynar_foreach(task->tasks_before,counter,dependency) {
+ INFO1(" %s",SD_task_get_name(dependency->src));
+ }
+ }
+ if (xbt_dynar_length(task->tasks_after)) {
+ INFO0(" - post-dependencies:");
+ xbt_dynar_foreach(task->tasks_after,counter,dependency) {
+ INFO1(" %s",SD_task_get_name(dependency->dst));
+ }
}
- INFO0("----------------------------");
}
/* Destroys a dependency between two tasks.
dynar = src->tasks_after;
length = xbt_dynar_length(dynar);
-
-
if (src == dst)
THROW1(arg_error, 0,
"Cannot add a dependency between task '%s' and itself",
dependency = xbt_new(s_SD_dependency_t, 1);
- if (name != NULL)
- dependency->name = xbt_strdup(name);
- else
- dependency->name = NULL;
-
+ dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
dependency->data = data;
dependency->src = src;
dependency->dst = dst;
*
* \param src a task
* \param dst a task depending on \a src
+ *
+ * If src is NULL, checks whether dst has any pre-dependency.
+ * If dst is NULL, checks whether src has any post-dependency.
*/
int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
{
- xbt_dynar_t dynar;
- int length;
- int i;
+ unsigned int counter;
SD_dependency_t dependency;
SD_CHECK_INIT_DONE();
- xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
-
- dynar = src->tasks_after;
- length = xbt_dynar_length(dynar);
+ xbt_assert0(src != NULL || dst != NULL, "Invalid parameter: both src and dst are NULL");
- for (i = 0; i < length; i++) {
- xbt_dynar_get_cpy(dynar, i, &dependency);
- if (dependency->dst == dst)
- return 1;
+ if (src) {
+ if (dst) {
+ xbt_dynar_foreach(src->tasks_after,counter,dependency) {
+ if (dependency->dst == dst)
+ return 1;
+ }
+ } else {
+ return xbt_dynar_length(src->tasks_after);
+ }
+ } else {
+ return xbt_dynar_length(dst->tasks_before);
}
return 0;
}
DEBUG0("Task destroyed.");
}
+
+
+/** @brief create a end-to-end communication task that can then be auto-scheduled
+ *
+ * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
+ * allows to specify the task costs at creation, and decorelate them from the
+ * scheduling process where you just specify which resource should deliver the
+ * mandatory power.
+ *
+ * A end-to-end communication must be scheduled on 2 hosts, and the amount
+ * specified at creation is sent from hosts[0] to hosts[1].
+ */
+SD_task_t SD_task_create_comm_e2e(const char*name, void *data, double amount) {
+ SD_task_t res = SD_task_create(name,data,amount);
+ res->kind=SD_TASK_COMM_E2E;
+ return res;
+}
+/** @brief create a sequential computation task that can then be auto-scheduled
+ *
+ * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
+ * allows to specify the task costs at creation, and decorelate them from the
+ * scheduling process where you just specify which resource should deliver the
+ * mandatory power.
+ *
+ * A sequential computation must be scheduled on 1 host, and the amount
+ * specified at creation to be run on hosts[0].
+ */
+SD_task_t SD_task_create_comp_seq(const char*name, void *data, double amount) {
+ SD_task_t res = SD_task_create(name,data,amount);
+ res->kind=SD_TASK_COMP_SEQ;
+ return res;
+}
+
+/** @brief Auto-schedules a task.
+ *
+ * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
+ * allows to specify the task costs at creation, and decorelate them from the
+ * scheduling process where you just specify which resource should deliver the
+ * mandatory power.
+ *
+ * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e() or
+ * SD_task_create_comp_seq(). Check their definitions for the exact semantic of each
+ * of them.
+ *
+ * @todo
+ * We should create tasks kind for the following categories:
+ * - Point to point communication (done)
+ * - Sequential computation (done)
+ * - group communication (redistribution, several kinds)
+ * - parallel tasks with no internal communication (one kind per speedup model such as amdal)
+ * - idem+ internal communication. Task type not enough since we cannot store comm cost alongside to comp one)
+ */
+void SD_task_schedulev(SD_task_t task, int count, const SD_workstation_t*list) {
+ xbt_assert1(task->kind != 0,"Task %s is not typed. Cannot automatically schedule it.",SD_task_get_name(task));
+ double *comp,*comms;
+ switch(task->kind) {
+ case SD_TASK_COMM_E2E:
+ xbt_assert2(count == 2,
+ "Task %s is end to end communication, but scheduled with %d hosts",
+ SD_task_get_name(task),count);
+ comms=xbt_new(double,count);
+ comms[0]=0;
+ comms[1]=SD_task_get_amount(task);
+ SD_task_schedule(task,count,list,NULL,comms,1);
+ break;
+ case SD_TASK_COMP_SEQ:
+ xbt_assert2(count==1,
+ "Task %s is sequential computation, but scheduled with %d hosts",
+ SD_task_get_name(task),count);
+ comp=xbt_new(double,count);
+ comp[0]=SD_task_get_amount(task);
+ SD_task_schedule(task,count,list,comp,NULL,1);
+ break;
+ default:
+ xbt_die(bprintf("Kind of task %s not supported by SD_task_schedulev()",
+ SD_task_get_name(task)));
+ }
+}
+/** @brief autoschedule a task on a list of workstations
+ *
+ * This function is very similar to SD_task_schedulev(),
+ * but takes the list of workstations to schedule onto as separate parameters.
+ * It builds a proper vector of workstations and then call SD_task_schedulev()
+ */
+void SD_task_schedulel(SD_task_t task, int count, ...) {
+ va_list ap;
+ SD_workstation_t *list=xbt_new(SD_workstation_t,count);
+ int i;
+ va_start(ap,count);
+ for (i=0;i<count;i++) {
+ list[i] = va_arg(ap,SD_workstation_t);
+ }
+ va_end(ap);
+ SD_task_schedulev(task,count,list);
+}