scc  2022.4.0
SystemC components library
scv_tr_lz4.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 #ifdef FMT_SPDLOG_INTERNAL
31 #include <fmt/fmt.h>
32 #else
33 #include <fmt/format.h>
34 #endif
35 #include <util/lz4_streambuf.h>
36 // clang-format off
37 #ifdef HAS_SCV
38 #include <scv.h>
39 #else
40 #include <scv-tr.h>
41 namespace scv_tr {
42 #endif
43 // clang-format on
44 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
46 using namespace std;
47 
48 // ----------------------------------------------------------------------------
49 enum EventType { BEGIN, RECORD, END };
50 struct AttrDesc {
51  EventType const evt;
52  scv_extensions_if::data_type const type;
53  std::string const name;
54  AttrDesc(EventType evt, scv_extensions_if::data_type type, std::string const& name)
55  : evt(evt)
56  , type(type)
57  , name(name) {}
58 };
59 using data_type = scv_extensions_if::data_type;
60 // ----------------------------------------------------------------------------
61 namespace {
62 const std::array<char const*, scv_extensions_if::STRING + 1> data_type_str = {{
63  "BOOLEAN", // bool
64  "ENUMERATION", // enum
65  "INTEGER", // char, short, int, long, long long, sc_int, sc_bigint
66  "UNSIGNED", // unsigned { char, short, int, long, long long }, sc_uint, sc_biguint
67  "FLOATING_POINT_NUMBER", // float, double
68  "BIT_VECTOR", // sc_bit, sc_bv
69  "LOGIC_VECTOR", // sc_logic, sc_lv
70  "FIXED_POINT_INTEGER", // sc_fixed
71  "UNSIGNED_FIXED_POINT_INTEGER", // sc_ufixed
72  "RECORD", // struct/class
73  "POINTER", // T*
74  "ARRAY", // T[N]
75  "STRING" // string, std::string
76 
77 }};
78 class PlainWriter {
79 public:
80  std::ofstream out;
81  PlainWriter(const std::string& name)
82  : out(name) {}
83  ~PlainWriter() {
84  if(out.is_open())
85  out.close();
86  }
87  bool is_open() { return out.is_open(); }
88 };
89 class LZ4Writer {
90  std::ofstream ofs;
91  std::unique_ptr<util::lz4c_steambuf> strbuf;
92 
93 public:
94  std::ostream out;
95  LZ4Writer(const std::string& name)
96  : ofs(name, std::ios::binary | std::ios::trunc)
97  , strbuf(new util::lz4c_steambuf(ofs, 8192))
98  , out(strbuf.get()) {}
99  ~LZ4Writer() {
100  if(is_open()) {
101  strbuf->close();
102  ofs.close();
103  }
104  }
105 
106  bool is_open() { return ofs.is_open(); }
107 };
108 
109 template <typename WRITER> struct Formatter {
110  std::unique_ptr<WRITER> writer;
111  Formatter(const std::string& name)
112  : writer(new WRITER(name)) {}
113 
114  Formatter() {}
115 
116  inline bool open(const std::string& name) {
117  writer.reset(new WRITER(name));
118  return writer->is_open();
119  }
120 
121  inline void close() { delete writer.release(); }
122 
123  inline void writeStream(uint64_t id, std::string const& name, std::string const& kind) {
124  auto buf = fmt::format("scv_tr_stream (ID {}, name \"{}\", kind \"{}\")\n", id, name.c_str(), kind.c_str());
125  writer->out.write(buf.c_str(), buf.size());
126  }
127 
128  inline void writeGenerator(uint64_t id, std::string const& name, uint64_t stream, std::vector<AttrDesc> const& attributes) {
129  auto buf = fmt::format("scv_tr_generator (ID {}, name \"{}\", scv_tr_stream {},\n", id, name.c_str(), stream);
130  writer->out.write(buf.c_str(), buf.size());
131  auto idx = 0U;
132  for(auto attr : attributes) {
133  if(attr.evt == BEGIN) {
134  auto buf = fmt::format("begin_attribute (ID {}, name \"{}\", type \"{}\")\n", idx, attr.name, data_type_str[attr.type]);
135  writer->out.write(buf.c_str(), buf.size());
136  } else if(attr.evt == END) {
137  auto buf = fmt::format("end_attribute (ID {}, name \"{}\", type \"{}\")\n", idx, attr.name, data_type_str[attr.type]);
138  writer->out.write(buf.c_str(), buf.size());
139  }
140  ++idx;
141  }
142  writer->out.write(")\n", 2);
143  }
144 
145  inline void writeTransaction(uint64_t id, uint64_t generator, EventType type, uint64_t time) {
146  auto buf = type == BEGIN ? fmt::format("tx_begin {} {} {} ps\n", id, generator, time)
147  : fmt::format("tx_end {} {} {} ps\n", id, generator, time);
148  writer->out.write(buf.c_str(), buf.size());
149  }
150 
151  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, const string& value) {
152  // data_type::BOOLEAN, data_type::ENUMERATION, data_type::BIT_VECTOR, data_type::LOGIC_VECTOR, data_type::STRING
153  auto buf = event == EventType::RECORD
154  ? fmt::format("tx_record_attribute {} \"{}\" {} = \"{}\"\n", id, name, data_type_str[type], value)
155  : fmt::format("a \"{}\"\n", value);
156  writer->out.write(buf.c_str(), buf.size());
157  }
158 
159  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, int64_t value) {
160  // data_type::INTEGER, data_type::UNSIGNED, data_type::FIXED_POINT_INTEGER, data_type::UNSIGNED_FIXED_POINT_INTEGER
161  auto buf = event == EventType::RECORD ? fmt::format("tx_record_attribute {} \"{}\" {} = {}\n", id, name, data_type_str[type], value)
162  : fmt::format("a {}\n", value);
163  writer->out.write(buf.c_str(), buf.size());
164  }
165 
166  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, uint64_t value) {
167  // data_type::INTEGER, data_type::UNSIGNED, data_type::FIXED_POINT_INTEGER, data_type::UNSIGNED_FIXED_POINT_INTEGER
168  auto buf = event == EventType::RECORD ? fmt::format("tx_record_attribute {} \"{}\" {} = {}\n", id, name, data_type_str[type], value)
169  : fmt::format("a {}\n", value);
170  writer->out.write(buf.c_str(), buf.size());
171  }
172 
173  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, bool value) {
174  // data_type::INTEGER, data_type::UNSIGNED, data_type::FIXED_POINT_INTEGER, data_type::UNSIGNED_FIXED_POINT_INTEGER
175  auto buf = event == EventType::RECORD
176  ? fmt::format("tx_record_attribute {} \"{}\" {} = {}\n", id, name, data_type_str[type], value ? "true" : "false")
177  : fmt::format("a {}\n", value ? "true" : "false");
178  writer->out.write(buf.c_str(), buf.size());
179  }
180 
181  inline void writeAttribute(uint64_t id, EventType event, const string& name, data_type type, double value) {
182  // data_type::FLOATING_POINT_NUMBER
183  auto buf = event == EventType::RECORD ? fmt::format("tx_record_attribute {} \"{}\" {} = {}\n", id, name, data_type_str[type], value)
184  : fmt::format("a {}\n", value);
185  writer->out.write(buf.c_str(), buf.size());
186  }
187 
188  inline void writeRelation(const std::string& name, uint64_t sink_id, uint64_t src_id) {
189  auto buf = fmt::format("tx_relation \"{}\" {} {}\n", name, sink_id, src_id);
190  writer->out.write(buf.c_str(), buf.size());
191  }
192  static Formatter& get() {
193  static Formatter db;
194  return db;
195  }
196 };
197 template <typename DB> void dbCb(const scv_tr_db& _scv_tr_db, scv_tr_db::callback_reason reason, void* data) {
198  // This is called from the scv_tr_db ctor.
199  static string fName("DEFAULT_scv_tr_sqlite");
200  switch(reason) {
201  case scv_tr_db::CREATE:
202  if((_scv_tr_db.get_name() != nullptr) && (strlen(_scv_tr_db.get_name()) != 0))
203  fName = _scv_tr_db.get_name();
204  try {
205  DB::get().open(fName);
206  } catch(...) {
207  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't open recording file");
208  }
209  break;
210  case scv_tr_db::DELETE:
211  try {
212  DB::get().close();
213  } catch(...) {
214  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't close recording file");
215  }
216  break;
217  default:
218  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Unknown reason in scv_tr_db callback");
219  }
220 }
221 // ----------------------------------------------------------------------------
222 template <typename DB> void streamCb(const scv_tr_stream& s, scv_tr_stream::callback_reason reason, void* data) {
223  if(reason == scv_tr_stream::CREATE) {
224  try {
225  DB::get().writeStream(s.get_id(), s.get_name(), s.get_stream_kind());
226  } catch(std::runtime_error& e) {
227  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create stream");
228  }
229  }
230 }
231 // ----------------------------------------------------------------------------
232 template <typename DB> inline void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, const string& value) {
233  try {
234  DB::get().writeAttribute(id, event, name, type, value);
235  } catch(std::runtime_error& e) {
236  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
237  }
238 }
239 // ----------------------------------------------------------------------------
240 inline std::string get_name(const char* prefix, const scv_extensions_if* my_exts_p) {
241  string name;
242  if(!prefix || strlen(prefix) == 0) {
243  name = my_exts_p->get_name();
244  } else {
245  if((my_exts_p->get_name() == nullptr) || (strlen(my_exts_p->get_name()) == 0)) {
246  name = prefix;
247  } else {
248  name = fmt::format("{}.{}", prefix, my_exts_p->get_name());
249  }
250  }
251  return (name == "") ? "<unnamed>" : name;
252 }
253 
254 // ----------------------------------------------------------------------------
255 template <typename DB>
256 inline void recordAttributes(uint64_t id, EventType eventType, char const* prefix, const scv_extensions_if* my_exts_p) {
257  if(my_exts_p == nullptr)
258  return;
259  auto name = get_name(prefix, my_exts_p);
260  switch(my_exts_p->get_type()) {
261  case scv_extensions_if::RECORD: {
262  int num_fields = my_exts_p->get_num_fields();
263  if(num_fields > 0) {
264  for(int field_counter = 0; field_counter < num_fields; field_counter++) {
265  const scv_extensions_if* field_data_p = my_exts_p->get_field(field_counter);
266  recordAttributes<DB>(id, eventType, prefix, field_data_p);
267  }
268  }
269  } break;
270  case scv_extensions_if::POINTER:
271  if(auto ptr = my_exts_p->get_pointer()) {
272  std::stringstream ss;
273  ss << prefix << "*";
274  recordAttributes<DB>(id, eventType, ss.str().c_str(), ptr);
275  }
276  break;
277  case scv_extensions_if::ENUMERATION:
278  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::ENUMERATION,
279  my_exts_p->get_enum_string((int)(my_exts_p->get_integer())));
280  break;
281  case scv_extensions_if::BOOLEAN:
282  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::BOOLEAN, my_exts_p->get_bool());
283  break;
284  case scv_extensions_if::INTEGER:
285  case scv_extensions_if::FIXED_POINT_INTEGER:
286  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::INTEGER, (int64_t)my_exts_p->get_integer());
287  break;
288  case scv_extensions_if::UNSIGNED:
289  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::UNSIGNED, (uint64_t)my_exts_p->get_unsigned());
290  break;
291  case scv_extensions_if::STRING:
292  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::STRING, my_exts_p->get_string());
293  break;
294  case scv_extensions_if::FLOATING_POINT_NUMBER:
295  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::FLOATING_POINT_NUMBER, my_exts_p->get_double());
296  break;
297  case scv_extensions_if::BIT_VECTOR: {
298  sc_bv_base tmp_bv(my_exts_p->get_bitwidth());
299  my_exts_p->get_value(tmp_bv);
300  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::BIT_VECTOR, tmp_bv.to_string());
301  } break;
302  case scv_extensions_if::LOGIC_VECTOR: {
303  sc_lv_base tmp_lv(my_exts_p->get_bitwidth());
304  my_exts_p->get_value(tmp_lv);
305  DB::get().writeAttribute(id, eventType, name, scv_extensions_if::LOGIC_VECTOR, tmp_lv.to_string());
306  } break;
307  case scv_extensions_if::ARRAY:
308  for(int array_elt_index = 0; array_elt_index < my_exts_p->get_array_size(); array_elt_index++) {
309  const scv_extensions_if* field_data_p = my_exts_p->get_array_elt(array_elt_index);
310  recordAttributes<DB>(id, eventType, prefix, field_data_p);
311  }
312  break;
313  default: {
314  std::array<char, 100> tmpString;
315  sprintf(tmpString.data(), "Unsupported attribute type = %d", my_exts_p->get_type());
316  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, tmpString.data());
317  }
318  }
319 }
320 // ----------------------------------------------------------------------------
321 template <typename DB> void generatorCb(const scv_tr_generator_base& g, scv_tr_generator_base::callback_reason reason, void* data) {
322  if(reason == scv_tr_generator_base::CREATE) {
323  try {
324  std::vector<AttrDesc> attrs;
325  const scv_extensions_if* my_begin_exts_p = g.get_begin_exts_p();
326  if(my_begin_exts_p != nullptr) {
327  attrs.emplace_back(BEGIN, my_begin_exts_p->get_type(), g.get_begin_attribute_name() ? g.get_begin_attribute_name() : "");
328  }
329  const scv_extensions_if* my_end_exts_p = g.get_end_exts_p();
330  if(my_end_exts_p != nullptr) {
331  attrs.emplace_back(END, my_end_exts_p->get_type(), g.get_end_attribute_name() ? g.get_end_attribute_name() : "");
332  }
333  DB::get().writeGenerator(g.get_id(), g.get_name(), g.get_scv_tr_stream().get_id(), attrs);
334  } catch(std::runtime_error& e) {
335  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create generator entry");
336  }
337  }
338 }
339 // ----------------------------------------------------------------------------
340 template <typename DB> void transactionCb(const scv_tr_handle& t, scv_tr_handle::callback_reason reason, void* data) {
341  if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
342  return;
343  if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
344  return;
345 
346  uint64_t id = t.get_id();
347  vector<uint64_t>::size_type concurrencyIdx;
348  const scv_extensions_if* my_exts_p;
349  switch(reason) {
350  case scv_tr_handle::BEGIN: {
351  DB::get().writeTransaction(t.get_id(), t.get_scv_tr_generator_base().get_id(), BEGIN, t.get_begin_sc_time().value());
352  my_exts_p = t.get_begin_exts_p();
353  if(my_exts_p == nullptr)
354  my_exts_p = t.get_scv_tr_generator_base().get_begin_exts_p();
355  if(my_exts_p) {
356  auto tmp_str =
357  t.get_scv_tr_generator_base().get_begin_attribute_name() ? t.get_scv_tr_generator_base().get_begin_attribute_name() : "";
358  recordAttributes<DB>(id, BEGIN, tmp_str, my_exts_p);
359  }
360  } break;
361  case scv_tr_handle::END: {
362  DB::get().writeTransaction(t.get_id(), t.get_scv_tr_generator_base().get_id(), END, t.get_begin_sc_time().value());
363  my_exts_p = t.get_end_exts_p();
364  if(my_exts_p == nullptr)
365  my_exts_p = t.get_scv_tr_generator_base().get_end_exts_p();
366  if(my_exts_p) {
367  auto tmp_str =
368  t.get_scv_tr_generator_base().get_end_attribute_name() ? t.get_scv_tr_generator_base().get_end_attribute_name() : "";
369  recordAttributes<DB>(t.get_id(), END, tmp_str, my_exts_p);
370  }
371  } break;
372  default:;
373  }
374 }
375 // ----------------------------------------------------------------------------
376 template <typename DB> void attributeCb(const scv_tr_handle& t, const char* name, const scv_extensions_if* ext, void* data) {
377  if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
378  return;
379  if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
380  return;
381  recordAttributes<DB>(t.get_id(), RECORD, name == nullptr ? "" : name, ext);
382 }
383 // ----------------------------------------------------------------------------
384 template <typename DB>
385 void relationCb(const scv_tr_handle& tr_1, const scv_tr_handle& tr_2, void* data, scv_tr_relation_handle_t relation_handle) {
386  if(tr_1.get_scv_tr_stream().get_scv_tr_db() == nullptr)
387  return;
388  if(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
389  return;
390  try {
391  DB::get().writeRelation(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_relation_name(relation_handle), tr_1.get_id(), tr_2.get_id());
392  } catch(std::runtime_error& e) {
393  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create transaction relation");
394  }
395 }
396 } // namespace
397 // ----------------------------------------------------------------------------
399  scv_tr_db::register_class_cb(dbCb<Formatter<LZ4Writer>>);
400  scv_tr_stream::register_class_cb(streamCb<Formatter<LZ4Writer>>);
401  scv_tr_generator_base::register_class_cb(generatorCb<Formatter<LZ4Writer>>);
402  scv_tr_handle::register_class_cb(transactionCb<Formatter<LZ4Writer>>);
403  scv_tr_handle::register_record_attribute_cb(attributeCb<Formatter<LZ4Writer>>);
404  scv_tr_handle::register_relation_cb(relationCb<Formatter<LZ4Writer>>);
405 }
407  scv_tr_db::register_class_cb(dbCb<Formatter<PlainWriter>>);
408  scv_tr_stream::register_class_cb(streamCb<Formatter<PlainWriter>>);
409  scv_tr_generator_base::register_class_cb(generatorCb<Formatter<PlainWriter>>);
410  scv_tr_handle::register_class_cb(transactionCb<Formatter<PlainWriter>>);
411  scv_tr_handle::register_record_attribute_cb(attributeCb<Formatter<PlainWriter>>);
412  scv_tr_handle::register_relation_cb(relationCb<Formatter<PlainWriter>>);
413 }
414 // ----------------------------------------------------------------------------
415 #ifndef HAS_SCV
416 }
417 #endif
SystemC Verification Library (SCV) Transaction Recording.
void scv_tr_plain_init()
initializes the infrastructure to use a plain text based transaction recording database
Definition: scv_tr_lz4.cpp:406
void scv_tr_lz4_init()
initializes the infrastructure to use a LZ4 compressed text based transaction recording database
Definition: scv_tr_lz4.cpp:398
SCC common utilities.
Definition: bit_field.h:30