17 #include <boost/filesystem.hpp>
27 #include <unordered_map>
28 #include <unordered_set>
30 #ifdef FMT_SPDLOG_INTERNAL
33 #include <fmt/format.h>
35 #include <util/lz4_streambuf.h>
49 enum EventType { BEGIN, RECORD, END };
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)
59 using data_type = scv_extensions_if::data_type;
62 const std::array<char const*, scv_extensions_if::STRING + 1> data_type_str = {{
67 "FLOATING_POINT_NUMBER",
70 "FIXED_POINT_INTEGER",
71 "UNSIGNED_FIXED_POINT_INTEGER",
81 PlainWriter(
const std::string& name)
87 bool is_open() {
return out.is_open(); }
91 std::unique_ptr<util::lz4c_steambuf> strbuf;
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()) {}
106 bool is_open() {
return ofs.is_open(); }
109 template <
typename WRITER>
struct Formatter {
110 std::unique_ptr<WRITER> writer;
111 Formatter(
const std::string& name)
112 : writer(new WRITER(name)) {}
116 inline bool open(
const std::string& name) {
117 writer.reset(
new WRITER(name));
118 return writer->is_open();
121 inline void close() {
delete writer.release(); }
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());
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());
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());
142 writer->out.write(
")\n", 2);
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());
151 inline void writeAttribute(uint64_t
id, EventType event,
const string& name, data_type type,
const string& value) {
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());
159 inline void writeAttribute(uint64_t
id, EventType event,
const string& name, data_type type, int64_t value) {
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());
166 inline void writeAttribute(uint64_t
id, EventType event,
const string& name, data_type type, uint64_t value) {
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());
173 inline void writeAttribute(uint64_t
id, EventType event,
const string& name, data_type type,
bool value) {
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());
181 inline void writeAttribute(uint64_t
id, EventType event,
const string& name, data_type type,
double value) {
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());
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());
192 static Formatter& get() {
197 template <
typename DB>
void dbCb(
const scv_tr_db& _scv_tr_db, scv_tr_db::callback_reason reason,
void* data) {
199 static string fName(
"DEFAULT_scv_tr_sqlite");
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();
205 DB::get().open(fName);
207 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL,
"Can't open recording file");
210 case scv_tr_db::DELETE:
214 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL,
"Can't close recording file");
218 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL,
"Unknown reason in scv_tr_db callback");
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) {
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");
232 template <
typename DB>
inline void recordAttribute(uint64_t
id, EventType event,
const string& name, data_type type,
const string& value) {
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");
240 inline std::string get_name(
const char* prefix,
const scv_extensions_if* my_exts_p) {
242 if(!prefix || strlen(prefix) == 0) {
243 name = my_exts_p->get_name();
245 if((my_exts_p->get_name() ==
nullptr) || (strlen(my_exts_p->get_name()) == 0)) {
248 name = fmt::format(
"{}.{}", prefix, my_exts_p->get_name());
251 return (name ==
"") ?
"<unnamed>" : name;
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)
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();
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);
270 case scv_extensions_if::POINTER:
271 if(
auto ptr = my_exts_p->get_pointer()) {
272 std::stringstream ss;
274 recordAttributes<DB>(
id, eventType, ss.str().c_str(), ptr);
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())));
281 case scv_extensions_if::BOOLEAN:
282 DB::get().writeAttribute(
id, eventType, name, scv_extensions_if::BOOLEAN, my_exts_p->get_bool());
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());
288 case scv_extensions_if::UNSIGNED:
289 DB::get().writeAttribute(
id, eventType, name, scv_extensions_if::UNSIGNED, (uint64_t)my_exts_p->get_unsigned());
291 case scv_extensions_if::STRING:
292 DB::get().writeAttribute(
id, eventType, name, scv_extensions_if::STRING, my_exts_p->get_string());
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());
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());
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());
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);
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());
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) {
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() :
"");
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() :
"");
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");
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)
343 if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() ==
false)
346 uint64_t
id = t.get_id();
347 vector<uint64_t>::size_type concurrencyIdx;
348 const scv_extensions_if* my_exts_p;
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();
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);
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();
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);
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)
379 if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() ==
false)
381 recordAttributes<DB>(t.get_id(), RECORD, name ==
nullptr ?
"" : name, ext);
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)
388 if(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_recording() ==
false)
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");
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>>);
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>>);
SystemC Verification Library (SCV) Transaction Recording.
void scv_tr_plain_init()
initializes the infrastructure to use a plain text based transaction recording database
void scv_tr_lz4_init()
initializes the infrastructure to use a LZ4 compressed text based transaction recording database