Esempio n. 1
0
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;
}
Esempio n. 3
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;
}
Esempio n. 4
0
/* 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;
}
Esempio n. 5
0
/* 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;
}
Esempio n. 6
0
/* 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;
}
Esempio n. 7
0
/* 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;
}
Esempio n. 8
0
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);
    }
Esempio n. 9
0
/* 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;
}
Esempio n. 10
0
  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);
Esempio n. 11
0
/** @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());
}
Esempio n. 12
0
    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");
Esempio n. 13
0
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;
}
Esempio n. 14
0
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);
      }
    }
  }