PandA-2024.02
vcd_trace_head.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2015-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
37 #include "vcd_trace_head.hpp"
38 
39 // include from HLS/
40 #include "hls.hpp"
41 #include "hls_manager.hpp"
42 
43 // include from HLS/binding/storage_value_information/
45 
46 // include from HLS/stg/
49 
50 // include from tree/
51 #include "tree_manager.hpp"
52 #include "tree_node.hpp"
53 
54 // include from utility/
55 #include "exceptions.hpp"
56 #include "string_manipulation.hpp"
57 
58 // include from STL
59 #include <functional>
60 #include <utility>
61 
62 static bool is_valid_state_string(const std::string& s, bool one_hot_fsm_encoding)
63 {
64  if(s.find_first_not_of("10") != std::string::npos)
65  {
66  /*
67  * the vcd state string contains values that are not 0 or 1. something
68  * went wrong, so the result is always false
69  */
70  return false;
71  }
72  if(one_hot_fsm_encoding)
73  {
74  const auto first_1_pos = s.find_first_of('1');
75  const auto last_1_pos = s.find_last_of('1');
76  if(first_1_pos != last_1_pos)
77  {
78  /*
79  * not really one hot encoding. something went wrong, so the result is
80  * always false
81  */
82  return false;
83  }
84  }
85  return true;
86 }
87 
88 static unsigned int compute_state_id(const std::string& s, bool one_hot_fsm_encoding)
89 {
90  THROW_ASSERT(is_valid_state_string(s, one_hot_fsm_encoding), "String does not represent a valid binary state: " + s);
91  if(one_hot_fsm_encoding)
92  {
93  const auto first_1_pos = s.find_first_of('1');
94  return static_cast<unsigned int>(s.length() - first_1_pos - 1U);
95  }
96  return static_cast<unsigned int>(std::stoul(s, nullptr, 2));
97 }
98 
99 static bool is_binary_string_repr(const std::string& s, unsigned int id, bool one_hot_fsm_encoding)
100 {
101  if(!is_valid_state_string(s, one_hot_fsm_encoding))
102  {
103  THROW_ERROR("invalid state_string: " + s);
104  }
105 
106  return compute_state_id(s, one_hot_fsm_encoding) == id;
107 }
108 
109 static bool string_represents_one_of_the_states(const std::string& val, const CustomOrderedSet<unsigned int>& state_ids,
110  bool one_hot_fsm_encoding)
111 {
112  if(!is_valid_state_string(val, one_hot_fsm_encoding))
113  {
114  return false;
115  }
116  const auto id = compute_state_id(val, one_hot_fsm_encoding);
117  return state_ids.count(id);
118 }
119 
120 static bool is_exec(const sig_variation& state_var, const DiscrepancyOpInfo& i, bool one_hot_fsm_encoding)
121 {
122  THROW_ASSERT(!i.exec_states.empty(), "no executing states for operation " + STR(i.stg_fun_id) + "_" + STR(i.op_id));
123  return string_represents_one_of_the_states(state_var.value, i.exec_states, one_hot_fsm_encoding);
124 }
125 
126 static bool is_start(const sig_variation& state_var, const DiscrepancyOpInfo& i, bool one_hot_fsm_encoding)
127 {
128  THROW_ASSERT(!i.start_states.empty(), "no starting states for operation " + STR(i.stg_fun_id) + "_" + STR(i.op_id));
129  return string_represents_one_of_the_states(state_var.value, i.start_states, one_hot_fsm_encoding);
130 }
131 
132 #if HAVE_ASSERTS
133 static bool is_end(const sig_variation& state_var, const DiscrepancyOpInfo& i, bool one_hot_fsm_encoding)
134 {
135  THROW_ASSERT(!i.end_states.empty(), "no ending states for operation " + STR(i.stg_fun_id) + "_" + STR(i.op_id));
136  return string_represents_one_of_the_states(state_var.value, i.end_states, one_hot_fsm_encoding);
137 }
138 #endif
139 
140 static bool all_ones(const std::string& s)
141 {
142  return std::all_of(s.begin(), s.end(), [](const char c) { return c == '1'; });
143 }
144 
145 static bool var_has_value_ones(const sig_variation& v)
146 {
147  return all_ones(v.value);
148 }
149 
150 static bool var_is_later_or_equal(const sig_variation& v, const unsigned long long time)
151 {
152  return v >= time;
153 }
154 
155 vcd_trace_head::vcd_trace_head(const DiscrepancyOpInfo& op, std::string signame, const std::list<sig_variation>& fv,
156  const std::list<sig_variation>& ov, const std::list<sig_variation>& sv,
157  unsigned int init_state_id, unsigned long long clock_p,
158  const HLS_managerConstRef _HLSMgr, const tree_managerConstRef _TM,
159  const bool _one_hot_fsm_encoding)
160  : state(uninitialized),
161  failed(fail_none),
162  one_hot_fsm_encoding(_one_hot_fsm_encoding),
163  op_info(op),
164  is_phi(_TM->get_tree_node_const(op.op_id)->get_kind() == gimple_phi_K),
165  is_in_reg(_HLSMgr->get_HLS(op_info.stg_fun_id)
166  ->storage_value_information->is_a_storage_value(nullptr, op.ssa_name_node_id)),
167  HLSMgr(_HLSMgr),
168  TM(_TM),
169  initial_state_id(init_state_id),
170  fsm_vars(fv),
171  fsm_ss_it(fv.cbegin()),
172  fsm_end(fv.cend()),
173  out_vars(ov),
174  out_var_it(ov.cbegin()),
175  out_var_end(ov.cend()),
176  start_vars(sv),
177  sp_var_it(sv.cbegin()),
178  sp_var_end(sv.cend()),
179  fullsigname(std::move(signame)),
180  op_start_time(0),
181  op_end_time(0),
182  clock_period(clock_p),
183  exec_times_in_current_state(0),
184  consecutive_state_executions(0),
185  has_been_initialized(false),
186  fsm_has_a_single_state(boost::num_vertices(*_HLSMgr->get_HLS(op.stg_fun_id)->STG->CGetStg()) == 3),
187  start_state_is_initial(false)
188 {
189 }
190 
192 {
193  THROW_ASSERT((fsm_ss_it->duration == std::numeric_limits<decltype(fsm_ss_it->duration)>::max()) ||
194  (fsm_ss_it->duration + fsm_ss_it->time_stamp - op_start_time) % clock_period == 0,
195  "state transition is not aligned with clock signal\n"
196  "timestamp = " +
197  STR(fsm_ss_it->time_stamp) +
198  "\n"
199  "op_start_time = " +
200  STR(op_start_time) +
201  "\n"
202  "duration = " +
203  STR(fsm_ss_it->duration) +
204  "\n"
205  "clock_period = " +
206  STR(clock_period) + "\n");
208  if(fsm_ss_it->duration == std::numeric_limits<decltype(fsm_ss_it->duration)>::max())
209  {
211  {
213  }
214  else
215  {
217  }
218  }
219  else
220  {
222  }
224  THROW_ASSERT(consecutive_state_executions > 0, "state execution time is 0");
225 }
226 
228 {
230  {
231  auto fsm_es_it = fsm_ss_it;
232  THROW_ASSERT(is_end(*fsm_es_it, op_info, one_hot_fsm_encoding),
233  "unbounded operation " + STR(op_info.stg_fun_id) + "_" + STR(op_info.op_id) +
234  " with starting state " + fsm_es_it->value + " which is not ending\n");
235  THROW_ASSERT(not is_phi, "\n/--------------------------------------------------------------------\n"
236  "| operation: " +
237  STR(op_info.stg_fun_id) + "_" + STR(op_info.op_id) +
238  "\n"
239  "| is UNBOUNDED and is a phi\n"
240  "\\--------------------------------------------------------------------\n");
241  /*
242  * if the operation is not bounded then the state machine has a
243  * dummy state after the call state, where it waits for the
244  * operation to complete if the operation is not completed in the
245  * same cycle as the call.
246  * for this reason, to find the real ending state of an unbounded
247  * operation we have to skip the advance to the following state
248  * until we find that the next is not in execution or it is a new
249  * starting state
250  */
251  if(is_exec(*std::next(fsm_es_it), op_info, one_hot_fsm_encoding) and
252  not is_start(*std::next(fsm_es_it), op_info, one_hot_fsm_encoding))
253  {
254  fsm_es_it++;
255  if(fsm_es_it == fsm_end)
256  {
257  state = init_fail;
259  return;
260  }
261  THROW_ASSERT(is_end(*fsm_es_it, op_info, one_hot_fsm_encoding),
262  "dummy state of unbounded operation " + STR(op_info.stg_fun_id) + "_" + STR(op_info.op_id) +
263  " must be ending state\n");
264  }
265  op_end_time = std::next(fsm_es_it)->time_stamp;
266  }
267  else
268  {
271  }
272 }
273 
275 {
276  /* find the next starting state for an execution of this operation */
278  {
279  ++fsm_ss_it;
280  }
281  const auto is_starting_state = [&](const sig_variation& s) { return is_start(s, op_info, one_hot_fsm_encoding); };
282  const auto fsm_prev_ss_it = fsm_ss_it;
283  fsm_ss_it = std::find_if(fsm_ss_it, fsm_end, is_starting_state);
284  if(fsm_ss_it == fsm_end)
285  {
286  fsm_ss_it = fsm_prev_ss_it;
287  state = init_fail;
289  return;
290  }
291  /*
292  * now we want to detect precisely when the operation starts. this may
293  * not be the exact time when the fsm enters in a starting state for
294  * the operation.
295  * the cases when the operation starting time is different from the
296  * time when fsm enters in a starting state are 2:
297  * 1) for the state S_0, which is the state where the functional unit
298  * stays until the start port rises
299  * 2) when the state has a self edge. in such a case multiple execution
300  * of the same operation can be performed without variation in the
301  * vcd signal _present_state.
302  */
303  op_start_time = fsm_ss_it->time_stamp;
306  {
307  /*
308  * the next executing starting states for this operation is the initial
309  * state. the initial state is special, because it's also the state
310  * in which the FSM of the function stays when the function is not in
311  * execution. so we have to look for the start port assertion
312  */
314  if(sp_var_it == sp_var_end)
315  {
316  state = init_fail;
318  return;
319  }
320  op_start_time = sp_var_it->time_stamp;
321  ++sp_var_it;
322  }
323  THROW_ASSERT(op_start_time >= fsm_ss_it->time_stamp, "operation start time is before starting state" +
324  STR(op_start_time) + " " + STR(fsm_ss_it->time_stamp));
325  /*
326  * here we know the correct starting state and the start time of the
327  * operation. we know detect the number of consecutive state executions
328  */
330  /*
331  * now we found the correct starting time for the current operation.
332  * but we have to analyze the output signal at the end of the operation
333  * in order to perform discrepancy analysis. so we have to dectect the
334  * time when the current execution of this operation ends.
335  */
337  {
338  /*
339  * if the operation is bounded the ending state does not matter, because
340  * the end time of the operation can be calculated from start time, given
341  * that we know its execution time
342  */
343  /* default calculation of the end time */
344  if(op_info.n_cycles == 0)
345  {
347  }
348  else
349  {
351  }
352  /* handle duplicated operations in more than one state */
353  if(is_in_reg && is_phi)
354  {
355  const auto gp = GetPointer<const gimple_phi>(TM->CGetTreeNode(op_info.op_id));
356  const auto state_id = compute_state_id(fsm_ss_it->value, one_hot_fsm_encoding);
357  const auto state_info = HLSMgr->get_HLS(op_info.stg_fun_id)->STG->CGetStg()->CGetStateInfo(state_id);
358  if(state_info->is_duplicated && !state_info->isOriginalState && !state_info->all_paths)
359  {
360  for(const auto& def_edge : gp->CGetDefEdgesList())
361  {
362  if(state_info->moved_op_def_set.find(def_edge.first->index) != state_info->moved_op_def_set.end() or
363  state_info->moved_op_use_set.find(op_info.ssa_name_node_id) != state_info->moved_op_use_set.end())
364  {
366  break;
367  }
368  }
369  }
370  }
371  }
372  else
373  {
375  }
376 }
377 
379 {
382  {
384  }
385  else
386  {
388  }
389 }
390 
392 {
393  switch(state)
394  {
395  case uninitialized:
396  case running:
397  {
399  update();
400  if(state == init_fail)
401  {
402  return;
403  }
404  if(not has_been_initialized)
405  {
406  has_been_initialized = true;
407  }
408  break;
409  }
410  case suspended:
411  {
413  if(state == init_fail)
414  {
415  return;
416  }
417  break;
418  }
419  case checked:
420  case init_fail:
421  case initialized:
422  case after_discrepancy:
423  case discrepancy_found:
424  default:
425  {
426  THROW_UNREACHABLE("advance() works only on suspended, uninitialized or running");
427  return;
428  }
429  }
430  const auto& end = op_end_time;
431  const auto var_later_or_equal_than_end = [&end](const sig_variation& s) { return var_is_later_or_equal(s, end); };
432  out_var_it = std::find_if(out_var_it, out_var_end, var_later_or_equal_than_end);
433  --out_var_it;
434  state = initialized;
435 }
CustomOrderedSet< unsigned int > start_states
unsigned long n_cycles
Data structure representing the entire HLS information.
CustomOrderedSet< unsigned int > exec_states
unsigned long long consecutive_state_executions
enum vcd_head_state state
This file contains the structures needed to manage a graph that will represent the state transition g...
This algorithm is to find coloring of a graph Algorithm: Let G = (V,E) be a graph with vertices v_1...
enum vcd_head_failure failed
static unsigned int compute_state_id(const std::string &s, bool one_hot_fsm_encoding)
static bool is_start(const sig_variation &state_var, const DiscrepancyOpInfo &i, bool one_hot_fsm_encoding)
unsigned long long op_start_time
vcd_trace_head(const DiscrepancyOpInfo &op_info, std::string signame, const std::list< sig_variation > &fv, const std::list< sig_variation > &ov, const std::list< sig_variation > &sv, unsigned int init_state_id, unsigned long long clock_period, const HLS_managerConstRef _HLSMgr, const tree_managerConstRef _TM, const bool one_hot_fsm_encoding)
exceptions managed by PandA
Definition of hash function for EdgeDescriptor.
Definition: graph.hpp:1321
static bool all_ones(const std::string &s)
std::list< sig_variation >::const_iterator out_var_it
static bool string_represents_one_of_the_states(const std::string &val, const CustomOrderedSet< unsigned int > &state_ids, bool one_hot_fsm_encoding)
const unsigned long long clock_period
const tree_managerConstRef TM
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
unsigned long long op_end_time
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
This class models a single variation of a signal in vcd.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
void unbounded_find_end_time()
const bool is_in_reg
std::list< sig_variation >::const_iterator out_var_end
const HLS_managerConstRef HLSMgr
This file contains the structures needed to manage a graph that will represent the state transition g...
const bool one_hot_fsm_encoding
Classes specification of the tree_node data structures.
std::list< sig_variation >::const_iterator sp_var_end
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
void set_consecutive_state_executions()
static bool is_exec(const sig_variation &state_var, const DiscrepancyOpInfo &i, bool one_hot_fsm_encoding)
This package is used to define the storage value scheme adopted by the register allocation algorithms...
std::string value
new value of the signal.
const unsigned int initial_state_id
unsigned int ssa_name_node_id
static bool var_is_later_or_equal(const sig_variation &v, const unsigned long long time)
const DiscrepancyOpInfo & op_info
CustomOrderedSet< unsigned int > end_states
static bool var_has_value_ones(const sig_variation &v)
void detect_new_start_end_times()
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
static bool is_valid_state_string(const std::string &s, bool one_hot_fsm_encoding)
std::list< sig_variation >::const_iterator sp_var_it
std::list< sig_variation >::const_iterator fsm_end
unsigned long long exec_times_in_current_state
std::list< sig_variation >::const_iterator fsm_ss_it
Data structure definition for high-level synthesis flow.
static bool is_binary_string_repr(const std::string &s, unsigned int id, bool one_hot_fsm_encoding)
Class specification of the manager of the tree structures extracted from the raw file.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:54 for PandA-2024.02 by doxygen 1.8.13