PandA-2024.02
HWDiscrepancyAnalysis.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 
38 #include "Discrepancy.hpp"
39 #include "Parameter.hpp"
40 #include "basic_block.hpp"
41 #include "behavioral_helper.hpp"
43 #include "call_graph_manager.hpp"
44 #include "custom_map.hpp"
45 #include "custom_set.hpp"
46 #include "fileIO.hpp"
47 #include "function_behavior.hpp"
48 #include "hls.hpp"
49 #include "hls_device.hpp"
50 #include "hls_manager.hpp"
51 #include "language_writer.hpp"
52 #include "parse_discrepancy.hpp"
55 #include "string_manipulation.hpp"
56 #include "structural_manager.hpp"
57 #include "tree_basic_block.hpp"
58 #include "tree_helper.hpp"
59 #include "tree_manager.hpp"
60 #include "tree_reindex.hpp"
61 
62 #include "config_HAVE_ASSERTS.hpp"
63 
64 #include <boost/algorithm/string/case_conv.hpp>
65 #include <boost/tokenizer.hpp>
66 
67 #include <algorithm>
68 #include <limits>
69 #include <list>
70 #include <string>
71 #include <tuple>
72 #include <utility>
73 #include <vector>
74 
76 #define MAX_METADATA_BITSIZE 10
77 
79 #define FIXED_METADATA_SIZE 6
80 
82  const DesignFlowManagerConstRef _design_flow_manager)
83  : HLS_step(_parameters, _HLSMgr, _design_flow_manager, HLSFlowStep_Type::HW_DISCREPANCY_ANALYSIS),
84  Discr(_HLSMgr->RDiscr),
85  present_state_name(static_cast<HDLWriter_Language>(_parameters->getOption<unsigned int>(OPT_writer_language)) ==
87  "_present_state" :
88  "present_state")
89 {
90  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
91 }
92 
95 {
97  switch(relationship_type)
98  {
100  {
101  ret.insert(std::make_tuple(
104  CBackendInformation::CB_DISCREPANCY_ANALYSIS,
105  parameters->getOption<std::string>(OPT_output_directory) + "/simulation/discrepancy.c",
106  parameters->getOption<std::string>(OPT_output_directory) + "/simulation/dynamic_discrepancy_stats")),
112  break;
113  }
116  {
117  break;
118  }
119  default:
120  {
121  THROW_UNREACHABLE("");
122  break;
123  }
124  }
125  return ret;
126 }
127 
129 {
130  return true;
131 }
132 
134 {
135  THROW_ASSERT(Discr, "Discr data structure is not correctly initialized");
136  // parse the file containing the C traces
137  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Parsing C trace: " + Discr->c_trace_filename);
138  parse_discrepancy(Discr->c_trace_filename, Discr);
139  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Parsed C trace: " + Discr->c_trace_filename);
140 #ifndef NDEBUG
141  {
142  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Printing parsed C control flow trace");
143  for(const auto& fid2ctxtrace : Discr->c_control_flow_trace)
144  {
145  const auto f_id = fid2ctxtrace.first;
146  const auto f_name = tree_helper::name_function(HLSMgr->get_tree_manager(), f_id);
147  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->FUNCTION_ID " + STR(f_id) + ": " + f_name);
148  for(const auto& ctx2trace : fid2ctxtrace.second)
149  {
150  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->CONTEXT: " + STR(ctx2trace.first));
151  for(const auto& bb_id : ctx2trace.second)
152  {
153  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---BB: " + STR(bb_id));
154  }
156  }
158  }
159  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--End of parsed C control flow trace");
160  }
161 #endif
162  // untangle control flow traces
164  CustomUnorderedMap<std::string, std::list<std::pair<size_t, size_t>>> scope_to_best_epp_trace_with_metadata;
167  CustomUnorderedMap<std::string, size_t> scope_to_best_metadata_bits;
168  std::vector<size_t> tot_memory_usage_per_bits = std::vector<size_t>(MAX_METADATA_BITSIZE, 0);
169  size_t min_memory_usage = 0;
170  size_t total_state_of_the_art_memory_usage = 0;
171  size_t total_state_of_the_art_fixed_memory_usage = 0;
172  size_t total_state_of_the_art_opt_memory_usage = 0;
173  for(const auto& f : Discr->c_control_flow_trace)
174  {
175  const auto f_id = f.first;
177  "-->Untangling software control flow trace of function: " + STR(f_id) + " " +
178  HLSMgr->CGetFunctionBehavior(f_id)->CGetBehavioralHelper()->get_function_name());
179  const auto& stg = HLSMgr->get_HLS(f_id)->STG->CGetStg();
180  const auto& epp_stg = HLSMgr->get_HLS(f_id)->STG->CGetEPPStg();
181  const auto& stg_info = stg->CGetStateTransitionGraphInfo();
182  const auto fsm_entry_node = stg_info->entry_node;
183  const auto fsm_exit_node = stg_info->exit_node;
184  const auto& state_id_to_check = Discr->hw_discrepancy_info->fu_id_to_states_to_check.at(f_id);
185 #if HAVE_ASSERTS
186  const auto& state_id_to_check_on_feedback =
187  Discr->hw_discrepancy_info->fu_id_to_feedback_states_to_check.at(f_id);
188  const auto& reset_transitions = Discr->hw_discrepancy_info->fu_id_to_reset_edges.at(f_id);
189 #endif
190 
191  for(auto& context2trace : f.second)
192  {
193  const auto context_id = context2trace.first;
194  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Analyzing context: " + STR(context_id));
195  const auto& scope = Discr->context_to_scope.at(context_id);
196  scope_to_function_id[scope] = f_id;
197  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---scope: " + scope);
198 
199  size_t epp_counter = 0;
200  vertex current_state = fsm_entry_node;
201  bool takes_feedback_edge = false;
202  {
203  /*
204  * the entry state is not a real FSM state, so it is never to check.
205  * but it may have a non zero increment on its single outgoing edge,
206  * so we must check it and potentially add it to the epp_counter
207  */
208  THROW_ASSERT(boost::out_degree(current_state, *stg) == 1,
209  "entry state has out degree = " + STR(boost::out_degree(current_state, *stg)));
210  // select the only outgoing edge (must not be a feedback edge)
211  OutEdgeIterator out_edge, out_end;
212  boost::tie(out_edge, out_end) = boost::out_edges(current_state, *stg);
213  const EdgeDescriptor taken_edge = *out_edge;
214  THROW_ASSERT(reset_transitions.find(taken_edge) == reset_transitions.cend(), "");
215  // update epp counter
216  const auto taken_edge_info = stg->CGetTransitionInfo(taken_edge);
217  epp_counter += taken_edge_info->get_epp_increment();
218  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "epp_counter " + STR(epp_counter));
219  // update the current_state with the only successor of entry
220  current_state = boost::target(taken_edge, *stg);
221  // check that the first state is not a loop header
222  THROW_ASSERT(state_id_to_check_on_feedback.find(stg_info->vertex_to_state_id.at(current_state)) ==
223  state_id_to_check_on_feedback.cend(),
224  "");
225  }
226  if(HLSMgr->get_HLS(f_id)->registered_inputs)
227  {
228  /*
229  * if the FSM has registered inputs, the first real state of the FSM
230  * is spent registering the inputs and for this reason is not mapped
231  * on any real BB identifier.
232  * like the entry state, this is not a real FSM state, so it is never to check.
233  * but it may have a non zero increment on its single outgoing edge,
234  * so we must check it and potentially add it to the epp_counter
235  */
236  THROW_ASSERT(boost::out_degree(current_state, *stg) == 1,
237  "registered input state has out degree = " + STR(boost::out_degree(current_state, *stg)));
238  THROW_ASSERT(
239  state_id_to_check.find(stg_info->vertex_to_state_id.at(current_state)) == state_id_to_check.cend(), "");
240  // select the only outgoing edge (must not be a feedback edge)
241  OutEdgeIterator out_edge, out_end;
242  boost::tie(out_edge, out_end) = boost::out_edges(current_state, *stg);
243  const EdgeDescriptor taken_edge = *out_edge;
244  THROW_ASSERT(reset_transitions.find(taken_edge) == reset_transitions.cend(), "");
245  // update epp counter
246  const auto taken_edge_info = stg->CGetTransitionInfo(taken_edge);
247  epp_counter += taken_edge_info->get_epp_increment();
248  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "epp_counter " + STR(epp_counter));
249  // update the current_state with the only successor of entry
250  current_state = boost::target(taken_edge, *stg);
251  // check that the first state is not a loop header
252  const auto next_state_id = stg_info->vertex_to_state_id.at(current_state);
253  scope_to_state_trace[scope].push_back(next_state_id);
254  THROW_ASSERT(state_id_to_check_on_feedback.find(next_state_id) == state_id_to_check_on_feedback.cend(), "");
255  }
256  const std::list<unsigned int>& bb_trace = context2trace.second;
257  auto bb_id_it = bb_trace.cbegin();
258  const auto bb_id_end = bb_trace.cend();
259  for(; bb_id_it != bb_id_end; bb_id_it++)
260  {
261  const auto bb_id = *bb_id_it;
262  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->BB: " + STR(bb_id));
263  if(bb_id == BB_ENTRY)
264  {
266  continue;
267  }
268  bool goes_to_next_bb_execution = false;
269  do
270  {
271  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---find next state with bb_id: " + STR(bb_id));
272  const auto cur_state_id = stg_info->vertex_to_state_id.at(current_state);
273  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---current_state is: " + STR(cur_state_id));
274  // if the current state is to check, write the trace
275  if(not takes_feedback_edge and state_id_to_check.find(cur_state_id) != state_id_to_check.cend())
276  {
277  scope_to_epp_trace[scope].push_back(epp_counter);
278  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "epp_trace " + STR(epp_counter));
279  }
280  /* detect the taken edge and the next state */
281  bool found_valid_next_state = false;
282  bool end_of_bb_execution = false;
283  takes_feedback_edge = false;
284  vertex next_state = nullptr;
285  EdgeDescriptor taken_edge(NULL_VERTEX, NULL_VERTEX, nullptr);
286  // look for the next state belonging to the same bb, without following a feedback edge
287  BOOST_FOREACH(const EdgeDescriptor e, boost::out_edges(current_state, *stg))
288  {
289  const auto dst = boost::target(e, *stg);
290  const auto dst_info = stg->CGetStateInfo(dst);
293  "---analyzing next state: " +
294  ((dst == fsm_exit_node) ? STR("EXIT") : STR(stg_info->vertex_to_state_id.at(dst))) +
295  " in the same BB " + STR(bb_id));
296  if((not dst_info->is_dummy) and (*dst_info->BB_ids.begin() == bb_id))
297  {
298  if(not(stg->GetSelector(e) & TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK))
299  {
300  THROW_ASSERT(not found_valid_next_state,
301  "two neighbors of state S_" + STR(stg_info->vertex_to_state_id.at(current_state)) +
302  " have the same BB id = " + STR(bb_id));
303  found_valid_next_state = true;
304  taken_edge = e;
305  next_state = dst;
307  "---FOUND next state: " + STR(stg_info->vertex_to_state_id.at(next_state)) +
308  " in the same BB " + STR(bb_id));
309  }
310  }
311  else if(dst_info->is_dummy)
312  {
313  scope_to_state_trace[scope].push_back(stg_info->vertex_to_state_id.at(dst));
314  }
315  }
316  // if the next state was not found in the same BB without feedback edges there are two cases
317  if(not found_valid_next_state)
318  {
319  if(std::next(bb_id_it) != bb_id_end)
320  {
321  // the execution branches to another BB (or to the same with a feedback edge)
322  const auto next_bb_id = *std::next(bb_id_it);
323  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---look for next BB " + STR(next_bb_id));
324  BOOST_FOREACH(const EdgeDescriptor e, boost::out_edges(current_state, *stg))
325  {
326  const auto dst = boost::target(e, *stg);
327  const auto dst_info = stg->CGetStateInfo(dst);
328  if((not dst_info->is_dummy) and (*dst_info->BB_ids.begin() == next_bb_id))
329  {
330  THROW_ASSERT(not found_valid_next_state,
331  "two neighbors of state S_" +
332  STR(stg_info->vertex_to_state_id.at(current_state)) +
333  " have the same BB id = " + STR(next_bb_id));
334 #if HAVE_ASSERTS
335  found_valid_next_state = true;
336 #endif
337  end_of_bb_execution = true;
338  taken_edge = e;
339  next_state = dst;
341  "---FOUND next state: " + STR(stg_info->vertex_to_state_id.at(next_state)) +
342  " in new BB " + STR(next_bb_id));
343  if(stg->GetSelector(taken_edge) & TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK)
344  {
345  takes_feedback_edge = true;
346  }
347  }
348  else if(dst_info->is_dummy)
349  {
350  scope_to_state_trace[scope].push_back(stg_info->vertex_to_state_id.at(dst));
351  }
352  }
353  }
354  else
355  {
356  // the execution ends
357  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---look for EXIT");
358  BOOST_FOREACH(const EdgeDescriptor e, boost::out_edges(current_state, *stg))
359  {
360  const auto dst = boost::target(e, *stg);
361  if(dst == fsm_exit_node)
362  {
363 #if HAVE_ASSERTS
364  found_valid_next_state = true;
365 #endif
366  end_of_bb_execution = true;
367  taken_edge = e;
368  next_state = dst;
369  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---found next state: EXIT");
370  }
371  }
372  }
373  THROW_ASSERT(end_of_bb_execution, "");
374  }
375  THROW_ASSERT(found_valid_next_state, "next valid state not found");
376  THROW_ASSERT(takes_feedback_edge == (reset_transitions.find(taken_edge) != reset_transitions.cend()),
377  "");
378  if(next_state != fsm_exit_node)
379  {
380  const auto next_state_id = stg_info->vertex_to_state_id.at(next_state);
381  scope_to_state_trace[scope].push_back(next_state_id);
382  THROW_ASSERT((not takes_feedback_edge) or (state_id_to_check_on_feedback.find(next_state_id) !=
383  state_id_to_check_on_feedback.cend()),
384  "");
385  }
386  const auto taken_edge_info = epp_stg->CGetTransitionInfo(taken_edge);
387  epp_counter += taken_edge_info->get_epp_increment();
388  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "epp_counter " + STR(epp_counter));
389 
390  if(takes_feedback_edge)
391  {
392  /*
393  * the execution takes a feedback edge. feedback edges have no
394  * associated epp_increment. to compute increments and reset
395  * values we have to look onto the EPP edges.
396  * the reset value is equal to the epp_increment on the EPP
397  * edge going from the entry node of the FSM to the target of
398  * the feedback edge.
399  * the increment value before reset is the epp_increment of
400  * the EPP edge going from the source of the feedback edge to
401  * the exit node of the STG.
402  * note that these entry and exit nodes are not real states of
403  * the FSM but just placeholders.
404  */
405  const auto src = boost::source(taken_edge, *stg);
406  const auto dst = boost::target(taken_edge, *stg);
407  const auto epp_edge_from_entry = epp_stg->CGetEdge(fsm_entry_node, dst);
408  const auto epp_edge_to_exit = epp_stg->CGetEdge(src, fsm_exit_node);
409  const auto from_entry_edge_info = epp_stg->CGetTransitionInfo(epp_edge_from_entry);
410  const auto to_exit_edge_info = epp_stg->CGetTransitionInfo(epp_edge_to_exit);
411  scope_to_epp_trace[scope].push_back(epp_counter + to_exit_edge_info->get_epp_increment());
413  "epp_trace " + STR(epp_counter + to_exit_edge_info->get_epp_increment()));
414  epp_counter = from_entry_edge_info->get_epp_increment();
415  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "reset epp_counter " + STR(epp_counter));
416  }
417  current_state = next_state;
418  goes_to_next_bb_execution = end_of_bb_execution;
419  } while(not goes_to_next_bb_execution);
421  }
422  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed context: " + STR(context_id));
423  }
424 
425  // state_of_the_art memory usage
426  {
427  std::string vendor;
428  const auto tgt_device = HLSMgr->get_HLS_device();
429  if(tgt_device->has_parameter("vendor"))
430  {
431  vendor = tgt_device->get_parameter<std::string>("vendor");
432  boost::algorithm::to_lower(vendor);
433  }
434  unsigned int n_states = HLSMgr->get_HLS(f_id)->STG->get_number_of_states();
435  bool one_hot_encoding = false;
436  if(parameters->getOption<std::string>(OPT_fsm_encoding) == "one-hot")
437  {
438  one_hot_encoding = true;
439  }
440  else if(parameters->getOption<std::string>(OPT_fsm_encoding) == "auto" && vendor == "xilinx" && n_states < 256)
441  {
442  one_hot_encoding = true;
443  }
444 
445  unsigned int bitsnumber = language_writer::bitnumber(n_states - 1);
447  unsigned max_value = 0;
448  for(const auto& s : stg_info->state_id_to_vertex)
449  {
450  max_value = std::max(max_value, s.first);
451  }
452  if(max_value != n_states - 1)
453  {
454  bitsnumber = language_writer::bitnumber(max_value);
455  }
457  "---f_id " + STR(f_id) + " ONE HOT" + STR(one_hot_encoding ? " true" : " false"));
458 
459  const unsigned int state_bitsize = one_hot_encoding ? (max_value + 1) : bitsnumber;
461  "---f_id " + STR(f_id) + " STATE BITSIZE " + STR(state_bitsize));
462 
463  size_t f_state_of_the_art_usage = 0;
464  size_t f_state_of_the_art_usage_fixed = 0;
465  size_t f_state_of_the_art_usage_opt = 0;
466  for(const auto& scope : Discr->f_id_to_scope.at(f_id))
467  {
468  if(scope_to_state_trace.find(scope) == scope_to_state_trace.end())
469  {
470  continue;
471  }
472  const auto& state_trace = scope_to_state_trace.at(scope);
473  size_t scope_memory_usage = state_bitsize * state_trace.size();
475  "---scope " + scope + " state_of_the_art memory usage (BITS): " + STR(scope_memory_usage));
477  "---scope " + scope + " state_of_the_art memory usage (BYTES): " +
478  STR((scope_memory_usage / 8) + (((scope_memory_usage % 8) == 0) ? 0 : 1)));
479  f_state_of_the_art_usage += scope_memory_usage;
480 
481  size_t prev_state = std::numeric_limits<std::size_t>::max() - 1;
482  size_t incremental_counter_fixed = 0;
483  CustomMap<unsigned int, size_t> incremental_counter_opt;
484  size_t scope_memory_usage_fixed = 0;
485  CustomMap<unsigned int, size_t> scope_memory_usage_opt;
486  for(const auto state_id : state_trace)
487  {
488  if(state_id != (prev_state + 1))
489  {
490  scope_memory_usage_fixed += state_bitsize + FIXED_METADATA_SIZE;
491  for(unsigned int metadata_bitsize = 0; metadata_bitsize < MAX_METADATA_BITSIZE; metadata_bitsize++)
492  {
493  scope_memory_usage_opt[metadata_bitsize] += state_bitsize + metadata_bitsize;
494  }
495  incremental_counter_fixed = 0;
496  for(unsigned int metadata_bitsize = 0; metadata_bitsize < MAX_METADATA_BITSIZE; metadata_bitsize++)
497  {
498  incremental_counter_opt[metadata_bitsize] = 0;
499  }
500  }
501  else
502  {
503  incremental_counter_fixed++;
504  for(unsigned int metadata_bitsize = 0; metadata_bitsize < MAX_METADATA_BITSIZE; metadata_bitsize++)
505  {
506  incremental_counter_opt[metadata_bitsize]++;
507  }
508  if(incremental_counter_fixed >= (1ULL << FIXED_METADATA_SIZE))
509  {
510  scope_memory_usage_fixed += state_bitsize + FIXED_METADATA_SIZE;
511  incremental_counter_fixed = 0;
512  }
513  for(unsigned int metadata_bitsize = 0; metadata_bitsize < MAX_METADATA_BITSIZE; metadata_bitsize++)
514  {
515  if(incremental_counter_opt[metadata_bitsize] >= (1ULL << metadata_bitsize))
516  {
517  scope_memory_usage_opt[metadata_bitsize] += state_bitsize + metadata_bitsize;
518  incremental_counter_opt[metadata_bitsize] = 0;
519  }
520  }
521  }
522  prev_state = state_id;
523  }
525  "---scope " + scope +
526  " state_of_the_art fixed memory usage (BITS): " + STR(scope_memory_usage_fixed));
528  "---scope " + scope + " state_of_the_art fixed memory usage (BYTES): " +
529  STR((scope_memory_usage_fixed / 8) + (((scope_memory_usage_fixed % 8) == 0) ? 0 : 1)));
530  f_state_of_the_art_usage_fixed += scope_memory_usage_fixed;
531  size_t min_scope_memory_usage_opt = std::numeric_limits<size_t>::max();
532  for(unsigned int metadata_bitsize = 0; metadata_bitsize < MAX_METADATA_BITSIZE; metadata_bitsize++)
533  {
534  min_scope_memory_usage_opt =
535  std::min(min_scope_memory_usage_opt, scope_memory_usage_opt[metadata_bitsize]);
536  }
538  "---scope " + scope +
539  " state_of_the_art opt memory usage (BITS): " + STR(min_scope_memory_usage_opt));
542  "---scope " + scope + " state_of_the_art opt memory usage (BYTES): " +
543  STR((min_scope_memory_usage_opt / 8) + (((min_scope_memory_usage_opt % 8) == 0) ? 0 : 1)));
544  f_state_of_the_art_usage_opt += min_scope_memory_usage_opt;
545  }
547  "---f_id " + STR(f_id) +
548  " state_of_the_art memory usage (BITS): " + STR(f_state_of_the_art_usage));
550  "---f_id " + STR(f_id) + " state_of_the_art memory usage (BYTES): " +
551  STR((f_state_of_the_art_usage / 8) + (((f_state_of_the_art_usage % 8) == 0) ? 0 : 1)));
553  "---f_id " + STR(f_id) +
554  " state_of_the_art fixed memory usage (BITS): " + STR(f_state_of_the_art_usage_fixed));
557  "---f_id " + STR(f_id) + " state_of_the_art fixed memory usage (BYTES): " +
558  STR((f_state_of_the_art_usage_fixed / 8) + (((f_state_of_the_art_usage_fixed % 8) == 0) ? 0 : 1)));
560  "---f_id " + STR(f_id) +
561  " state_of_the_art opt memory usage (BITS): " + STR(f_state_of_the_art_usage_opt));
564  "---f_id " + STR(f_id) + " state_of_the_art opt memory usage (BYTES): " +
565  STR((f_state_of_the_art_usage_opt / 8) + (((f_state_of_the_art_usage_opt % 8) == 0) ? 0 : 1)));
566  total_state_of_the_art_memory_usage += f_state_of_the_art_usage;
567  total_state_of_the_art_fixed_memory_usage += f_state_of_the_art_usage_fixed;
568  total_state_of_the_art_opt_memory_usage += f_state_of_the_art_usage_opt;
569  }
570  // our memory usage
571  {
572  std::vector<size_t> f_memory_usage = std::vector<size_t>(MAX_METADATA_BITSIZE, 0);
573  size_t f_min_memory_usage = 0;
574  std::map<std::string, std::map<size_t, size_t>> scope_to_bits_to_usage;
575  if(Discr->hw_discrepancy_info->fu_id_control_flow_skip.find(f_id) ==
576  Discr->hw_discrepancy_info->fu_id_control_flow_skip.end())
577  {
578  size_t f_id_epp_trace_memory_word_bitsize = Discr->hw_discrepancy_info->fu_id_to_epp_trace_bitsize.at(f_id);
579  if((Discr->hw_discrepancy_info->fu_id_to_max_epp_path_val.at(f_id) + 1) ==
580  (1ULL << f_id_epp_trace_memory_word_bitsize))
581  {
582  f_id_epp_trace_memory_word_bitsize++;
583  }
585  "---f_id " + STR(f_id) + " EPP TRACE BITSIZE " + STR(f_id_epp_trace_memory_word_bitsize));
586  for(const auto& scope : Discr->f_id_to_scope.at(f_id))
587  {
588  if(scope_to_epp_trace.find(scope) == scope_to_epp_trace.end())
589  {
590  continue;
591  }
592  const auto epp_trace = scope_to_epp_trace.at(scope);
594  "---f_id " + STR(f_id) + " scope " + scope + " EPP TRACE LENGTH " +
595  STR(epp_trace.size()));
597  "---f_id " + STR(f_id) + " scope " + scope + " expected baseline EPP TRACE LENGTH " +
598  STR(f_id_epp_trace_memory_word_bitsize * epp_trace.size()));
599  size_t best_metadata_bitsize = 0;
600  size_t min_scope_memory_usage = std::numeric_limits<size_t>::max();
601  for(size_t i = 0; i < MAX_METADATA_BITSIZE; i++)
602  {
603  std::list<std::pair<size_t, size_t>> compressed_epp_trace_with_metadata;
604  if(epp_trace.size())
605  {
606  size_t prev_epp_counter = epp_trace.front();
607  // this represents the number of subsequent entries that
608  // are repeated in the trace
609  size_t metadata_counter = 0;
610  for(const auto epp_counter : epp_trace)
611  {
612  if(epp_counter != prev_epp_counter)
613  {
614  compressed_epp_trace_with_metadata.emplace_back(metadata_counter - 1, prev_epp_counter);
615  metadata_counter = 0;
616  }
617  else
618  {
619  if(metadata_counter > ((1ULL << i) - 1))
620  {
621  compressed_epp_trace_with_metadata.emplace_back(metadata_counter - 1, prev_epp_counter);
622  metadata_counter = 0;
623  }
624  }
625  metadata_counter++;
626  prev_epp_counter = epp_counter;
627  }
628  if(metadata_counter)
629  {
630  compressed_epp_trace_with_metadata.emplace_back(metadata_counter - 1, prev_epp_counter);
631  }
632  }
633  size_t scope_memory_usage =
634  (f_id_epp_trace_memory_word_bitsize + i) * compressed_epp_trace_with_metadata.size();
635  scope_to_bits_to_usage[scope][i] = scope_memory_usage;
637  "---scope " + scope + " memory usage (METADATA) " + STR(i) +
638  " (BITS): " + STR(scope_memory_usage));
640  "---scope " + scope + " memory usage (METADATA) " + STR(i) + " (BYTES): " +
641  STR((scope_memory_usage / 8) + (((scope_memory_usage % 8) == 0) ? 0 : 1)));
642  if(scope_memory_usage < min_scope_memory_usage)
643  {
644  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---new best metadata bitsize = " + STR(i));
645  best_metadata_bitsize = i;
646  min_scope_memory_usage = scope_memory_usage;
647  scope_to_best_epp_trace_with_metadata[scope].swap(compressed_epp_trace_with_metadata);
648  }
649  }
650  scope_to_best_metadata_bits[scope] = best_metadata_bitsize;
651  }
652  for(const auto& s2b2u : scope_to_bits_to_usage)
653  {
654  size_t min_scope_usage = std::numeric_limits<size_t>::max();
655  for(size_t i = 0; i < MAX_METADATA_BITSIZE; i++)
656  {
657  f_memory_usage.at(i) += s2b2u.second.at(i);
658  min_scope_usage = std::min(min_scope_usage, s2b2u.second.at(i));
659  }
660  f_min_memory_usage += min_scope_usage;
661  }
662  }
663  else
664  {
666  "---f_id " + STR(f_id) + " NO CONTROL FLOW CHECKS NEEDED");
667  }
668 
669  for(size_t i = 0; i < MAX_METADATA_BITSIZE; i++)
670  {
671  tot_memory_usage_per_bits.at(i) += f_memory_usage.at(i);
673  "---f_id " + STR(f_id) + " memory usage (METADATA) " + STR(i) +
674  " (BITS): " + STR(f_memory_usage.at(i)));
676  "---f_id " + STR(f_id) + " memory usage (METADATA) " + STR(i) + " (BYTES): " +
677  STR((f_memory_usage.at(i) / 8) + (((f_memory_usage.at(i) % 8) == 0) ? 0 : 1)));
678  }
679  min_memory_usage += f_min_memory_usage;
681  "---f_id " + STR(f_id) + " memory usage (BITS): " + STR(f_min_memory_usage));
683  "---f_id " + STR(f_id) + " memory usage (BYTES): " +
684  STR((f_min_memory_usage / 8) + (((f_min_memory_usage % 8) == 0) ? 0 : 1)));
685  }
687  "<--Untangled software control flow trace of function: " + STR(f_id));
688  }
689 #ifndef NDEBUG
690  for(const auto& i : scope_to_state_trace)
691  {
693  "---state trace length for function scope: " + i.first + ": " + STR(i.second.size()));
694  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->scope " + i.first);
695  for(const auto id : i.second)
696  {
698  }
699 
701  }
702  for(const auto& i : scope_to_epp_trace)
703  {
705  "---EPP trace length for function scope: " + i.first + ": " + STR(i.second.size()));
706  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->scope " + i.first);
707  for(const auto id : i.second)
708  {
710  }
711 
713  }
714 #endif
715 
716  const auto top_symbols = parameters->getOption<std::vector<std::string>>(OPT_top_functions_names);
717  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
718  const auto top_id = GET_INDEX_CONST_NODE(HLSMgr->get_tree_manager()->GetFunction(top_symbols.front()));
719  const auto top_module = HLSMgr->get_HLS(top_id)->top->get_circ();
720 
721  // scope_id starts from 1 because 0 are the non-initialized ones
722  size_t scope_id = 1;
723  for(const auto& i : scope_to_best_epp_trace_with_metadata)
724  {
725  const std::string& scope = i.first;
726  const auto f_id = scope_to_function_id.at(i.first);
727  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Initializing checker for scope " + i.first);
728  {
729  if(i.second.empty())
730  {
732  "<--Skipping scope " + i.first + " since it is not executed");
733  continue;
734  }
735  if(Discr->hw_discrepancy_info->fu_id_control_flow_skip.find(f_id) !=
736  Discr->hw_discrepancy_info->fu_id_control_flow_skip.end())
737  {
739  "<--Skipping scope " + i.first +
740  " since it is belongs to a function without control flow instructions");
741  continue;
742  }
743  }
744  using tokenizer = boost::tokenizer<boost::char_separator<char>>;
745  boost::char_separator<char> sep("/", nullptr);
746  tokenizer module_path_tokens(scope, sep);
747  tokenizer::iterator tok_iter;
748  tokenizer::iterator tok_iter_end = module_path_tokens.end();
749  for(tok_iter = module_path_tokens.begin(); tok_iter != tok_iter_end; ++tok_iter)
750  {
751  if(*tok_iter == top_module->get_id())
752  {
753  break;
754  }
755  }
756  THROW_ASSERT(tok_iter != tok_iter_end, "unexpected condition");
757  ++tok_iter;
758  THROW_ASSERT(tok_iter != tok_iter_end, "unexpected condition");
759  structural_objectRef curr_module = top_module;
760  for(; tok_iter != tok_iter_end; ++tok_iter)
761  {
763  "---Looking for " + *tok_iter + " in " + curr_module->get_path());
764  curr_module = curr_module->find_member(*tok_iter, component_o_K, curr_module);
765  THROW_ASSERT(curr_module, "unexpected condition");
766  }
767  const std::string datapath_id = "Datapath_i";
768  curr_module = curr_module->find_member(datapath_id, component_o_K, curr_module);
769  THROW_ASSERT(curr_module, "unexpected condition");
770  const std::string cfc_id = "ControlFlowChecker_i";
771  curr_module = curr_module->find_member(cfc_id, component_o_K, curr_module);
772  THROW_ASSERT(curr_module, "unexpected condition");
774  "---Found " + curr_module->get_path() + " of type " + GET_TYPE_NAME(curr_module));
775  GetPointer<module>(curr_module)->SetParameter("EPP_MISMATCH_ID", STR(scope_id));
776 
777  const size_t trace_len =
778  i.second.size() + 1; // use one entry more in the trace to avoid ever accessing out of bounds
779  const size_t metadata_word_size = scope_to_best_metadata_bits.at(scope);
780  auto data_word_size = std::stoul(GetPointer<module>(curr_module)->GetParameter("EPP_TRACE_BITSIZE"));
781  if((Discr->hw_discrepancy_info->fu_id_to_max_epp_path_val.at(f_id) + 1) == (1ULL << data_word_size))
782  {
783  data_word_size++;
784  GetPointer<module>(curr_module)->SetParameter("EPP_TRACE_BITSIZE", STR(data_word_size));
785  }
786  const size_t invalid_epp_id = (1ULL << data_word_size) - 1;
787  GetPointer<module>(curr_module)->SetParameter("EPP_TRACE_LENGTH", STR(trace_len));
788  GetPointer<module>(curr_module)->SetParameter("EPP_TRACE_METADATA_BITSIZE", STR(metadata_word_size));
789  GetPointer<module>(curr_module)->SetParameter("EPP_TRACE_INITIAL_METADATA", STR(i.second.begin()->first));
790 #ifndef NDEBUG
791  for(const auto& id : i.second)
792  {
793  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---COMPRESSED_EPP " + STR(id.first) + ":" + STR(id.second));
794  }
795 #endif
796  const std::string init_filename = "epp_control_flow_trace_scope__" + STR(scope_id) + ".mem";
797  std::ofstream init_file(GetPath(init_filename));
798 
799  for(const auto& id : i.second)
800  {
801  const auto metadata = id.first;
802  const auto data = id.second;
803  if(metadata >> metadata_word_size)
804  {
805  THROW_ERROR("metadata " + STR(metadata) + " cannot be represented with " + STR(metadata_word_size) +
806  " bits");
807  }
808  if(data >> data_word_size)
809  {
810  THROW_ERROR("data " + STR(data) + " cannot be represented with " + STR(data_word_size) + " bits");
811  }
812  if(metadata_word_size)
813  {
814  init_file << NumberToBinaryString(metadata, metadata_word_size);
815  }
816  init_file << NumberToBinaryString(data, data_word_size) << std::endl;
817  }
818  if(metadata_word_size)
819  {
820  init_file << NumberToBinaryString(0, metadata_word_size);
821  }
822  init_file << NumberToBinaryString(invalid_epp_id, data_word_size) << std::endl;
823  init_file.close();
824  GetPointer<module>(curr_module)->SetParameter("MEMORY_INIT_file", "\"\"" + GetPath(init_filename) + "\"\"");
825  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Initialized checker for scope " + i.first);
826  scope_id++;
827  }
828  for(size_t i = 0; i < MAX_METADATA_BITSIZE; i++)
829  {
831  "---tot memory usage (METADATA) " + STR(i) + " (BITS): " + STR(tot_memory_usage_per_bits.at(i)));
834  "---tot memory usage (METADATA) " + STR(i) + " (BYTES): " +
835  STR((tot_memory_usage_per_bits.at(i) / 8) + (((tot_memory_usage_per_bits.at(i) % 8) == 0) ? 0 : 1)));
836  }
838  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---HW Discrepancy Analysis results:");
840  "---tot memory usage BASE (BITS): " + STR(tot_memory_usage_per_bits.at(0)));
842  "---tot memory usage BASE (BYTES): " + STR((tot_memory_usage_per_bits.at(0) / 8) +
843  (((tot_memory_usage_per_bits.at(0) % 8) == 0) ? 0 : 1)));
845  "---tot memory usage FIXED (BITS): " + STR(tot_memory_usage_per_bits.at(FIXED_METADATA_SIZE)));
847  "---tot memory usage FIXED (BYTES): " +
848  STR((tot_memory_usage_per_bits.at(FIXED_METADATA_SIZE) / 8) +
849  (((tot_memory_usage_per_bits.at(FIXED_METADATA_SIZE) % 8) == 0) ? 0 : 1)));
850  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---minimal tot memory usage (BITS): " + STR(min_memory_usage));
852  "---minimal tot memory usage (BYTES): " +
853  STR((min_memory_usage / 8) + (((min_memory_usage % 8) == 0) ? 0 : 1)));
855  "---total state_of_the_art memory usage (BITS): " + STR(total_state_of_the_art_memory_usage));
858  "---total state_of_the_art memory usage (BYTES): " +
859  STR((total_state_of_the_art_memory_usage / 8) + (((total_state_of_the_art_memory_usage % 8) == 0) ? 0 : 1)));
861  "---total state_of_the_art fixed memory usage (BITS): " +
862  STR(total_state_of_the_art_fixed_memory_usage));
864  "---total state_of_the_art fixed memory usage (BYTES): " +
865  STR((total_state_of_the_art_fixed_memory_usage / 8) +
866  (((total_state_of_the_art_fixed_memory_usage % 8) == 0) ? 0 : 1)));
868  "---total state_of_the_art opt memory usage (BITS): " + STR(total_state_of_the_art_opt_memory_usage));
870  "---total state_of_the_art opt memory usage (BYTES): " +
871  STR((total_state_of_the_art_opt_memory_usage / 8) +
872  (((total_state_of_the_art_opt_memory_usage % 8) == 0) ? 0 : 1)));
875 }
876 
877 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
878 #pragma GCC diagnostic pop
879 #endif
const HLS_managerRef HLSMgr
information about all the HLS synthesis
Definition: hls_step.hpp:205
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
boost::graph_traits< graph >::out_edge_iterator OutEdgeIterator
out_edge_iterator definition.
Definition: graph.hpp:1312
static std::string name_function(const tree_managerConstRef &tm, const unsigned int index)
Return the name of the function.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
This file contains the structures needed to manage a graph that will represent the state transition g...
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
const int output_level
The output level.
void parse_discrepancy(const std::string &c_trace_filename, DiscrepancyRef Discrepancy)
RelationshipType
The relationship type.
#define FIXED_METADATA_SIZE
FIXED metadata bit size.
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
virtual structural_objectRef find_member(const std::string &id, so_kind type, const structural_objectRef owner) const =0
Return the object named id of a given type which belongs to or it is associated with the object...
#define min(x, y)
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMapUnstable
Definition: custom_map.hpp:156
std::string NumberToBinaryString(const T number, const size_t precision=0)
Function which print number in binary format.
Data structure describing a basic block at tree level.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
redefinition of map to manage ordered/unordered structures
#define GET_TYPE_NAME(structural_obj)
Macro returning the string name of a type.
Base class to pass information to a c backend.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
HDLWriter_Language
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
#define MAX_METADATA_BITSIZE
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
HLSFlowStep_Type
Definition: hls_step.hpp:95
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
const std::string get_path() const
Return a unique identifier of the structural object.
redefinition of set to manage ordered/unordered structures
#define BB_ENTRY
constant identifying the basic block node of type entry
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
utility function used to read files.
This file contains the structures needed to manage a graph that will represent the state transition g...
const DiscrepancyRef Discr
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
DesignFlowStep_Status Exec() override
Execute the step.
This file collects some utility functions.
HWDiscrepancyAnalysis(const ParameterConstRef parameters, const HLS_managerRef HLSMgr, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
std::string GetPath(std::filesystem::path path)
Definition: fileIO.hpp:140
Class specification of the tree_reindex support class.
Class specification of the basic_block structure.
static unsigned int bitnumber(unsigned long long n)
Counts the number of bits in an unsigned int.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
this class is used to manage the command-line or XML options.
Wrapper to call graph.
Class implementation of the structural_manager.
int debug_level
The debug level.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
Base class to pass information to a c backend.
Data structure definition for high-level synthesis flow.
#define NULL_VERTEX
null vertex definition
Definition: graph.hpp:1305
Class specification of the manager of the tree structures extracted from the raw file.
HLS specialization of generic_device.
A brief description of the C++ Header File.
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
Definition: graph.hpp:1316
#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