/** * \brief Remove a dependency between two tasks * * \param src a task * \param dst a task depending on \a src * \see SD_task_dependency_add() */ void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) { XBT_DEBUG("SD_task_dependency_remove: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst)); if (src->successors->find(dst) == src->successors->end() && src->outputs->find(dst) == src->outputs->end()) THROWF(arg_error, 0, "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'", SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src)); e_SD_task_kind_t src_kind = SD_task_get_kind(src); e_SD_task_kind_t dst_kind = SD_task_get_kind(dst); if (src_kind == SD_TASK_COMM_E2E || src_kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){ if (dst_kind == SD_TASK_COMP_SEQ || dst_kind == SD_TASK_COMP_PAR_AMDAHL){ dst->inputs->erase(src); } else { dst->predecessors->erase(src); } src->successors->erase(dst); } else { if (dst_kind == SD_TASK_COMM_E2E|| dst_kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){ src->outputs->erase(dst); } else { src->successors->erase(dst); } dst->predecessors->erase(src); } /* if the task was scheduled and dependencies are satisfied, we can make it runnable */ if (dst->predecessors->empty() && dst->inputs->empty() && SD_task_get_state(dst) == SD_SCHEDULED) SD_task_set_state(dst, SD_RUNNABLE); }
xbt_dynar_foreach(dax, cursor, task) { int kind = SD_task_get_kind(task); SD_workstation_t *wsl = SD_task_get_workstation_list(task); switch (kind) { case SD_TASK_COMP_SEQ: fprintf(out, "[%f] %s compute %f # %s\n", SD_task_get_start_time(task), SD_workstation_get_name(wsl[0]), SD_task_get_amount(task), SD_task_get_name(task)); break; case SD_TASK_COMM_E2E: fprintf(out, "[%f] %s send %s %f # %s\n", SD_task_get_start_time(task), SD_workstation_get_name(wsl[0]), SD_workstation_get_name(wsl[1]), SD_task_get_amount(task), SD_task_get_name(task)); fprintf(out, "[%f] %s recv %s %f # %s\n", SD_task_get_finish_time(task), SD_workstation_get_name(wsl[1]), SD_workstation_get_name(wsl[0]), SD_task_get_amount(task), SD_task_get_name(task)); break; default: xbt_die("Task %s is of unknown kind %d", SD_task_get_name(task), SD_task_get_kind(task)); } SD_task_destroy(task); }
/** * \brief Adds a dependency between two tasks * * \a dst will depend on \a src, ie \a dst will not start before \a src is finished. * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE. * * \param name the name of the new dependency (can be \c nullptr) * \param data the user data you want to associate with this dependency (can be \c nullptr) * \param src the task which must be executed first * \param dst the task you want to make depend on \a src * \see SD_task_dependency_remove() */ void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) { if (src == dst) THROWF(arg_error, 0, "Cannot add a dependency between task '%s' and itself", SD_task_get_name(src)); e_SD_task_state_t state = SD_task_get_state(src); if (state == SD_DONE || state == SD_FAILED) THROWF(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNABLE, or SD_RUNNING", SD_task_get_name(src)); state = SD_task_get_state(dst); if (state == SD_DONE || state == SD_FAILED || state == SD_RUNNING) THROWF(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED, or SD_RUNNABLE", SD_task_get_name(dst)); if (src->successors->find(dst) != src->successors->end() || dst->predecessors->find(src) != dst->predecessors->end() || dst->inputs->find(src) != dst->inputs->end() || src->outputs->find(dst) != src->outputs->end()) THROWF(arg_error, 0, "A dependency already exists between task '%s' and task '%s'", SD_task_get_name(src), SD_task_get_name(dst)); XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst)); e_SD_task_kind_t src_kind = SD_task_get_kind(src); e_SD_task_kind_t dst_kind = SD_task_get_kind(dst); if (src_kind == SD_TASK_COMM_E2E || src_kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){ if (dst_kind == SD_TASK_COMP_SEQ || dst_kind == SD_TASK_COMP_PAR_AMDAHL){ dst->inputs->insert(src); } else { dst->predecessors->insert(src); } src->successors->insert(dst); } else { if (dst_kind == SD_TASK_COMM_E2E|| dst_kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){ src->outputs->insert(dst); } else { src->successors->insert(dst); } dst->predecessors->insert(src); } /* if the task was runnable, the task goes back to SD_SCHEDULED because of the new dependency*/ if (SD_task_get_state(dst) == SD_RUNNABLE) { XBT_DEBUG("SD_task_dependency_add: %s was runnable and becomes scheduled!", SD_task_get_name(dst)); SD_task_set_state(dst, SD_SCHEDULED); } }
static double finish_on_at(SD_task_t task, sg_host_t host) { double result; unsigned int i; double data_available = 0.; double redist_time = 0; double last_data_available; xbt_dynar_t parents = SD_task_get_parents(task); if (!xbt_dynar_is_empty(parents)) { /* compute last_data_available */ SD_task_t parent; last_data_available = -1.0; xbt_dynar_foreach(parents, i, parent) { /* normal case */ if (SD_task_get_kind(parent) == SD_TASK_COMM_E2E) { xbt_dynar_t grand_parents = SD_task_get_parents(parent); SD_task_t grand_parent; xbt_assert(xbt_dynar_length(grand_parents) <2, "Error: transfer %s has 2 parents", SD_task_get_name(parent)); xbt_dynar_get_cpy(grand_parents, 0, &grand_parent); sg_host_t * grand_parent_host_list = SD_task_get_workstation_list(grand_parent); /* Estimate the redistribution time from this parent */ if (SD_task_get_amount(parent) <= 1e-6){ redist_time= 0; } else { redist_time = SD_route_get_latency(grand_parent_host_list[0], host) + SD_task_get_amount(parent) / SD_route_get_bandwidth(grand_parent_host_list[0], host); } data_available = SD_task_get_finish_time(grand_parent) + redist_time; xbt_dynar_free_container(&grand_parents); } /* no transfer, control dependency */ if (SD_task_get_kind(parent) == SD_TASK_COMP_SEQ) { data_available = SD_task_get_finish_time(parent); } if (last_data_available < data_available) last_data_available = data_available; } xbt_dynar_free_container(&parents); result = MAX(sg_host_get_available_at(host), last_data_available) + SD_task_get_amount(task)/sg_host_speed(host); } else {
static void scheduleDAX(xbt_dynar_t dax) { unsigned int cursor; SD_task_t task; const SD_workstation_t *ws_list = SD_workstation_get_list(); int totalHosts = SD_workstation_get_number(); qsort((void *) ws_list, totalHosts, sizeof(SD_workstation_t), name_compare_hosts); int count = SD_workstation_get_number(); //fprintf(stdout, "No. workstations: %d, %d\n", count, (dax != NULL)); xbt_dynar_foreach(dax, cursor, task) { if (SD_task_get_kind(task) == SD_TASK_COMP_SEQ) { if (!strcmp(SD_task_get_name(task), "end") || !strcmp(SD_task_get_name(task), "root")) { fprintf(stdout, "Scheduling %s to node: %s\n", SD_task_get_name(task), SD_workstation_get_name(ws_list[0])); SD_task_schedulel(task, 1, ws_list[0]); } else { fprintf(stdout, "Scheduling %s to node: %s\n", SD_task_get_name(task), SD_workstation_get_name(ws_list[(cursor) % count])); SD_task_schedulel(task, 1, ws_list[(cursor) % count]); } } } }
/* * Estimate the time at which all the input data of a task are available (i.e., * have been transfered to) on its current allocation. This estimation * corresponds to the maximum value among the compute parents of the task of * the sum of the estimated finish time of the parent and estimated transfer * time of the data sent by this parent. For control dependencies, the second * part is obviously discarded. */ double SD_task_estimate_last_data_arrival_time (SD_task_t task){ unsigned int i; double last_data_arrival = -1., data_availability, estimated_transfer_time; SD_task_t parent, grand_parent; xbt_dynar_t parents, grand_parents; parents = SD_task_get_parents(task); xbt_dynar_foreach(parents, i, parent){ if (SD_task_get_kind(parent) == SD_TASK_COMM_PAR_MXN_1D_BLOCK) { grand_parents = SD_task_get_parents(parent); xbt_dynar_get_cpy(grand_parents, 0, &grand_parent); estimated_transfer_time = SD_task_estimate_transfer_time_from(grand_parent, task, SD_task_get_amount(parent)); data_availability = SD_task_get_estimated_finish_time(grand_parent)+ estimated_transfer_time; xbt_dynar_free_container(&grand_parents); } else { data_availability = SD_task_get_estimated_finish_time(parent); } if (last_data_arrival < data_availability) last_data_arrival = data_availability; } xbt_dynar_free_container(&parents); return last_data_arrival; }
/* This function is actually not used by biCPA */ double top_level_recursive_computation(SD_task_t task){ unsigned int i; double max_top_level = 0.0, my_top_level, current_parent_top_level = 0.0; SD_task_t parent, grand_parent=NULL; xbt_dynar_t parents, grand_parents; max_top_level = -1.0; if (!strcmp(SD_task_get_name(task),"root")){ XBT_DEBUG("root's top level is 0.0"); SD_task_mark(task); SD_task_set_top_level(task, 0.0); return 0.0; } parents = SD_task_get_parents(task); xbt_dynar_foreach(parents, i, parent){ if (SD_task_get_kind(parent) == SD_TASK_COMM_PAR_MXN_1D_BLOCK) { grand_parents = SD_task_get_parents(parent); xbt_dynar_get_cpy(grand_parents, 0, &grand_parent); if (SD_task_is_marked(grand_parent)){ current_parent_top_level = SD_task_get_top_level(grand_parent) + SD_task_estimate_execution_time(grand_parent, SD_task_get_allocation_size(grand_parent)); } else { current_parent_top_level = top_level_recursive_computation(grand_parent) + SD_task_estimate_execution_time(grand_parent, SD_task_get_allocation_size(grand_parent)); } xbt_dynar_free_container(&grand_parents); } else { if (SD_task_is_marked(parent)){ current_parent_top_level = SD_task_get_top_level(parent) + SD_task_estimate_execution_time(parent, SD_task_get_allocation_size(parent)); } else { current_parent_top_level = top_level_recursive_computation(parent) + SD_task_estimate_execution_time(parent, SD_task_get_allocation_size(parent)); } } if (max_top_level < current_parent_top_level) max_top_level = current_parent_top_level; } my_top_level = max_top_level; SD_task_set_top_level(task, my_top_level); SD_task_mark(task); XBT_DEBUG("%s's top level is %f", SD_task_get_name(task), my_top_level); xbt_dynar_free_container(&parents); return my_top_level; }
/* Build the set of the compute successors of a task that are ready (i.e., with all parents already scheduled). Both * data and control dependencies are checked. As more than one transfer may exist between two compute tasks, it is * mandatory to check whether the successor is not already in the set. */ xbt_dynar_t SD_task_get_ready_children(SD_task_t t){ unsigned int i; xbt_dynar_t children=NULL, ready_children; xbt_dynar_t output_transfers = SD_task_get_children(t); SD_task_t output, child; ready_children = xbt_dynar_new(sizeof(SD_task_t), NULL); xbt_dynar_foreach(output_transfers, i, output){ if (SD_task_get_kind(output) == SD_TASK_COMM_E2E) { /* Data dependency case: a compute task is followed by a data transfer. Its child (in a scheduling sense) is * then the grand child */ children = SD_task_get_children(output); xbt_dynar_get_cpy(children, 0, &child); /* check if this child is already in the set */ if (xbt_dynar_member(ready_children, &child)){ XBT_DEBUG("%s already seen, ignore", SD_task_get_name(child)); xbt_dynar_free_container(&children); /* avoid memory leaks */ continue; } if (SD_task_get_kind(child) == SD_TASK_COMP_SEQ && (SD_task_get_state(child) == SD_NOT_SCHEDULED || SD_task_get_state(child) == SD_SCHEDULABLE) && SD_task_is_ready(child)){ xbt_dynar_push(ready_children, &child); } xbt_dynar_free_container(&children); /* avoid memory leaks */ } else { /* Control dependency case: a compute task successor is another compute task. */ /* check if this child is already in the set */ if (xbt_dynar_member(ready_children, &output)){ XBT_DEBUG("%s already seen, ignore", SD_task_get_name(output)); continue; } if (SD_task_get_kind(output) == SD_TASK_COMP_SEQ && (SD_task_get_state(output) == SD_NOT_SCHEDULED || SD_task_get_state(output) == SD_SCHEDULABLE)&& SD_task_is_ready(output)){ xbt_dynar_push(ready_children, &output); } } } xbt_dynar_free_container(&output_transfers); /* avoid memory leaks */ return ready_children; }
xbt_dynar_foreach(dax, cursor, task) { if (SD_task_get_kind(task) == SD_TASK_COMP_SEQ) { if (!strcmp(SD_task_get_name(task), "end")) SD_task_schedulel(task, 1, ws_list[0]); else SD_task_schedulel(task, 1, ws_list[cursor % hosts_count]); } }
xbt_dynar_foreach(dot, cursor, task) { int kind = SD_task_get_kind(task); sg_host_t *wsl = SD_task_get_workstation_list(task); switch (kind) { case SD_TASK_COMP_SEQ: fprintf(out, "[%f->%f] %s compute %f flops # %s\n", SD_task_get_start_time(task), SD_task_get_finish_time(task), sg_host_get_name(wsl[0]), SD_task_get_amount(task), SD_task_get_name(task)); break; case SD_TASK_COMM_E2E: fprintf(out, "[%f -> %f] %s -> %s transfer of %.0f bytes # %s\n", SD_task_get_start_time(task), SD_task_get_finish_time(task), sg_host_get_name(wsl[0]), sg_host_get_name(wsl[1]), SD_task_get_amount(task), SD_task_get_name(task)); break; default: xbt_die("Task %s is of unknown kind %d", SD_task_get_name(task), SD_task_get_kind(task)); } SD_task_destroy(task); }
double bottom_level_recursive_computation(SD_task_t task){ unsigned int i; double my_bottom_level = 0.0, max_bottom_level, current_child_bottom_level = 0.0; SD_task_t child, grand_child; xbt_dynar_t children, grand_children; my_bottom_level = SD_task_estimate_execution_time(task, SD_task_get_allocation_size(task)); max_bottom_level = -1.0; if (!strcmp(SD_task_get_name(task),"end")){ XBT_DEBUG("end's bottom level is 0.0"); SD_task_mark(task); SD_task_set_bottom_level(task, 0.0); return 0.0; } children = SD_task_get_children(task); xbt_dynar_foreach(children, i, child){ if (SD_task_get_kind(child) == SD_TASK_COMM_PAR_MXN_1D_BLOCK) { grand_children = SD_task_get_children(child); xbt_dynar_get_cpy(grand_children, 0, &grand_child); if (SD_task_is_marked(grand_child)){ current_child_bottom_level = SD_task_get_bottom_level(grand_child); } else { current_child_bottom_level = bottom_level_recursive_computation(grand_child); } xbt_dynar_free_container(&grand_children); } else { if (SD_task_is_marked(child)){ current_child_bottom_level = SD_task_get_bottom_level(child); } else { current_child_bottom_level = bottom_level_recursive_computation(child); } } if (max_bottom_level < current_child_bottom_level) max_bottom_level = current_child_bottom_level; } my_bottom_level += max_bottom_level; SD_task_set_bottom_level(task, my_bottom_level); SD_task_mark(task); XBT_DEBUG("%s's bottom level is %f", SD_task_get_name(task), my_bottom_level); xbt_dynar_free_container(&children); return my_bottom_level ; }
/* This function is actually not used by biCPA */ int precedence_level_recursive_computation(SD_task_t task){ unsigned int i; int my_prec_level = -1, current_parent_prec_level = 0; SD_task_t parent, grand_parent=NULL; xbt_dynar_t parents, grand_parents; if (!strcmp(SD_task_get_name(task),"root")){ XBT_DEBUG("root's precedence level is 0.0"); SD_task_mark(task); SD_task_set_precedence_level(task, 0); return 0; } parents = SD_task_get_parents(task); xbt_dynar_foreach(parents, i, parent){ if (SD_task_get_kind(parent) == SD_TASK_COMM_PAR_MXN_1D_BLOCK) { grand_parents = SD_task_get_parents(parent); xbt_dynar_get_cpy(grand_parents, 0, &grand_parent); if (SD_task_is_marked(grand_parent)){ current_parent_prec_level = SD_task_get_precedence_level(grand_parent) + 1; } else { current_parent_prec_level = precedence_level_recursive_computation(grand_parent) + 1; } xbt_dynar_free_container(&grand_parents); } else { if (SD_task_is_marked(parent)){ current_parent_prec_level = SD_task_get_precedence_level(parent) + 1; } else { current_parent_prec_level = precedence_level_recursive_computation(parent) + 1; } } if (my_prec_level < current_parent_prec_level) my_prec_level = current_parent_prec_level; } SD_task_set_precedence_level(task, my_prec_level); SD_task_mark(task); XBT_DEBUG("%s's precedence level is %d", SD_task_get_name(task), my_prec_level); xbt_dynar_free_container(&parents); return my_prec_level; }
static xbt_dynar_t get_ready_tasks(xbt_dynar_t dax) { unsigned int i; xbt_dynar_t ready_tasks; SD_task_t task; ready_tasks = xbt_dynar_new(sizeof(SD_task_t), NULL); xbt_dynar_foreach(dax, i, task) { if (SD_task_get_kind(task) == SD_TASK_COMP_SEQ && SD_task_get_state(task) == SD_SCHEDULABLE) { xbt_dynar_push(ready_tasks, &task); } } XBT_DEBUG("There are %lu ready tasks", xbt_dynar_length(ready_tasks)); return ready_tasks; }
/* * Return an estimation of the minimal time before which a task can start. This * time depends on the estimated finished time of the compute ancestors of the * task, as set when they have been scheduled. Two cases are considered, * depending on whether an ancestor is 'linked' to the task through a flow or * control dependency. Flow dependencies imply to look at the grand parents of * the task, while control dependencies look at the parent tasks directly. */ double SD_task_estimate_minimal_start_time(SD_task_t task){ unsigned int i; double min_start_time=0.0; xbt_dynar_t parents, grand_parents; SD_task_t parent, grand_parent; parents = SD_task_get_parents(task); xbt_dynar_foreach(parents, i, parent){ if (SD_task_get_kind(parent) == SD_TASK_COMM_PAR_MXN_1D_BLOCK) { grand_parents = SD_task_get_parents(parent); xbt_dynar_get_cpy(grand_parents, 0, &grand_parent); if (SD_task_get_estimated_finish_time(grand_parent) > min_start_time) min_start_time = SD_task_get_estimated_finish_time(grand_parent); xbt_dynar_free_container(&grand_parents); } else{ if (SD_task_get_estimated_finish_time(parent) > min_start_time) min_start_time = SD_task_get_estimated_finish_time(parent); } } xbt_dynar_free_container(&parents); return min_start_time; }
/* Determine if a task is ready. The condition to meet is that all its compute predecessors have to be in one of the * following state: * - SD_RUNNABLE * - SD_RUNNING * - SD_DONE */ int SD_task_is_ready(SD_task_t task){ unsigned int i; int is_ready = 1; xbt_dynar_t parents, grand_parents; SD_task_t parent, grand_parent; parents = SD_task_get_parents(task); if (xbt_dynar_length(parents)) { xbt_dynar_foreach(parents, i, parent){ if (SD_task_get_kind(parent) == SD_TASK_COMM_E2E) { /* Data dependency case: a compute task is preceded by a data transfer. Its parent (in a scheduling sense) is * then the grand parent */ grand_parents = SD_task_get_parents(parent); xbt_dynar_get_cpy(grand_parents, 0, &grand_parent); if (SD_task_get_state(grand_parent) < SD_SCHEDULED) { is_ready =0; xbt_dynar_free_container(&grand_parents); /* avoid memory leaks */ break; } else { xbt_dynar_free_container(&grand_parents); /* avoid memory leaks */ } } else { /* Control dependency case: a compute task predecessor is another compute task. */ if (SD_task_get_state(parent) < SD_SCHEDULED) { is_ready =0; break; } } } } xbt_dynar_free_container(&parents); /* avoid memory leaks */ return is_ready; }
/** @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 decouple them from the scheduling process where you just specify which resource should deliver the * mandatory power. * * To be auto-schedulable, a task must be type and created with one of the specialized creation functions. * * @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 Amdahl) * - 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 sg_host_t * list) { int i; int j; xbt_assert(task->kind != 0, "Task %s is not typed. Cannot automatically schedule it.", SD_task_get_name(task)); switch (task->kind) { case SD_TASK_COMP_PAR_AMDAHL: SD_task_distribute_comp_amdahl(task, count); /* no break */ case SD_TASK_COMM_E2E: case SD_TASK_COMP_SEQ: xbt_assert(task->host_count == count, "Got %d locations, but were expecting %d locations", count,task->host_count); for (i = 0; i < count; i++) task->host_list[i] = list[i]; if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->flops_amount){ /*This task has failed and is rescheduled. Reset the flops_amount*/ task->flops_amount = xbt_new0(double, 1); task->flops_amount[0] = task->remains; } SD_task_do_schedule(task); break; default: xbt_die("Kind of task %s not supported by SD_task_schedulev()", SD_task_get_name(task)); }
/** * \brief Returns the alpha parameter of a SD_TASK_COMP_PAR_AMDAHL task * * \param task a parallel task assuming Amdahl's law as speedup model * \return the alpha parameter (serial part of a task in percent) for this task */ double SD_task_get_alpha(SD_task_t task) { xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL, "Alpha parameter is not defined for this kind of task"); return task->alpha; }
int main(int argc, char **argv) { unsigned int flag, cursor, cursor2; char *platform_file = NULL, *daxname = NULL, *priority=NULL; int total_nworkstations = 0; const SD_workstation_t *workstations = NULL; xbt_dynar_t daxes = NULL, current_dax = NULL; int completed_daxes = 0; SD_task_t task; scheduling_globals_t globals; WorkstationAttribute attr; double total_cost = 0.0, score = 0.0; SD_init(&argc, argv); /* get rid off some logs that are useless */ xbt_log_control_set("sd_daxparse.thresh:critical"); xbt_log_control_set("surf_workstation.thresh:critical"); xbt_log_control_set("root.fmt:[%9.3r]%e[%13c/%7p]%e%m%n"); globals = new_scheduling_globals(); daxes = xbt_dynar_new(sizeof(xbt_dynar_t), NULL); opterr = 0; while (1){ static struct option long_options[] = { {"alg", 1, 0, 'a'}, {"platform", 1, 0, 'b'}, {"dax", 1, 0, 'c'}, {"priority", 1, 0, 'd'}, {"deadline", 1, 0, 'e'}, {"budget", 1, 0, 'f'}, {"price", 1, 0, 'g'}, {"period", 1, 0, 'h'}, {"uh", 1, 0, 'i'}, {"ul", 1, 0, 'j'}, {"provisioning_delay", 1, 0, 'k'}, {"silent", 0, 0, 'y'}, {"dump", 1, 0, 'z'}, {0, 0, 0, 0} }; int option_index = 0; flag = getopt_long (argc, argv, "", long_options, &option_index); /* Detect the end of the options. */ if (flag == -1) break; switch (flag) { case 0: /* If this option set a flag, do nothing else now. */ if (long_options[option_index].flag != 0) break; printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case 'a': /* Algorithm name */ /* DPDS, WA-DPDS, SPSS, Ours*/ globals->alg = getAlgorithmByName(optarg); break; case 'b': platform_file = optarg; SD_create_environment(platform_file); total_nworkstations = SD_workstation_get_number(); workstations = SD_workstation_get_list(); /* Sort the hosts by name for sake of simplicity */ qsort((void *)workstations,total_nworkstations, sizeof(SD_workstation_t), nameCompareWorkstations); for(cursor=0; cursor<total_nworkstations; cursor++){ SD_workstation_allocate_attribute(workstations[cursor]); } break; case 'c': /* List of DAGs to schedule concurrently (just file names here) */ daxname = optarg; XBT_DEBUG("Loading %s", daxname); current_dax = SD_daxload(daxname); xbt_dynar_foreach(current_dax,cursor,task) { if (SD_task_get_kind(task) == SD_TASK_COMP_SEQ){ SD_task_watch(task, SD_DONE); } SD_task_allocate_attribute(task); SD_task_set_dax_name(task, daxname); } xbt_dynar_push(daxes,¤t_dax); break; case 'd': priority = optarg; if (!strcmp(priority,"random")) globals->priority_method = RANDOM; else if (!strcmp(priority, "sorted")) globals->priority_method = SORTED; else { XBT_ERROR("Unknown priority setting method."); exit(1); } break; case 'e': globals->deadline = atof(optarg); break; case 'f': globals->budget = atof(optarg); break; case 'g': globals->price = atof(optarg); break; case 'h': globals->period = atof(optarg); break; case 'i': globals->uh = atof(optarg); break; case 'j': globals->ul = atof(optarg); break; case 'k': globals->provisioning_delay = atof(optarg); break; case 'y': xbt_log_control_set("root.thresh:critical"); break; case 'z': break; } } /* Display some information about the current run */ XBT_INFO("Algorithm: %s",getAlgorithmName(globals->alg)); XBT_INFO(" Priority method: %s", globals->priority_method ? "SORTED" : "RANDOM"); XBT_INFO(" Dynamic provisioning period: %.0fs", globals->period); XBT_INFO(" Lower utilization threshold: %.2f%%", globals->ul); XBT_INFO(" Upper utilization threshold: %.2f%%", globals->uh); XBT_INFO("Platform: %s (%d potential VMs)", platform_file, SD_workstation_get_number()); XBT_INFO(" VM hourly cost: $%f", globals->price); XBT_INFO(" VM provisioning delay: %.0fs", globals->provisioning_delay); if (ceil(globals->budget/((globals->deadline/3600.)*globals->price))> SD_workstation_get_number()){ XBT_ERROR("The platform file doesn't have enough nodes. Stop here"); exit(1); } /* Assign price and provisioning delay to workstation/VM (for the sake of * simplicity) */ for(cursor=0; cursor<total_nworkstations; cursor++){ SD_workstation_set_price(workstations[cursor], globals->price); SD_workstation_set_provisioning_delay(workstations[cursor], globals->provisioning_delay); } XBT_INFO("Ensemble: %lu DAXes", xbt_dynar_length(daxes)); /* Assign priorities to the DAXes composing the ensemble according to the * chosen method: RANDOM (default) or SORTED. * Then display the result. */ assign_dax_priorities(daxes, globals->priority_method); xbt_dynar_foreach(daxes, cursor, current_dax){ task = get_root(current_dax); XBT_INFO(" %s", SD_task_get_dax_name(task)); XBT_INFO(" Priority: %d", SD_task_get_dax_priority(task)); }
int main(int argc, char **argv) { int i; const char *platform_file; const SD_workstation_t *workstations; int kind; SD_task_t task, taskA, taskB, taskC; xbt_dynar_t changed_tasks; SD_workstation_t workstation_list[2]; double computation_amount[2]; double communication_amount[4] = { 0 }; double rate = -1.0; SD_workstation_t w1, w2; /* SD initialization */ SD_init(&argc, argv); /* xbt_log_control_set("sd.thres=debug"); */ if (argc < 2) { XBT_INFO("Usage: %s platform_file", argv[0]); XBT_INFO("example: %s sd_platform.xml", argv[0]); exit(1); } /* creation of the environment */ platform_file = argv[1]; SD_create_environment(platform_file); /* Change the access mode of the workstations */ workstations = SD_workstation_get_list(); w1 = workstations[0]; w2 = workstations[1]; for (i = 0; i < 2; i++) { SD_workstation_set_access_mode(workstations[i], SD_WORKSTATION_SEQUENTIAL_ACCESS); XBT_INFO("Access mode of %s is %s", SD_workstation_get_name(workstations[i]), (SD_workstation_get_access_mode(workstations[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) ? "sequential" : "shared"); } /* creation of the tasks and their dependencies */ taskA = SD_task_create_comp_seq("Task A", NULL, 2e9); taskB = SD_task_create_comm_e2e("Task B", NULL, 2e9); taskC = SD_task_create_comp_seq("Task C", NULL, 1e9); TRACE_category ("taskA"); TRACE_category ("taskB"); TRACE_category ("taskC"); TRACE_sd_set_task_category (taskA, "taskA"); TRACE_sd_set_task_category (taskB, "taskB"); TRACE_sd_set_task_category (taskC, "taskC"); /* if everything is ok, no exception is forwarded or rethrown by main() */ /* watch points */ SD_task_watch(taskA, SD_RUNNING); SD_task_watch(taskB, SD_RUNNING); SD_task_watch(taskC, SD_RUNNING); SD_task_watch(taskC, SD_DONE); /* scheduling parameters */ workstation_list[0] = w1; workstation_list[1] = w2; computation_amount[0] = SD_task_get_amount(taskA); computation_amount[1] = SD_task_get_amount(taskB); communication_amount[1] = SD_task_get_amount(taskC); communication_amount[2] = 0.0; SD_task_schedule(taskA, 1, &w1, &(computation_amount[0]), SD_SCHED_NO_COST, rate); SD_task_schedule(taskB, 2, workstation_list, SD_SCHED_NO_COST, communication_amount, rate); SD_task_schedule(taskC, 1, &w1, &(computation_amount[1]), SD_SCHED_NO_COST, rate); /* let's launch the simulation! */ while (!xbt_dynar_is_empty(changed_tasks = SD_simulate(-1.0))) { for (i = 0; i < 2; i++) { task = SD_workstation_get_current_task(workstations[i]); if (task) kind = SD_task_get_kind(task); else { XBT_INFO("There is no task running on %s", SD_workstation_get_name(workstations[i])); continue; } switch (kind) { case SD_TASK_COMP_SEQ: XBT_INFO("%s is currently running on %s (SD_TASK_COMP_SEQ)", SD_task_get_name(task), SD_workstation_get_name(workstations[i])); break; case SD_TASK_COMM_E2E: XBT_INFO("%s is currently running on %s (SD_TASK_COMM_E2E)", SD_task_get_name(task), SD_workstation_get_name(workstations[i])); break; case SD_TASK_NOT_TYPED: XBT_INFO("Task running on %s has no type", SD_workstation_get_name(workstations[i])); break; default: XBT_ERROR("Shouldn't be here"); } } xbt_dynar_free_container(&changed_tasks); } xbt_dynar_free_container(&changed_tasks); XBT_DEBUG("Destroying tasks..."); SD_task_destroy(taskA); SD_task_destroy(taskB); SD_task_destroy(taskC); XBT_DEBUG("Tasks destroyed. Exiting SimDag..."); SD_exit(); return 0; }
xbt_dynar_foreach(dot, cursor, task) { if (SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL) { SD_task_schedulev(task, count, ws_list); } }