2 #include "simdag/simdag.h"
3 #include "xbt/sysdep.h"
8 SD_task_t SD_task_create(const char *name, void *data, double amount) {
10 xbt_assert0(amount > 0, "amount must be positive");
12 SD_task_t task = xbt_new0(s_SD_task_t, 1);
14 /* general information */
15 task->data = data; /* user data */
17 task->name = xbt_strdup(name);
21 task->state_set = sd_global->not_scheduled_task_set;
22 xbt_swag_insert(task,task->state_set);
24 task->amount = amount;
25 task->surf_action = NULL;
26 task->watch_points = 0;
27 task->state_changed = 0;
30 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
31 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
33 /* scheduling parameters */
34 task->workstation_nb = 0;
35 task->workstation_list = NULL;
36 task->computation_amount = NULL;
37 task->communication_amount = NULL;
43 /* Returns the data of a task.
45 void* SD_task_get_data(SD_task_t task) {
47 xbt_assert0(task != NULL, "Invalid parameter");
51 /* Returns the state of a task: SD_NOT_SCHEDULED, SD_SCHEDULED, SD_READY, SD_RUNNING, SD_DONE or SD_FAILED.
53 e_SD_task_state_t SD_task_get_state(SD_task_t task) {
55 xbt_assert0(task != NULL, "Invalid parameter");
57 if (task->state_set == sd_global->scheduled_task_set)
59 if (task->state_set == sd_global->done_task_set)
61 if (task->state_set == sd_global->running_task_set)
63 if (task->state_set == sd_global->ready_task_set)
65 if (task->state_set == sd_global->not_scheduled_task_set)
66 return SD_NOT_SCHEDULED;
70 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
72 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) {
73 xbt_swag_remove(task, task->state_set);
75 case SD_NOT_SCHEDULED:
76 task->state_set = sd_global->not_scheduled_task_set;
79 task->state_set = sd_global->scheduled_task_set;
82 task->state_set = sd_global->ready_task_set;
85 task->state_set = sd_global->running_task_set;
88 task->state_set = sd_global->done_task_set;
91 task->state_set = sd_global->failed_task_set;
94 xbt_assert0(0, "Invalid state");
96 xbt_swag_insert(task,task->state_set);
98 if (task->watch_points & new_state) {
99 printf("Watch point reached with task '%s' in state %d!\n", SD_task_get_name(task), new_state);
100 sd_global->watch_point_reached = 1;
104 /* Sets the data of a task.
106 void SD_task_set_data(SD_task_t task, void *data) {
107 SD_CHECK_INIT_DONE();
108 xbt_assert0(task != NULL, "Invalid parameter");
112 /* Returns the name of a task. The name can be NULL.
114 const char* SD_task_get_name(SD_task_t task) {
115 SD_CHECK_INIT_DONE();
116 xbt_assert0(task != NULL, "Invalid parameter");
120 /* Returns the computing amount of a task.
122 double SD_task_get_amount(SD_task_t task) {
123 SD_CHECK_INIT_DONE();
124 xbt_assert0(task != NULL, "Invalid parameter");
128 /* Returns the remaining computing amount of a task.
130 double SD_task_get_remaining_amount(SD_task_t task) {
131 SD_CHECK_INIT_DONE();
132 xbt_assert0(task != NULL, "Invalid parameter");
134 if (task->surf_action)
137 return task->surf_action->remains;
140 /* temporary function for debbuging */
141 static void __SD_print_dependencies(SD_task_t task) {
142 printf("The following tasks must be executed before %s:", SD_task_get_name(task));
143 xbt_dynar_t dynar = task->tasks_before;
144 int length = xbt_dynar_length(dynar);
146 SD_dependency_t dependency;
147 for (i = 0; i < length; i++) {
148 xbt_dynar_get_cpy(dynar, i, &dependency);
149 printf(" %s", SD_task_get_name(dependency->src));
152 printf("\nThe following tasks must be executed after %s:", SD_task_get_name(task));
154 dynar = task->tasks_after;
155 length = xbt_dynar_length(dynar);
156 for (i = 0; i < length; i++) {
157 xbt_dynar_get_cpy(dynar, i, &dependency);
158 printf(" %s", SD_task_get_name(dependency->dst));
160 printf("\n----------------------------\n");
163 /* Destroys a dependency between two tasks.
165 static void __SD_task_dependency_destroy(void *dependency) {
166 if (((SD_dependency_t) dependency)->name != NULL)
167 xbt_free(((SD_dependency_t) dependency)->name);
168 xbt_free(dependency);
171 /* Adds a dependency between two tasks. Their state must be SD_NOT_SCHEDULED, SD_SCHEDULED
174 void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) {
175 SD_CHECK_INIT_DONE();
176 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
177 xbt_assert1(src != dst, "Cannot add a dependency between task '%s' and itself", SD_task_get_name(src));
178 xbt_assert1(__SD_task_is_not_scheduled(src) || __SD_task_is_scheduled_or_ready(src),
179 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(src));
180 xbt_assert1(__SD_task_is_not_scheduled(dst) || __SD_task_is_scheduled_or_ready(dst),
181 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(dst));
183 xbt_dynar_t dynar = src->tasks_after;
184 int length = xbt_dynar_length(dynar);
187 SD_dependency_t dependency;
188 for (i = 0; i < length && !found; i++) {
189 xbt_dynar_get_cpy(dynar, i, &dependency);
190 found = (dependency->dst == dst);
192 xbt_assert2(!found, "A dependency already exists between task '%s' and task '%s'",
193 SD_task_get_name(src), SD_task_get_name(dst));
195 dependency = xbt_new0(s_SD_dependency_t, 1);
198 dependency->name = xbt_strdup(name);
199 dependency->data = data;
200 dependency->src = src;
201 dependency->dst = dst;
203 /* src must be executed before dst */
204 xbt_dynar_push(src->tasks_after, &dependency);
205 xbt_dynar_push(dst->tasks_before, &dependency);
207 /* if the task was ready, then dst->tasks_before is not empty anymore,
208 so we must go back to state SD_SCHEDULED */
209 if (__SD_task_is_ready(dst)) {
210 printf("SD_task_dependency_add: %s was ready and becomes scheduled!\n", SD_task_get_name(dst));
211 __SD_task_set_state(dst, SD_SCHEDULED);
214 /* __SD_print_dependencies(src);
215 __SD_print_dependencies(dst); */
218 /* Removes a dependency between two tasks.
220 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
221 SD_CHECK_INIT_DONE();
222 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
224 /* remove the dependency from src->tasks_after */
225 xbt_dynar_t dynar = src->tasks_after;
226 int length = xbt_dynar_length(dynar);
229 SD_dependency_t dependency;
230 for (i = 0; i < length && !found; i++) {
231 xbt_dynar_get_cpy(dynar, i, &dependency);
232 if (dependency->dst == dst) {
233 xbt_dynar_remove_at(dynar, i, NULL);
237 xbt_assert4(found, "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
238 SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src));
240 /* remove the dependency from dst->tasks_before */
241 dynar = dst->tasks_before;
242 length = xbt_dynar_length(dynar);
245 for (i = 0; i < length && !found; i++) {
246 xbt_dynar_get_cpy(dynar, i, &dependency);
247 if (dependency->src == src) {
248 xbt_dynar_remove_at(dynar, i, NULL);
249 __SD_task_dependency_destroy(dependency);
253 xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
254 SD_task_get_name(dst), SD_task_get_name(src), SD_task_get_name(src), SD_task_get_name(dst)); /* should never happen... */
256 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
257 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
258 __SD_task_set_state(dst, SD_READY);
260 /* __SD_print_dependencies(src);
261 __SD_print_dependencies(dst);*/
264 /* Returns the data associated to a dependency between two tasks. This data can be NULL.
266 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
267 SD_CHECK_INIT_DONE();
268 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
270 xbt_dynar_t dynar = src->tasks_after;
271 int length = xbt_dynar_length(dynar);
274 SD_dependency_t dependency;
275 for (i = 0; i < length && !found; i++) {
276 xbt_dynar_get_cpy(dynar, i, &dependency);
277 found = (dependency->dst == dst);
279 xbt_assert2(found, "No dependency found between task '%s' and '%s'", SD_task_get_name(src), SD_task_get_name(dst));
280 return dependency->data;
283 /* temporary function for debugging */
284 static void __SD_print_watch_points(SD_task_t task) {
285 static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED};
286 static const char* state_names[] = {"scheduled", "running", "ready", "done", "failed"};
288 printf("Task '%s' watch points (%x): ", SD_task_get_name(task), task->watch_points);
291 for (i = 0; i < 5; i++) {
292 if (task->watch_points & state_masks[i])
293 printf("%s ", state_names[i]);
298 /* Adds a watch point to a task.
299 SD_simulate will stop as soon as the state of this task is the one given in argument.
300 Watch point is then automatically removed.
301 The given state must be SD_SCHEDULED, SD_READY, SD_RUNNING, SD_DONE or SD_FAILED.
303 void SD_task_watch(SD_task_t task, e_SD_task_state_t state) {
304 SD_CHECK_INIT_DONE();
305 xbt_assert0(task != NULL, "Invalid parameter");
306 xbt_assert0(state != SD_NOT_SCHEDULED, "Cannot add a watch point for state SD_NOT_SCHEDULED");
308 task->watch_points = task->watch_points | state;
309 __SD_print_watch_points(task);
312 /* Removes a watch point from a task.
313 The given state must be SD_SCHEDULED, SD_READY, SD_RUNNING, SD_DONE or SD_FAILED.
315 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) {
316 SD_CHECK_INIT_DONE();
317 xbt_assert0(task != NULL, "Invalid parameter");
318 xbt_assert0(state != SD_NOT_SCHEDULED, "Cannot have a watch point for state SD_NOT_SCHEDULED");
320 task->watch_points = task->watch_points & ~state;
321 __SD_print_watch_points(task);
324 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
326 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
327 SD_CHECK_INIT_DONE();
328 xbt_assert1(__SD_task_is_scheduled_or_ready(task),
329 "Task '%s' must be SD_SCHEDULED or SD_READY", SD_task_get_name(task));
330 xbt_free(task->workstation_list);
331 xbt_free(task->computation_amount);
332 xbt_free(task->communication_amount);
336 * task: the task to schedule
337 * workstation_nb: number of workstations where the task will be executed
338 * workstation_list: workstations where the task will be executed
339 * computation_amount: computation amount for each workstation
340 * communication_amount: communication amount between each pair of workstations
341 * rate: task execution speed rate
343 void SD_task_schedule(SD_task_t task, int workstation_nb,
344 const SD_workstation_t *workstation_list, double *computation_amount,
345 double *communication_amount, double rate) {
346 SD_CHECK_INIT_DONE();
347 xbt_assert0(task, "Invalid parameter");
348 xbt_assert1(__SD_task_is_not_scheduled(task), "Task '%s' has already been scheduled.", SD_task_get_name(task));
349 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
351 task->workstation_nb = workstation_nb;
354 task->computation_amount = xbt_new0(double, workstation_nb);
355 memcpy(task->computation_amount, computation_amount, sizeof(double) * workstation_nb);
357 int communication_nb = workstation_nb * workstation_nb;
358 task->communication_amount = xbt_new0(double, communication_nb);
359 memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
361 /* we have to create a Surf workstation array instead of the SimDag workstation array */
362 task->workstation_list = xbt_new0(void*, workstation_nb);
364 for (i = 0; i < workstation_nb; i++) {
365 task->workstation_list[i] = workstation_list[i]->surf_workstation;
368 /* update the task state */
369 if (xbt_dynar_length(task->tasks_before) == 0)
370 __SD_task_set_state(task, SD_READY);
372 __SD_task_set_state(task, SD_SCHEDULED);
375 /* Unschedules a task. The state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED.
376 * The task is reinitialised and its state becomes SD_NOT_SCHEDULED.
377 * Call SD_task_schedule to schedule it again.
379 void SD_task_unschedule(SD_task_t task) {
380 SD_CHECK_INIT_DONE();
381 xbt_assert0(task != NULL, "Invalid parameter");
382 xbt_assert1(task->state_set == sd_global->scheduled_task_set ||
383 task->state_set == sd_global->ready_task_set ||
384 task->state_set == sd_global->running_task_set ||
385 task->state_set == sd_global->failed_task_set,
386 "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
387 SD_task_get_name(task));
389 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
390 __SD_task_destroy_scheduling_data(task);
392 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
393 surf_workstation_resource->common_public->action_cancel(task->surf_action);
395 __SD_task_set_state(task, SD_NOT_SCHEDULED);
398 /* Runs a task. This function is called by SD_simulate when a scheduled task can start
399 * (ie when its dependencies are satisfied).
401 surf_action_t __SD_task_run(SD_task_t task) {
402 SD_CHECK_INIT_DONE();
403 xbt_assert0(task != NULL, "Invalid parameter");
404 xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
405 SD_task_get_name(task), SD_task_get_state(task));
407 surf_action_t surf_action = surf_workstation_resource->extension_public->
408 execute_parallel_task(task->workstation_nb,
409 task->workstation_list,
410 task->computation_amount,
411 task->communication_amount,
415 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
416 __SD_task_set_state(task, SD_RUNNING);
421 /* Remove all dependencies associated with a task. This function is called when the task is done.
423 void __SD_task_remove_dependencies(SD_task_t task) {
424 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
425 because each one is stored twice */
426 SD_dependency_t dependency;
427 while (xbt_dynar_length(task->tasks_before) > 0) {
428 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
429 SD_task_dependency_remove(dependency->src, dependency->dst);
432 while (xbt_dynar_length(task->tasks_after) > 0) {
433 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
434 SD_task_dependency_remove(dependency->src, dependency->dst);
438 /* Destroys a task. The user data (if any) should have been destroyed first.
440 void SD_task_destroy(SD_task_t task) {
441 SD_CHECK_INIT_DONE();
442 xbt_assert0(task != NULL, "Invalid parameter");
444 /*printf("Destroying task %s...\n", SD_task_get_name(task));*/
446 __SD_task_remove_dependencies(task);
448 /* if the task was scheduled or ready we have to free the scheduling parameters */
449 if (__SD_task_is_scheduled_or_ready(task))
450 __SD_task_destroy_scheduling_data(task);
452 if (task->name != NULL)
453 xbt_free(task->name);
455 xbt_dynar_free(&task->tasks_before);
456 xbt_dynar_free(&task->tasks_after);
459 /*printf("Task destroyed.\n");*/