PandA-2024.02
test_vector_parser.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) 2004-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  */
40 #include "test_vector_parser.hpp"
41 
42 #include "Parameter.hpp"
45 #include "behavioral_helper.hpp"
46 #include "call_graph.hpp"
47 #include "call_graph_manager.hpp"
48 #include "custom_set.hpp"
49 #include "dbgPrintHelper.hpp"
50 #include "design_flow_graph.hpp"
51 #include "design_flow_manager.hpp"
52 #include "exceptions.hpp"
53 #include "fileIO.hpp"
55 #include "function_behavior.hpp"
57 #include "hls_manager.hpp"
58 #include "string_manipulation.hpp"
59 #include "tree_helper.hpp"
60 #include "tree_manager.hpp"
61 #include "tree_reindex.hpp"
62 #include "utility.hpp"
63 #include "xml_document.hpp"
64 #include "xml_dom_parser.hpp"
65 
66 #include <boost/algorithm/string.hpp>
67 #include <regex>
68 #include <tuple>
69 #include <utility>
70 
72  const DesignFlowManagerConstRef _design_flow_manager)
73  : HLS_step(_parameters, _HLSMgr, _design_flow_manager, HLSFlowStep_Type::TEST_VECTOR_PARSER)
74 {
75  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
76 }
77 
80 {
82  switch(relationship_type)
83  {
85  {
88  break;
89  }
91  {
92  break;
93  }
95  {
96  break;
97  }
98  default:
100  }
101  return ret;
102 }
103 
105 {
106  return true;
107 }
108 
110 {
112 
113  if(parameters->isOption(OPT_testbench_input_file))
114  {
115  const auto tb_files = parameters->getOption<CustomSet<std::string>>(OPT_testbench_input_file);
116  if(ends_with(*tb_files.begin(), ".xml"))
117  {
118  THROW_ASSERT(tb_files.size() == 1, "XML testbench initialization must be in a single file.");
119  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Examining " + *tb_files.begin());
120  HLSMgr->RSim->test_vectors = ParseXMLFile(*tb_files.begin());
121  }
122  else
123  {
125  "<--User provided co-simulation files will be used for test vectors generation");
127  }
128  }
129  else if(parameters->isOption(OPT_testbench_input_string))
130  {
131  const auto input_string = parameters->getOption<std::string>(OPT_testbench_input_string);
132  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Examining " + input_string);
133  HLSMgr->RSim->test_vectors = ParseUserString(input_string);
134  }
135  else
136  {
137  THROW_UNREACHABLE("");
138  }
140  "<--Number of input test vectors: " + STR(HLSMgr->RSim->test_vectors.size()));
142 }
143 
144 std::vector<std::map<std::string, std::string>> TestVectorParser::ParseUserString(const std::string& input_string) const
145 {
146  std::vector<std::map<std::string, std::string>> test_vectors;
147  auto tb_strings = string_to_container<std::vector<std::string>>(input_string, STR_CST_string_separator);
148  for(auto& tb_string : tb_strings)
149  {
151  std::string::iterator last_comma = tb_string.end();
152  for(auto it = tb_string.begin(), it_end = tb_string.end(); it != it_end; ++it)
153  {
154  if(*it == ',')
155  {
156  last_comma = it;
157  }
158  else if(*it == '=' && last_comma != it_end)
159  {
160  *last_comma = '$';
161  }
162  }
163  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Preprocessed string " + tb_string);
164  test_vectors.push_back(std::map<std::string, std::string>());
165  std::vector<std::string> testbench_parameters = SplitString(tb_string, "$");
166  for(const auto& parameter : testbench_parameters)
167  {
168  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Examining " + parameter);
169  std::vector<std::string> temp = SplitString(parameter, "=");
170  if(temp.size() != 2)
171  {
172  THROW_ERROR("Error in processing --generate-tb arg");
173  }
174  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---" + temp[0] + "=" + temp[1]);
175  test_vectors.back()[temp[0]] = temp[1];
176  }
178  }
179  return test_vectors;
180 }
181 
182 std::vector<std::map<std::string, std::string>>
183 TestVectorParser::ParseXMLFile(const std::filesystem::path& input_xml_filename) const
184 {
185  const auto CGM = HLSMgr->CGetCallGraphManager();
186  THROW_ASSERT(boost::num_vertices(*(CGM->CGetCallGraph())) != 0, "The call graph has not been computed yet");
187  const auto top_symbols = parameters->getOption<std::vector<std::string>>(OPT_top_functions_names);
188  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
189  const auto top_fnode = HLSMgr->get_tree_manager()->GetFunction(top_symbols.front());
190  const auto BH = HLSMgr->CGetFunctionBehavior(GET_INDEX_CONST_NODE(top_fnode))->CGetBehavioralHelper();
191 
192  if(!std::filesystem::exists(input_xml_filename))
193  {
194  THROW_WARNING("XML file \"" + input_xml_filename.string() +
195  "\" cannot be opened, creating a stub with random values");
196  xml_document document;
197  const auto nodeRoot = document.create_root_node("function");
198  const auto node = nodeRoot->add_child_element("testbench");
199 
200  for(const auto& function_parameter : BH->GetParameters())
201  {
202  if(tree_helper::IsPointerType(function_parameter))
203  {
204  THROW_UNREACHABLE("Random testbench parameters generation is not available for pointer parameters. Please "
205  "provide a valid testbench XML file.");
206  continue;
207  }
208  const auto param = BH->PrintVariable(function_parameter->index);
209 
210  auto value = (rand() % 20);
211  if(tree_helper::IsBooleanType(function_parameter))
212  {
213  value = value % 2;
214  }
215  node->set_attribute(param, STR(value));
216  }
217 
218  document.write_to_file_formatted(input_xml_filename);
219  }
220  try
221  {
222  XMLDomParser parser(input_xml_filename.string());
223  parser.Exec();
224  if(parser)
225  {
226  std::vector<std::map<std::string, std::string>> test_vectors;
227 
228  // Walk the tree:
229  const xml_element* node = parser.get_document()->get_root_node(); // deleted by DomParser.
230  const xml_node::node_list list = node->get_children();
231  for(const auto& iter : list)
232  {
233  const auto* Enode = GetPointer<const xml_element>(iter);
234 
235  if(!Enode || Enode->get_name() != "testbench")
236  {
237  continue;
238  }
239 
240  std::map<std::string, std::string> test_vector;
241 
242  for(const auto function_parameter : BH->get_parameters())
243  {
244  std::string param = BH->PrintVariable(function_parameter);
246  "Parameter: " + param +
247  (BH->is_a_pointer(function_parameter) ? " (memory access)" : " (input value)"));
248  if((Enode)->get_attribute(param))
249  {
250  test_vector[param] = STR((Enode)->get_attribute(param)->get_value());
251  }
252  else if((Enode)->get_attribute(param + ":init_file"))
253  {
254  const auto input_file_name = GetPath(input_xml_filename.parent_path()) + "/" +
255  Enode->get_attribute(param + ":init_file")->get_value();
256  if(ends_with(input_file_name, ".dat"))
257  {
258  test_vector[param] = input_file_name;
259  }
260  else
261  {
262  const auto input_file = fileIO_istream_open(input_file_name);
263  test_vector[param] =
264  std::string(std::istreambuf_iterator<char>(*input_file), std::istreambuf_iterator<char>());
265  }
266  }
267  else if(!BH->is_a_pointer(function_parameter))
268  {
269  THROW_ERROR("Missing input value for parameter: " + param);
270  }
271  }
272  test_vectors.emplace_back(std::move(test_vector));
273  }
274  return test_vectors;
275  }
276  }
277  catch(const char* msg)
278  {
279  std::cerr << msg << std::endl;
280  }
281  catch(const std::string& msg)
282  {
283  std::cerr << msg << std::endl;
284  }
285  catch(const std::exception& ex)
286  {
287  std::cout << "Exception caught: " << ex.what() << std::endl;
288  }
289  catch(...)
290  {
291  std::cerr << "unknown exception" << std::endl;
292  }
293  THROW_ERROR("Error parsing the test vectors file " + input_xml_filename.string());
294  return std::vector<std::map<std::string, std::string>>();
295 }
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
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;.
TVMValue param[3]
File containing functions and utilities to support the printing of debug messagges.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
std::vector< std::map< std::string, std::string > > ParseUserString(const std::string &input_string) const
Parse a user defined string extracting the test vectors.
#define STR_CST_string_separator
The character used to separate concatenated string.
Definition: utility.hpp:61
#define GET_CLASS(obj)
Macro returning the actual type of an object.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
TestVectorParser(const ParameterConstRef _parameters, const HLS_managerRef _HLSMgr, const DesignFlowManagerConstRef _design_flow_manager)
RelationshipType
The relationship type.
Source must be executed to satisfy target.
exceptions managed by PandA
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
DesignFlowStep_Status Exec() override
Execute the step.
refcount< SimulationInformation > SimulationInformationRef
Factory for hls flow step.
static bool IsBooleanType(const tree_nodeConstRef &type)
Return true if the treenode is of bool type.
HLSFlowStep_Type
Definition: hls_step.hpp:95
Classes to describe design flow graph.
redefinition of set to manage ordered/unordered structures
xml_element * create_root_node(const std::string &_name)
Creates the root node.
XML DOM parser.
XML DOM parser.
utility function used to read files.
bool ends_with(const std::string &str, const std::string &pattern)
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This file collects some utility functions and macros.
Call graph hierarchy.
fileIO_istreamRef fileIO_istream_open(const std::string &name)
this function returns an istream compressed or not.
Definition: fileIO.cpp:55
std::list< xml_nodeRef > node_list
type for list of xml nodes
Definition: xml_node.hpp:90
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Wrapper of design_flow.
This file collects some utility functions.
std::string GetPath(std::filesystem::path path)
Definition: fileIO.hpp:140
Class specification of the tree_reindex support class.
std::vector< std::map< std::string, std::string > > ParseXMLFile(const std::filesystem::path &input_xml) const
Parse a user defined xml file extracting the test vectors.
This class contains the methods to create a frontend flow step.
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.
node_list const & get_children()
Obtain the list of child nodes.
Definition: xml_node.hpp:310
Wrapper to call graph.
int debug_level
The debug level.
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
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.
static bool IsPointerType(const tree_nodeConstRef &type)
Return true if treenode index is a pointer.
This class contains the base representation for a generic frontend flow step which works on the whole...
xml_element * add_child_element(const std::string &name)
Add a child element to this node.
Definition: xml_node.cpp:54
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
#define DEBUG_LEVEL_MINIMUM
minimum debugging print is performed.
#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