scc  2022.4.0
SystemC components library
scv_tr_mtc.cpp
1 /*******************************************************************************
2  * Copyright 2018 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 #include <array>
17 #include <boost/filesystem.hpp>
18 #include <cmath>
19 #include <cstdio>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <iostream>
24 #include <sstream>
25 #include <stdexcept>
26 #include <string>
27 #include <unordered_map>
28 #include <unordered_set>
29 #include <vector>
30 // clang-format off
31 #ifdef HAS_SCV
32 #include <scv.h>
33 #else
34 #include <scv-tr.h>
35 namespace scv_tr {
36 #endif
37 // clang-format on
38 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
40 using namespace std;
41 
42 // ----------------------------------------------------------------------------
43 enum EventType { BEGIN, RECORD, END };
44 using data_type = scv_extensions_if::data_type;
45 // ----------------------------------------------------------------------------
46 namespace {
47 class Base {
48 protected:
49  boost::filesystem::path dir;
50  std::ofstream out;
51  bool const is_open;
52  std::array<char, 1024> buffer;
53  Base(const std::string& name)
54  : dir(name.c_str())
55  , out(name)
56  , is_open(out.is_open()) {
57  // if(boost::filesystem::exists(dir))
58  // boost::filesystem::remove_all(dir);
59  // boost::filesystem::create_directory(dir);
60  }
61  ~Base() {
62  if(is_open)
63  out.close();
64  }
65 };
66 
67 struct Database : Base {
68  uint64_t idx{0};
69  Database(const std::string& name)
70  : Base(name) {}
71 
72  inline uint64_t getIdOf(const std::string& str) { return idx; }
73 
74  inline void writeStream(uint64_t id, std::string const& name, std::string const& kind) {
75  if(is_open) {
76  auto len = sprintf(buffer.data(), "scv_tr_stream (ID %lu, name \"%s\", kind \"%s\")\n", id, name.c_str(), kind.c_str());
77  out.write(buffer.data(), len);
78  }
79  }
80 
81  inline void writeGenerator(uint64_t id, std::string const& name, uint64_t stream) {
82  if(is_open) {
83  auto len = sprintf(buffer.data(), "scv_tr_generator (ID %lu, name \"%s\", scv_tr_stream %lu,\n", id, name.c_str(), stream);
84  out.write(buffer.data(), len);
85  }
86  }
87 
88  inline uint64_t writeTransaction(uint64_t id, uint64_t generator) {
89  return ++idx; // d.writeTx(id, generator, concurrencyLevel);
90  }
91 
92  inline void writeTxTimepoint(uint64_t id, int type, uint64_t time, uint64_t file_offset) {
93  // t.append(type, time, file_offset);
94  }
95 
96  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, const string& value) {
97  // d.writeAttribute(id, event, c.getIdOf(name), type, c.getIdOf(value));
98  }
99 
100  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, uint64_t value) {
101  // d.writeAttribute(id, event, c.getIdOf(name), type, value);
102  }
103 
104  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, double value) {
105  // int exponent;
106  // const double mantissa = frexp(value, &exponent);
107  }
108 
109  inline void writeRelation(const std::string& name, uint64_t sink_id, uint64_t src_id) {
110  // d.writeRelation(c.getIdOf(name), src_id, sink_id);
111  }
112 };
113 
114 Database* db;
115 std::unordered_map<uint64_t, uint64_t> id2offset;
116 
117 void dbCb(const scv_tr_db& _scv_tr_db, scv_tr_db::callback_reason reason, void* data) {
118  // This is called from the scv_tr_db ctor.
119  static string fName("DEFAULT_scv_tr_sqlite");
120  switch(reason) {
121  case scv_tr_db::CREATE:
122  if((_scv_tr_db.get_name() != nullptr) && (strlen(_scv_tr_db.get_name()) != 0))
123  fName = _scv_tr_db.get_name();
124  try {
125  db = new Database(fName);
126  } catch(...) {
127  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't open recording file");
128  }
129  break;
130  case scv_tr_db::DELETE:
131  try {
132  delete db;
133  } catch(...) {
134  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't close recording file");
135  }
136  break;
137  default:
138  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Unknown reason in scv_tr_db callback");
139  }
140 }
141 // ----------------------------------------------------------------------------
142 void streamCb(const scv_tr_stream& s, scv_tr_stream::callback_reason reason, void* data) {
143  if(reason == scv_tr_stream::CREATE) {
144  try {
145  db->writeStream(s.get_id(), s.get_name(), s.get_stream_kind());
146  } catch(std::runtime_error& e) {
147  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create stream");
148  }
149  }
150 }
151 // ----------------------------------------------------------------------------
152 inline void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, const string& value) {
153  try {
154  db->writeAttribute(id, event, name, type, value);
155  } catch(std::runtime_error& e) {
156  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
157  }
158 }
159 // ----------------------------------------------------------------------------
160 inline void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, long long value) {
161  try {
162  db->writeAttribute(id, event, name, type, static_cast<uint64_t>(value));
163  } catch(std::runtime_error& e) {
164  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
165  }
166 }
167 // ----------------------------------------------------------------------------
168 inline void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, double value) {
169  try {
170  db->writeAttribute(id, event, name, type, value);
171  } catch(std::runtime_error& e) {
172  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
173  }
174 }
175 
176 inline std::string get_name(const char* prefix, const scv_extensions_if* my_exts_p) {
177  static thread_local std::unordered_map<const scv_extensions_if*, std::string> name_lut;
178  auto it = name_lut.find(my_exts_p);
179  if(it != name_lut.end())
180  return it->second;
181  string name;
182  if(!prefix || strlen(prefix) == 0) {
183  name = my_exts_p->get_name();
184  } else {
185  if((my_exts_p->get_name() == nullptr) || (strlen(my_exts_p->get_name()) == 0)) {
186  name = prefix;
187  } else {
188  name = std::string(prefix) + "." + my_exts_p->get_name();
189  }
190  }
191  name_lut[my_exts_p] = (name == "") ? "<unnamed>" : name;
192  return (name == "") ? "<unnamed>" : name;
193 }
194 
195 // ----------------------------------------------------------------------------
196 void recordAttributes(uint64_t id, EventType eventType, char const* prefix, const scv_extensions_if* my_exts_p) {
197  if(my_exts_p == nullptr)
198  return;
199  auto name = get_name(prefix, my_exts_p);
200  switch(my_exts_p->get_type()) {
201  case scv_extensions_if::RECORD: {
202  int num_fields = my_exts_p->get_num_fields();
203  if(num_fields > 0) {
204  for(int field_counter = 0; field_counter < num_fields; field_counter++) {
205  const scv_extensions_if* field_data_p = my_exts_p->get_field(field_counter);
206  recordAttributes(id, eventType, prefix, field_data_p);
207  }
208  }
209  } break;
210  case scv_extensions_if::ENUMERATION:
211  recordAttribute(id, eventType, name, scv_extensions_if::ENUMERATION, my_exts_p->get_enum_string((int)(my_exts_p->get_integer())));
212  break;
213  case scv_extensions_if::BOOLEAN:
214  recordAttribute(id, eventType, name, scv_extensions_if::BOOLEAN, my_exts_p->get_bool() ? "TRUE" : "FALSE");
215  break;
216  case scv_extensions_if::INTEGER:
217  case scv_extensions_if::FIXED_POINT_INTEGER:
218  recordAttribute(id, eventType, name, scv_extensions_if::INTEGER, my_exts_p->get_integer());
219  break;
220  case scv_extensions_if::UNSIGNED:
221  recordAttribute(id, eventType, name, scv_extensions_if::UNSIGNED, my_exts_p->get_integer());
222  break;
223  case scv_extensions_if::POINTER:
224  recordAttribute(id, eventType, name, scv_extensions_if::POINTER, (long long)my_exts_p->get_pointer());
225  break;
226  case scv_extensions_if::STRING:
227  recordAttribute(id, eventType, name, scv_extensions_if::STRING, my_exts_p->get_string());
228  break;
229  case scv_extensions_if::FLOATING_POINT_NUMBER:
230  recordAttribute(id, eventType, name, scv_extensions_if::FLOATING_POINT_NUMBER, my_exts_p->get_double());
231  break;
232  case scv_extensions_if::BIT_VECTOR: {
233  sc_bv_base tmp_bv(my_exts_p->get_bitwidth());
234  my_exts_p->get_value(tmp_bv);
235  recordAttribute(id, eventType, name, scv_extensions_if::BIT_VECTOR, tmp_bv.to_string());
236  } break;
237  case scv_extensions_if::LOGIC_VECTOR: {
238  sc_lv_base tmp_lv(my_exts_p->get_bitwidth());
239  my_exts_p->get_value(tmp_lv);
240  recordAttribute(id, eventType, name, scv_extensions_if::LOGIC_VECTOR, tmp_lv.to_string());
241  } break;
242  case scv_extensions_if::ARRAY:
243  for(int array_elt_index = 0; array_elt_index < my_exts_p->get_array_size(); array_elt_index++) {
244  const scv_extensions_if* field_data_p = my_exts_p->get_array_elt(array_elt_index);
245  recordAttributes(id, eventType, prefix, field_data_p);
246  }
247  break;
248  default: {
249  std::array<char, 100> tmpString;
250  sprintf(tmpString.data(), "Unsupported attribute type = %d", my_exts_p->get_type());
251  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, tmpString.data());
252  }
253  }
254 }
255 // ----------------------------------------------------------------------------
256 void generatorCb(const scv_tr_generator_base& g, scv_tr_generator_base::callback_reason reason, void* data) {
257  if(reason == scv_tr_generator_base::CREATE && db) {
258  try {
259  db->writeGenerator(g.get_id(), g.get_name(), g.get_scv_tr_stream().get_id());
260  } catch(std::runtime_error& e) {
261  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create generator entry");
262  }
263  }
264 }
265 // ----------------------------------------------------------------------------
266 void transactionCb(const scv_tr_handle& t, scv_tr_handle::callback_reason reason, void* data) {
267  if(!db)
268  return;
269  if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
270  return;
271  if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
272  return;
273 
274  uint64_t id = t.get_id();
275  vector<uint64_t>::size_type concurrencyIdx;
276  const scv_extensions_if* my_exts_p;
277  switch(reason) {
278  case scv_tr_handle::BEGIN: {
279  my_exts_p = t.get_begin_exts_p();
280  if(my_exts_p == nullptr)
281  my_exts_p = t.get_scv_tr_generator_base().get_begin_exts_p();
282  if(my_exts_p) {
283  auto tmp_str =
284  t.get_scv_tr_generator_base().get_begin_attribute_name() ? t.get_scv_tr_generator_base().get_begin_attribute_name() : "";
285  recordAttributes(id, BEGIN, tmp_str, my_exts_p);
286  }
287  } break;
288  case scv_tr_handle::END: {
289  my_exts_p = t.get_end_exts_p();
290  if(my_exts_p == nullptr)
291  my_exts_p = t.get_scv_tr_generator_base().get_end_exts_p();
292  if(my_exts_p) {
293  auto tmp_str =
294  t.get_scv_tr_generator_base().get_end_attribute_name() ? t.get_scv_tr_generator_base().get_end_attribute_name() : "";
295  recordAttributes(t.get_id(), END, tmp_str, my_exts_p);
296  }
297  } break;
298  default:;
299  }
300 }
301 // ----------------------------------------------------------------------------
302 void attributeCb(const scv_tr_handle& t, const char* name, const scv_extensions_if* ext, void* data) {
303  if(!db)
304  return;
305  if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
306  return;
307  if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
308  return;
309  recordAttributes(t.get_id(), RECORD, name == nullptr ? "" : name, ext);
310 }
311 // ----------------------------------------------------------------------------
312 void relationCb(const scv_tr_handle& tr_1, const scv_tr_handle& tr_2, void* data, scv_tr_relation_handle_t relation_handle) {
313  if(!db)
314  return;
315  if(tr_1.get_scv_tr_stream().get_scv_tr_db() == nullptr)
316  return;
317  if(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
318  return;
319  try {
320  db->writeRelation(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_relation_name(relation_handle), tr_1.get_id(), tr_2.get_id());
321  } catch(std::runtime_error& e) {
322  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create transaction relation");
323  }
324 }
325 } // namespace
326 // ----------------------------------------------------------------------------
328  scv_tr_db::register_class_cb(dbCb);
329  scv_tr_stream::register_class_cb(streamCb);
330  scv_tr_generator_base::register_class_cb(generatorCb);
331  scv_tr_handle::register_class_cb(transactionCb);
332  scv_tr_handle::register_record_attribute_cb(attributeCb);
333  scv_tr_handle::register_relation_cb(relationCb);
334 }
335 // ----------------------------------------------------------------------------
336 #ifndef HAS_SCV
337 }
338 #endif
SystemC Verification Library (SCV) Transaction Recording.
void scv_tr_mtc_init()
initializes the infrastructure to use a compressed text based transaction recording database with a m...
Definition: scv_tr_mtc.cpp:327