int main(int argc, char **argv) { char *platformFile = NULL; unsigned int totalHosts, totalLinks; int timings=0; int version = 4; const char *link_ctn = "link_ctn"; unsigned int i; xbt_dict_t props = NULL; xbt_dict_cursor_t cursor = NULL; xbt_lib_cursor_t cursor_src = NULL; xbt_lib_cursor_t cursor_dst = NULL; char *src,*dst,*key,*data; sg_netcard_t value1; sg_netcard_t value2; const sg_host_t *hosts; const SD_link_t *links; xbt_os_timer_t parse_time = xbt_os_timer_new(); SD_init(&argc, argv); if (parse_cmdline(&timings, &platformFile, argc, argv) || !platformFile) { xbt_die("Invalid command line arguments: expected [--timings] platformFile"); } XBT_DEBUG("%d,%s", timings, platformFile); create_environment(parse_time, platformFile); if (timings) { XBT_INFO("Parsing time: %fs (%zu hosts, %d links)", xbt_os_timer_elapsed(parse_time), sg_host_count(), sg_link_count()); } else { printf("<?xml version='1.0'?>\n"); printf("<!DOCTYPE platform SYSTEM \"http://simgrid.gforge.inria.fr/simgrid/simgrid.dtd\">\n"); printf("<platform version=\"%d\">\n", version); printf("<AS id=\"AS0\" routing=\"Full\">\n"); // Hosts totalHosts = sg_host_count(); hosts = sg_host_list(); qsort((void *) hosts, totalHosts, sizeof(sg_host_t), name_compare_hosts); for (i = 0; i < totalHosts; i++) { printf(" <host id=\"%s\" speed=\"%.0f\"", sg_host_get_name(hosts[i]), sg_host_speed(hosts[i])); props = sg_host_get_properties(hosts[i]); if (sg_host_core_count(hosts[i])>1) { printf(" core=\"%d\"", sg_host_core_count(hosts[i])); } if (props && !xbt_dict_is_empty(props)) { printf(">\n"); xbt_dict_foreach(props, cursor, key, data) { printf(" <prop id=\"%s\" value=\"%s\"/>\n", key, data); } printf(" </host>\n"); } else {
int main(int argc, char **argv) { int i, j; xbt_os_timer_t timer = xbt_os_timer_new(); SD_init(&argc, argv); SD_create_environment(argv[1]); sg_host_t *hosts = sg_host_list(); int host_count = sg_host_count(); /* Random number initialization */ srand( (int) (xbt_os_time()*1000) ); do { i = rand()%host_count; j = rand()%host_count; } while(i==j); sg_host_t h1 = hosts[i]; sg_host_t h2 = hosts[j]; printf("%d\tand\t%d\t\t",i,j); xbt_os_cputimer_start(timer); SD_route_get_list(h1, h2); xbt_os_cputimer_stop(timer); printf("%f\n", xbt_os_timer_elapsed(timer) ); xbt_free(hosts); SD_exit(); return 0; }
/* Build an array that contains all the idle hosts/VMs in the platform */ xbt_dynar_t get_idle_VMs(){ int i; const sg_host_t *hosts = sg_host_list(); int nhosts = sg_host_count(); xbt_dynar_t idleVMs = xbt_dynar_new(sizeof(sg_host_t), NULL); for (i = 0; i < nhosts; i++){ if (is_on_and_idle(hosts[i])) xbt_dynar_push(idleVMs, &(hosts[i])); } return idleVMs; }
/* Build an array that contains all the busy hosts/VMs in the platform */ xbt_dynar_t get_running_VMs(){ int i; const sg_host_t *hosts = sg_host_list (); int nhosts = sg_host_count (); HostAttribute attr; xbt_dynar_t runningVMs = xbt_dynar_new(sizeof(sg_host_t), NULL); for (i = 0; i < nhosts; i++){ attr = sg_host_user(hosts[i]); if (attr->on_off) xbt_dynar_push(runningVMs, &(hosts[i])); } return runningVMs; }
/* Determine the current utilization of VM in the system. This utilization is defined in the paper by Malawski et al. * as "the percentage of idle VMs over time". * The source code shows that it is the number of busy VMs divided by the total number of active VMs (busy and idle) */ double compute_current_VM_utilization(){ int i=0; const sg_host_t *hosts = sg_host_list (); int nhosts = sg_host_count (); HostAttribute attr; int nActiveVMs = 0, nBusyVMs = 0; for (i = 0; i < nhosts; i++){ attr = sg_host_user(hosts[i]); if (attr->on_off){ nActiveVMs++; if (!attr->idle_busy) nBusyVMs++; } } return (100.*nBusyVMs)/nActiveVMs; }
/* Determine how much money has already been spent. Each host/VM has an attribute that sums the cost (#hours*price) * for each period in which the VM is on. */ double compute_budget_consumption(){ double consumed_budget = 0.0; int i=0; HostAttribute attr; const sg_host_t *hosts = sg_host_list (); int nhosts = sg_host_count (); for(i=0;i<nhosts;i++){ attr = sg_host_user(hosts[i]); consumed_budget += attr->total_cost; if (attr->on_off){ XBT_DEBUG("%s : Account for %d consumed hours", sg_host_get_name(hosts[i]), (int)(SD_get_clock()-attr->start_time)/3600); consumed_budget += (((int)(SD_get_clock()-attr->start_time)/3600))*attr->price; } } return consumed_budget; }
/* Build an array that contains all the hosts/VMs that are "approaching their hourly billing cycle" in the platform * Remark: In the paper by Malawski et al., no details are provided about when a VM is "approaching" the end of a * paid hour. This is hard coded in the source code of cloudworkflowsim: 90s (provisioner interval, a.k.a period) + * 1s (optimistic deprovisioning delay) */ xbt_dynar_t get_ending_billing_cycle_VMs(double period, double margin){ int i; const sg_host_t *hosts = sg_host_list (); int nhosts = sg_host_count (); HostAttribute attr; xbt_dynar_t endingVMs = xbt_dynar_new(sizeof(sg_host_t), NULL); for (i = 0; i < nhosts; i++){ attr = sg_host_user(hosts[i]); /* To determine how far a VM is from the end of a hourly billing cycle, we compute the time spent between the * start of the VM and the current, and keep the time spent in the last hour. As times are expressed in seconds, * it amounts to computing the modulo to 3600s=1h. Then the current VM is selected if this modulo is greater than * 3600-period-margin. */ if (attr->on_off && ((int)(SD_get_clock() - attr->start_time) % 3600) > (3600-period-margin)) xbt_dynar_push(endingVMs, &(hosts[i])); } return endingVMs; }
int main(int argc, char **argv) { xbt_os_timer_t timer = xbt_os_timer_new(); /* initialization of SD */ SD_init(&argc, argv); if (argc > 1) { SD_create_environment(argv[1]); } else { SD_create_environment("../../platforms/One_cluster_no_backbone.xml"); } ws_list = sg_host_list(); reclaimed = xbt_dynar_new(sizeof(bcast_task_t),xbt_free_ref); xbt_dynar_t done = NULL; xbt_os_cputimer_start(timer); send_one(0,sg_host_count()); do { if (done != NULL && !xbt_dynar_is_empty(done)) { unsigned int cursor; SD_task_t task; xbt_dynar_foreach(done, cursor, task) { bcast_task_t bt = SD_task_get_data(task); if (bt->i != bt->j -1) send_one(bt->i,bt->j); if (bt->j != bt->k -1) send_one(bt->j,bt->k); if (xbt_dynar_length(reclaimed)<100) { xbt_dynar_push_as(reclaimed,bcast_task_t,bt); } else { free(bt); } SD_task_destroy(task); } xbt_dynar_free(&done); }
/* Return the first inactive host/VM (currently set to OFF) that we find in the platform. * Remarks: * 1) Straightforward selection, all VMs are assumed to be similar * 2) It may happen that no such VM is found. This means that the platform file given as input of the simulator was * too small. The simulation cannot continue while the size of the resource pool represented by the platform file * is not increased. */ sg_host_t find_inactive_VM_to_start(){ int i=0; const sg_host_t *hosts = sg_host_list (); int nhosts = sg_host_count (); HostAttribute attr; sg_host_t host = NULL; while (i < nhosts){ attr = sg_host_user(hosts[i]); if (!attr->on_off){ host = hosts[i]; break; } i++; } if (!host){ xbt_die("Argh. We reached the pool limit. Have to increase the size of the cluster in the platform file."); } return host; }
xbt_dynar_foreach(dax, cursor, task) { SD_task_dump(task); } FILE *dotout = fopen("dax.dot", "w"); fprintf(dotout, "digraph A {\n"); xbt_dynar_foreach(dax, cursor, task) { SD_task_dotty(task, dotout); } fprintf(dotout, "}\n"); fclose(dotout); /* Schedule them all on the first host */ XBT_INFO("------------------- Schedule tasks ---------------------------"); const sg_host_t *ws_list = sg_host_list(); int hosts_count = sg_host_count(); qsort((void *) ws_list, hosts_count, sizeof(sg_host_t), name_compare_hosts); 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_INFO("------------------- Run the schedule ---------------------------"); SD_simulate(-1); XBT_INFO("------------------- Produce the trace file---------------------------"); XBT_INFO("Producing the trace of the run into %s", tracefilename);
/** @brief Returns the host list * * Uses sg_host_count() to know the array size. * * \return an array of \ref sg_host_t containing all the hosts in the platform. * \remark The host order in this array is generally different from the * creation/declaration order in the XML platform (we use a hash table * internally). * \see sg_host_count() */ sg_host_t *sg_host_list(void) { xbt_assert(sg_host_count() > 0, "There is no host!"); return (sg_host_t*)xbt_dynar_to_array(sg_hosts_as_dynar()); }
SD_task_dump(task); } FILE *dotout = fopen("dot.dot", "w"); fprintf(dotout, "digraph A {\n"); xbt_dynar_foreach(dot, cursor, task) { SD_task_dotty(task, dotout); } fprintf(dotout, "}\n"); fclose(dotout); /* Schedule them all on the first workstation */ XBT_INFO("------------------- Schedule tasks ---------------------------"); const sg_host_t *ws_list = sg_host_list(); int count = sg_host_count(); xbt_dynar_foreach(dot, 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 % count]); } } XBT_INFO("------------------- Run the schedule ---------------------------"); SD_simulate(-1); XBT_INFO("------------------- Produce the trace file---------------------------"); XBT_INFO("Producing the trace of the run into %s", basename(tracefilename)); FILE *out = fopen(tracefilename, "w");
xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, bool schedule) { xbt_assert(filename, "Unable to use a null file descriptor\n"); FILE *in_file = fopen(filename, "r"); xbt_assert(in_file != nullptr, "Failed to open file: %s", filename); SD_task_t root; SD_task_t end; SD_task_t task; std::vector<SD_task_t>* computer; std::unordered_map<std::string, std::vector<SD_task_t>*> computers; bool schedule_success = true; std::unordered_map<std::string, SD_task_t> jobs; xbt_dynar_t result = xbt_dynar_new(sizeof(SD_task_t), dot_task_p_free); Agraph_t * dag_dot = agread(in_file, NIL(Agdisc_t *)); /* Create all the nodes */ Agnode_t *node = nullptr; for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { char *name = agnameof(node); double amount = atof(agget(node, (char*)"size")); if (jobs.find(name) == jobs.end()) { if (sequential) { XBT_DEBUG("See <job id=%s amount =%.0f>", name, amount); task = SD_task_create_comp_seq(name, nullptr , amount); } else { double alpha = atof(agget(node, (char *) "alpha")); XBT_DEBUG("See <job id=%s amount =%.0f alpha = %.3f>", name, amount, alpha); task = SD_task_create_comp_par_amdahl(name, nullptr , amount, alpha); } jobs.insert({std::string(name), task}); if (strcmp(name,"root") && strcmp(name,"end")) xbt_dynar_push(result, &task); if ((sequential) && ((schedule && schedule_success) || XBT_LOG_ISENABLED(sd_dotparse, xbt_log_priority_verbose))) { /* try to take the information to schedule the task only if all is right*/ char *char_performer = agget(node, (char *) "performer"); char *char_order = agget(node, (char *) "order"); /* Tasks will execute on in a given "order" on a given set of "performer" hosts */ int performer = ((not char_performer || not strcmp(char_performer, "")) ? -1 : atoi(char_performer)); int order = ((not char_order || not strcmp(char_order, "")) ? -1 : atoi(char_order)); if ((performer != -1 && order != -1) && performer < static_cast<int>(sg_host_count())) { /* required parameters are given and less performers than hosts are required */ XBT_DEBUG ("Task '%s' is scheduled on workstation '%d' in position '%d'", task->name, performer, order); auto comp = computers.find(char_performer); if (comp != computers.end()) { computer = comp->second; } else { computer = new std::vector<SD_task_t>; computers.insert({char_performer, computer}); } if (static_cast<unsigned int>(order) < computer->size()) { SD_task_t task_test = computer->at(order); if (task_test && task_test != task) { /* the user gave the same order to several tasks */ schedule_success = false; XBT_VERB("Task '%s' wants to start on performer '%s' at the same position '%s' as task '%s'", task_test->name, char_performer, char_order, task->name); continue; } } else computer->resize(order); computer->insert(computer->begin() + order, task); } else { /* one of required parameters is not given */ schedule_success = false; XBT_VERB("The schedule is ignored, task '%s' can not be scheduled on %d hosts", task->name, performer); } } } else { XBT_WARN("Task '%s' is defined more than once", name); } } /*Check if 'root' and 'end' nodes have been explicitly declared. If not, create them. */ if (jobs.find("root") == jobs.end()) root = (sequential ? SD_task_create_comp_seq("root", nullptr, 0) : SD_task_create_comp_par_amdahl("root", nullptr, 0, 0)); else root = jobs.at("root"); SD_task_set_state(root, SD_SCHEDULABLE); /* by design the root task is always SCHEDULABLE */ xbt_dynar_insert_at(result, 0, &root); /* Put it at the beginning of the dynar */ if (jobs.find("end") == jobs.end()) end = (sequential ? SD_task_create_comp_seq("end", nullptr, 0) : SD_task_create_comp_par_amdahl("end", nullptr, 0, 0)); else end = jobs.at("end"); /* Create edges */ std::vector<Agedge_t*> edges; for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { edges.clear(); for (Agedge_t* edge = agfstout(dag_dot, node); edge; edge = agnxtout(dag_dot, edge)) edges.push_back(edge); /* Be sure edges are sorted */ std::sort(edges.begin(), edges.end(), [](const Agedge_t* a, const Agedge_t* b) { return AGSEQ(a) < AGSEQ(b); }); for (Agedge_t* edge : edges) { char *src_name=agnameof(agtail(edge)); char *dst_name=agnameof(aghead(edge)); double size = atof(agget(edge, (char *) "size")); SD_task_t src = jobs.at(src_name); SD_task_t dst = jobs.at(dst_name); if (size > 0) { std::string name = std::string(src_name) + "->" + dst_name; XBT_DEBUG("See <transfer id=%s amount = %.0f>", name.c_str(), size); if (jobs.find(name) == jobs.end()) { if (sequential) task = SD_task_create_comm_e2e(name.c_str(), nullptr, size); else task = SD_task_create_comm_par_mxn_1d_block(name.c_str(), nullptr, size); SD_task_dependency_add(src, task); SD_task_dependency_add(task, dst); jobs.insert({name, task}); xbt_dynar_push(result, &task); } else { XBT_WARN("Task '%s' is defined more than once", name.c_str()); } } else { SD_task_dependency_add(src, dst); } } } XBT_DEBUG("All tasks have been created, put %s at the end of the dynar", end->name); xbt_dynar_push(result, &end); /* Connect entry tasks to 'root', and exit tasks to 'end'*/ unsigned i; xbt_dynar_foreach (result, i, task){ if (task->predecessors->empty() && task->inputs->empty() && task != root) { XBT_DEBUG("Task '%s' has no source. Add dependency from 'root'", task->name); SD_task_dependency_add(root, task); } if (task->successors->empty() && task->outputs->empty() && task != end) { XBT_DEBUG("Task '%s' has no destination. Add dependency to 'end'", task->name); SD_task_dependency_add(task, end); } } agclose(dag_dot); fclose(in_file); if(schedule){ if (schedule_success) { std::vector<simgrid::s4u::Host*> hosts = simgrid::s4u::Engine::get_instance()->get_all_hosts(); for (auto const& elm : computers) { SD_task_t previous_task = nullptr; for (auto const& cur_task : *elm.second) { /* add dependency between the previous and the task to avoid parallel execution */ if (cur_task) { if (previous_task && not SD_task_dependency_exists(previous_task, cur_task)) SD_task_dependency_add(previous_task, cur_task); SD_task_schedulel(cur_task, 1, hosts[std::stod(elm.first)]); previous_task = cur_task; } } delete elm.second; } } else { XBT_WARN("The scheduling is ignored"); for (auto const& elm : computers) delete elm.second; xbt_dynar_free(&result); result = nullptr; } } if (result && not acyclic_graph_detail(result)) { std::string base = simgrid::xbt::Path(filename).get_base_name(); XBT_ERROR("The DOT described in %s is not a DAG. It contains a cycle.", base.c_str()); xbt_dynar_free(&result); result = nullptr; } return result; }
xbt_dynar_t SD_dotload_generic(const char * filename, seq_par_t seq_or_par, bool schedule){ xbt_assert(filename, "Unable to use a null file descriptor\n"); FILE *in_file = fopen(filename, "r"); xbt_assert(in_file != nullptr, "Failed to open file: %s", filename); unsigned int i; SD_task_t root; SD_task_t end; SD_task_t task; xbt_dict_t computers; xbt_dynar_t computer = nullptr; xbt_dict_cursor_t dict_cursor; bool schedule_success = true; xbt_dict_t jobs = xbt_dict_new_homogeneous(nullptr); xbt_dynar_t result = xbt_dynar_new(sizeof(SD_task_t), dot_task_p_free); Agraph_t * dag_dot = agread(in_file, NIL(Agdisc_t *)); if (schedule) computers = xbt_dict_new_homogeneous(nullptr); /* Create all the nodes */ Agnode_t *node = nullptr; for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { char *name = agnameof(node); double amount = atof(agget(node, (char*)"size")); task = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, name)); if (task == nullptr) { if (seq_or_par == sequential){ XBT_DEBUG("See <job id=%s amount =%.0f>", name, amount); task = SD_task_create_comp_seq(name, nullptr , amount); } else { double alpha = atof(agget(node, (char *) "alpha")); XBT_DEBUG("See <job id=%s amount =%.0f alpha = %.3f>", name, amount, alpha); task = SD_task_create_comp_par_amdahl(name, nullptr , amount, alpha); } xbt_dict_set(jobs, name, task, nullptr); if (strcmp(name,"root") && strcmp(name,"end")) xbt_dynar_push(result, &task); if((seq_or_par == sequential) && ((schedule && schedule_success) || XBT_LOG_ISENABLED(sd_dotparse, xbt_log_priority_verbose))){ /* try to take the information to schedule the task only if all is right*/ char *char_performer = agget(node, (char *) "performer"); char *char_order = agget(node, (char *) "order"); /* Tasks will execute on in a given "order" on a given set of "performer" hosts */ int performer = ((!char_performer || !strcmp(char_performer,"")) ? -1:atoi(char_performer)); int order = ((!char_order || !strcmp(char_order, ""))? -1:atoi(char_order)); if((performer != -1 && order != -1) && performer < (int) sg_host_count()){ /* required parameters are given and less performers than hosts are required */ XBT_DEBUG ("Task '%s' is scheduled on workstation '%d' in position '%d'", task->name, performer, order); if(!(computer = (xbt_dynar_t) xbt_dict_get_or_null(computers, char_performer))){ computer = xbt_dynar_new(sizeof(SD_task_t), nullptr); xbt_dict_set(computers, char_performer, computer, nullptr); } if((unsigned int)order < xbt_dynar_length(computer)){ SD_task_t *task_test = (SD_task_t *)xbt_dynar_get_ptr(computer,order); if(*task_test && *task_test != task){ /* the user gave the same order to several tasks */ schedule_success = false; XBT_VERB("Task '%s' wants to start on performer '%s' at the same position '%s' as task '%s'", (*task_test)->name, char_performer, char_order, task->name); continue; } } /* the parameter seems to be ok */ xbt_dynar_set_as(computer, order, SD_task_t, task); } else { /* one of required parameters is not given */ schedule_success = false; XBT_VERB("The schedule is ignored, task '%s' can not be scheduled on %d hosts", task->name, performer); } } } else { XBT_WARN("Task '%s' is defined more than once", name); } } /*Check if 'root' and 'end' nodes have been explicitly declared. If not, create them. */ if (!(root = (SD_task_t)xbt_dict_get_or_null(jobs, "root"))) root = (seq_or_par == sequential?SD_task_create_comp_seq("root", nullptr, 0): SD_task_create_comp_par_amdahl("root", nullptr, 0, 0)); SD_task_set_state(root, SD_SCHEDULABLE); /* by design the root task is always SCHEDULABLE */ xbt_dynar_insert_at(result, 0, &root); /* Put it at the beginning of the dynar */ if (!(end = (SD_task_t)xbt_dict_get_or_null(jobs, "end"))) end = (seq_or_par == sequential?SD_task_create_comp_seq("end", nullptr, 0): SD_task_create_comp_par_amdahl("end", nullptr, 0, 0)); /* Create edges */ xbt_dynar_t edges = xbt_dynar_new(sizeof(Agedge_t*), nullptr); for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { Agedge_t * edge; xbt_dynar_reset(edges); for (edge = agfstout(dag_dot, node); edge; edge = agnxtout(dag_dot, edge)) xbt_dynar_push_as(edges, Agedge_t *, edge); /* Be sure edges are sorted */ xbt_dynar_sort(edges, edge_compare); xbt_dynar_foreach(edges, i, edge) { char *src_name=agnameof(agtail(edge)), *dst_name=agnameof(aghead(edge)); double size = atof(agget(edge, (char *) "size")); SD_task_t src = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, src_name)); SD_task_t dst = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, dst_name)); if (size > 0) { char *name = bprintf("%s->%s", src_name, dst_name); XBT_DEBUG("See <transfer id=%s amount = %.0f>", name, size); task = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, name)); if (task == nullptr) { if (seq_or_par == sequential) task = SD_task_create_comm_e2e(name, nullptr , size); else task = SD_task_create_comm_par_mxn_1d_block(name, nullptr , size); SD_task_dependency_add(nullptr, nullptr, src, task); SD_task_dependency_add(nullptr, nullptr, task, dst); xbt_dict_set(jobs, name, task, nullptr); xbt_dynar_push(result, &task); } else { XBT_WARN("Task '%s' is defined more than once", name); } xbt_free(name); } else { SD_task_dependency_add(nullptr, nullptr, src, dst); } } }