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->not_scheduled_task_set)
58 return SD_NOT_SCHEDULED;
59 if (task->state_set == sd_global->scheduled_task_set)
61 if (task->state_set == sd_global->ready_task_set)
63 if (task->state_set == sd_global->running_task_set)
65 if (task->state_set == sd_global->done_task_set)
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;
90 default: /* SD_FAILED */
91 task->state_set = sd_global->failed_task_set;
93 xbt_swag_insert(task,task->state_set);
95 if (task->watch_points & new_state) {
96 printf("Watch point reached with task '%s' in state %d!\n", SD_task_get_name(task), new_state);
97 sd_global->watch_point_reached = 1;
101 /* Sets the data of a task.
103 void SD_task_set_data(SD_task_t task, void *data) {
104 SD_CHECK_INIT_DONE();
105 xbt_assert0(task != NULL, "Invalid parameter");
109 /* Returns the name of a task. The name can be NULL.
111 const char* SD_task_get_name(SD_task_t task) {
112 SD_CHECK_INIT_DONE();
113 xbt_assert0(task != NULL, "Invalid parameter");
117 /* Returns the computing amount of a task.
119 double SD_task_get_amount(SD_task_t task) {
120 SD_CHECK_INIT_DONE();
121 xbt_assert0(task != NULL, "Invalid parameter");
125 /* Returns the remaining computing amount of a task.
127 double SD_task_get_remaining_amount(SD_task_t task) {
128 SD_CHECK_INIT_DONE();
129 xbt_assert0(task != NULL, "Invalid parameter");
131 if (task->surf_action)
134 return task->surf_action->remains;
137 /* temporary function for debbuging */
138 static void __SD_print_dependencies(SD_task_t task) {
139 printf("The following tasks must be executed before %s:", SD_task_get_name(task));
140 xbt_dynar_t dynar = task->tasks_before;
141 int length = xbt_dynar_length(dynar);
143 SD_dependency_t dependency;
144 for (i = 0; i < length; i++) {
145 xbt_dynar_get_cpy(dynar, i, &dependency);
146 printf(" %s", SD_task_get_name(dependency->src));
149 printf("\nThe following tasks must be executed after %s:", SD_task_get_name(task));
151 dynar = task->tasks_after;
152 length = xbt_dynar_length(dynar);
153 for (i = 0; i < length; i++) {
154 xbt_dynar_get_cpy(dynar, i, &dependency);
155 printf(" %s", SD_task_get_name(dependency->dst));
157 printf("\n----------------------------\n");
160 /* Destroys a dependency between two tasks.
162 static void __SD_task_dependency_destroy(void *dependency) {
163 if (((SD_dependency_t) dependency)->name != NULL)
164 xbt_free(((SD_dependency_t) dependency)->name);
165 xbt_free(dependency);
168 /* Adds a dependency between two tasks. Their state must be SD_NOT_SCHEDULED, SD_SCHEDULED
171 void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) {
172 SD_CHECK_INIT_DONE();
173 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
174 xbt_assert1(src != dst, "Cannot add a dependency between task '%s' and itself", SD_task_get_name(src));
175 xbt_assert1(__SD_task_is_not_scheduled(src) || __SD_task_is_scheduled_or_ready(src),
176 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(src));
177 xbt_assert1(__SD_task_is_not_scheduled(dst) || __SD_task_is_scheduled_or_ready(dst),
178 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(dst));
180 xbt_dynar_t dynar = src->tasks_after;
181 int length = xbt_dynar_length(dynar);
184 SD_dependency_t dependency;
185 for (i = 0; i < length && !found; i++) {
186 xbt_dynar_get_cpy(dynar, i, &dependency);
187 found = (dependency->dst == dst);
189 xbt_assert2(!found, "A dependency already exists between task '%s' and task '%s'",
190 SD_task_get_name(src), SD_task_get_name(dst));
192 dependency = xbt_new0(s_SD_dependency_t, 1);
195 dependency->name = xbt_strdup(name);
196 dependency->data = data;
197 dependency->src = src;
198 dependency->dst = dst;
200 /* src must be executed before dst */
201 xbt_dynar_push(src->tasks_after, &dependency);
202 xbt_dynar_push(dst->tasks_before, &dependency);
204 /* if the task was ready, then dst->tasks_before is not empty anymore,
205 so we must go back to state SD_SCHEDULED */
206 if (__SD_task_is_ready(dst)) {
207 printf("SD_task_dependency_add: %s was ready and becomes scheduled!\n", SD_task_get_name(dst));
208 __SD_task_set_state(dst, SD_SCHEDULED);
211 /* __SD_print_dependencies(src);
212 __SD_print_dependencies(dst); */
215 /* Removes a dependency between two tasks.
217 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
218 SD_CHECK_INIT_DONE();
219 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
221 /* remove the dependency from src->tasks_after */
222 xbt_dynar_t dynar = src->tasks_after;
223 int length = xbt_dynar_length(dynar);
226 SD_dependency_t dependency;
227 for (i = 0; i < length && !found; i++) {
228 xbt_dynar_get_cpy(dynar, i, &dependency);
229 if (dependency->dst == dst) {
230 xbt_dynar_remove_at(dynar, i, NULL);
234 xbt_assert4(found, "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
235 SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src));
237 /* remove the dependency from dst->tasks_before */
238 dynar = dst->tasks_before;
239 length = xbt_dynar_length(dynar);
242 for (i = 0; i < length && !found; i++) {
243 xbt_dynar_get_cpy(dynar, i, &dependency);
244 if (dependency->src == src) {
245 xbt_dynar_remove_at(dynar, i, NULL);
246 __SD_task_dependency_destroy(dependency);
250 xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
251 SD_task_get_name(dst), SD_task_get_name(src), SD_task_get_name(src), SD_task_get_name(dst)); /* should never happen... */
253 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
254 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
255 __SD_task_set_state(dst, SD_READY);
257 /* __SD_print_dependencies(src);
258 __SD_print_dependencies(dst);*/
261 /* Returns the data associated to a dependency between two tasks. This data can be NULL.
263 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
264 SD_CHECK_INIT_DONE();
265 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
267 xbt_dynar_t dynar = src->tasks_after;
268 int length = xbt_dynar_length(dynar);
271 SD_dependency_t dependency;
272 for (i = 0; i < length && !found; i++) {
273 xbt_dynar_get_cpy(dynar, i, &dependency);
274 found = (dependency->dst == dst);
276 xbt_assert2(found, "No dependency found between task '%s' and '%s'", SD_task_get_name(src), SD_task_get_name(dst));
277 return dependency->data;
280 /* temporary function for debugging */
281 static void __SD_print_watch_points(SD_task_t task) {
282 static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED};
283 static const char* state_names[] = {"scheduled", "running", "ready", "done", "failed"};
285 printf("Task '%s' watch points (%x): ", SD_task_get_name(task), task->watch_points);
288 for (i = 0; i < 5; i++) {
289 if (task->watch_points & state_masks[i])
290 printf("%s ", state_names[i]);
295 /* Adds a watch point to a task.
296 SD_simulate will stop as soon as the state of this task is the one given in argument.
297 Watch point is then automatically removed.
298 The given state must be SD_SCHEDULED, SD_READY, SD_RUNNING, SD_DONE or SD_FAILED.
300 void SD_task_watch(SD_task_t task, e_SD_task_state_t state) {
301 SD_CHECK_INIT_DONE();
302 xbt_assert0(task != NULL, "Invalid parameter");
303 xbt_assert0(state != SD_NOT_SCHEDULED, "Cannot add a watch point for state SD_NOT_SCHEDULED");
305 task->watch_points = task->watch_points | state;
306 __SD_print_watch_points(task);
309 /* Removes a watch point from a task.
310 The given state must be SD_SCHEDULED, SD_READY, SD_RUNNING, SD_DONE or SD_FAILED.
312 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) {
313 SD_CHECK_INIT_DONE();
314 xbt_assert0(task != NULL, "Invalid parameter");
315 xbt_assert0(state != SD_NOT_SCHEDULED, "Cannot have a watch point for state SD_NOT_SCHEDULED");
317 task->watch_points = task->watch_points & ~state;
318 __SD_print_watch_points(task);
321 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
323 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
324 SD_CHECK_INIT_DONE();
325 xbt_assert1(__SD_task_is_scheduled_or_ready(task),
326 "Task '%s' must be SD_SCHEDULED or SD_READY", SD_task_get_name(task));
327 xbt_free(task->workstation_list);
328 xbt_free(task->computation_amount);
329 xbt_free(task->communication_amount);
333 * task: the task to schedule
334 * workstation_nb: number of workstations where the task will be executed
335 * workstation_list: workstations where the task will be executed
336 * computation_amount: computation amount for each workstation
337 * communication_amount: communication amount between each pair of workstations
338 * rate: task execution speed rate
340 void SD_task_schedule(SD_task_t task, int workstation_nb,
341 const SD_workstation_t *workstation_list, double *computation_amount,
342 double *communication_amount, double rate) {
343 SD_CHECK_INIT_DONE();
344 xbt_assert0(task, "Invalid parameter");
345 xbt_assert1(__SD_task_is_not_scheduled(task), "Task '%s' has already been scheduled.", SD_task_get_name(task));
346 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
348 task->workstation_nb = workstation_nb;
351 task->computation_amount = xbt_new0(double, workstation_nb);
352 memcpy(task->computation_amount, computation_amount, sizeof(double) * workstation_nb);
354 int communication_nb = workstation_nb * workstation_nb;
355 task->communication_amount = xbt_new0(double, communication_nb);
356 memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
358 /* we have to create a Surf workstation array instead of the SimDag workstation array */
359 task->workstation_list = xbt_new0(void*, workstation_nb);
361 for (i = 0; i < workstation_nb; i++) {
362 task->workstation_list[i] = workstation_list[i]->surf_workstation;
365 /* update the task state */
366 if (xbt_dynar_length(task->tasks_before) == 0)
367 __SD_task_set_state(task, SD_READY);
369 __SD_task_set_state(task, SD_SCHEDULED);
372 /* Unschedules a task. The state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED.
373 * The task is reinitialised and its state becomes SD_NOT_SCHEDULED.
374 * Call SD_task_schedule to schedule it again.
376 void SD_task_unschedule(SD_task_t task) {
377 SD_CHECK_INIT_DONE();
378 xbt_assert0(task != NULL, "Invalid parameter");
379 xbt_assert1(task->state_set == sd_global->scheduled_task_set ||
380 task->state_set == sd_global->ready_task_set ||
381 task->state_set == sd_global->running_task_set ||
382 task->state_set == sd_global->failed_task_set,
383 "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
384 SD_task_get_name(task));
386 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
387 __SD_task_destroy_scheduling_data(task);
389 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
390 surf_workstation_resource->common_public->action_cancel(task->surf_action);
392 __SD_task_set_state(task, SD_NOT_SCHEDULED);
395 /* Runs a task. This function is called by SD_simulate when a scheduled task can start
396 * (ie when its dependencies are satisfied).
398 surf_action_t __SD_task_run(SD_task_t task) {
399 SD_CHECK_INIT_DONE();
400 xbt_assert0(task != NULL, "Invalid parameter");
401 xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
402 SD_task_get_name(task), SD_task_get_state(task));
404 surf_action_t surf_action = surf_workstation_resource->extension_public->
405 execute_parallel_task(task->workstation_nb,
406 task->workstation_list,
407 task->computation_amount,
408 task->communication_amount,
412 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
413 __SD_task_set_state(task, SD_RUNNING);
418 /* Remove all dependencies associated with a task. This function is called when the task is done.
420 void __SD_task_remove_dependencies(SD_task_t task) {
421 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
422 because each one is stored twice */
423 SD_dependency_t dependency;
424 while (xbt_dynar_length(task->tasks_before) > 0) {
425 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
426 SD_task_dependency_remove(dependency->src, dependency->dst);
429 while (xbt_dynar_length(task->tasks_after) > 0) {
430 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
431 SD_task_dependency_remove(dependency->src, dependency->dst);
435 /* Destroys a task. The user data (if any) should have been destroyed first.
437 void SD_task_destroy(SD_task_t task) {
438 SD_CHECK_INIT_DONE();
439 xbt_assert0(task != NULL, "Invalid parameter");
441 /*printf("Destroying task %s...\n", SD_task_get_name(task));*/
443 __SD_task_remove_dependencies(task);
445 /* if the task was scheduled or ready we have to free the scheduling parameters */
446 if (__SD_task_is_scheduled_or_ready(task))
447 __SD_task_destroy_scheduling_data(task);
449 if (task->name != NULL)
450 xbt_free(task->name);
452 xbt_dynar_free(&task->tasks_before);
453 xbt_dynar_free(&task->tasks_after);
456 /*printf("Task destroyed.\n");*/