CGRA-ME
OpScheduler.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 #include <CGRA/OpScheduler.h>
11 #include <CGRA/Exception.h>
12 #include <CGRA/GraphAlgorithms.h>
14 #include <CGRA/MRRGProcedures.h>
15 #include <CGRA/dotparse.h>
16 
17 #include <iostream>
18 #include <sstream>
19 #include <cmath>
20 #include <algorithm>
21 #include <limits>
22 #include <stack>
23 #include <fstream>
24 
25 #include <gurobi_c++.h> //NOLINT
26 
27 
28 
29 // Op scheduler class to create a schedule to the operations within the opgraph
31  const MRRG& mrrg,
32  std::string arch_name,
33  std::string supported_ops_file_name)
34  : op_graph(opgraph)
35  , mrrg(mrrg) {
36  // If no directory is given to the scheduler look within the
37  // sched directory to find a supported ops file
38  std::string network_latency_filename = supported_ops_file_name;
39  if (supported_ops_file_name.empty()) {
40  std::string cgrame_rootdir = "CGRA_ME_ROOTDIR";
41  std::string dir = std::getenv(cgrame_rootdir.c_str());
42  dir = dir + "/src/sched/" + arch_name + "_supported_ops.dot";
43  network_latency_filename = dir;
44  }
45  parseNetworkSchedule(network_latency_filename);
46 
47  // Set up the function nodes from the MRRG file
48  const auto classes = computeNodeClassLists(mrrg);
49  for (const auto& mrrg_node : classes.function_nodes) {
50  function_nodes.push_back(mrrg_node);
51  }
52 }
53 
54 void OpScheduler::parseNetworkSchedule(std::string network_latency_filename) {
55  // Parsing the network schedule file
56  ConfigGraph parsed_network_latency_dot;
57  std::cout << "[INFO] Getting network latency from DOT file: " << network_latency_filename<< std::endl;
58  auto network_latency_ifstream = std::ifstream(network_latency_filename);
59  parsed_network_latency_dot = parseDot(network_latency_ifstream, network_latency_filename);
60 
61  for (const auto& v : parsed_network_latency_dot.allNodes()) {
62  // Setting up the operation latency
63  const auto& v_attrs = parsed_network_latency_dot.attributes(v);
64  op_latency.emplace(opcode_from_string(parsed_network_latency_dot.name(v)), v_attrs.getInt("OP_LATENCY"));
65 
66  for (const auto& out_edge : parsed_network_latency_dot.outEdges(v)) {
67  // Setting up the edges upper and lower latencies
68  const auto& e_attrs = parsed_network_latency_dot.attributes(out_edge);
69  std::string out_name = parsed_network_latency_dot.name(v);
70  std::string in_name = parsed_network_latency_dot.name(parsed_network_latency_dot.target(out_edge));
71  OpGraphOpCode out_op_code = opcode_from_string(out_name);
72  OpGraphOpCode in_op_code = opcode_from_string(in_name);
73  OpCodeEdge op_code_edge = {out_op_code, in_op_code};
74  lower_bound_op_code_edge.emplace(op_code_edge, e_attrs.getInt("LOWER_BOUND_NETWORK_LATENCY"));
75  upper_bound_op_code_edge.emplace(op_code_edge, e_attrs.getInt("UPPER_BOUND_NETWORK_LATENCY"));
76  }
77  }
78  return;
79 }
80 
82  if (op->getOpCode() == OpCode::CONST
83  || op->getOpCode() == OpCode::PHI
84  || op->getOpCode() == OpCode::INPUT
85  || op->getOpCode() == OpCode::INPUT_PRED)
86  return false;
87 
88  OpGraphVal* val = op->output;
89  if (!val) return false;
90  for (auto& sink_op : val->output) {
91  if (sink_op->getOpCode() == OpCode::PHI)
92  return true;
93  if (sink_op == op)
94  return true;
95  }
96  return false;
97 }
98 
100  if (op_latency.find(op->getOpCode()) == op_latency.end())
101  throw cgrame_error("ERROR: Cannot find Op Code: " + to_string(op->getOpCode()) + " within the supported ops");
102  if (op->getOpCode() != OpCode::PHI) {
103  return 0;
104  }
105  int r = 0;
106 
107  for (auto& edge : op->input) {
108  if (edge->input->getOpCode() == OpCode::CONST) {
110  } else if (edge->input->getOpCode() == OpCode::INPUT) {
112  }
113  }
114  return op_latency[op->getOpCode()];
115 }
116 
117 int OpScheduler::calcEdgeDist(OpGraphVal* val, OpGraphOp* sink_op, unsigned II, bool ignore_backedge) {
118  OpGraphOp* source_op = val->input;
119 
120  if (source_op == sink_op) return -1;
121  if (ignore_backedge) {
122  if (sink_op->getOpCode() == OpCode::PHI
123  && source_op->getOpCode() != OpCode::INPUT
124  && source_op->getOpCode() != OpCode::CONST
125  && source_op->getOpCode() != OpCode::INPUT_PRED) {
126  return -1;
127  }
128  }
129 
130  int latency = 0;
131  switch (val->getKind()) {
132  case EdgeKind::kDataFlow :
133  return op_latency[source_op->getOpCode()] +
134  lower_bound_op_code_edge[{source_op->getOpCode(), sink_op->getOpCode()}];
135  case EdgeKind::kAlias :
136  if (source_op->getOpCode() == OpCode::LOAD) {
137  if (sink_op->getOpCode() != OpCode::STORE)
138  throw cgrame_error("ERR: Alias edge: " + val->getName() + " does not connect a load to a store");
139  latency = 1 + lower_bound_op_code_edge[{source_op->getOpCode(), sink_op->getOpCode()}];
140  } else if (source_op->getOpCode() == OpCode::STORE) {
141  if (sink_op->getOpCode() == OpCode::STORE) {
142  latency = 1;
143  } else if (sink_op->getOpCode() == OpCode::LOAD) {
144  latency = op_latency[source_op->getOpCode()]
145  + lower_bound_op_code_edge[{source_op->getOpCode(), sink_op->getOpCode()}];
146  } else {
147  throw cgrame_error("ERR: Alias edge: " + val->getName()
148  + " does not connect store to another store/load");
149  }
150  } else {
151  throw cgrame_error("ERR: Alias edge: " + val->getName() + " does not connect to a store or a load");
152  }
153  return -latency + (II * val->dist);
154  default :
155  assert(0 && "ERROR: edge does not have a kind");
156  return 0;
157  }
158  return 0;
159 }
160 
161 int OpScheduler::addOpConstr(GRBmodel* model, unsigned II, int max_step, bool ignore_backedge, int exit_id) {
162  std::vector<bool> is_exit_pred(op_graph.opNodes().size(), true);
163 
164  // Constraint format s_a - s_b <= cnst
165  const int diff_constr_var_count = 2;
166 
167  int ind[diff_constr_var_count];
168  double value[diff_constr_var_count];
169  for (auto op_pair : extended_sched_const) {
170  ind[0] = op_graph.getOpIndex(op_pair.first.first);
171  ind[1] = op_graph.getOpIndex(op_pair.first.second);
172  value[0] = +1.0;
173  value[1] = -1.0;
174  double fd = -(static_cast<double>(op_pair.second));
175  std::string val_name = "m_" + std::to_string(op_graph.getOpIndex(op_pair.first.first));
176  val_name = val_name + "_" + std::to_string(op_graph.getOpIndex(op_pair.first.second));
177  int err = GRBaddconstr(model, diff_constr_var_count, ind, value, GRB_LESS_EQUAL, fd, val_name.c_str());
178  }
179 
180  for (auto& edge_v : {&op_graph.valNodes(), &op_graph.aliasNodes()}) {
181  for (const auto& val : *edge_v) {
182  OpGraphOp* source_op = val->input;
183  for (const auto& sink_op : val->output) {
184  int dist = calcEdgeDist(val, sink_op, II, ignore_backedge);
185  if (dist == -1) continue;
186  ind[0] = op_graph.getOpIndex(source_op);
187  ind[1] = op_graph.getOpIndex(sink_op);
188  value[0] = +1.0;
189  value[1] = -1.0;
190 
191  if (sink_op->getOpCode() == OpCode::PHI &&
192  source_op->getOpCode() != OpCode::INPUT &&
193  source_op->getOpCode() != OpCode::CONST &&
194  source_op->getOpCode() != OpCode::INPUT_PRED)
195  dist = max_step; // II*dist - op_latency[source_op->getOpCode()] - 1;
196 
197  double fd = -(static_cast<double>(dist));
198  std::string val_name;
199  if (val->getKind() == EdgeKind::kDataFlow) {
200  val_name = "v_" + std::to_string(op_graph.getValIndex(val));
201  val_name = val_name + "_" + std::to_string(op_graph.getOpIndex(sink_op));
202  } else if (val->getKind() == EdgeKind::kAlias) {
203  val_name = "a_" + std::to_string(op_graph.getAliasIndex(val));
204  val_name = val_name + "_" + std::to_string(op_graph.getOpIndex(sink_op));
205  } else {
206  throw cgrame_error("Edge kind is not recognised");
207  }
208  int err = GRBaddconstr(model, diff_constr_var_count, ind, value, GRB_LESS_EQUAL, fd, val_name.c_str());
209 
210  // TODO(raghebom) :: REMOVE THIS HARD CODE::
211  if (source_op->getOpCode() == OpCode::CONST) {
212  val_name = val_name + "_1";
213  int err =
214  GRBaddconstr(model, diff_constr_var_count, ind, value, GRB_GREATER_EQUAL, fd, val_name.c_str());
215  }
216 
217  if (source_op->getOpCode() == OpCode::PHI && source_op->output->output.size() == 1) {
218  val_name = val_name + "_1";
219  int err =
220  GRBaddconstr(model, diff_constr_var_count, ind, value, GRB_GREATER_EQUAL, fd, val_name.c_str());
221  }
222 
223  if ( err ) return err;
224 
225  if (exit_id != -1 && val->getKind() != EdgeKind::kAlias)
226  is_exit_pred[ind[0]] = false;
227  }
228  }
229  }
230 
231 
232  // exit dependencies ??
233  if (exit_id != -1) {
234  for (auto& op : op_graph.opNodes()) {
235  if (is_exit_pred[op_graph.getOpIndex(op)]) {
236  ind[0] = op_graph.getOpIndex(op);
237  ind[1] = exit_id;
238  value[0] = +1.0;
239  value[1] = -1.0;
240  int d = isBackEdge(op) ? (op_latency[op->getOpCode()] + 1) : 0;
241 
242  double fd = -(static_cast<double>(d));
243  std::string nm = "x_" + std::to_string(ind[0]);
244  int err = GRBaddconstr(model, diff_constr_var_count, ind, value, GRB_LESS_EQUAL, fd, nm.c_str());
245  if (err) return err;
246  }
247  }
248  }
249  return 0;
250 }
251 
252 int OpScheduler::schedASLAP(unsigned II, unsigned max_cycles, SchedType algo) {
253  //if (algo == SchedType::ALAP) setBackEdges();
254  if (algo != SchedType::ASAP && algo != SchedType::ALAP) return -1;
255  std::vector<OpGraphOp*> ops = op_graph.opNodes();
256  int node_count = ops.size();
257  int ext_node_count = node_count;
258  int exit_id = ext_node_count++;
259 
260  GRBenv* env = NULL;
261  GRBmodel* model = NULL;
262  int err = 0;
263 
264  double* sol = new double[ext_node_count];
265  double* obj = new double[ext_node_count];
266  double* lower_bound = new double[ext_node_count];
267  double* upper_bound = NULL;
268  int opt_status;
269  double obj_val;
270  int result_max_step = -1;
271 
272  const char* log_file_nm = (algo == SchedType::ASAP) ? "asap.log" : "alap.log";
273  const char* model_nm = (algo == SchedType::ASAP) ? "asap" :"alap";
274  const char* lp_file_nm = (algo == SchedType::ASAP) ? "asap.lp" :"alap.lp";
275  const char* iis_file_nm = (algo == SchedType::ASAP) ? "asap.ilp" :"alap.ilp";
276 
277  // Create envirtoment and set the output to a logfile
278  err = GRBemptyenv(&env);
279  if (err) goto QUIT;
280  err = GRBsetstrparam(env, "LogFile", log_file_nm);
281  if (err) goto QUIT;
282  err = GRBsetintparam(env, "LogToConsole", 0);
283  if (err) goto QUIT;
284  err = GRBstartenv(env);
285  if (err) goto QUIT;
286 
287  // Create an empty model
288  err = GRBnewmodel(env, &model, model_nm, 0, NULL, NULL, NULL, NULL, NULL);
289  if (err) goto QUIT;
290 
291  // set variable lower bounds
292  memset(lower_bound, 0, ext_node_count * sizeof(double));
293  for (int i = 0; i < node_count; i++) {
294  lower_bound[i] = 0;
295  }
296  lower_bound[exit_id] = 0;
297 
298  if (algo == SchedType::ALAP) {
299  upper_bound = new double[ext_node_count];
300  for (int i = 0; i < node_count; i++) {
301  upper_bound[i] = max_cycles;
302  }
303  upper_bound[exit_id] = max_cycles;
304  }
305 
306  for (int i = 0; i < node_count; i++) {
307  obj[i] = 1.0;
308  }
309  obj[exit_id] = 1.0;
310 
311  err = GRBaddvars(model, ext_node_count, 0, NULL, NULL, NULL, obj, lower_bound, upper_bound, NULL, NULL);
312  if (err) goto QUIT;
313 
314  err = GRBsetintattr(model, GRB_INT_ATTR_MODELSENSE, (algo == SchedType::ASAP) ? GRB_MINIMIZE : GRB_MAXIMIZE);
315  if (err) goto QUIT;
316 
317  err = addOpConstr(model, II, (algo == SchedType::ASAP) ? -1 : max_cycles, (algo == SchedType::ASAP), exit_id);
318  if (err) goto QUIT;
319 
320  err = GRBoptimize(model);
321  if (err) goto QUIT;
322 
323  err = GRBwrite(model, lp_file_nm);
324  if (err) goto QUIT;
325 
326  err = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &opt_status);
327  if (err) goto QUIT;
328 
329  if (opt_status == GRB_INFEASIBLE) {
330  for (int i = 0; i < ops.size(); i++) {
331  std::cout << i << " " << ops[i]->getName() << std::endl;
332  }
333  GRBcomputeIIS(model);
334  GRBwrite(model, iis_file_nm);
335  return -1;
336  }
337  assert(opt_status == GRB_OPTIMAL);
338 
339  err = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &obj_val);
340  if (err) goto QUIT;
341 
342  err = GRBgetdblattrarray(model, GRB_DBL_ATTR_X, 0, ext_node_count, sol);
343  if (err) goto QUIT;
344 
345  for (int i = 0; i < node_count; i++) {
346  if (SchedType::ALAP == algo) {
347  alap_schedule[op_graph.getOpByIndex(i)] = static_cast<int>(sol[i]);
348  } else if (SchedType::ASAP == algo) {
349  asap_schedule[op_graph.getOpByIndex(i)] = static_cast<int>(sol[i]);
350  }
351  }
352 
353  result_max_step = static_cast<int>(sol[exit_id]);
354 
355 QUIT:
356 
357  if ( err ) {
358  std::string err_msg(GRBgeterrormsg(env));
359  throw cgrame_error("ERR: " + err_msg);
360  }
361 
362  // Free model
363  GRBfreemodel(model);
364 
365  // Free enviroment
366  GRBfreeenv(env);
367 
368  delete [] sol;
369  delete [] obj;
370  delete [] lower_bound;
371  delete [] upper_bound;
372 
373  return result_max_step;
374 }
375 
377  assert(asap_schedule[op] <= step);
378  return 1024 * (step - asap_schedule[op]) + asap_schedule[op];
379 }
380 
381 void OpScheduler::buildLastUseTable(int& ext_node_count, int exit_id, std::map<OpGraphOp*, int>& last_use) {
382  for (auto& op : op_graph.opNodes()) {
383  if (isBackEdge(op)) {
384  last_use.emplace(op, exit_id);
385  continue;
386  }
387 
388  OpGraphVal* val = op->output;
389  if (!val) {
390  last_use.emplace(op, exit_id);
391  continue;
392  }
393 
394  if (val->output.size() == 1) {
395  last_use.emplace(op, op_graph.getOpIndex(val->output[0]));
396  } else if (val->output.size() > 1) {
397  int lu_id = ext_node_count++;
398  last_use.emplace(op, lu_id);
399  }
400  }
401 }
402 
403 int OpScheduler::addLastUseConstr(GRBmodel* model , std::map<OpGraphOp*, int> last_use) {
404  for (auto& op : op_graph.opNodes()) {
405  if (isBackEdge(op)) continue;
406  OpGraphVal* val = op->output;
407 
408  if (!val) continue;
409  if (val->output.size() == 1) continue;
410  for (auto& sink_op : val->output) {
411  int Kdiff_constr_var_count = 2;
412  int ind[Kdiff_constr_var_count];
413  double value[Kdiff_constr_var_count];
414 
415  int lu_id = last_use[op];
416  ind[0] = op_graph.getOpIndex(sink_op);
417  ind[1] = lu_id;
418  value[0] = +1.0;
419  value[1] = -1.0;
420 
421  double fd = 0.0;
422  std::string nm = "lu" + std::to_string(ind[0]) + "_" + std::to_string(lu_id);
423  int err = GRBaddconstr(model, Kdiff_constr_var_count, ind, value, GRB_LESS_EQUAL, fd, nm.c_str());
424  if (err) return err;
425  }
426  }
427  return 0;
428 }
429 
430 int OpScheduler::schedSDCMod(unsigned II, SchedType algo) {
431  if (algo != SchedType::SDCLIST && algo != SchedType::SDCLRO) return -1;
432 
433  std::vector<OpGraphOp*> ops = op_graph.opNodes();
434  int node_count = ops.size();
435  int ext_node_count = node_count;
436  int exit_id = ext_node_count++;
437 
438 
439  std::map<OpGraphOp*, int> last_use;
440  if (algo == SchedType::SDCLRO)
441  buildLastUseTable(ext_node_count, exit_id, last_use);
442 
443  GRBenv* env = NULL;
444  GRBmodel* model = NULL;
445  int err = 0;
446  double* sol = new double[ext_node_count];
447  double* obj = new double[ext_node_count];
448  double* lower_bound = new double[ext_node_count];
449  int opt_status;
450  double obj_val;
451  int result_max_step = -1;
452 
453  const char* log_file_nm = (algo == SchedType::SDCLRO) ? "lro.log" : "list.log";
454  const char* model_nm = (algo == SchedType::SDCLRO) ? "lro" : "list";
455  const char* lp_file_nm = (algo == SchedType::SDCLRO) ? "lro.lp" : "list.lp";
456 
457  // Create envirtoment and set the output to a logfile
458  err = GRBemptyenv(&env);
459  if (err) goto QUIT;
460  err = GRBsetstrparam(env, "LogFile", log_file_nm);
461  if (err) goto QUIT;
462  err = GRBsetintparam(env, "LogToConsole", 0);
463  if (err) goto QUIT;
464  err = GRBstartenv(env);
465  if (err) goto QUIT;
466 
467  // Create an empty model
468  err = GRBnewmodel(env, &model, model_nm, 0, NULL, NULL, NULL, NULL, NULL);
469  if (err) goto QUIT;
470 
471  switch (algo) {
472  case SchedType::SDCLIST:
473  for (int i = 0; i < node_count; i++) {
474  obj[i] = 1.0;
475  }
476  obj[exit_id] = 1.0;
477  break;
478  case SchedType::SDCLRO:
479  for (int i = 0; i < ext_node_count; i++) {
480  obj[i] = 0.0;
481  }
482  for (auto& op : op_graph.opNodes()) {
483  if (last_use.find(op) == last_use.end()) {
484  throw cgrame_error("ERR: LRO operation: " + op->getName() + " has no entry to last use table");
485  }
486  int op_index = op_graph.getOpIndex(op);
487  obj[last_use[op]] = obj[last_use[op]] + 1.0;
488  obj[op_index] = obj[op_index] - 1.0;
489  }
490  break;
491  default:
492  break;
493  }
494  // set variable lower bounds
495  memset(lower_bound, 0, ext_node_count * sizeof(double));
496  for (int i = 0; i < ext_node_count; i++) {
497  lower_bound[i] = 0;
498  }
499  lower_bound[exit_id] = 0;
500  err = GRBaddvars(model, ext_node_count, 0, NULL, NULL, NULL, obj, lower_bound, NULL, NULL, NULL);
501  if (err) goto QUIT;
502 
503  err = GRBsetintattr(model, GRB_INT_ATTR_MODELSENSE, GRB_MINIMIZE);
504  if (err) goto QUIT;
505 
506  err = addOpConstr(model, II, -1, true, exit_id);
507  if (err) goto QUIT;
508 
509  if (algo == SchedType::SDCLRO) {
510  err = addLastUseConstr(model, last_use);
511  if (err) goto QUIT;
512  }
513 
514  err = GRBoptimize(model);
515  if (err) goto QUIT;
516 
517  err = GRBwrite(model, lp_file_nm);
518  if (err) goto QUIT;
519 
520  err = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &opt_status);
521  if (err) goto QUIT;
522 
523  if (opt_status == GRB_INFEASIBLE)
524  return -1;
525  assert(opt_status == GRB_OPTIMAL);
526 
527  err = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &obj_val);
528  if (err) goto QUIT;
529 
530  err = GRBgetdblattrarray(model, GRB_DBL_ATTR_X, 0, ext_node_count, sol);
531  if (err) goto QUIT;
532 
533  {
534  // resource constraint
535  using PN = std::pair<int, OpGraphOp*>;
536  using MinPrioQueue = std::priority_queue<PN, std::vector<PN>, std::greater<PN>>;
537  MinPrioQueue p_queue;
538 
539  auto mrrgNodesByCycle = computeNodeClassListsByCycle(mrrg);
540  std::vector<std::vector<bool>> rsrv_station
541  (II, std::vector<bool>(mrrgNodesByCycle.function_nodes[II-1].size(), false));
542 
543  int scheduled_node_count = 0;
544  int step = 0;
545 
546  while (scheduled_node_count < node_count) {
547  for (auto& op : op_graph.opNodes()) {
548  if (sol[op_graph.getOpIndex(op)] == step) {
549  p_queue.push({calcNodePrio(op, step), op});
550  }
551  }
552  while (!p_queue.empty()) {
553  PN temp = p_queue.top();
554  p_queue.pop();
555 
556  bool back_search_fail = true;
557  if (temp.second->getOpCode() == OpCode::CONST || temp.second->getOpCode() == OpCode::PHI) {
558  scheduled_node_count++;
559  continue;
560  }
561  for (int s = step; s >= asap_schedule[temp.second]; s--) {
562  for (int i = 0; i < mrrgNodesByCycle.function_nodes[step%II].size(); i++) {
563  if (rsrv_station[s%II][i]) continue;
564  if (!mrrgNodesByCycle.function_nodes[step%II][i]->canMapOp(temp.second)) continue;
565  int ind = op_graph.getOpIndex(temp.second);
566  double val = +1.0;
567  double fd = static_cast<double>(step);
568  std::string e_nm = "rc" + std::to_string(ind);
569  int err = GRBaddconstr(model, 1, &ind, &val, GRB_EQUAL, fd, e_nm.c_str());
570  if (err) goto QUIT;
571  err = GRBwrite(model, lp_file_nm);
572  if (err) goto QUIT;
573  err = GRBoptimize(model);
574  if (err) goto QUIT;
575  err = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &opt_status);
576  if (err) goto QUIT;
577  assert(opt_status == GRB_OPTIMAL);
578  err = GRBgetdblattrarray(model, GRB_DBL_ATTR_X, 0, ext_node_count, sol);
579  assert(!err);
580  rsrv_station[s%II][i] = true;
581  scheduled_node_count++;
582  back_search_fail = false;
583  break;
584  }
585  }
586  if (back_search_fail) {
587  int ind = op_graph.getOpIndex(temp.second);
588  double val = 1.0;
589  double fd = static_cast<double>(step + 1);
590  std::string e_nm = "bf" + std::to_string(ind) + "_" + std::to_string(step);
591  int err = GRBaddconstr(model, 1, &ind, &val, GRB_GREATER_EQUAL, fd, e_nm.c_str());
592  assert(!err);
593  err = GRBoptimize(model);
594  assert(!err);
595  err = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &opt_status);
596  assert(!err);
597  if (opt_status == GRB_INFEASIBLE) {
598  goto GIVE_UP;
599  } else {
600  assert(opt_status == GRB_OPTIMAL);
601  err = GRBgetdblattrarray(model, GRB_DBL_ATTR_X, 0, ext_node_count, sol);
602  if (err) goto QUIT;
603  }
604  }
605  }
606  step = step + 1;
607  if (step > 10 * node_count) {
608  cgrame_error("ERR: unable to schedule application!");
609  }
610  }
611 
612  for (int i = 0; i < node_count; i++) {
613  if (algo == SchedType::SDCLIST) {
614  sdc_mod_schedule[op_graph.getOpByIndex(i)] = static_cast<int>(sol[i]);
615  } else if (algo == SchedType::SDCLRO) {
616  sdc_lro_schedule[op_graph.getOpByIndex(i)] = static_cast<int>(sol[i]);
617  }
618  }
619  result_max_step = static_cast<int>(sol[exit_id]);
620  }
621 
622  QUIT:
623 
624  if ( err ) {
625  std::string err_msg(GRBgeterrormsg(env));
626  throw cgrame_error("ERR: " + err_msg);
627  }
628 
629  GIVE_UP:
630 
631  // Free model
632  GRBfreemodel(model);
633 
634  // Free enviroment
635  GRBfreeenv(env);
636 
637  delete [] sol;
638  delete [] obj;
639 
640  return result_max_step;
641 }
642 
643 std::unordered_map<const OpGraphOp*, int> OpScheduler::getSchedule(SchedType type) {
644  int II = mrrg.initiationInterval();
645  int r = -1;
646  r = schedASLAP(II, -1, SchedType::ASAP);
647  if (r == -1)
648  throw cgrame_error("ASAP FAILED");
649  if (type == SchedType::ASAP) {
650  return asap_schedule;
651  }
652 
653 
654  if (r == -1)
655  throw cgrame_error("ALAP FAILED");
656  if (type == SchedType::ALAP) {
657  r = schedASLAP(II, r, SchedType::ALAP);
658  return alap_schedule;
659  }
660  if (type == SchedType::SDCLIST) {
662  if (r == -1)
663  throw cgrame_error("LIST FAILED");
664  return sdc_mod_schedule;
665  }
667  if (r == -1)
668  throw cgrame_error("LRO FAILED");
669  if (type == SchedType::SDCLRO) {
670  return sdc_lro_schedule;
671  }
672 
673  return alap_schedule;
674 }
OpGraphVal::output
std::vector< OpGraphOp * > output
Definition: OpGraph.h:196
OpScheduler::getSchedule
std::unordered_map< const OpGraphOp *, int > getSchedule(SchedType type)
Definition: OpScheduler.cpp:643
ConfigGraph::allNodes
auto allNodes() const
Definition: ConfigGraph.h:142
ConfigGraph::attributes
const ConfigStore & attributes(const VertexID &v) const
Definition: ConfigGraph.h:128
OpGraphOp::output
OpGraphVal * output
Definition: OpGraph.h:166
ConfigGraph.h
OpCode::CONST
@ CONST
MRRG
Definition: MRRG.h:216
dotparse.h
OpCode::PHI
@ PHI
GraphAlgorithms.h
OpGraph::getOpIndex
int getOpIndex(OpGraphOp *op) const
Definition: OpGraph.cpp:747
SchedType
SchedType
Definition: OpScheduler.h:29
OpScheduler::asap_schedule
std::unordered_map< const OpGraphOp *, int > asap_schedule
Definition: OpScheduler.h:94
OpScheduler::parseNetworkSchedule
void parseNetworkSchedule(std::string netwrok_latency_filename)
Definition: OpScheduler.cpp:54
OpGraphVal::dist
int dist
Definition: OpGraph.h:199
SchedType::SDCLRO
@ SDCLRO
OpScheduler::OpScheduler
OpScheduler(const OpGraph &opgraph, const MRRG &mrrg, std::string arch_name, std::string supported_ops_file_name="")
Definition: OpScheduler.cpp:30
OpCode::STORE
@ STORE
OpGraph::valNodes
auto & valNodes() const
Definition: OpGraph.h:314
ConfigGraph
Definition: ConfigGraph.h:72
OpGraph::getAliasIndex
int getAliasIndex(OpGraphVal *op) const
Definition: OpGraph.cpp:765
OpCodeEdge
std::pair< OpGraphOpCode, OpGraphOpCode > OpCodeEdge
Definition: OpScheduler.h:36
ConfigGraph::outEdges
auto outEdges(const VertexID &v) const
Definition: ConfigGraph.h:148
computeNodeClassListsByCycle
MRRGNodeClassListsByCycle computeNodeClassListsByCycle(const MRRG &mrrg)
Definition: MRRGProcedures.cpp:138
OpScheduler::buildLastUseTable
void buildLastUseTable(int &ext_node_count, int exit_id, std::map< OpGraphOp *, int > &last_use)
Definition: OpScheduler.cpp:381
OpScheduler::isBackEdge
bool isBackEdge(OpGraphOp *)
Definition: OpScheduler.cpp:81
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
ConfigGraph::name
const std::string & name(const VertexID &v) const
Definition: ConfigGraph.h:123
OpGraphOpCode
signed char OpCode OpGraphOpCode
Definition: OpGraph.h:15
OpCode::LOAD
@ LOAD
OpGraphOp::input
std::vector< OpGraphVal * > input
Definition: OpGraph.h:164
OpGraph::aliasNodes
auto & aliasNodes() const
Definition: OpGraph.h:315
OpScheduler::alap_schedule
std::unordered_map< const OpGraphOp *, int > alap_schedule
Definition: OpScheduler.h:95
Exception.h
OpScheduler::sdc_lro_schedule
std::unordered_map< const OpGraphOp *, int > sdc_lro_schedule
Definition: OpScheduler.h:97
SchedType::SDCLIST
@ SDCLIST
SchedType::ALAP
@ ALAP
OpScheduler::addLastUseConstr
int addLastUseConstr(GRBmodel *model, std::map< OpGraphOp *, int > last_use)
Definition: OpScheduler.cpp:403
OpScheduler::mrrg
const MRRG & mrrg
Definition: OpScheduler.h:93
OpCode::INPUT
@ INPUT
OpGraph::opNodes
auto & opNodes() const
Definition: OpGraph.h:313
OpCode::INPUT_PRED
@ INPUT_PRED
OpScheduler::schedASLAP
int schedASLAP(unsigned II, unsigned max_cycles, SchedType algo)
Definition: OpScheduler.cpp:252
OpGraphVal::getKind
EdgeKind getKind()
Definition: OpGraph.h:193
SchedType::ASAP
@ ASAP
OpScheduler::calcLowerBound
int calcLowerBound(OpGraphOp *op)
Definition: OpScheduler.cpp:99
OpScheduler::schedSDCMod
int schedSDCMod(unsigned II, SchedType algo)
Definition: OpScheduler.cpp:430
parseDot
ConfigGraph parseDot(std::istream &input, std::string file_name)
OpGraph::getOpByIndex
const OpGraphOp * getOpByIndex(int index) const
Definition: OpGraph.cpp:774
OpScheduler::op_graph
const OpGraph & op_graph
Definition: OpScheduler.h:92
OpScheduler.h
OpGraphVal
Definition: OpGraph.h:178
OpGraphOp
Definition: OpGraph.h:131
ConfigGraph::target
const VertexID & target(const EdgeID &e) const
Definition: ConfigGraph.h:134
EdgeKind::kAlias
@ kAlias
OpGraphOp::getOpCode
auto getOpCode() const
Definition: OpGraph.h:156
OpScheduler::sdc_mod_schedule
std::unordered_map< const OpGraphOp *, int > sdc_mod_schedule
Definition: OpScheduler.h:96
EdgeKind::kDataFlow
@ kDataFlow
OpScheduler::extended_sched_const
std::unordered_map< opPair, int, pair_hash > extended_sched_const
Definition: OpScheduler.h:89
OpScheduler::op_latency
std::unordered_map< OpGraphOpCode, int > op_latency
Definition: OpScheduler.h:100
OpScheduler::upper_bound_op_code_edge
std::unordered_map< OpCodeEdge, int, pair_hash > upper_bound_op_code_edge
Definition: OpScheduler.h:102
OpScheduler::function_nodes
std::vector< const MRRGNode * > function_nodes
Definition: OpScheduler.h:98
OpGraphVal::input
OpGraphOp * input
Definition: OpGraph.h:190
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
MRRGProcedures.h
opcode_from_string
OpGraphOpCode opcode_from_string(const std::string &str)
Definition: OpGraph.cpp:113
OpScheduler::calcNodePrio
int calcNodePrio(OpGraphOp *, int)
Definition: OpScheduler.cpp:376
OpGraph
Definition: OpGraph.h:215
OpScheduler::calcEdgeDist
int calcEdgeDist(OpGraphVal *val, OpGraphOp *sink_op, unsigned II, bool ignore_backedge)
Definition: OpScheduler.cpp:117
OpGraph::getValIndex
int getValIndex(OpGraphVal *op) const
Definition: OpGraph.cpp:756
cgrame_error
Definition: Exception.h:20
computeNodeClassLists
MRRGNodeClassLists computeNodeClassLists(const MRRG &mrrg)
Definition: MRRGProcedures.cpp:169
OpGraphNode::getName
const std::string & getName() const
Definition: OpGraph.h:121
OpScheduler::lower_bound_op_code_edge
std::unordered_map< OpCodeEdge, int, pair_hash > lower_bound_op_code_edge
Definition: OpScheduler.h:101
OpScheduler::addOpConstr
int addOpConstr(GRBmodel *model, unsigned II, int max_step, bool ignore_backedge, int exit_id)
Definition: OpScheduler.cpp:161