Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
java: setup a RAII wrapper to properly deal with GetStringUTFChars/ReleaseStringUTFChar
[simgrid.git] / src / simdag / sd_dotloader.cpp
1 /* Copyright (c) 2009-2021. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "simdag_private.hpp"
8 #include "simgrid/s4u/Activity.hpp"
9 #include "simgrid/s4u/Comm.hpp"
10 #include "simgrid/s4u/Engine.hpp"
11 #include "simgrid/s4u/Exec.hpp"
12 #include "src/internal_config.h"
13 #include "xbt/file.hpp"
14 #include <algorithm>
15 #include <cstring>
16 #include <unordered_map>
17 #include <vector>
18
19 #if HAVE_GRAPHVIZ
20 #include <graphviz/cgraph.h>
21
22 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_dotparse, sd, "Parsing DOT files");
23
24 namespace simgrid {
25 namespace s4u {
26
27 std::vector<ActivityPtr> create_DAG_from_dot(const std::string& filename)
28 {
29   FILE* in_file = fopen(filename.c_str(), "r");
30   xbt_assert(in_file != nullptr, "Failed to open file: %s", filename.c_str());
31
32   Agraph_t* dag_dot = agread(in_file, NIL(Agdisc_t*));
33
34   std::unordered_map<std::string, ActivityPtr> activities;
35   std::vector<ActivityPtr> dag;
36
37   ActivityPtr root;
38   ActivityPtr end;
39   ActivityPtr act;
40   /* Create all the nodes */
41   Agnode_t* node = nullptr;
42   for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) {
43     char* name    = agnameof(node);
44     double amount = atof(agget(node, (char*)"size"));
45
46     if (activities.find(name) == activities.end()) {
47       XBT_DEBUG("See <Exec id = %s amount = %.0f>", name, amount);
48       act = Exec::init()->set_name(name)->set_flops_amount(amount)->vetoable_start();
49       activities.insert({std::string(name), act});
50       if (strcmp(name, "root") && strcmp(name, "end"))
51         dag.push_back(act);
52     } else {
53       XBT_WARN("Exec '%s' is defined more than once", name);
54     }
55   }
56   /*Check if 'root' and 'end' nodes have been explicitly declared.  If not, create them. */
57   if (activities.find("root") == activities.end())
58     root = Exec::init()->set_name("root")->set_flops_amount(0)->vetoable_start();
59   else
60     root = activities.at("root");
61
62   if (activities.find("end") == activities.end())
63     end = Exec::init()->set_name("end")->set_flops_amount(0)->vetoable_start();
64   else
65     end = activities.at("end");
66
67   /* Create edges */
68   std::vector<Agedge_t*> edges;
69   for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) {
70     edges.clear();
71     for (Agedge_t* edge = agfstout(dag_dot, node); edge; edge = agnxtout(dag_dot, edge))
72       edges.push_back(edge);
73
74     /* Be sure edges are sorted */
75     std::sort(edges.begin(), edges.end(), [](const Agedge_t* a, const Agedge_t* b) { return AGSEQ(a) < AGSEQ(b); });
76
77     for (Agedge_t* edge : edges) {
78       const char* src_name = agnameof(agtail(edge));
79       const char* dst_name = agnameof(aghead(edge));
80       double size          = atof(agget(edge, (char*)"size"));
81
82       ActivityPtr src = activities.at(src_name);
83       ActivityPtr dst = activities.at(dst_name);
84       if (size > 0) {
85         std::string name = std::string(src_name) + "->" + dst_name;
86         XBT_DEBUG("See <Comm id=%s amount = %.0f>", name.c_str(), size);
87         if (activities.find(name) == activities.end()) {
88           act = Comm::sendto_init()->set_name(name)->set_payload_size(size)->vetoable_start();
89           src->add_successor(act);
90           act->add_successor(dst);
91           activities.insert({name, act});
92           dag.push_back(act);
93         } else {
94           XBT_WARN("Comm '%s' is defined more than once", name.c_str());
95         }
96       } else {
97         src->add_successor(dst);
98       }
99     }
100   }
101
102   XBT_DEBUG("All activities have been created, put %s at the beginning and %s at the end", root->get_cname(),
103             end->get_cname());
104   dag.insert(dag.begin(), root);
105   dag.push_back(end);
106
107   /* Connect entry tasks to 'root', and exit tasks to 'end'*/
108   for (const auto& a : dag) {
109     if (a->dependencies_solved() && a != root) {
110       XBT_DEBUG("Activity '%s' has no dependencies. Add dependency from 'root'", a->get_cname());
111       root->add_successor(a);
112     }
113
114     if (a->is_waited_by() == 0 && a != end) {
115       XBT_DEBUG("Activity '%s' has no successors. Add dependency to 'end'", a->get_cname());
116       a->add_successor(end);
117     }
118   }
119   agclose(dag_dot);
120   fclose(in_file);
121
122   if (not check_for_cycle(dag)) {
123     std::string base = simgrid::xbt::Path(filename).get_base_name();
124     XBT_ERROR("The DOT described in %s is not a DAG. It contains a cycle.", base.c_str());
125     for (const auto& a : dag)
126       a->cancel();
127     dag.clear();
128   }
129
130   return dag;
131 }
132
133 } // namespace s4u
134 } // namespace simgrid
135
136 #else
137 namespace simgrid {
138 namespace s4u {
139 std::vector<ActivityPtr> create_DAG_from_dot(const std::string& filename)
140 {
141   xbt_die("create_DAG_from_dot() is not usable because graphviz was not found.\n"
142           "Please install graphviz, graphviz-dev, and libgraphviz-dev (and erase CMakeCache.txt) before recompiling.");
143 }
144 } // namespace s4u
145 } // namespace simgrid
146
147 #endif