From fe8b52cc83c34a9cafc80f0f5643c16956ea1afc Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 20 Nov 2024 07:31:16 +0100 Subject: [PATCH 01/17] factor out report backend implementation into separate header report.h contains only the macros for simplified use of the SC report infrastructure. logger.h now contains the declaration of a custom lSC logging backend. report.cpp still needs to be refactored. --- examples/CMakeLists.txt | 1 + examples/smoke_logger.cc | 214 +++++++++++++++++++++++++++++++++++ examples/smoke_report.cc | 63 +---------- report/include/scp/helpers.h | 9 +- report/include/scp/logger.h | 142 +++++++++++++++++++++++ report/include/scp/report.h | 119 +------------------ report/src/report.cpp | 11 +- 7 files changed, 370 insertions(+), 189 deletions(-) create mode 100644 examples/smoke_logger.cc create mode 100644 report/include/scp/logger.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 09e9286..c92e57b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -10,3 +10,4 @@ endmacro() run_test(smoke) run_test(smoke_report) +run_test(smoke_logger) diff --git a/examples/smoke_logger.cc b/examples/smoke_logger.cc new file mode 100644 index 0000000..898e9cf --- /dev/null +++ b/examples/smoke_logger.cc @@ -0,0 +1,214 @@ +/***************************************************************************** + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +SC_MODULE (test4) { + SC_CTOR (test4) { + SCP_INFO(()) << " . T4 Logger() 1"; + SCP_WARN(()) << " . T4 Logger() 1"; + SCP_INFO(()) << " . T4 Logger() 2"; + SCP_WARN(()) << " . T4 Logger() 2"; + } + SCP_LOGGER(); +}; + +SC_MODULE (test3) { + SC_CTOR (test3) { + SCP_INFO((D)) << " . T3 D Logger \"other\" \"feature.one\""; + SCP_WARN((D)) << " . T3 D Logger \"other\" \"feature.one\""; + SCP_INFO(()) << " . T3 Logger ()"; + SCP_WARN(()) << " . T3 Logger ()"; + } + SCP_LOGGER((D), "other", "feature.one"); + SCP_LOGGER(()); +}; + +SC_MODULE (test2) { + SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") { + SCP_INFO(()) << " T2 Logger()"; + SCP_WARN(()) << " T2 Logger()"; + } + SCP_LOGGER(); + test3 t31, t32; + test4 t4; +}; + +SC_MODULE (test1) { + SC_CTOR (test1) : t2("t2") { + SCP_WARN((), "My.Name") << " T1 My.Name typed log"; + SCP_INFO(()) << " T1 Logger()"; + SCP_WARN(()) << " T1 Logger()"; + + SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing1"); + SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing2"); + + SCP_INFO((vec[0])) << "Thing1?"; + SCP_WARN((vec[0])) << "Thing1?"; + SCP_INFO((vec[1])) << "Thing2?"; + SCP_WARN((vec[1])) << "Thing2?"; + } + SCP_LOGGER("something", "else"); + SCP_LOGGER_VECTOR(vec); + test2 t2; +}; + +class outside_class +{ + SCP_LOGGER("out.class", "thing1"); + +public: + outside_class() { + SCP_INFO(())("constructor"); + SCP_WARN(())("constructor"); + } +}; + +SC_MODULE (test) { + outside_class oc; + SC_CTOR (test) { + SCP_DEBUG(SCMOD) << "First part"; + scp::tlm_extensions::path_trace ext; + ext.stamp(this); + SCP_INFO(SCMOD) << ext.to_string(); + ext.reset(); + + ext.stamp(this); + ext.stamp(this); + ext.stamp(this); + + SCP_INFO(SCMOD) << ext.to_string(); + ext.reset(); + + SCP_DEBUG(SCMOD) << "Second part"; + scp::tlm_extensions::initiator_id mid(0x1234); + mid = 0x2345; + mid &= 0xff; + mid <<= 4; + uint64_t myint = mid + mid; + myint += mid; + if (mid == 0x450) { + SC_REPORT_INFO("ext test", "Success"); + } else { + SC_REPORT_INFO("ext test", "Failour"); + } + + SCP_INFO() << "Uncached version empty"; + SCP_INFO(())("FMT String : Cached version default"); + SCP_INFO(SCMOD) << "UnCached version feature using SCMOD macro"; + SCP_INFO((m_my_logger)) << "Cached version using (m_my_logger)"; + SCP_INFO((D)) << "Cached version with D"; + } + + SCP_LOGGER((m_my_logger)); + SCP_LOGGER(()); + SCP_LOGGER((1), "other"); + SCP_LOGGER((D), "other", "feature.one"); +}; + +int sc_main(int argc, char** argv) { + cci_utils::consuming_broker broker("global_broker"); + cci_register_broker(broker); + cci::cci_originator orig("config"); + broker.set_preset_cci_value("log_level", cci::cci_value(1), orig); + broker.set_preset_cci_value("top.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("feature.log_level", cci::cci_value(5), orig); + + broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); + broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); + + std::string logfile = "/tmp/scp_smoke_report_test." + + std::to_string(getpid()); + scp::init_logging( + scp::LogConfig() + .logLevel(scp::log::DEBUG) // set log level to debug + .msgTypeFieldWidth(20) + .fileInfoFrom(5) + .logAsync(false) + .printSimTime(false) + .logFileName(logfile)); // make the msg type column a bit tighter + SCP_INFO() << "Constructing design"; + test toptest("top"); + test1 t1("t1"); + + SCP_INFO() << "Starting simulation"; + sc_core::sc_start(); + SCP_WARN() << "Ending simulation"; + +#ifdef FMT_SHARED + std::string fmtstr = "FMT String : Cached version default"; +#else + std::string fmtstr = "Please add FMT library for FMT support."; +#endif + + std::string expected = + R"([ info] [ 0 s ]SystemC : Constructing design +[ info] [ 0 s ]out.class : constructor +[ warning] [ 0 s ]out.class : constructor +[ debug] [ 0 s ]top : First part +[ info] [ 0 s ]top : top +[ info] [ 0 s ]top : top->top->top +[ debug] [ 0 s ]top : Second part +[ info] [ 0 s ]ext test : Success +[ info] [ 0 s ]SystemC : Uncached version empty +[ info] [ 0 s ]top : )" + + fmtstr + R"( +[ info] [ 0 s ]top : UnCached version feature using SCMOD macro +[ info] [ 0 s ]top : Cached version using (m_my_logger) +[ info] [ 0 s ]top : Cached version with D +[ info] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" +[ warning] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" +[ info] [ 0 s ]t1.t2.t3_1 : . T3 Logger () +[ warning] [ 0 s ]t1.t2.t3_1 : . T3 Logger () +[ info] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" +[ warning] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" +[ warning] [ 0 s ]t1.t2.t3_2 : . T3 Logger () +[ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 +[ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 +[ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 +[ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 +[ warning] [ 0 s ]t1.t2 : T2 Logger() +[ warning] [ 0 s ]My.Name : T1 My.Name typed log +[ warning] [ 0 s ]t1 : T1 Logger() +[ info] [ 0 s ]t1 : Thing1? +[ warning] [ 0 s ]t1 : Thing1? +[ warning] [ 0 s ]t1 : Thing2? +[ info] [ 0 s ]SystemC : Starting simulation +[ warning] [ 0 s ]SystemC : Ending simulation +)"; + + std::ifstream lf(logfile); + std::string out((std::istreambuf_iterator(lf)), + std::istreambuf_iterator()); + + std::cout << "out file\n" << out << "\n"; + std::cout << "expected\n" << expected << "\n"; + std::cout << "Number of difference: " << out.compare(expected) << "\n"; + + std::remove(logfile.c_str()); + return out.compare(expected); +} diff --git a/examples/smoke_report.cc b/examples/smoke_report.cc index 3a86de7..e42aeb6 100644 --- a/examples/smoke_report.cc +++ b/examples/smoke_report.cc @@ -23,8 +23,6 @@ #include #include -#include -#include #include SC_MODULE (test4) { @@ -144,14 +142,6 @@ int sc_main(int argc, char** argv) { std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); - scp::init_logging( - scp::LogConfig() - .logLevel(scp::log::DEBUG) // set log level to debug - .msgTypeFieldWidth(20) - .fileInfoFrom(5) - .logAsync(false) - .printSimTime(false) - .logFileName(logfile)); // make the msg type column a bit tighter SCP_INFO() << "Constructing design"; test toptest("top"); test1 t1("t1"); @@ -160,56 +150,5 @@ int sc_main(int argc, char** argv) { sc_core::sc_start(); SCP_WARN() << "Ending simulation"; -#ifdef FMT_SHARED - std::string fmtstr = "FMT String : Cached version default"; -#else - std::string fmtstr = "Please add FMT library for FMT support."; -#endif - - std::string expected = - R"([ info] [ 0 s ]SystemC : Constructing design -[ info] [ 0 s ]out.class : constructor -[ warning] [ 0 s ]out.class : constructor -[ debug] [ 0 s ]top : First part -[ info] [ 0 s ]top : top -[ info] [ 0 s ]top : top->top->top -[ debug] [ 0 s ]top : Second part -[ info] [ 0 s ]ext test : Success -[ info] [ 0 s ]SystemC : Uncached version empty -[ info] [ 0 s ]top : )" + - fmtstr + R"( -[ info] [ 0 s ]top : UnCached version feature using SCMOD macro -[ info] [ 0 s ]top : Cached version using (m_my_logger) -[ info] [ 0 s ]top : Cached version with D -[ info] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" -[ warning] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" -[ info] [ 0 s ]t1.t2.t3_1 : . T3 Logger () -[ warning] [ 0 s ]t1.t2.t3_1 : . T3 Logger () -[ info] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" -[ warning] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" -[ warning] [ 0 s ]t1.t2.t3_2 : . T3 Logger () -[ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 -[ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 -[ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 -[ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 -[ warning] [ 0 s ]t1.t2 : T2 Logger() -[ warning] [ 0 s ]My.Name : T1 My.Name typed log -[ warning] [ 0 s ]t1 : T1 Logger() -[ info] [ 0 s ]t1 : Thing1? -[ warning] [ 0 s ]t1 : Thing1? -[ warning] [ 0 s ]t1 : Thing2? -[ info] [ 0 s ]SystemC : Starting simulation -[ warning] [ 0 s ]SystemC : Ending simulation -)"; - - std::ifstream lf(logfile); - std::string out((std::istreambuf_iterator(lf)), - std::istreambuf_iterator()); - - std::cout << "out file\n" << out << "\n"; - std::cout << "expected\n" << expected << "\n"; - std::cout << "Number of difference: " << out.compare(expected) << "\n"; - - std::remove(logfile.c_str()); - return out.compare(expected); + return 0; } diff --git a/report/include/scp/helpers.h b/report/include/scp/helpers.h index 9303965..2332ee5 100644 --- a/report/include/scp/helpers.h +++ b/report/include/scp/helpers.h @@ -16,11 +16,11 @@ permissions and limitations under the License. *****************************************************************************/ - -#include -#include #ifndef _SCP_HELPERS_H_ #define _SCP_HELPERS_H_ + +#include + namespace scp { static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) { std::stringstream info; @@ -36,8 +36,7 @@ static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) { cmd = "READ"; break; } - info << cmd << " to address: " - << "0x" << std::hex << trans.get_address(); + info << cmd << " to address: " << "0x" << std::hex << trans.get_address(); info << " len: " << trans.get_data_length(); unsigned char* ptr = trans.get_data_ptr(); info << " data: 0x"; diff --git a/report/include/scp/logger.h b/report/include/scp/logger.h new file mode 100644 index 0000000..bfcb4ac --- /dev/null +++ b/report/include/scp/logger.h @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright 2016-2022 MINRES Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + +#ifndef _SCP_LOGGER_H_ +#define _SCP_LOGGER_H_ + +#include "report.h" + +/** \ingroup scp-report + * @{ + */ +/**@{*/ +//! @brief reporting backend utilities +namespace scp { +/** + * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) + * @brief initializes the SystemC logging system with a particular logging + * level + * + * @param level the log level + * @param type_field_width the with of the type field in the output + * @param print_time whether to print the system time stamp + */ +void init_logging(log level = log::WARNING, unsigned type_field_width = 24, + bool print_time = false); +/** + * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) + * @brief initializes the SystemC logging system with a particular logging + * level + * + * @param level the log level + * @param type_field_width the with of the type field in the output + * @param print_time whether to print the system time stamp + */ +void reinit_logging(log level = log::WARNING); +/** + * @struct LogConfig + * @brief the configuration class for the logging setup + * + * using this class allows to configure the logging output in many aspects. The + * class follows the builder pattern. + */ +struct LogConfig { + log level{ log::WARNING }; + unsigned msg_type_field_width{ 24 }; + bool print_sys_time{ false }; + bool print_sim_time{ true }; + bool print_delta{ false }; + bool print_severity{ true }; + bool colored_output{ true }; + std::string log_file_name{ "" }; + std::string log_filter_regex{ "" }; + bool log_async{ true }; + bool report_only_first_error{ false }; + int file_info_from{ sc_core::SC_INFO }; + + //! set the logging level + LogConfig& logLevel(log); + //! define the width of the message field, 0 to disable, + //! std::numeric_limits::max() for arbitrary width + LogConfig& msgTypeFieldWidth(unsigned); + //! enable/disable printing of system time + LogConfig& printSysTime(bool = true); + //! enable/disable printing of simulation time on console + LogConfig& printSimTime(bool = true); + //! enable/disable printing delta cycles + LogConfig& printDelta(bool = true); + //! enable/disable printing of severity level + LogConfig& printSeverity(bool = true); + //! enable/disable colored output + LogConfig& coloredOutput(bool = true); + //! set the file name for the log output file + LogConfig& logFileName(std::string&&); + //! set the file name for the log output file + LogConfig& logFileName(const std::string&); + //! set the regular expression to filter the output + LogConfig& logFilterRegex(std::string&&); + //! set the regular expression to filter the output + LogConfig& logFilterRegex(const std::string&); + //! enable/disable asynchronous output (write to file in separate thread + LogConfig& logAsync(bool = true); + //! disable the printing of the file name from this level upwards. + LogConfig& fileInfoFrom(int); + //! disable/enable the supression of all error messages after the first + LogConfig& reportOnlyFirstError(bool = true); +}; + +/** + * @fn void init_logging(const LogConfig&) + * @brief initializes the SystemC logging system with a particular + * configuration + * + * @param log_config the logging configuration + */ +void init_logging(const LogConfig& log_config); +/** + * @fn void set_logging_level(log) + * @brief sets the SystemC logging level + * + * @param level the logging level + */ +void set_logging_level(log level); +/** + * @fn log get_logging_level() + * @brief get the SystemC logging level + * + * @return the logging level + */ +log get_logging_level(); +/** + * @fn void set_cycle_base(sc_core::sc_time) + * @brief sets the cycle base for cycle based logging + * + * if this is set to a non-SC_ZERO_TIME value all logging timestamps are + * printed as cyles (multiple of this value) + * + * @param period the cycle period + */ +void set_cycle_base(sc_core::sc_time period); +/** + * @fn sc_core::sc_verbosity get_log_verbosity() + * @brief get the global verbosity level + * + * @return the global verbosity level + */ + +} // namespace scp +/** @} */ // end of scp logger +#endif /* _SCP_LOGGER_H_ */ diff --git a/report/include/scp/report.h b/report/include/scp/report.h index 4ba6f9a..99c85f6 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -18,18 +18,13 @@ #define _SCP_REPORT_H_ #include -#include #include #include #include -#include #include -#include -#include #ifdef __GNUG__ #include -#include #include #endif @@ -126,78 +121,6 @@ inline std::ostream& operator<<(std::ostream& os, log const& val) { os << buffer[static_cast(val)]; return os; } -/** - * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) - * @brief initializes the SystemC logging system with a particular logging - * level - * - * @param level the log level - * @param type_field_width the with of the type field in the output - * @param print_time whether to print the system time stamp - */ -void init_logging(log level = log::WARNING, unsigned type_field_width = 24, - bool print_time = false); -/** - * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) - * @brief initializes the SystemC logging system with a particular logging - * level - * - * @param level the log level - * @param type_field_width the with of the type field in the output - * @param print_time whether to print the system time stamp - */ -void reinit_logging(log level = log::WARNING); -/** - * @struct LogConfig - * @brief the configuration class for the logging setup - * - * using this class allows to configure the logging output in many aspects. The - * class follows the builder pattern. - */ -struct LogConfig { - log level{ log::WARNING }; - unsigned msg_type_field_width{ 24 }; - bool print_sys_time{ false }; - bool print_sim_time{ true }; - bool print_delta{ false }; - bool print_severity{ true }; - bool colored_output{ true }; - std::string log_file_name{ "" }; - std::string log_filter_regex{ "" }; - bool log_async{ true }; - bool report_only_first_error{ false }; - int file_info_from{ sc_core::SC_INFO }; - - //! set the logging level - LogConfig& logLevel(log); - //! define the width of the message field, 0 to disable, - //! std::numeric_limits::max() for arbitrary width - LogConfig& msgTypeFieldWidth(unsigned); - //! enable/disable printing of system time - LogConfig& printSysTime(bool = true); - //! enable/disable printing of simulation time - LogConfig& printSimTime(bool = true); - //! enable/disable printing delta cycles - LogConfig& printDelta(bool = true); - //! enable/disable printing of severity level - LogConfig& printSeverity(bool = true); - //! enable/disable colored output - LogConfig& coloredOutput(bool = true); - //! set the file name for the log output file - LogConfig& logFileName(std::string&&); - //! set the file name for the log output file - LogConfig& logFileName(const std::string&); - //! set the regular expression to filter the output - LogConfig& logFilterRegex(std::string&&); - //! set the regular expression to filter the output - LogConfig& logFilterRegex(const std::string&); - //! enable/disable asynchronous output (write to file in separate thread - LogConfig& logAsync(bool = true); - //! disable the printing of the file name from this level upwards. - LogConfig& fileInfoFrom(int); - //! disable/enable the supression of all error messages after the first - LogConfig& reportOnlyFirstError(bool = true); -}; /** * @brief cached logging information used in the (logger) form. @@ -216,44 +139,6 @@ struct scp_logger_cache { sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); }; -/** - * @fn void init_logging(const LogConfig&) - * @brief initializes the SystemC logging system with a particular - * configuration - * - * @param log_config the logging configuration - */ -void init_logging(const LogConfig& log_config); -/** - * @fn void set_logging_level(log) - * @brief sets the SystemC logging level - * - * @param level the logging level - */ -void set_logging_level(log level); -/** - * @fn log get_logging_level() - * @brief get the SystemC logging level - * - * @return the logging level - */ -log get_logging_level(); -/** - * @fn void set_cycle_base(sc_core::sc_time) - * @brief sets the cycle base for cycle based logging - * - * if this is set to a non-SC_ZERO_TIME value all logging timestamps are - * printed as cyles (multiple of this value) - * - * @param period the cycle period - */ -void set_cycle_base(sc_core::sc_time period); -/** - * @fn sc_core::sc_verbosity get_log_verbosity() - * @brief get the global verbosity level - * - * @return the global verbosity level - */ inline sc_core::sc_verbosity get_log_verbosity() { return static_cast( ::sc_core::sc_report_handler::get_verbosity_level()); @@ -431,8 +316,8 @@ struct ScLogger { class call_sc_name_fn { template - static auto test(T* p) - -> decltype(p->sc_core::sc_module::name(), std::true_type()); + static auto test(T* p) -> decltype(p->sc_core::sc_module::name(), + std::true_type()); template static auto test(...) -> decltype(std::false_type()); diff --git a/report/src/report.cpp b/report/src/report.cpp index f5a87a7..0d0f615 100644 --- a/report/src/report.cpp +++ b/report/src/report.cpp @@ -20,11 +20,13 @@ * Author: eyck@minres.com */ -#include +#include #include #include #include +#include #include +#include #ifdef HAS_CCI #include #endif @@ -157,8 +159,8 @@ auto time2string(const sc_core::sc_time& t) -> std::string { } return oss.str(); } -auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) - -> const std::string { +auto compose_message(const sc_core::sc_report& rep, + const scp::LogConfig& cfg) -> const std::string { if (rep.get_severity() > sc_core::SC_INFO || cfg.log_filter_regex.length() == 0 || rep.get_verbosity() == sc_core::SC_MEDIUM || @@ -188,8 +190,7 @@ auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) } } if (unlikely(rep.get_id() >= 0)) - os << "(" - << "IWEF"[rep.get_severity()] << rep.get_id() << ") " + os << "(" << "IWEF"[rep.get_severity()] << rep.get_id() << ") " << rep.get_msg_type() << ": "; else if (cfg.msg_type_field_width) { if (cfg.msg_type_field_width == From 07cb8d698960af8b136630bff7458955b7a3354f Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 20 Nov 2024 07:54:38 +0100 Subject: [PATCH 02/17] changes messages in smoke_logger --- examples/smoke.cc | 4 ++-- examples/smoke_logger.cc | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/smoke.cc b/examples/smoke.cc index 1159b0b..9d6aa5c 100644 --- a/examples/smoke.cc +++ b/examples/smoke.cc @@ -41,9 +41,9 @@ SC_MODULE (test) { uint64_t myint = mid + mid; myint += mid; if (mid == 0x450) { - SC_REPORT_INFO("ext test", "Success"); + SCP_INFO("ext test") << "Success"; } else { - SC_REPORT_INFO("ext test", "Failour"); + SCP_INFO("ext test") << "Failure"; } } }; diff --git a/examples/smoke_logger.cc b/examples/smoke_logger.cc index 898e9cf..7922457 100644 --- a/examples/smoke_logger.cc +++ b/examples/smoke_logger.cc @@ -116,11 +116,12 @@ SC_MODULE (test) { SC_REPORT_INFO("ext test", "Failour"); } - SCP_INFO() << "Uncached version empty"; - SCP_INFO(())("FMT String : Cached version default"); - SCP_INFO(SCMOD) << "UnCached version feature using SCMOD macro"; - SCP_INFO((m_my_logger)) << "Cached version using (m_my_logger)"; - SCP_INFO((D)) << "Cached version with D"; + SCP_INFO() << "Globally cached version empty"; + SCP_INFO(())("FMT String : Locally cached version default"); + SCP_INFO(SCMOD) << "Globally cached version feature using SCMOD macro"; + SCP_INFO((m_my_logger)) + << "Locally cached version using (m_my_logger)"; + SCP_INFO((D)) << "Locally cached version with D"; } SCP_LOGGER((m_my_logger)); @@ -160,7 +161,7 @@ int sc_main(int argc, char** argv) { SCP_WARN() << "Ending simulation"; #ifdef FMT_SHARED - std::string fmtstr = "FMT String : Cached version default"; + std::string fmtstr = "FMT String : Locally cached version default"; #else std::string fmtstr = "Please add FMT library for FMT support."; #endif @@ -174,12 +175,12 @@ int sc_main(int argc, char** argv) { [ info] [ 0 s ]top : top->top->top [ debug] [ 0 s ]top : Second part [ info] [ 0 s ]ext test : Success -[ info] [ 0 s ]SystemC : Uncached version empty +[ info] [ 0 s ]SystemC : Globally cached version empty [ info] [ 0 s ]top : )" + fmtstr + R"( -[ info] [ 0 s ]top : UnCached version feature using SCMOD macro -[ info] [ 0 s ]top : Cached version using (m_my_logger) -[ info] [ 0 s ]top : Cached version with D +[ info] [ 0 s ]top : Globally cached version feature using SCMOD macro +[ info] [ 0 s ]top : Locally cached version using (m_my_logger) +[ info] [ 0 s ]top : Locally cached version with D [ info] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" [ warning] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" [ info] [ 0 s ]t1.t2.t3_1 : . T3 Logger () From c0cda7358201da2c852fbfa8b5a8cc2705158366 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 27 Nov 2024 11:52:48 +0100 Subject: [PATCH 03/17] factors logger function into separate source --- report/CMakeLists.txt | 70 +++--- report/src/logger.cpp | 531 ++++++++++++++++++++++++++++++++++++++++++ report/src/report.cpp | 442 ----------------------------------- 3 files changed, 566 insertions(+), 477 deletions(-) create mode 100644 report/src/logger.cpp diff --git a/report/CMakeLists.txt b/report/CMakeLists.txt index c4b89d2..abd7a7e 100644 --- a/report/CMakeLists.txt +++ b/report/CMakeLists.txt @@ -22,34 +22,35 @@ cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") cpmaddpackage( NAME SystemCLanguage - GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git + GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git GIT_SHALLOW True GIT_TAG main ) cpmaddpackage( NAME SystemCCCI - GIT_REPOSITORY ${GITHUB}accellera-official/cci.git + GIT_REPOSITORY ${GITHUB}accellera-official/cci.git GIT_SHALLOW True GIT_TAG main ) set(WITH_FMT "true" CACHE STRING "Include FMT library") -if (WITH_FMT) -cpmaddpackage( - NAME fmt - GIT_REPOSITORY ${GITHUB}fmtlib/fmt.git - GIT_SHALLOW True - GIT_TAG 9.1.0 - OPTIONS FMT_INSTALL "" ON -) + +if(WITH_FMT) + cpmaddpackage( + NAME fmt + GIT_REPOSITORY ${GITHUB}fmtlib/fmt.git + GIT_SHALLOW True + GIT_TAG 9.1.0 + OPTIONS FMT_INSTALL "" ON + ) endif() FetchContent_Declare( - spdlog_git - GIT_REPOSITORY "https://github.com/gabime/spdlog.git" - GIT_TAG "v1.9.2" - GIT_SHALLOW ON + spdlog_git + GIT_REPOSITORY "https://github.com/gabime/spdlog.git" + GIT_TAG "v1.9.2" + GIT_SHALLOW ON ) FetchContent_Populate(spdlog_git) FetchContent_GetProperties( @@ -58,8 +59,7 @@ FetchContent_GetProperties( POPULATED spdlog_git_FOUND ) -add_library(${PROJECT_NAME} src/report.cpp) - +add_library(${PROJECT_NAME} src/report.cpp src/logger.cpp) target_include_directories( ${PROJECT_NAME} PUBLIC $ @@ -71,34 +71,34 @@ if(TARGET fmt) endif() target_include_directories(${PROJECT_NAME} PRIVATE ${spdlog_git_SRC_DIR}/include) + if(TARGET SystemC::cci) target_compile_definitions(${PROJECT_NAME} PRIVATE HAS_CCI) target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::cci) endif() + target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::systemc) set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) -#No tests yet. WIP. -#if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) -# enable_testing() -# add_subdirectory(tests) -#endif() - +# No tests yet. WIP. +# if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) +# enable_testing() +# add_subdirectory(tests) +# endif() add_library("scp::report::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) packageproject( - NAME "${PROJECT_NAME}" - VERSION ${PROJECT_VERSION} - NAMESPACE scp - BINARY_DIR ${PROJECT_BINARY_DIR} - INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include - INCLUDE_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - VERSION_HEADER "${VERSION_HEADER_LOCATION}" - COMPATIBILITY SameMajorVersion + NAME "${PROJECT_NAME}" + VERSION ${PROJECT_VERSION} + NAMESPACE scp + BINARY_DIR ${PROJECT_BINARY_DIR} + INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include + INCLUDE_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + VERSION_HEADER "${VERSION_HEADER_LOCATION}" + COMPATIBILITY SameMajorVersion ) install( - TARGETS ${PROJECT_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT "${PROJECT_NAME}_Runtime" - NAMELINK_COMPONENT "${PROJECT_NAME}_Development" + TARGETS ${PROJECT_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT "${PROJECT_NAME}_Runtime" + NAMELINK_COMPONENT "${PROJECT_NAME}_Development" ) - diff --git a/report/src/logger.cpp b/report/src/logger.cpp new file mode 100644 index 0000000..12c03d5 --- /dev/null +++ b/report/src/logger.cpp @@ -0,0 +1,531 @@ +/******************************************************************************* + * Copyright 2017-2022 MINRES Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +/* + * report.cpp + * + * Created on: 19.09.2017 + * Author: eyck@minres.com + */ + +#include +#include +#include +#include +#include +#include +#ifdef HAS_CCI +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__GNUC__) || defined(__clang__) +#define likely(x) __builtin_expect(x, 1) +#define unlikely(x) __builtin_expect(x, 0) +#else +#define likely(x) x +#define unlikely(x) x +#endif + +#include +#ifdef ERROR +#undef ERROR +#endif + +namespace { +// Making this thread_local could cause thread copies of the same cache +// entries, but more likely naming will be thread local too, and this avoids +// races in the unordered_map + +#ifdef DISABLE_REPORT_THREAD_LOCAL +std::unordered_map lut; +#else +thread_local std::unordered_map lut; +#endif + +struct ExtLogConfig : public scp::LogConfig { + std::shared_ptr file_logger; + std::shared_ptr console_logger; + std::regex reg_ex; + sc_core::sc_time cycle_base{ 0, sc_core::SC_NS }; + auto operator=(const scp::LogConfig& o) -> ExtLogConfig& { + scp::LogConfig::operator=(o); + return *this; + } + auto match(const char* type) -> bool { return regex_search(type, reg_ex); } +}; + +/* normally put the config in thread local. If two threads try to use logging + * they would both need to init the config from both threads. The alternative + * is to switch on this define, but then care has to be taken not to + * (re)initialize from different threads which would then be unsafe.*/ +#ifdef DISABLE_REPORT_THREAD_LOCAL +ExtLogConfig log_cfg; +#else +thread_local ExtLogConfig log_cfg; +#endif + +inline std::string padded(std::string str, size_t width, + bool show_ellipsis = true) { + if (width < 7) + return str; + if (str.length() > width) { + if (show_ellipsis) { + auto pos = str.size() - (width - 6); + return str.substr(0, 3) + "..." + + str.substr(pos, str.size() - pos); + } else + return str.substr(0, width); + } else { + return str + std::string(width - str.size(), ' '); + } +} + +auto get_tuple(const sc_core::sc_time& t) + -> std::tuple { + auto val = t.value(); + auto tr = (uint64_t)(sc_core::sc_time::from_value(1).to_seconds() * 1E15); + auto scale = 0U; + while ((tr % 10) == 0) { + tr /= 10; + scale++; + } + sc_assert(tr == 1); + + auto tu = scale / 3; + while (tu < sc_core::SC_SEC && (val % 10) == 0) { + val /= 10; + scale++; + tu += (0 == (scale % 3)); + } + for (scale %= 3; scale != 0; scale--) + val *= 10; + return std::make_tuple(val, static_cast(tu)); +} + +auto time2string(const sc_core::sc_time& t) -> std::string { + const std::array time_units{ "fs", "ps", "ns", + "us", "ms", "s " }; + const std::array multiplier{ 1ULL, + 1000ULL, + 1000ULL * 1000, + 1000ULL * 1000 * 1000, + 1000ULL * 1000 * 1000 * 1000, + 1000ULL * 1000 * 1000 * 1000 * + 1000 }; + std::ostringstream oss; + if (!t.value()) { + oss << "0 s "; + } else { + const auto tt = get_tuple(t); + const auto val = std::get<0>(tt); + const auto scale = std::get<1>(tt); + const auto fs_val = val * multiplier[scale]; + for (int j = multiplier.size() - 1; j >= scale; --j) { + if (fs_val >= multiplier[j]) { + const auto i = val / multiplier[j - scale]; + const auto f = val % multiplier[j - scale]; + oss << i << '.' << std::setw(3 * (j - scale)) + << std::setfill('0') << std::right << f << ' ' + << time_units[j]; + break; + } + } + } + return oss.str(); +} +auto compose_message(const sc_core::sc_report& rep, + const scp::LogConfig& cfg) -> const std::string { + if (rep.get_severity() > sc_core::SC_INFO || + cfg.log_filter_regex.length() == 0 || + rep.get_verbosity() == sc_core::SC_MEDIUM || + log_cfg.match(rep.get_msg_type())) { + std::stringstream os; + if (likely(cfg.print_sim_time)) { + if (unlikely(log_cfg.cycle_base.value())) { + if (unlikely(cfg.print_delta)) + os << "[" << std::setw(7) << std::setfill(' ') + << sc_core::sc_time_stamp().value() / + log_cfg.cycle_base.value() + << "(" << std::setw(5) << sc_core::sc_delta_count() + << ")]"; + else + os << "[" << std::setw(7) << std::setfill(' ') + << sc_core::sc_time_stamp().value() / + log_cfg.cycle_base.value() + << "]"; + } else { + auto t = time2string(sc_core::sc_time_stamp()); + if (unlikely(cfg.print_delta)) + os << "[" << std::setw(20) << std::setfill(' ') << t << "(" + << std::setw(5) << sc_core::sc_delta_count() << ")]"; + else + os << "[" << std::setw(20) << std::setfill(' ') << t + << "]"; + } + } + if (unlikely(rep.get_id() >= 0)) + os << "(" << "IWEF"[rep.get_severity()] << rep.get_id() << ") " + << rep.get_msg_type() << ": "; + else if (cfg.msg_type_field_width) { + if (cfg.msg_type_field_width == + std::numeric_limits::max()) + os << rep.get_msg_type() << ": "; + else + os << padded(rep.get_msg_type(), cfg.msg_type_field_width) + << ": "; + } + if (*rep.get_msg()) + os << rep.get_msg(); + if (rep.get_severity() >= cfg.file_info_from) { + if (rep.get_line_number()) + os << "\n [FILE:" << rep.get_file_name() << ":" + << rep.get_line_number() << "]"; + sc_core::sc_simcontext* simc = sc_core::sc_get_curr_simcontext(); + if (simc && sc_core::sc_is_running()) { + const char* proc_name = rep.get_process_name(); + if (proc_name) + os << "\n [PROCESS:" << proc_name << "]"; + } + } + return os.str(); + } else + return ""; +} + +inline auto get_verbosity(const sc_core::sc_report& rep) -> int { + return rep.get_verbosity() > sc_core::SC_NONE && + rep.get_verbosity() < sc_core::SC_LOW + ? rep.get_verbosity() * 10 + : rep.get_verbosity(); +} + +inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, + const scp::LogConfig& cfg) { + auto msg = compose_message(rep, cfg); + if (!msg.size()) + return; + switch (rep.get_severity()) { + case sc_core::SC_INFO: + switch (get_verbosity(rep)) { + case sc_core::SC_DEBUG: + case sc_core::SC_FULL: + logger.trace(msg); + break; + case sc_core::SC_HIGH: + logger.debug(msg); + break; + default: + logger.info(msg); + break; + } + break; + case sc_core::SC_WARNING: + logger.warn(msg); + break; + case sc_core::SC_ERROR: + logger.error(msg); + break; + case sc_core::SC_FATAL: + logger.critical(msg); + break; + default: + break; + } +} + +inline void log2logger(spdlog::logger& logger, scp::log lvl, + const std::string& msg) { + switch (lvl) { + case scp::log::DBGTRACE: + case scp::log::TRACE: + logger.trace(msg); + return; + case scp::log::DEBUG: + logger.debug(msg); + return; + case scp::log::INFO: + logger.info(msg); + return; + case scp::log::WARNING: + logger.warn(msg); + return; + case scp::log::ERROR: + logger.error(msg); + return; + case scp::log::FATAL: + logger.critical(msg); + return; + default: + break; + } +} + +void report_handler(const sc_core::sc_report& rep, + const sc_core::sc_actions& actions) { + thread_local bool sc_stop_called = false; + if (actions & sc_core::SC_DO_NOTHING) + return; + if (rep.get_severity() == sc_core::SC_INFO || + !log_cfg.report_only_first_error || + sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) < 2) { + if ((actions & sc_core::SC_DISPLAY) && + (!log_cfg.file_logger || get_verbosity(rep) < sc_core::SC_HIGH)) + log2logger(*log_cfg.console_logger, rep, log_cfg); + if ((actions & sc_core::SC_LOG) && log_cfg.file_logger) { + scp::LogConfig lcfg(log_cfg); + lcfg.print_sim_time = true; + if (!lcfg.msg_type_field_width) + lcfg.msg_type_field_width = 24; + log2logger(*log_cfg.file_logger, rep, lcfg); + } + } + if (actions & sc_core::SC_STOP) { + std::this_thread::sleep_for(std::chrono::milliseconds( + static_cast(log_cfg.level) * 10)); + if (sc_core::sc_is_running() && !sc_stop_called) { + sc_core::sc_stop(); + sc_stop_called = true; + } + } + if (actions & sc_core::SC_ABORT) { + std::this_thread::sleep_for(std::chrono::milliseconds( + static_cast(log_cfg.level) * 20)); + abort(); + } + if (actions & sc_core::SC_THROW) { + std::this_thread::sleep_for(std::chrono::milliseconds( + static_cast(log_cfg.level) * 20)); + throw rep; + } + if (sc_core::sc_time_stamp().value() && !sc_core::sc_is_running()) { + log_cfg.console_logger->flush(); + if (log_cfg.file_logger) + log_cfg.file_logger->flush(); + } +} + +// // BKDR hash algorithm +// auto char_hash(char const* str) -> uint64_t { +// constexpr unsigned int seed = 131; // 31 131 1313 13131131313 etc// +// uint64_t hash = 0; +// while (*str) { +// hash = (hash * seed) + (*str); +// str++; +// } +// return hash; +// } +} // namespace + +static const std::array severity = { + sc_core::SC_FATAL, // scp::log::NONE + sc_core::SC_FATAL, // scp::log::FATAL + sc_core::SC_ERROR, // scp::log::ERROR + sc_core::SC_WARNING, // scp::log::WARNING + sc_core::SC_INFO, // scp::log::INFO + sc_core::SC_INFO, // scp::log::DEBUG + sc_core::SC_INFO, // scp::log::TRACE + sc_core::SC_INFO // scp::log::TRACEALL +}; +static const std::array verbosity = { + sc_core::SC_NONE, // scp::log::NONE + sc_core::SC_LOW, // scp::log::FATAL + sc_core::SC_LOW, // scp::log::ERROR + sc_core::SC_LOW, // scp::log::WARNING + sc_core::SC_MEDIUM, // scp::log::INFO + sc_core::SC_HIGH, // scp::log::DEBUG + sc_core::SC_FULL, // scp::log::TRACE + sc_core::SC_DEBUG // scp::log::TRACEALL +}; +static std::mutex cfg_guard; +static void configure_logging() { + std::lock_guard lock(cfg_guard); + static bool spdlog_initialized = false; + + sc_core::sc_report_handler::set_actions( + sc_core::SC_ERROR, + sc_core::SC_DEFAULT_ERROR_ACTIONS | sc_core::SC_DISPLAY); + sc_core::sc_report_handler::set_actions(sc_core::SC_FATAL, + sc_core::SC_DEFAULT_FATAL_ACTIONS); + sc_core::sc_report_handler::set_verbosity_level( + verbosity[static_cast(log_cfg.level)]); + sc_core::sc_report_handler::set_handler(report_handler); + if (!spdlog_initialized) { + spdlog::init_thread_pool( + 1024U, + log_cfg.log_file_name.size() + ? 2U + : 1U); // queue with 8k items and 1 backing thread. + log_cfg.console_logger = log_cfg.log_async + ? spdlog::stdout_color_mt< + spdlog::async_factory>( + "console_logger") + : spdlog::stdout_color_mt( + "console_logger"); + auto logger_fmt = log_cfg.print_severity ? "[%L] %v" : "%v"; + if (log_cfg.colored_output) { + std::ostringstream os; + os << "%^" << logger_fmt << "%$"; + log_cfg.console_logger->set_pattern(os.str()); + } else + log_cfg.console_logger->set_pattern("[%L] %v"); + log_cfg.console_logger->flush_on(spdlog::level::warn); + log_cfg.console_logger->set_level(spdlog::level::level_enum::trace); + if (log_cfg.log_file_name.size()) { + { + std::ofstream ofs; + ofs.open(log_cfg.log_file_name, + std::ios::out | std::ios::trunc); + } + log_cfg.file_logger = log_cfg.log_async + ? spdlog::basic_logger_mt< + spdlog::async_factory>( + "file_logger", + log_cfg.log_file_name) + : spdlog::basic_logger_mt( + "file_logger", + log_cfg.log_file_name); + if (log_cfg.print_severity) + log_cfg.file_logger->set_pattern("[%8l] %v"); + else + log_cfg.file_logger->set_pattern("%v"); + log_cfg.file_logger->flush_on(spdlog::level::warn); + log_cfg.file_logger->set_level(spdlog::level::level_enum::trace); + } + spdlog_initialized = true; + } else { + log_cfg.console_logger = spdlog::get("console_logger"); + if (log_cfg.log_file_name.size()) + log_cfg.file_logger = spdlog::get("file_logger"); + } + if (log_cfg.log_filter_regex.size()) { + log_cfg.reg_ex = std::regex(log_cfg.log_filter_regex, + std::regex::extended | std::regex::icase); + } +} + +void scp::reinit_logging(scp::log level) { + sc_core::sc_report_handler::set_handler(report_handler); + log_cfg.level = level; + lut.clear(); +} + +void scp::init_logging(scp::log level, unsigned type_field_width, + bool print_time) { + log_cfg.msg_type_field_width = type_field_width; + log_cfg.print_sys_time = print_time; + log_cfg.level = level; + configure_logging(); +} + +void scp::init_logging(const scp::LogConfig& log_config) { + log_cfg = log_config; + configure_logging(); +} + +void scp::set_logging_level(scp::log level) { + log_cfg.level = level; + sc_core::sc_report_handler::set_verbosity_level( + verbosity[static_cast(level)]); + log_cfg.console_logger->set_level(static_cast( + SPDLOG_LEVEL_OFF - + std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); +} + +auto scp::get_logging_level() -> scp::log { + return log_cfg.level; +} + +void scp::set_cycle_base(sc_core::sc_time period) { + log_cfg.cycle_base = period; +} + +auto scp::LogConfig::logLevel(scp::log level) -> scp::LogConfig& { + this->level = level; + return *this; +} + +auto scp::LogConfig::msgTypeFieldWidth(unsigned width) -> scp::LogConfig& { + this->msg_type_field_width = width; + return *this; +} + +auto scp::LogConfig::printSysTime(bool enable) -> scp::LogConfig& { + this->print_sys_time = enable; + return *this; +} + +auto scp::LogConfig::printSimTime(bool enable) -> scp::LogConfig& { + this->print_sim_time = enable; + return *this; +} + +auto scp::LogConfig::printDelta(bool enable) -> scp::LogConfig& { + this->print_delta = enable; + return *this; +} + +auto scp::LogConfig::printSeverity(bool enable) -> scp::LogConfig& { + this->print_severity = enable; + return *this; +} + +auto scp::LogConfig::logFileName(std::string&& name) -> scp::LogConfig& { + this->log_file_name = name; + return *this; +} + +auto scp::LogConfig::logFileName(const std::string& name) -> scp::LogConfig& { + this->log_file_name = name; + return *this; +} + +auto scp::LogConfig::coloredOutput(bool enable) -> scp::LogConfig& { + this->colored_output = enable; + return *this; +} + +auto scp::LogConfig::logFilterRegex(std::string&& expr) -> scp::LogConfig& { + this->log_filter_regex = expr; + return *this; +} + +auto scp::LogConfig::logFilterRegex(const std::string& expr) + -> scp::LogConfig& { + this->log_filter_regex = expr; + return *this; +} + +auto scp::LogConfig::logAsync(bool v) -> scp::LogConfig& { + this->log_async = v; + return *this; +} + +auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& { + this->report_only_first_error = v; + return *this; +} + +auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { + this->file_info_from = v; + return *this; +} + diff --git a/report/src/report.cpp b/report/src/report.cpp index 0d0f615..081f0fc 100644 --- a/report/src/report.cpp +++ b/report/src/report.cpp @@ -22,21 +22,15 @@ #include #include -#include -#include #include #include -#include #ifdef HAS_CCI #include #endif -#include #include #include #include #include -#include -#include #include #if defined(__GNUC__) || defined(__clang__) #define likely(x) __builtin_expect(x, 1) @@ -46,7 +40,6 @@ #define unlikely(x) x #endif -#include #ifdef ERROR #undef ERROR #endif @@ -68,268 +61,6 @@ cci::cci_originator scp_global_originator("scp_reporting_global"); std::set logging_parameters; -struct ExtLogConfig : public scp::LogConfig { - std::shared_ptr file_logger; - std::shared_ptr console_logger; - std::regex reg_ex; - sc_core::sc_time cycle_base{ 0, sc_core::SC_NS }; - auto operator=(const scp::LogConfig& o) -> ExtLogConfig& { - scp::LogConfig::operator=(o); - return *this; - } - auto match(const char* type) -> bool { return regex_search(type, reg_ex); } -}; - -/* normally put the config in thread local. If two threads try to use logging - * they would both need to init the config from both threads. The alternative - * is to switch on this define, but then care has to be taken not to - * (re)initialize from different threads which would then be unsafe.*/ -#ifdef DISABLE_REPORT_THREAD_LOCAL -ExtLogConfig log_cfg; -#else -thread_local ExtLogConfig log_cfg; -#endif - -inline std::string padded(std::string str, size_t width, - bool show_ellipsis = true) { - if (width < 7) - return str; - if (str.length() > width) { - if (show_ellipsis) { - auto pos = str.size() - (width - 6); - return str.substr(0, 3) + "..." + - str.substr(pos, str.size() - pos); - } else - return str.substr(0, width); - } else { - return str + std::string(width - str.size(), ' '); - } -} - -auto get_tuple(const sc_core::sc_time& t) - -> std::tuple { - auto val = t.value(); - auto tr = (uint64_t)(sc_core::sc_time::from_value(1).to_seconds() * 1E15); - auto scale = 0U; - while ((tr % 10) == 0) { - tr /= 10; - scale++; - } - sc_assert(tr == 1); - - auto tu = scale / 3; - while (tu < sc_core::SC_SEC && (val % 10) == 0) { - val /= 10; - scale++; - tu += (0 == (scale % 3)); - } - for (scale %= 3; scale != 0; scale--) - val *= 10; - return std::make_tuple(val, static_cast(tu)); -} - -auto time2string(const sc_core::sc_time& t) -> std::string { - const std::array time_units{ "fs", "ps", "ns", - "us", "ms", "s " }; - const std::array multiplier{ 1ULL, - 1000ULL, - 1000ULL * 1000, - 1000ULL * 1000 * 1000, - 1000ULL * 1000 * 1000 * 1000, - 1000ULL * 1000 * 1000 * 1000 * - 1000 }; - std::ostringstream oss; - if (!t.value()) { - oss << "0 s "; - } else { - const auto tt = get_tuple(t); - const auto val = std::get<0>(tt); - const auto scale = std::get<1>(tt); - const auto fs_val = val * multiplier[scale]; - for (int j = multiplier.size() - 1; j >= scale; --j) { - if (fs_val >= multiplier[j]) { - const auto i = val / multiplier[j - scale]; - const auto f = val % multiplier[j - scale]; - oss << i << '.' << std::setw(3 * (j - scale)) - << std::setfill('0') << std::right << f << ' ' - << time_units[j]; - break; - } - } - } - return oss.str(); -} -auto compose_message(const sc_core::sc_report& rep, - const scp::LogConfig& cfg) -> const std::string { - if (rep.get_severity() > sc_core::SC_INFO || - cfg.log_filter_regex.length() == 0 || - rep.get_verbosity() == sc_core::SC_MEDIUM || - log_cfg.match(rep.get_msg_type())) { - std::stringstream os; - if (likely(cfg.print_sim_time)) { - if (unlikely(log_cfg.cycle_base.value())) { - if (unlikely(cfg.print_delta)) - os << "[" << std::setw(7) << std::setfill(' ') - << sc_core::sc_time_stamp().value() / - log_cfg.cycle_base.value() - << "(" << std::setw(5) << sc_core::sc_delta_count() - << ")]"; - else - os << "[" << std::setw(7) << std::setfill(' ') - << sc_core::sc_time_stamp().value() / - log_cfg.cycle_base.value() - << "]"; - } else { - auto t = time2string(sc_core::sc_time_stamp()); - if (unlikely(cfg.print_delta)) - os << "[" << std::setw(20) << std::setfill(' ') << t << "(" - << std::setw(5) << sc_core::sc_delta_count() << ")]"; - else - os << "[" << std::setw(20) << std::setfill(' ') << t - << "]"; - } - } - if (unlikely(rep.get_id() >= 0)) - os << "(" << "IWEF"[rep.get_severity()] << rep.get_id() << ") " - << rep.get_msg_type() << ": "; - else if (cfg.msg_type_field_width) { - if (cfg.msg_type_field_width == - std::numeric_limits::max()) - os << rep.get_msg_type() << ": "; - else - os << padded(rep.get_msg_type(), cfg.msg_type_field_width) - << ": "; - } - if (*rep.get_msg()) - os << rep.get_msg(); - if (rep.get_severity() >= cfg.file_info_from) { - if (rep.get_line_number()) - os << "\n [FILE:" << rep.get_file_name() << ":" - << rep.get_line_number() << "]"; - sc_core::sc_simcontext* simc = sc_core::sc_get_curr_simcontext(); - if (simc && sc_core::sc_is_running()) { - const char* proc_name = rep.get_process_name(); - if (proc_name) - os << "\n [PROCESS:" << proc_name << "]"; - } - } - return os.str(); - } else - return ""; -} - -inline auto get_verbosity(const sc_core::sc_report& rep) -> int { - return rep.get_verbosity() > sc_core::SC_NONE && - rep.get_verbosity() < sc_core::SC_LOW - ? rep.get_verbosity() * 10 - : rep.get_verbosity(); -} - -inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, - const scp::LogConfig& cfg) { - auto msg = compose_message(rep, cfg); - if (!msg.size()) - return; - switch (rep.get_severity()) { - case sc_core::SC_INFO: - switch (get_verbosity(rep)) { - case sc_core::SC_DEBUG: - case sc_core::SC_FULL: - logger.trace(msg); - break; - case sc_core::SC_HIGH: - logger.debug(msg); - break; - default: - logger.info(msg); - break; - } - break; - case sc_core::SC_WARNING: - logger.warn(msg); - break; - case sc_core::SC_ERROR: - logger.error(msg); - break; - case sc_core::SC_FATAL: - logger.critical(msg); - break; - default: - break; - } -} - -inline void log2logger(spdlog::logger& logger, scp::log lvl, - const std::string& msg) { - switch (lvl) { - case scp::log::DBGTRACE: - case scp::log::TRACE: - logger.trace(msg); - return; - case scp::log::DEBUG: - logger.debug(msg); - return; - case scp::log::INFO: - logger.info(msg); - return; - case scp::log::WARNING: - logger.warn(msg); - return; - case scp::log::ERROR: - logger.error(msg); - return; - case scp::log::FATAL: - logger.critical(msg); - return; - default: - break; - } -} - -void report_handler(const sc_core::sc_report& rep, - const sc_core::sc_actions& actions) { - thread_local bool sc_stop_called = false; - if (actions & sc_core::SC_DO_NOTHING) - return; - if (rep.get_severity() == sc_core::SC_INFO || - !log_cfg.report_only_first_error || - sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) < 2) { - if ((actions & sc_core::SC_DISPLAY) && - (!log_cfg.file_logger || get_verbosity(rep) < sc_core::SC_HIGH)) - log2logger(*log_cfg.console_logger, rep, log_cfg); - if ((actions & sc_core::SC_LOG) && log_cfg.file_logger) { - scp::LogConfig lcfg(log_cfg); - lcfg.print_sim_time = true; - if (!lcfg.msg_type_field_width) - lcfg.msg_type_field_width = 24; - log2logger(*log_cfg.file_logger, rep, lcfg); - } - } - if (actions & sc_core::SC_STOP) { - std::this_thread::sleep_for(std::chrono::milliseconds( - static_cast(log_cfg.level) * 10)); - if (sc_core::sc_is_running() && !sc_stop_called) { - sc_core::sc_stop(); - sc_stop_called = true; - } - } - if (actions & sc_core::SC_ABORT) { - std::this_thread::sleep_for(std::chrono::milliseconds( - static_cast(log_cfg.level) * 20)); - abort(); - } - if (actions & sc_core::SC_THROW) { - std::this_thread::sleep_for(std::chrono::milliseconds( - static_cast(log_cfg.level) * 20)); - throw rep; - } - if (sc_core::sc_time_stamp().value() && !sc_core::sc_is_running()) { - log_cfg.console_logger->flush(); - if (log_cfg.file_logger) - log_cfg.file_logger->flush(); - } -} - // BKDR hash algorithm auto char_hash(char const* str) -> uint64_t { constexpr unsigned int seed = 131; // 31 131 1313 13131131313 etc// @@ -362,179 +93,6 @@ static const std::array verbosity = { sc_core::SC_FULL, // scp::log::TRACE sc_core::SC_DEBUG // scp::log::TRACEALL }; -static std::mutex cfg_guard; -static void configure_logging() { - std::lock_guard lock(cfg_guard); - static bool spdlog_initialized = false; - - sc_core::sc_report_handler::set_actions( - sc_core::SC_ERROR, - sc_core::SC_DEFAULT_ERROR_ACTIONS | sc_core::SC_DISPLAY); - sc_core::sc_report_handler::set_actions(sc_core::SC_FATAL, - sc_core::SC_DEFAULT_FATAL_ACTIONS); - sc_core::sc_report_handler::set_verbosity_level( - verbosity[static_cast(log_cfg.level)]); - sc_core::sc_report_handler::set_handler(report_handler); - if (!spdlog_initialized) { - spdlog::init_thread_pool( - 1024U, - log_cfg.log_file_name.size() - ? 2U - : 1U); // queue with 8k items and 1 backing thread. - log_cfg.console_logger = log_cfg.log_async - ? spdlog::stdout_color_mt< - spdlog::async_factory>( - "console_logger") - : spdlog::stdout_color_mt( - "console_logger"); - auto logger_fmt = log_cfg.print_severity ? "[%L] %v" : "%v"; - if (log_cfg.colored_output) { - std::ostringstream os; - os << "%^" << logger_fmt << "%$"; - log_cfg.console_logger->set_pattern(os.str()); - } else - log_cfg.console_logger->set_pattern("[%L] %v"); - log_cfg.console_logger->flush_on(spdlog::level::warn); - log_cfg.console_logger->set_level(spdlog::level::level_enum::trace); - if (log_cfg.log_file_name.size()) { - { - std::ofstream ofs; - ofs.open(log_cfg.log_file_name, - std::ios::out | std::ios::trunc); - } - log_cfg.file_logger = log_cfg.log_async - ? spdlog::basic_logger_mt< - spdlog::async_factory>( - "file_logger", - log_cfg.log_file_name) - : spdlog::basic_logger_mt( - "file_logger", - log_cfg.log_file_name); - if (log_cfg.print_severity) - log_cfg.file_logger->set_pattern("[%8l] %v"); - else - log_cfg.file_logger->set_pattern("%v"); - log_cfg.file_logger->flush_on(spdlog::level::warn); - log_cfg.file_logger->set_level(spdlog::level::level_enum::trace); - } - spdlog_initialized = true; - } else { - log_cfg.console_logger = spdlog::get("console_logger"); - if (log_cfg.log_file_name.size()) - log_cfg.file_logger = spdlog::get("file_logger"); - } - if (log_cfg.log_filter_regex.size()) { - log_cfg.reg_ex = std::regex(log_cfg.log_filter_regex, - std::regex::extended | std::regex::icase); - } -} - -void scp::reinit_logging(scp::log level) { - sc_core::sc_report_handler::set_handler(report_handler); - log_cfg.level = level; - lut.clear(); -} - -void scp::init_logging(scp::log level, unsigned type_field_width, - bool print_time) { - log_cfg.msg_type_field_width = type_field_width; - log_cfg.print_sys_time = print_time; - log_cfg.level = level; - configure_logging(); -} - -void scp::init_logging(const scp::LogConfig& log_config) { - log_cfg = log_config; - configure_logging(); -} - -void scp::set_logging_level(scp::log level) { - log_cfg.level = level; - sc_core::sc_report_handler::set_verbosity_level( - verbosity[static_cast(level)]); - log_cfg.console_logger->set_level(static_cast( - SPDLOG_LEVEL_OFF - - std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); -} - -auto scp::get_logging_level() -> scp::log { - return log_cfg.level; -} - -void scp::set_cycle_base(sc_core::sc_time period) { - log_cfg.cycle_base = period; -} - -auto scp::LogConfig::logLevel(scp::log level) -> scp::LogConfig& { - this->level = level; - return *this; -} - -auto scp::LogConfig::msgTypeFieldWidth(unsigned width) -> scp::LogConfig& { - this->msg_type_field_width = width; - return *this; -} - -auto scp::LogConfig::printSysTime(bool enable) -> scp::LogConfig& { - this->print_sys_time = enable; - return *this; -} - -auto scp::LogConfig::printSimTime(bool enable) -> scp::LogConfig& { - this->print_sim_time = enable; - return *this; -} - -auto scp::LogConfig::printDelta(bool enable) -> scp::LogConfig& { - this->print_delta = enable; - return *this; -} - -auto scp::LogConfig::printSeverity(bool enable) -> scp::LogConfig& { - this->print_severity = enable; - return *this; -} - -auto scp::LogConfig::logFileName(std::string&& name) -> scp::LogConfig& { - this->log_file_name = name; - return *this; -} - -auto scp::LogConfig::logFileName(const std::string& name) -> scp::LogConfig& { - this->log_file_name = name; - return *this; -} - -auto scp::LogConfig::coloredOutput(bool enable) -> scp::LogConfig& { - this->colored_output = enable; - return *this; -} - -auto scp::LogConfig::logFilterRegex(std::string&& expr) -> scp::LogConfig& { - this->log_filter_regex = expr; - return *this; -} - -auto scp::LogConfig::logFilterRegex(const std::string& expr) - -> scp::LogConfig& { - this->log_filter_regex = expr; - return *this; -} - -auto scp::LogConfig::logAsync(bool v) -> scp::LogConfig& { - this->log_async = v; - return *this; -} - -auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& { - this->report_only_first_error = v; - return *this; -} - -auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { - this->file_info_from = v; - return *this; -} std::vector split(const std::string& s) { std::vector result; From 4e70605728df99e8145b5227fc4093abe359ea37 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 27 Nov 2024 12:22:20 +0100 Subject: [PATCH 04/17] applies clang-format --- .gitignore | 2 ++ report/include/scp/helpers.h | 3 ++- report/include/scp/report.h | 4 ++-- report/src/logger.cpp | 8 ++++---- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 8616a41..3a337ac 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /_build/ /.cproject /.project +/.venv +/.vscode diff --git a/report/include/scp/helpers.h b/report/include/scp/helpers.h index 2332ee5..d05bf6e 100644 --- a/report/include/scp/helpers.h +++ b/report/include/scp/helpers.h @@ -36,7 +36,8 @@ static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) { cmd = "READ"; break; } - info << cmd << " to address: " << "0x" << std::hex << trans.get_address(); + info << cmd << " to address: " + << "0x" << std::hex << trans.get_address(); info << " len: " << trans.get_data_length(); unsigned char* ptr = trans.get_data_ptr(); info << " data: 0x"; diff --git a/report/include/scp/report.h b/report/include/scp/report.h index 99c85f6..56f3303 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -316,8 +316,8 @@ struct ScLogger { class call_sc_name_fn { template - static auto test(T* p) -> decltype(p->sc_core::sc_module::name(), - std::true_type()); + static auto test(T* p) + -> decltype(p->sc_core::sc_module::name(), std::true_type()); template static auto test(...) -> decltype(std::false_type()); diff --git a/report/src/logger.cpp b/report/src/logger.cpp index 12c03d5..e2cd965 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -152,8 +152,8 @@ auto time2string(const sc_core::sc_time& t) -> std::string { } return oss.str(); } -auto compose_message(const sc_core::sc_report& rep, - const scp::LogConfig& cfg) -> const std::string { +auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) + -> const std::string { if (rep.get_severity() > sc_core::SC_INFO || cfg.log_filter_regex.length() == 0 || rep.get_verbosity() == sc_core::SC_MEDIUM || @@ -183,7 +183,8 @@ auto compose_message(const sc_core::sc_report& rep, } } if (unlikely(rep.get_id() >= 0)) - os << "(" << "IWEF"[rep.get_severity()] << rep.get_id() << ") " + os << "(" + << "IWEF"[rep.get_severity()] << rep.get_id() << ") " << rep.get_msg_type() << ": "; else if (cfg.msg_type_field_width) { if (cfg.msg_type_field_width == @@ -528,4 +529,3 @@ auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { this->file_info_from = v; return *this; } - From b5985c0be634a1c423c4bbe733e1126fb16e38dd Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 5 Jun 2024 10:18:03 +0200 Subject: [PATCH 05/17] Fix for upstream install on mac RPATH issue Signed-off-by: Mark Burton --- report/CMakeLists.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/report/CMakeLists.txt b/report/CMakeLists.txt index abd7a7e..6b355c3 100644 --- a/report/CMakeLists.txt +++ b/report/CMakeLists.txt @@ -27,6 +27,15 @@ cpmaddpackage( GIT_TAG main ) +# upstream set INSTALL_NAME_DIR wrong ! +if (APPLE) + set_target_properties( + systemc + PROPERTIES + INSTALL_NAME_DIR "@rpath" + ) +endif() + cpmaddpackage( NAME SystemCCCI GIT_REPOSITORY ${GITHUB}accellera-official/cci.git @@ -34,6 +43,16 @@ cpmaddpackage( GIT_TAG main ) +# upstream set INSTALL_NAME_DIR wrong ! +if (APPLE) + set_target_properties( + cci + PROPERTIES + INSTALL_NAME_DIR "@rpath" + ) +endif() + + set(WITH_FMT "true" CACHE STRING "Include FMT library") if(WITH_FMT) From 59f337706ec58ded2558ad04757840218f0f9932 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 20 Mar 2024 20:34:57 +0100 Subject: [PATCH 06/17] Split the CCI mechanism from the rest of remote.h Signed-off-by: Mark Burton --- report/include/scp/report.h | 21 +- report/include/scp/report_cci_setter.h | 269 +++++++++++++++++++++++++ report/src/logger.cpp | 7 + report/src/report.cpp | 153 +------------- 4 files changed, 298 insertions(+), 152 deletions(-) create mode 100644 report/include/scp/report_cci_setter.h diff --git a/report/include/scp/report.h b/report/include/scp/report.h index 56f3303..f230cc2 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -39,7 +39,26 @@ #if defined(_MSC_VER) && defined(ERROR) #undef ERROR #endif - +static const std::array severity = { + sc_core::SC_FATAL, // scp::log::NONE + sc_core::SC_FATAL, // scp::log::FATAL + sc_core::SC_ERROR, // scp::log::ERROR + sc_core::SC_WARNING, // scp::log::WARNING + sc_core::SC_INFO, // scp::log::INFO + sc_core::SC_INFO, // scp::log::DEBUG + sc_core::SC_INFO, // scp::log::TRACE + sc_core::SC_INFO // scp::log::TRACEALL +}; +static const std::array verbosity = { + sc_core::SC_NONE, // scp::log::NONE + sc_core::SC_LOW, // scp::log::FATAL + sc_core::SC_LOW, // scp::log::ERROR + sc_core::SC_LOW, // scp::log::WARNING + sc_core::SC_MEDIUM, // scp::log::INFO + sc_core::SC_HIGH, // scp::log::DEBUG + sc_core::SC_FULL, // scp::log::TRACE + sc_core::SC_DEBUG // scp::log::TRACEALL +}; namespace sc_core { const sc_core::sc_verbosity SC_UNSET = (sc_core::sc_verbosity)INT_MAX; } diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h new file mode 100644 index 0000000..9f6c8cf --- /dev/null +++ b/report/include/scp/report_cci_setter.h @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +#ifndef _SCP_REPORT_CCI_SETTER_H_ +#define _SCP_REPORT_CCI_SETTER_H_ + +#include +#include +#include +#include + +namespace scp { +static std::set logging_parameters; + +class scp_logger_from_cci +{ + std::vector split(const std::string& s) const { + std::vector result; + std::istringstream iss(s); + std::string item; + while (std::getline(iss, item, '.')) { + result.push_back(item); + } + return result; + } + + std::string join(std::vector vec) const { + if (vec.empty()) + return ""; + return std::accumulate( + vec.begin(), vec.end(), std::string(), + [](const std::string& a, const std::string& b) -> std::string { + return a + (a.length() > 0 ? "." : "") + b; + }); + } + + void insert(std::multimap>& map, + std::string s, bool interesting) const { + int n = std::count(s.begin(), s.end(), '.'); + map.insert(make_pair(n, s)); + + if (interesting) { + logging_parameters.insert(s + "." SCP_LOG_LEVEL_PARAM_NAME); + } + } + sc_core::sc_verbosity cci_lookup(cci::cci_broker_handle broker, + std::string name) const { + auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME + : name + "." SCP_LOG_LEVEL_PARAM_NAME; + auto h = broker.get_param_handle(param_name); + if (h.is_valid()) { + return verbosity.at(std::min(h.get_cci_value().get_int(), + verbosity.size() - 1)); + } else { + auto val = broker.get_preset_cci_value(param_name); + + if (val.is_int()) { + broker.lock_preset_value(param_name); + return verbosity.at( + std::min(val.get_int(), verbosity.size() - 1)); + } + } + return sc_core::SC_UNSET; + } +#ifdef __GNUG__ + std::string demangle(const char* name) const { + int status = -4; // some arbitrary value to eliminate the compiler + // warning + + // enable c++11 by passing the flag -std=c++11 to g++ + std::unique_ptr res{ + abi::__cxa_demangle(name, NULL, NULL, &status), std::free + }; + + return (status == 0) ? res.get() : name; + } +#else + // does nothing if not GNUG + std::string demangle(const char* name) { return name; } +#endif +public: + sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, + const char* scname, + const char* tname) const { + try { + // we rely on there being a broker, allow this to throw if not + auto broker = sc_core::sc_get_current_object() + ? cci::cci_get_broker() + : cci::cci_get_global_broker(cci::cci_originator( + "scp_reporting_global")); + + std::multimap> allfeatures; + + /* initialize */ + for (auto scn = split(scname); scn.size(); scn.pop_back()) { + for (int first = 0; first < scn.size(); first++) { + auto f = scn.begin() + first; + std::vector p(f, scn.end()); + auto scn_str = ((first > 0) ? "*." : "") + join(p); + + for (auto ft : logger.features) { + for (auto ftn = split(ft); ftn.size(); + ftn.pop_back()) { + insert(allfeatures, scn_str + "." + join(ftn), + first == 0); + } + } + insert(allfeatures, scn_str + "." + demangle(tname), + first == 0); + insert(allfeatures, scn_str, first == 0); + } + } + for (auto ft : logger.features) { + for (auto ftn = split(ft); ftn.size(); ftn.pop_back()) { + insert(allfeatures, join(ftn), true); + insert(allfeatures, "*." + join(ftn), false); + } + } + insert(allfeatures, demangle(tname), true); + insert(allfeatures, "*", false); + insert(allfeatures, "", false); + + for (std::pair f : allfeatures) { + sc_core::sc_verbosity v = cci_lookup(broker, f.second); + if (v != sc_core::SC_UNSET) { + logger.level = v; + return v; + } + } + } catch (const std::exception&) { + // If there is no global broker, revert to initialized verbosity + // level + } + return logger.level = static_cast( + ::sc_core::sc_report_handler::get_verbosity_level()); + } + static std::vector get_logging_parameters() { + return std::vector(logging_parameters.begin(), + logging_parameters.end()); + } +}; + +#if 0 + +/*template +struct HasLogger : std::false_type { }; + +template +struct HasLogger : std::true_type +{ }; +*/ + +class set_logger_level +{ + template + static auto test(T* p) -> decltype(p->SCP_LOGGER_NAME(), std::true_type()); + template + static auto test(...) -> decltype(std::false_type()); + + template + static constexpr bool has_logger = decltype(test(nullptr))::value; + +public: + // define a function IF the method exists + template + auto operator()(TYPE* p, sc_core::sc_verbosity level) const + -> std::enable_if_t> { + p->SCP_LOGGER_NAME().level = level; + } + + // define a function IF NOT the method exists + template + auto operator()(TYPE* p, sc_core::sc_verbosity level) const + -> std::enable_if_t> {} +}; + +int set_log_levels(std::string path, sc_core::sc_verbosity level, + sc_core::sc_object* m = nullptr, bool set = false) { + int found = 0; + auto pathdot = path.find_first_of('.'); + auto lpath = (pathdot != std::string::npos) ? path.substr(pathdot) : path; + + if (m) { + std::string mname = std::string(m->name()); + auto namedot = mname.find_last_of('.'); + auto lname = (namedot != std::string::npos) ? mname.substr(namedot) + : mname; + + if (!((lpath == "*") || (lpath == lname))) { + // no match here + return found; + } + } + if (path.substr(pathdot) == SCP_LOG_LEVEL_PARAM_NAME) { + // Found it + set = true; + } + + if (set) { + found++; + scp::set_logger_level()(m, level); + } + std::vector children; + if (m) { + children = m->get_child_objects(); + } else { + children = sc_core::sc_get_top_level_objects(); + } + + for (auto c : children) { + if (lpath == "*") { + found += set_log_levels(path, level, c, set); + } + if (pathdot != std::string::npos) { + found += set_log_levels(path.substr(pathdot), level, c, set); + } + } + return found; +}; + +void cci_enable_logging(cci::cci_broker_handle broker) { + std::string pname = std::string(".") + SCP_LOG_LEVEL_PARAM_NAME; + int plen = std::string(SCP_LOG_LEVEL_PARAM_NAME).length(); + std::vector logging_paths; + for (auto path : broker.get_unconsumed_preset_values( + [&plen](const std::pair& iv) { + if (iv.first.length() >= plen) { + return (0 == iv.first.compare(iv.first.length() - plen, + plen, + SCP_LOG_LEVEL_PARAM_NAME)); + } else { + return false; + } + })) { + logging_paths.push_back(path); + } + + std::sort(logging_paths.begin(), logging_paths.end(), + [&](cci::cci_name_value_pair& s1, cci::cci_name_value_pair& s2) { + return std::count(s1.first.begin(), s1.first.end(), '.') > + std::count(s2.first.begin(), s2.first.end(), '.'); + }); + for (auto path : logging_paths) { + int found = set_log_levels( + path.first, (sc_core::sc_verbosity)(path.second.get_int())); + if (found == 0) { + SCP_WARN()("No logger named {} found", path.first); + } else { + SCP_INFO()("{} loggers enabled from name {}", found, path.first); + } + } +} +#endif + +} // namespace scp + +#endif \ No newline at end of file diff --git a/report/src/logger.cpp b/report/src/logger.cpp index e2cd965..07327ff 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -529,3 +529,10 @@ auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { this->file_info_from = v; return *this; } +auto scp::LogConfig::registerLogLevelFn( + std::function + fn) -> scp::LogConfig& { + this->log_level_lookup_fn = fn; + return *this; +} \ No newline at end of file diff --git a/report/src/report.cpp b/report/src/report.cpp index 081f0fc..dff44a9 100644 --- a/report/src/report.cpp +++ b/report/src/report.cpp @@ -24,9 +24,6 @@ #include #include #include -#ifdef HAS_CCI -#include -#endif #include #include #include @@ -55,11 +52,6 @@ std::unordered_map lut; thread_local std::unordered_map lut; #endif -#ifdef HAS_CCI -cci::cci_originator scp_global_originator("scp_reporting_global"); -#endif - -std::set logging_parameters; // BKDR hash algorithm auto char_hash(char const* str) -> uint64_t { @@ -73,101 +65,6 @@ auto char_hash(char const* str) -> uint64_t { } } // namespace -static const std::array severity = { - sc_core::SC_FATAL, // scp::log::NONE - sc_core::SC_FATAL, // scp::log::FATAL - sc_core::SC_ERROR, // scp::log::ERROR - sc_core::SC_WARNING, // scp::log::WARNING - sc_core::SC_INFO, // scp::log::INFO - sc_core::SC_INFO, // scp::log::DEBUG - sc_core::SC_INFO, // scp::log::TRACE - sc_core::SC_INFO // scp::log::TRACEALL -}; -static const std::array verbosity = { - sc_core::SC_NONE, // scp::log::NONE - sc_core::SC_LOW, // scp::log::FATAL - sc_core::SC_LOW, // scp::log::ERROR - sc_core::SC_LOW, // scp::log::WARNING - sc_core::SC_MEDIUM, // scp::log::INFO - sc_core::SC_HIGH, // scp::log::DEBUG - sc_core::SC_FULL, // scp::log::TRACE - sc_core::SC_DEBUG // scp::log::TRACEALL -}; - -std::vector split(const std::string& s) { - std::vector result; - std::istringstream iss(s); - std::string item; - while (std::getline(iss, item, '.')) { - result.push_back(item); - } - return result; -} - -std::string join(std::vector vec) { - if (vec.empty()) - return ""; - return std::accumulate( - vec.begin(), vec.end(), std::string(), - [](const std::string& a, const std::string& b) -> std::string { - return a + (a.length() > 0 ? "." : "") + b; - }); -} - -std::vector scp::get_logging_parameters() { - return std::vector(logging_parameters.begin(), - logging_parameters.end()); -} - -sc_core::sc_verbosity cci_lookup(cci::cci_broker_handle broker, - std::string name) { - auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME - : name + "." SCP_LOG_LEVEL_PARAM_NAME; - auto h = broker.get_param_handle(param_name); - if (h.is_valid()) { - return verbosity.at(std::min(h.get_cci_value().get_int(), - verbosity.size() - 1)); - } else { - auto val = broker.get_preset_cci_value(param_name); - - if (val.is_int()) { - broker.lock_preset_value(param_name); - return verbosity.at( - std::min(val.get_int(), verbosity.size() - 1)); - } - } - return sc_core::SC_UNSET; -} - -#ifdef __GNUG__ -std::string demangle(const char* name) { - int status = -4; // some arbitrary value to eliminate the compiler - // warning - - // enable c++11 by passing the flag -std=c++11 to g++ - std::unique_ptr res{ - abi::__cxa_demangle(name, NULL, NULL, &status), std::free - }; - - return (status == 0) ? res.get() : name; -} -#else -// does nothing if not GNUG -std::string demangle(const char* name) { - return name; -} -#endif - -void insert(std::multimap>& map, - std::string s, bool interesting) { - int n = std::count(s.begin(), s.end(), '.'); - map.insert(make_pair(n, s)); - - if (interesting) { - logging_parameters.insert(s + "." SCP_LOG_LEVEL_PARAM_NAME); - } -} - sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( const char* scname, const char* tname = "") { if (level != sc_core::SC_UNSET) { @@ -181,56 +78,10 @@ sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( type = std::string(scname); -#ifdef HAS_CCI - try { - // we rely on there being a broker, allow this to throw if not - auto broker = sc_core::sc_get_current_object() - ? cci::cci_get_broker() - : cci::cci_get_global_broker(scp_global_originator); - - std::multimap> allfeatures; - - /* initialize */ - for (auto scn = split(scname); scn.size(); scn.pop_back()) { - for (int first = 0; first < scn.size(); first++) { - auto f = scn.begin() + first; - std::vector p(f, scn.end()); - auto scn_str = ((first > 0) ? "*." : "") + join(p); - - for (auto ft : features) { - for (auto ftn = split(ft); ftn.size(); ftn.pop_back()) { - insert(allfeatures, scn_str + "." + join(ftn), - first == 0); - } - } - insert(allfeatures, scn_str + "." + demangle(tname), - first == 0); - insert(allfeatures, scn_str, first == 0); - } - } - for (auto ft : features) { - for (auto ftn = split(ft); ftn.size(); ftn.pop_back()) { - insert(allfeatures, join(ftn), true); - insert(allfeatures, "*." + join(ftn), false); - } - } - insert(allfeatures, demangle(tname), true); - insert(allfeatures, "*", false); - insert(allfeatures, "", false); - - for (std::pair f : allfeatures) { - sc_core::sc_verbosity v = cci_lookup(broker, f.second); - if (v != sc_core::SC_UNSET) { - level = v; - return v; - } - } - } catch (const std::exception&) { - // If there is no global broker, revert to initialized verbosity level + if (log_cfg.log_level_lookup_fn) { + return log_cfg.log_level_lookup_fn(*this, scname, tname); } -#endif - return level = static_cast( ::sc_core::sc_report_handler::get_verbosity_level()); } From 8a7689fcfb452b5f92f937dbb491ebfc9e31dfc9 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 30 Nov 2024 11:28:28 +0100 Subject: [PATCH 07/17] Maintain #include interface for ease of use Signed-off-by: Mark Burton --- report/include/scp/report.h | 457 +-------------------------------- report/include/scp/sc_report.h | 454 ++++++++++++++++++++++++++++++++ 2 files changed, 458 insertions(+), 453 deletions(-) create mode 100644 report/include/scp/sc_report.h diff --git a/report/include/scp/report.h b/report/include/scp/report.h index f230cc2..a962eaf 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -1,454 +1,5 @@ -/******************************************************************************* - * Copyright 2016-2022 MINRES Technologies GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ +/* this is merely a convenience */ -#ifndef _SCP_REPORT_H_ -#define _SCP_REPORT_H_ - -#include -#include -#include -#include -#include - -#ifdef __GNUG__ -#include -#include -#endif - -#include -#include -#include - -#ifdef FMT_SHARED -#include -#endif - -#if defined(_MSC_VER) && defined(ERROR) -#undef ERROR -#endif -static const std::array severity = { - sc_core::SC_FATAL, // scp::log::NONE - sc_core::SC_FATAL, // scp::log::FATAL - sc_core::SC_ERROR, // scp::log::ERROR - sc_core::SC_WARNING, // scp::log::WARNING - sc_core::SC_INFO, // scp::log::INFO - sc_core::SC_INFO, // scp::log::DEBUG - sc_core::SC_INFO, // scp::log::TRACE - sc_core::SC_INFO // scp::log::TRACEALL -}; -static const std::array verbosity = { - sc_core::SC_NONE, // scp::log::NONE - sc_core::SC_LOW, // scp::log::FATAL - sc_core::SC_LOW, // scp::log::ERROR - sc_core::SC_LOW, // scp::log::WARNING - sc_core::SC_MEDIUM, // scp::log::INFO - sc_core::SC_HIGH, // scp::log::DEBUG - sc_core::SC_FULL, // scp::log::TRACE - sc_core::SC_DEBUG // scp::log::TRACEALL -}; -namespace sc_core { -const sc_core::sc_verbosity SC_UNSET = (sc_core::sc_verbosity)INT_MAX; -} - -//! the name of the CCI property to attach to modules to control logging of -//! this module -#define SCP_LOG_LEVEL_PARAM_NAME "log_level" - -// must be global for macro to work. -static const char* _SCP_FMT_EMPTY_STR = ""; - -/** \ingroup scp-report - * @{ - */ -/**@{*/ -//! @brief reporting utilities -namespace scp { -//! \brief array holding string representations of log levels -static std::array buffer = { - { "NONE", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", - "TRACEALL" } -}; -//! \brief enum defining the log levels -enum class log { - NONE, - FATAL, - ERROR, - WARNING, - INFO, - DEBUG, - TRACE, - TRACEALL, - DBGTRACE = TRACEALL -}; - -/** - * @fn log as_log(int) - * @brief safely convert an integer into a log level - * - * @param logLevel the logging level - * @return the log level - */ -inline log as_log(int logLevel) { - assert(logLevel >= static_cast(log::NONE) && - logLevel <= static_cast(log::TRACEALL)); - std::array m = { { log::NONE, log::FATAL, log::ERROR, - log::WARNING, log::INFO, log::DEBUG, - log::TRACE, log::TRACEALL } }; - return m[logLevel]; -} -/** - * @fn std::istream& operator >>(std::istream&, log&) - * @brief read a log level from input stream e.g. used by boost::lexical_cast - * - * @param is input stream holding the string representation - * @param val the value holding the resulting value - * @return the input stream - */ -inline std::istream& operator>>(std::istream& is, log& val) { - std::string buf; - is >> buf; - for (auto i = 0U; i <= static_cast(log::TRACEALL); ++i) { - if (std::strcmp(buf.c_str(), buffer[i]) == 0) { - val = as_log(i); - return is; - } - } - return is; -} -/** - * @fn std::ostream& operator <<(std::ostream&, const log&) - * @brief output the textual representation of the log level - * - * @param os output stream - * @param val logging level - * @return reference to the stream for chaining - */ -inline std::ostream& operator<<(std::ostream& os, log const& val) { - os << buffer[static_cast(val)]; - return os; -} - -/** - * @brief cached logging information used in the (logger) form. - * - */ -struct scp_logger_cache { - sc_core::sc_verbosity level = sc_core::SC_UNSET; - std::string type; - std::vector features; - - /** - * @brief Initialize the verbosity cache and/or return the cached value. - * - * @return sc_core::sc_verbosity - */ - sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); -}; - -inline sc_core::sc_verbosity get_log_verbosity() { - return static_cast( - ::sc_core::sc_report_handler::get_verbosity_level()); -} -/** - * @fn sc_core::sc_verbosity get_log_verbosity(const char*) - * @brief get the scope-based verbosity level - * - * The function returns a scope specific verbosity level if defined (e.g. by - * using a CCI param named "log_level"). Otherwise the global verbosity level - * is being returned - * - * @param t the SystemC hierarchy scope name - * @return the verbosity level - */ -sc_core::sc_verbosity get_log_verbosity(char const* t); -/** - * @fn sc_core::sc_verbosity get_log_verbosity(const char*) - * @brief get the scope-based verbosity level - * - * The function returns a scope specific verbosity level if defined (e.g. by - * using a CCI param named "log_level"). Otherwise the global verbosity level - * is being returned - * - * @param t the SystemC hierarchy scope name - * @return the verbosity level - */ -inline sc_core::sc_verbosity get_log_verbosity(std::string const& t) { - return get_log_verbosity(t.c_str()); -} - -/** - * @brief Return list of logging parameters that have been used - * - */ -std::vector get_logging_parameters(); - -/** - * @struct ScLogger - * @brief the logger class - * - * The ScLogger creates a RTTI based output stream to be used similar to - * std::cout - * - * @tparam SEVERITY - */ -template -struct ScLogger { - /** - * @fn ScLogger(const char*, int, int=sc_core::SC_MEDIUM) - * @brief - * - * @param file where the log entry originates - * @param line number where the log entry originates - * @param verbosity the log level - */ - ScLogger(const char* file, int line, int verbosity = sc_core::SC_MEDIUM): - t(nullptr), file(file), line(line), level(verbosity){}; - - ScLogger() = delete; - - ScLogger(const ScLogger&) = delete; - - ScLogger(ScLogger&&) = delete; - - ScLogger& operator=(const ScLogger&) = delete; - - ScLogger& operator=(ScLogger&&) = delete; - /** - * @fn ~ScLogger() - * @brief the destructor generating the SystemC report - * - */ - virtual ~ScLogger() { - ::sc_core::sc_report_handler::report( - SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); - } - /** - * @fn ScLogger& type() - * @brief reset the category of the log entry - * - * @return reference to self for chaining - */ - inline ScLogger& type() { - this->t = nullptr; - return *this; - } - /** - * @fn ScLogger& type(const char*) - * @brief set the category of the log entry - * - * @param t type of th elog entry - * @return reference to self for chaining - */ - inline ScLogger& type(char const* t) { - this->t = const_cast(t); - return *this; - } - /** - * @fn ScLogger& type(std::string const&) - * @brief set the category of the log entry - * - * @param t type of th elog entry - * @return reference to self for chaining - */ - inline ScLogger& type(std::string const& t) { - this->t = const_cast(t.c_str()); - return *this; - } - /** - * @fn std::ostream& get() - * @brief get the underlying ostringstream - * - * @return the output stream collecting the log message - */ - inline std::ostream& get() { return os; }; - -protected: - std::ostringstream os{}; - char* t{ nullptr }; - const char* file; - const int line; - const int level; -}; - -/** - * logging macros - */ - -/** - * Boilerplate convenience macros - */ -#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) -#define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ - -#define IIF(c) PRIMITIVE_CAT(IIF_, c) -#define IIF_0(t, ...) __VA_ARGS__ -#define IIF_1(t, ...) t - -#define CHECK_N(x, n, ...) n -#define CHECK(...) CHECK_N(__VA_ARGS__, 0, ) -#define PROBE(x) x, 1, - -#define EXPAND(...) __VA_ARGS__ - -#define FIRST_ARG(f, ...) f -#define POP_ARG(f, ...) __VA_ARGS__ - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x) -#define IS_PAREN_PROBE(...) PROBE(~) -/********/ - -/* default logger cache name */ -#define SCP_LOGGER_NAME(x) CAT(_m_scp_log_level_cache_, x) - -/* User interface macros */ -#define SCMOD this->sc_core::sc_module::name() -#define SCP_LOGGER(...) \ - scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ - SCP_LOGGER_NAME()) = { sc_core::SC_UNSET, \ - "", \ - { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ - POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } - -#define SCP_LOGGER_VECTOR(NAME) \ - std::vector SCP_LOGGER_NAME(NAME) -#define SCP_LOGGER_VECTOR_PUSH_BACK(NAME, ...) \ - SCP_LOGGER_NAME(NAME).push_back( \ - { sc_core::SC_UNSET, "", { __VA_ARGS__ } }); - -class call_sc_name_fn -{ - template - static auto test(T* p) - -> decltype(p->sc_core::sc_module::name(), std::true_type()); - template - static auto test(...) -> decltype(std::false_type()); - - template - static constexpr bool has_method = decltype(test(nullptr))::value; - -public: - // define a function IF the method exists - template - auto operator()(TYPE* p) const - -> std::enable_if_t, const char*> { - return p->sc_core::sc_module::name(); - } - - // define a function IF NOT the method exists - template - auto operator()(TYPE* p) const - -> std::enable_if_t, const char*> { - return nullptr; - } -}; - -// critical thing is that the initial if 'fails' as soon as possible - if it is -// going to pass, we have all the time we want, as we will be logging anyway -// This HAS to be done as a macro, because the first argument may be a string -// or a cache'd level - -/*** Helper macros for SCP_ report macros ****/ -#define SCP_VBSTY_CHECK_CACHED(lvl, features, cached, ...) \ - (cached.level >= lvl) && \ - (cached.get_log_verbosity_cached(scp::call_sc_name_fn()(this), \ - typeid(*this).name()) >= lvl) - -#define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) \ - (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) - -#define SCP_VBSTY_CHECK(lvl, ...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (SCP_VBSTY_CHECK_CACHED( \ - lvl, FIRST_ARG(__VA_ARGS__), \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ - SCP_VBSTY_CHECK_UNCACHED(lvl, ##__VA_ARGS__)) - -#define SCP_GET_FEATURES(...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (FIRST_ARG EXPAND((POP_ARG( \ - __VA_ARGS__, \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ - __VA_ARGS__) - -#ifdef FMT_SHARED -#define _SCP_FMT_EMPTY_STR(...) fmt::format(__VA_ARGS__) -#else -#define _SCP_FMT_EMPTY_STR(...) "Please add FMT library for FMT support." -#endif - -#define SCP_LOG(lvl, ...) \ - ::scp::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, lvl / 10) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ - << _SCP_FMT_EMPTY_STR -/*** End HELPER Macros *******/ - -//! macro for debug trace level output -#define SCP_TRACEALL(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_DEBUG, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_DEBUG, __VA_ARGS__) -//! macro for trace level output -#define SCP_TRACE(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_FULL, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_FULL, __VA_ARGS__) -//! macro for debug level output -#define SCP_DEBUG(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_HIGH, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_HIGH, __VA_ARGS__) -//! macro for info level output -#define SCP_INFO(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_MEDIUM, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_MEDIUM, __VA_ARGS__) -//! macro for warning level output -#define SCP_WARN(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_LOW, ##__VA_ARGS__)) \ - ::scp::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, \ - sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ - << _SCP_FMT_EMPTY_STR -//! macro for error level output -#define SCP_ERR(...) \ - ::scp::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, \ - sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ - << _SCP_FMT_EMPTY_STR -//! macro for fatal message output -#define SCP_FATAL(...) \ - ::scp::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, \ - sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ - << _SCP_FMT_EMPTY_STR - -#ifdef NDEBUG -#define SCP_ASSERT(expr) ((void)0) -#else -#define SCP_ASSERT(expr) \ - ((void)((expr) ? 0 \ - : (SC_REPORT_FATAL(::sc_core::SC_ID_ASSERTION_FAILED_, \ - #expr), \ - 0))) -#endif - -} // namespace scp -/** @} */ // end of scp-report -#endif /* _SCP_REPORT_H_ */ +#include "scp/sc_report.h" +#include "scp/helpers.h" +#include "scp/logger.h" diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h new file mode 100644 index 0000000..f230cc2 --- /dev/null +++ b/report/include/scp/sc_report.h @@ -0,0 +1,454 @@ +/******************************************************************************* + * Copyright 2016-2022 MINRES Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + +#ifndef _SCP_REPORT_H_ +#define _SCP_REPORT_H_ + +#include +#include +#include +#include +#include + +#ifdef __GNUG__ +#include +#include +#endif + +#include +#include +#include + +#ifdef FMT_SHARED +#include +#endif + +#if defined(_MSC_VER) && defined(ERROR) +#undef ERROR +#endif +static const std::array severity = { + sc_core::SC_FATAL, // scp::log::NONE + sc_core::SC_FATAL, // scp::log::FATAL + sc_core::SC_ERROR, // scp::log::ERROR + sc_core::SC_WARNING, // scp::log::WARNING + sc_core::SC_INFO, // scp::log::INFO + sc_core::SC_INFO, // scp::log::DEBUG + sc_core::SC_INFO, // scp::log::TRACE + sc_core::SC_INFO // scp::log::TRACEALL +}; +static const std::array verbosity = { + sc_core::SC_NONE, // scp::log::NONE + sc_core::SC_LOW, // scp::log::FATAL + sc_core::SC_LOW, // scp::log::ERROR + sc_core::SC_LOW, // scp::log::WARNING + sc_core::SC_MEDIUM, // scp::log::INFO + sc_core::SC_HIGH, // scp::log::DEBUG + sc_core::SC_FULL, // scp::log::TRACE + sc_core::SC_DEBUG // scp::log::TRACEALL +}; +namespace sc_core { +const sc_core::sc_verbosity SC_UNSET = (sc_core::sc_verbosity)INT_MAX; +} + +//! the name of the CCI property to attach to modules to control logging of +//! this module +#define SCP_LOG_LEVEL_PARAM_NAME "log_level" + +// must be global for macro to work. +static const char* _SCP_FMT_EMPTY_STR = ""; + +/** \ingroup scp-report + * @{ + */ +/**@{*/ +//! @brief reporting utilities +namespace scp { +//! \brief array holding string representations of log levels +static std::array buffer = { + { "NONE", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", + "TRACEALL" } +}; +//! \brief enum defining the log levels +enum class log { + NONE, + FATAL, + ERROR, + WARNING, + INFO, + DEBUG, + TRACE, + TRACEALL, + DBGTRACE = TRACEALL +}; + +/** + * @fn log as_log(int) + * @brief safely convert an integer into a log level + * + * @param logLevel the logging level + * @return the log level + */ +inline log as_log(int logLevel) { + assert(logLevel >= static_cast(log::NONE) && + logLevel <= static_cast(log::TRACEALL)); + std::array m = { { log::NONE, log::FATAL, log::ERROR, + log::WARNING, log::INFO, log::DEBUG, + log::TRACE, log::TRACEALL } }; + return m[logLevel]; +} +/** + * @fn std::istream& operator >>(std::istream&, log&) + * @brief read a log level from input stream e.g. used by boost::lexical_cast + * + * @param is input stream holding the string representation + * @param val the value holding the resulting value + * @return the input stream + */ +inline std::istream& operator>>(std::istream& is, log& val) { + std::string buf; + is >> buf; + for (auto i = 0U; i <= static_cast(log::TRACEALL); ++i) { + if (std::strcmp(buf.c_str(), buffer[i]) == 0) { + val = as_log(i); + return is; + } + } + return is; +} +/** + * @fn std::ostream& operator <<(std::ostream&, const log&) + * @brief output the textual representation of the log level + * + * @param os output stream + * @param val logging level + * @return reference to the stream for chaining + */ +inline std::ostream& operator<<(std::ostream& os, log const& val) { + os << buffer[static_cast(val)]; + return os; +} + +/** + * @brief cached logging information used in the (logger) form. + * + */ +struct scp_logger_cache { + sc_core::sc_verbosity level = sc_core::SC_UNSET; + std::string type; + std::vector features; + + /** + * @brief Initialize the verbosity cache and/or return the cached value. + * + * @return sc_core::sc_verbosity + */ + sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); +}; + +inline sc_core::sc_verbosity get_log_verbosity() { + return static_cast( + ::sc_core::sc_report_handler::get_verbosity_level()); +} +/** + * @fn sc_core::sc_verbosity get_log_verbosity(const char*) + * @brief get the scope-based verbosity level + * + * The function returns a scope specific verbosity level if defined (e.g. by + * using a CCI param named "log_level"). Otherwise the global verbosity level + * is being returned + * + * @param t the SystemC hierarchy scope name + * @return the verbosity level + */ +sc_core::sc_verbosity get_log_verbosity(char const* t); +/** + * @fn sc_core::sc_verbosity get_log_verbosity(const char*) + * @brief get the scope-based verbosity level + * + * The function returns a scope specific verbosity level if defined (e.g. by + * using a CCI param named "log_level"). Otherwise the global verbosity level + * is being returned + * + * @param t the SystemC hierarchy scope name + * @return the verbosity level + */ +inline sc_core::sc_verbosity get_log_verbosity(std::string const& t) { + return get_log_verbosity(t.c_str()); +} + +/** + * @brief Return list of logging parameters that have been used + * + */ +std::vector get_logging_parameters(); + +/** + * @struct ScLogger + * @brief the logger class + * + * The ScLogger creates a RTTI based output stream to be used similar to + * std::cout + * + * @tparam SEVERITY + */ +template +struct ScLogger { + /** + * @fn ScLogger(const char*, int, int=sc_core::SC_MEDIUM) + * @brief + * + * @param file where the log entry originates + * @param line number where the log entry originates + * @param verbosity the log level + */ + ScLogger(const char* file, int line, int verbosity = sc_core::SC_MEDIUM): + t(nullptr), file(file), line(line), level(verbosity){}; + + ScLogger() = delete; + + ScLogger(const ScLogger&) = delete; + + ScLogger(ScLogger&&) = delete; + + ScLogger& operator=(const ScLogger&) = delete; + + ScLogger& operator=(ScLogger&&) = delete; + /** + * @fn ~ScLogger() + * @brief the destructor generating the SystemC report + * + */ + virtual ~ScLogger() { + ::sc_core::sc_report_handler::report( + SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); + } + /** + * @fn ScLogger& type() + * @brief reset the category of the log entry + * + * @return reference to self for chaining + */ + inline ScLogger& type() { + this->t = nullptr; + return *this; + } + /** + * @fn ScLogger& type(const char*) + * @brief set the category of the log entry + * + * @param t type of th elog entry + * @return reference to self for chaining + */ + inline ScLogger& type(char const* t) { + this->t = const_cast(t); + return *this; + } + /** + * @fn ScLogger& type(std::string const&) + * @brief set the category of the log entry + * + * @param t type of th elog entry + * @return reference to self for chaining + */ + inline ScLogger& type(std::string const& t) { + this->t = const_cast(t.c_str()); + return *this; + } + /** + * @fn std::ostream& get() + * @brief get the underlying ostringstream + * + * @return the output stream collecting the log message + */ + inline std::ostream& get() { return os; }; + +protected: + std::ostringstream os{}; + char* t{ nullptr }; + const char* file; + const int line; + const int level; +}; + +/** + * logging macros + */ + +/** + * Boilerplate convenience macros + */ +#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) +#define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ + +#define IIF(c) PRIMITIVE_CAT(IIF_, c) +#define IIF_0(t, ...) __VA_ARGS__ +#define IIF_1(t, ...) t + +#define CHECK_N(x, n, ...) n +#define CHECK(...) CHECK_N(__VA_ARGS__, 0, ) +#define PROBE(x) x, 1, + +#define EXPAND(...) __VA_ARGS__ + +#define FIRST_ARG(f, ...) f +#define POP_ARG(f, ...) __VA_ARGS__ + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x) +#define IS_PAREN_PROBE(...) PROBE(~) +/********/ + +/* default logger cache name */ +#define SCP_LOGGER_NAME(x) CAT(_m_scp_log_level_cache_, x) + +/* User interface macros */ +#define SCMOD this->sc_core::sc_module::name() +#define SCP_LOGGER(...) \ + scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ + SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ + SCP_LOGGER_NAME()) = { sc_core::SC_UNSET, \ + "", \ + { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ + POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } + +#define SCP_LOGGER_VECTOR(NAME) \ + std::vector SCP_LOGGER_NAME(NAME) +#define SCP_LOGGER_VECTOR_PUSH_BACK(NAME, ...) \ + SCP_LOGGER_NAME(NAME).push_back( \ + { sc_core::SC_UNSET, "", { __VA_ARGS__ } }); + +class call_sc_name_fn +{ + template + static auto test(T* p) + -> decltype(p->sc_core::sc_module::name(), std::true_type()); + template + static auto test(...) -> decltype(std::false_type()); + + template + static constexpr bool has_method = decltype(test(nullptr))::value; + +public: + // define a function IF the method exists + template + auto operator()(TYPE* p) const + -> std::enable_if_t, const char*> { + return p->sc_core::sc_module::name(); + } + + // define a function IF NOT the method exists + template + auto operator()(TYPE* p) const + -> std::enable_if_t, const char*> { + return nullptr; + } +}; + +// critical thing is that the initial if 'fails' as soon as possible - if it is +// going to pass, we have all the time we want, as we will be logging anyway +// This HAS to be done as a macro, because the first argument may be a string +// or a cache'd level + +/*** Helper macros for SCP_ report macros ****/ +#define SCP_VBSTY_CHECK_CACHED(lvl, features, cached, ...) \ + (cached.level >= lvl) && \ + (cached.get_log_verbosity_cached(scp::call_sc_name_fn()(this), \ + typeid(*this).name()) >= lvl) + +#define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) \ + (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) + +#define SCP_VBSTY_CHECK(lvl, ...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (SCP_VBSTY_CHECK_CACHED( \ + lvl, FIRST_ARG(__VA_ARGS__), \ + SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ + SCP_VBSTY_CHECK_UNCACHED(lvl, ##__VA_ARGS__)) + +#define SCP_GET_FEATURES(...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (FIRST_ARG EXPAND((POP_ARG( \ + __VA_ARGS__, \ + SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ + __VA_ARGS__) + +#ifdef FMT_SHARED +#define _SCP_FMT_EMPTY_STR(...) fmt::format(__VA_ARGS__) +#else +#define _SCP_FMT_EMPTY_STR(...) "Please add FMT library for FMT support." +#endif + +#define SCP_LOG(lvl, ...) \ + ::scp::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, lvl / 10) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ + << _SCP_FMT_EMPTY_STR +/*** End HELPER Macros *******/ + +//! macro for debug trace level output +#define SCP_TRACEALL(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_DEBUG, ##__VA_ARGS__)) \ + SCP_LOG(sc_core::SC_DEBUG, __VA_ARGS__) +//! macro for trace level output +#define SCP_TRACE(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_FULL, ##__VA_ARGS__)) \ + SCP_LOG(sc_core::SC_FULL, __VA_ARGS__) +//! macro for debug level output +#define SCP_DEBUG(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_HIGH, ##__VA_ARGS__)) \ + SCP_LOG(sc_core::SC_HIGH, __VA_ARGS__) +//! macro for info level output +#define SCP_INFO(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_MEDIUM, ##__VA_ARGS__)) \ + SCP_LOG(sc_core::SC_MEDIUM, __VA_ARGS__) +//! macro for warning level output +#define SCP_WARN(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_LOW, ##__VA_ARGS__)) \ + ::scp::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, \ + sc_core::SC_MEDIUM) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ + << _SCP_FMT_EMPTY_STR +//! macro for error level output +#define SCP_ERR(...) \ + ::scp::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, \ + sc_core::SC_MEDIUM) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ + << _SCP_FMT_EMPTY_STR +//! macro for fatal message output +#define SCP_FATAL(...) \ + ::scp::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, \ + sc_core::SC_MEDIUM) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ + << _SCP_FMT_EMPTY_STR + +#ifdef NDEBUG +#define SCP_ASSERT(expr) ((void)0) +#else +#define SCP_ASSERT(expr) \ + ((void)((expr) ? 0 \ + : (SC_REPORT_FATAL(::sc_core::SC_ID_ASSERTION_FAILED_, \ + #expr), \ + 0))) +#endif + +} // namespace scp +/** @} */ // end of scp-report +#endif /* _SCP_REPORT_H_ */ From 8c0d2922ad8578cb7d61e954b67bb07116e0a627 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 30 Nov 2024 15:28:39 +0100 Subject: [PATCH 08/17] Split CCI fixes Signed-off-by: Mark Burton --- report/include/scp/logger.h | 2 +- report/include/scp/report_cci_setter.h | 5 ++++- report/include/scp/sc_report.h | 6 ++++++ report/src/logger.cpp | 29 ++------------------------ report/src/report.cpp | 16 +++++++------- 5 files changed, 21 insertions(+), 37 deletions(-) diff --git a/report/include/scp/logger.h b/report/include/scp/logger.h index bfcb4ac..2a8c63f 100644 --- a/report/include/scp/logger.h +++ b/report/include/scp/logger.h @@ -17,7 +17,7 @@ #ifndef _SCP_LOGGER_H_ #define _SCP_LOGGER_H_ -#include "report.h" +#include "sc_report.h" /** \ingroup scp-report * @{ diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h index 9f6c8cf..95ea45f 100644 --- a/report/include/scp/report_cci_setter.h +++ b/report/include/scp/report_cci_setter.h @@ -20,11 +20,12 @@ #include #include #include +#include namespace scp { static std::set logging_parameters; -class scp_logger_from_cci +class scp_logger_from_cci : public scp_global_logger_handler { std::vector split(const std::string& s) const { std::vector result; @@ -152,6 +153,8 @@ class scp_logger_from_cci } }; +static scp_logger_from_cci _global_scp_logger_from_cci; + #if 0 /*template diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h index f230cc2..85db29e 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/scp/sc_report.h @@ -158,6 +158,12 @@ struct scp_logger_cache { sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); }; +struct scp_global_logger_handler : sc_core::sc_object { + virtual sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, + const char* scname, + const char* tname) const =0; +}; + inline sc_core::sc_verbosity get_log_verbosity() { return static_cast( ::sc_core::sc_report_handler::get_verbosity_level()); diff --git a/report/src/logger.cpp b/report/src/logger.cpp index 07327ff..1014d6a 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -27,7 +27,9 @@ #include #include #ifdef HAS_CCI +#include #include +#include "scp/report_cci_setter.h" #endif #include #include @@ -336,26 +338,6 @@ void report_handler(const sc_core::sc_report& rep, // } } // namespace -static const std::array severity = { - sc_core::SC_FATAL, // scp::log::NONE - sc_core::SC_FATAL, // scp::log::FATAL - sc_core::SC_ERROR, // scp::log::ERROR - sc_core::SC_WARNING, // scp::log::WARNING - sc_core::SC_INFO, // scp::log::INFO - sc_core::SC_INFO, // scp::log::DEBUG - sc_core::SC_INFO, // scp::log::TRACE - sc_core::SC_INFO // scp::log::TRACEALL -}; -static const std::array verbosity = { - sc_core::SC_NONE, // scp::log::NONE - sc_core::SC_LOW, // scp::log::FATAL - sc_core::SC_LOW, // scp::log::ERROR - sc_core::SC_LOW, // scp::log::WARNING - sc_core::SC_MEDIUM, // scp::log::INFO - sc_core::SC_HIGH, // scp::log::DEBUG - sc_core::SC_FULL, // scp::log::TRACE - sc_core::SC_DEBUG // scp::log::TRACEALL -}; static std::mutex cfg_guard; static void configure_logging() { std::lock_guard lock(cfg_guard); @@ -528,11 +510,4 @@ auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& { auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { this->file_info_from = v; return *this; -} -auto scp::LogConfig::registerLogLevelFn( - std::function - fn) -> scp::LogConfig& { - this->log_level_lookup_fn = fn; - return *this; } \ No newline at end of file diff --git a/report/src/report.cpp b/report/src/report.cpp index dff44a9..50d1d93 100644 --- a/report/src/report.cpp +++ b/report/src/report.cpp @@ -21,14 +21,9 @@ */ #include -#include -#include #include -#include -#include -#include -#include #include + #if defined(__GNUC__) || defined(__clang__) #define likely(x) __builtin_expect(x, 1) #define unlikely(x) __builtin_expect(x, 0) @@ -78,8 +73,13 @@ sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( type = std::string(scname); - if (log_cfg.log_level_lookup_fn) { - return log_cfg.log_level_lookup_fn(*this, scname, tname); + // find the first suitable registered sc_object that can handle the lookup + for (auto o : sc_core::sc_get_top_level_objects()) { + auto* h = dynamic_cast(o); + if (h) { + auto& h_ref = *h; + return h_ref(*this, scname, tname); + } } return level = static_cast( From 62601bed207e7db8e912849c3b2426c8e3b395c0 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Mon, 2 Dec 2024 10:27:05 +0100 Subject: [PATCH 09/17] update dependencies and cleanup Signed-off-by: Mark Burton --- .clang-format | 14 +- examples/smoke.cc | 3 +- examples/smoke_logger.cc | 38 +-- examples/smoke_report.cc | 15 +- report/CMakeLists.txt | 31 +-- report/include/scp/helpers.h | 6 +- report/include/scp/logger.h | 3 +- report/include/scp/report.h | 29 +- report/include/scp/report_cci_setter.h | 182 ++----------- report/include/scp/sc_report.h | 205 ++++++-------- report/src/logger.cpp | 248 ++++++++--------- report/src/{report.cpp => sc_report.cpp} | 27 +- report/tests/CMakeLists.txt | 11 + report/tests/logger.cc | 250 ++++++++++++++++++ .../include/scp/tlm_extensions/initiator_id.h | 19 +- tlm_extensions/initiator_id/tests/smoke.cc | 3 +- .../include/scp/tlm_extensions/path_trace.h | 10 +- tlm_extensions/path_trace/tests/smoke.cc | 3 +- 18 files changed, 598 insertions(+), 499 deletions(-) rename report/src/{report.cpp => sc_report.cpp} (85%) create mode 100644 report/tests/CMakeLists.txt create mode 100644 report/tests/logger.cc diff --git a/.clang-format b/.clang-format index 9efc891..ea0ba51 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ Language: Cpp BasedOnStyle: Google -ColumnLimit: 79 +ColumnLimit: 120 UseTab: Never IndentWidth: 4 IndentCaseLabels: false @@ -17,19 +17,23 @@ AlignConsecutiveMacros: true AlignConsecutiveAssignments: false AllowAllArgumentsOnNextLine: false -AllowShortFunctionsOnASingleLine: InlineOnly -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AllowShortLambdasOnASingleLine: true -BreakConstructorInitializers: AfterColon +BreakConstructorInitializers: BeforeComma BreakBeforeBinaryOperators: None BreakStringLiterals: true BreakBeforeBraces: Custom BraceWrapping: AfterClass: true + AfterFunction: true +# PackConstructorInitializers: Never # When we have clang14 SpaceBeforeCtorInitializerColon: false SpacesBeforeTrailingComments: 1 +AlignTrailingComments: true SortIncludes: false SortUsingDeclarations: false diff --git a/examples/smoke.cc b/examples/smoke.cc index 9d6aa5c..419e6a5 100644 --- a/examples/smoke.cc +++ b/examples/smoke.cc @@ -48,7 +48,8 @@ SC_MODULE (test) { } }; -int sc_main(int argc, char** argv) { +int sc_main(int argc, char** argv) +{ SCP_INFO() << "Constructing design"; test test1("test"); SCP_INFO() << "Starting simulation"; diff --git a/examples/smoke_logger.cc b/examples/smoke_logger.cc index 7922457..27d0e04 100644 --- a/examples/smoke_logger.cc +++ b/examples/smoke_logger.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,8 @@ SC_MODULE (test3) { }; SC_MODULE (test2) { - SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") { + SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") + { SCP_INFO(()) << " T2 Logger()"; SCP_WARN(()) << " T2 Logger()"; } @@ -58,7 +60,8 @@ SC_MODULE (test2) { }; SC_MODULE (test1) { - SC_CTOR (test1) : t2("t2") { + SC_CTOR (test1) : t2("t2") + { SCP_WARN((), "My.Name") << " T1 My.Name typed log"; SCP_INFO(()) << " T1 Logger()"; SCP_WARN(()) << " T1 Logger()"; @@ -81,7 +84,8 @@ class outside_class SCP_LOGGER("out.class", "thing1"); public: - outside_class() { + outside_class() + { SCP_INFO(())("constructor"); SCP_WARN(())("constructor"); } @@ -119,8 +123,7 @@ SC_MODULE (test) { SCP_INFO() << "Globally cached version empty"; SCP_INFO(())("FMT String : Locally cached version default"); SCP_INFO(SCMOD) << "Globally cached version feature using SCMOD macro"; - SCP_INFO((m_my_logger)) - << "Locally cached version using (m_my_logger)"; + SCP_INFO((m_my_logger)) << "Locally cached version using (m_my_logger)"; SCP_INFO((D)) << "Locally cached version with D"; } @@ -130,7 +133,8 @@ SC_MODULE (test) { SCP_LOGGER((D), "other", "feature.one"); }; -int sc_main(int argc, char** argv) { +int sc_main(int argc, char** argv) +{ cci_utils::consuming_broker broker("global_broker"); cci_register_broker(broker); cci::cci_originator orig("config"); @@ -142,16 +146,15 @@ int sc_main(int argc, char** argv) { broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); - std::string logfile = "/tmp/scp_smoke_report_test." + - std::to_string(getpid()); - scp::init_logging( - scp::LogConfig() - .logLevel(scp::log::DEBUG) // set log level to debug - .msgTypeFieldWidth(20) - .fileInfoFrom(5) - .logAsync(false) - .printSimTime(false) - .logFileName(logfile)); // make the msg type column a bit tighter + std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); + scp::scp_logger_from_cci cci_logger; + scp::init_logging(scp::LogConfig() + .logLevel(scp::log::DEBUG) // set log level to debug + .msgTypeFieldWidth(20) + .fileInfoFrom(5) + .logAsync(false) + .printSimTime(false) + .logFileName(logfile)); // make the msg type column a bit tighter SCP_INFO() << "Constructing design"; test toptest("top"); test1 t1("t1"); @@ -203,8 +206,7 @@ int sc_main(int argc, char** argv) { )"; std::ifstream lf(logfile); - std::string out((std::istreambuf_iterator(lf)), - std::istreambuf_iterator()); + std::string out((std::istreambuf_iterator(lf)), std::istreambuf_iterator()); std::cout << "out file\n" << out << "\n"; std::cout << "expected\n" << expected << "\n"; diff --git a/examples/smoke_report.cc b/examples/smoke_report.cc index e42aeb6..9b2ee5c 100644 --- a/examples/smoke_report.cc +++ b/examples/smoke_report.cc @@ -47,7 +47,8 @@ SC_MODULE (test3) { }; SC_MODULE (test2) { - SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") { + SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") + { SCP_INFO(()) << " T2 Logger()"; SCP_WARN(()) << " T2 Logger()"; } @@ -57,7 +58,8 @@ SC_MODULE (test2) { }; SC_MODULE (test1) { - SC_CTOR (test1) : t2("t2") { + SC_CTOR (test1) : t2("t2") + { SCP_WARN((), "My.Name") << " T1 My.Name typed log"; SCP_INFO(()) << " T1 Logger()"; SCP_WARN(()) << " T1 Logger()"; @@ -80,7 +82,8 @@ class outside_class SCP_LOGGER("out.class", "thing1"); public: - outside_class() { + outside_class() + { SCP_INFO(())("constructor"); SCP_WARN(())("constructor"); } @@ -128,7 +131,8 @@ SC_MODULE (test) { SCP_LOGGER((D), "other", "feature.one"); }; -int sc_main(int argc, char** argv) { +int sc_main(int argc, char** argv) +{ cci_utils::consuming_broker broker("global_broker"); cci_register_broker(broker); cci::cci_originator orig("config"); @@ -140,8 +144,7 @@ int sc_main(int argc, char** argv) { broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); - std::string logfile = "/tmp/scp_smoke_report_test." + - std::to_string(getpid()); + std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); SCP_INFO() << "Constructing design"; test toptest("top"); test1 t1("t1"); diff --git a/report/CMakeLists.txt b/report/CMakeLists.txt index 6b355c3..8497c59 100644 --- a/report/CMakeLists.txt +++ b/report/CMakeLists.txt @@ -8,15 +8,13 @@ set(GITHUB "https://github.com/" CACHE STRING "github base url") include(FetchContent) include(CTest) -FetchContent_Declare( - cpm-cmake - GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git - GIT_SHALLOW True - GIT_TAG v0.31.1 +# download CPM.cmake +file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.2/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake ) - -FetchContent_MakeAvailable(cpm-cmake) -include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) +include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") @@ -60,7 +58,7 @@ if(WITH_FMT) NAME fmt GIT_REPOSITORY ${GITHUB}fmtlib/fmt.git GIT_SHALLOW True - GIT_TAG 9.1.0 + GIT_TAG 11.0.2 OPTIONS FMT_INSTALL "" ON ) endif() @@ -68,17 +66,17 @@ endif() FetchContent_Declare( spdlog_git GIT_REPOSITORY "https://github.com/gabime/spdlog.git" - GIT_TAG "v1.9.2" + GIT_TAG "v1.15.0" GIT_SHALLOW ON ) -FetchContent_Populate(spdlog_git) +FetchContent_MakeAvailable(spdlog_git) FetchContent_GetProperties( spdlog_git SOURCE_DIR spdlog_git_SRC_DIR POPULATED spdlog_git_FOUND ) -add_library(${PROJECT_NAME} src/report.cpp src/logger.cpp) +add_library(${PROJECT_NAME} src/sc_report.cpp src/logger.cpp) target_include_directories( ${PROJECT_NAME} PUBLIC $ @@ -92,7 +90,6 @@ endif() target_include_directories(${PROJECT_NAME} PRIVATE ${spdlog_git_SRC_DIR}/include) if(TARGET SystemC::cci) - target_compile_definitions(${PROJECT_NAME} PRIVATE HAS_CCI) target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::cci) endif() @@ -100,10 +97,10 @@ target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::systemc) set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) # No tests yet. WIP. -# if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) -# enable_testing() -# add_subdirectory(tests) -# endif() +if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) +enable_testing() +add_subdirectory(tests) +endif() add_library("scp::report::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) packageproject( NAME "${PROJECT_NAME}" diff --git a/report/include/scp/helpers.h b/report/include/scp/helpers.h index d05bf6e..463f9b7 100644 --- a/report/include/scp/helpers.h +++ b/report/include/scp/helpers.h @@ -22,7 +22,8 @@ #include namespace scp { -static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) { +static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) +{ std::stringstream info; const char* cmd = "UNKOWN"; switch (trans.get_command()) { @@ -42,8 +43,7 @@ static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) { unsigned char* ptr = trans.get_data_ptr(); info << " data: 0x"; for (int i = trans.get_data_length(); i; i--) { - info << std::setw(2) << std::setfill('0') << std::hex - << (unsigned int)(ptr[i - 1]); + info << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)(ptr[i - 1]); } info << " status: " << trans.get_response_string() << " "; for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) { diff --git a/report/include/scp/logger.h b/report/include/scp/logger.h index 2a8c63f..c44095d 100644 --- a/report/include/scp/logger.h +++ b/report/include/scp/logger.h @@ -34,8 +34,7 @@ namespace scp { * @param type_field_width the with of the type field in the output * @param print_time whether to print the system time stamp */ -void init_logging(log level = log::WARNING, unsigned type_field_width = 24, - bool print_time = false); +void init_logging(log level = log::WARNING, unsigned type_field_width = 24, bool print_time = false); /** * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) * @brief initializes the SystemC logging system with a particular logging diff --git a/report/include/scp/report.h b/report/include/scp/report.h index a962eaf..42c3b59 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -1,5 +1,32 @@ -/* this is merely a convenience */ +/* this is merely a convenience to maintain the old API's */ #include "scp/sc_report.h" #include "scp/helpers.h" #include "scp/logger.h" + +#ifdef FMT_SHARED +#ifndef _FMT_CONVENIENCE_DEFINED +#define _FMT_CONVENIENCE_DEFINED +#include + +/* Convenience for common SystemC useage */ +// Allows Join to be used on vectors etc. +#include +// cover 'std' types +#include +// Make all enum's behave like their underlying types by default +#include +template +struct fmt::formatter>, char>> : fmt::formatter { + auto format(E e, format_context& ctx) const { return formatter::format("Test", ctx); } +}; +#endif // _FMT_CONVENIENCE_DEFINED +#endif + +#ifdef HAS_CCI +#ifndef _GLOBAL_SCP_LOGGER_FROM_CCI_DEFINED +#define _GLOBAL_SCP_LOGGER_FROM_CCI_DEFINED +#include "scp/report_cci_setter.h" +static scp::scp_logger_from_cci _global_scp_logger_from_cci; +#endif // _GLOBAL_SCP_LOGGER_FROM_CCI_DEFINED +#endif diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h index 95ea45f..01ba463 100644 --- a/report/include/scp/report_cci_setter.h +++ b/report/include/scp/report_cci_setter.h @@ -27,7 +27,8 @@ static std::set logging_parameters; class scp_logger_from_cci : public scp_global_logger_handler { - std::vector split(const std::string& s) const { + std::vector split(const std::string& s) const + { std::vector result; std::istringstream iss(s); std::string item; @@ -37,18 +38,17 @@ class scp_logger_from_cci : public scp_global_logger_handler return result; } - std::string join(std::vector vec) const { - if (vec.empty()) - return ""; - return std::accumulate( - vec.begin(), vec.end(), std::string(), - [](const std::string& a, const std::string& b) -> std::string { - return a + (a.length() > 0 ? "." : "") + b; - }); + std::string join(std::vector vec) const + { + if (vec.empty()) return ""; + return std::accumulate(vec.begin(), vec.end(), std::string(), + [](const std::string& a, const std::string& b) -> std::string { + return a + (a.length() > 0 ? "." : "") + b; + }); } - void insert(std::multimap>& map, - std::string s, bool interesting) const { + void insert(std::multimap>& map, std::string s, bool interesting) const + { int n = std::count(s.begin(), s.end(), '.'); map.insert(make_pair(n, s)); @@ -56,34 +56,30 @@ class scp_logger_from_cci : public scp_global_logger_handler logging_parameters.insert(s + "." SCP_LOG_LEVEL_PARAM_NAME); } } - sc_core::sc_verbosity cci_lookup(cci::cci_broker_handle broker, - std::string name) const { - auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME - : name + "." SCP_LOG_LEVEL_PARAM_NAME; + sc_core::sc_verbosity cci_lookup(cci::cci_broker_handle broker, std::string name) const + { + auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME : name + "." SCP_LOG_LEVEL_PARAM_NAME; auto h = broker.get_param_handle(param_name); if (h.is_valid()) { - return verbosity.at(std::min(h.get_cci_value().get_int(), - verbosity.size() - 1)); + return verbosity.at(std::min(h.get_cci_value().get_int(), verbosity.size() - 1)); } else { auto val = broker.get_preset_cci_value(param_name); if (val.is_int()) { broker.lock_preset_value(param_name); - return verbosity.at( - std::min(val.get_int(), verbosity.size() - 1)); + return verbosity.at(std::min(val.get_int(), verbosity.size() - 1)); } } return sc_core::SC_UNSET; } #ifdef __GNUG__ - std::string demangle(const char* name) const { + std::string demangle(const char* name) const + { int status = -4; // some arbitrary value to eliminate the compiler // warning // enable c++11 by passing the flag -std=c++11 to g++ - std::unique_ptr res{ - abi::__cxa_demangle(name, NULL, NULL, &status), std::free - }; + std::unique_ptr res{ abi::__cxa_demangle(name, NULL, NULL, &status), std::free }; return (status == 0) ? res.get() : name; } @@ -92,15 +88,13 @@ class scp_logger_from_cci : public scp_global_logger_handler std::string demangle(const char* name) { return name; } #endif public: - sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, - const char* scname, - const char* tname) const { + sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, const char* scname, const char* tname) const + { try { // we rely on there being a broker, allow this to throw if not auto broker = sc_core::sc_get_current_object() ? cci::cci_get_broker() - : cci::cci_get_global_broker(cci::cci_originator( - "scp_reporting_global")); + : cci::cci_get_global_broker(cci::cci_originator("scp_reporting_global")); std::multimap> allfeatures; @@ -112,14 +106,11 @@ class scp_logger_from_cci : public scp_global_logger_handler auto scn_str = ((first > 0) ? "*." : "") + join(p); for (auto ft : logger.features) { - for (auto ftn = split(ft); ftn.size(); - ftn.pop_back()) { - insert(allfeatures, scn_str + "." + join(ftn), - first == 0); + for (auto ftn = split(ft); ftn.size(); ftn.pop_back()) { + insert(allfeatures, scn_str + "." + join(ftn), first == 0); } } - insert(allfeatures, scn_str + "." + demangle(tname), - first == 0); + insert(allfeatures, scn_str + "." + demangle(tname), first == 0); insert(allfeatures, scn_str, first == 0); } } @@ -144,129 +135,14 @@ class scp_logger_from_cci : public scp_global_logger_handler // If there is no global broker, revert to initialized verbosity // level } - return logger.level = static_cast( - ::sc_core::sc_report_handler::get_verbosity_level()); + return logger.level = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); } - static std::vector get_logging_parameters() { - return std::vector(logging_parameters.begin(), - logging_parameters.end()); + static std::vector get_logging_parameters() + { + return std::vector(logging_parameters.begin(), logging_parameters.end()); } }; -static scp_logger_from_cci _global_scp_logger_from_cci; - -#if 0 - -/*template -struct HasLogger : std::false_type { }; - -template -struct HasLogger : std::true_type -{ }; -*/ - -class set_logger_level -{ - template - static auto test(T* p) -> decltype(p->SCP_LOGGER_NAME(), std::true_type()); - template - static auto test(...) -> decltype(std::false_type()); - - template - static constexpr bool has_logger = decltype(test(nullptr))::value; - -public: - // define a function IF the method exists - template - auto operator()(TYPE* p, sc_core::sc_verbosity level) const - -> std::enable_if_t> { - p->SCP_LOGGER_NAME().level = level; - } - - // define a function IF NOT the method exists - template - auto operator()(TYPE* p, sc_core::sc_verbosity level) const - -> std::enable_if_t> {} -}; - -int set_log_levels(std::string path, sc_core::sc_verbosity level, - sc_core::sc_object* m = nullptr, bool set = false) { - int found = 0; - auto pathdot = path.find_first_of('.'); - auto lpath = (pathdot != std::string::npos) ? path.substr(pathdot) : path; - - if (m) { - std::string mname = std::string(m->name()); - auto namedot = mname.find_last_of('.'); - auto lname = (namedot != std::string::npos) ? mname.substr(namedot) - : mname; - - if (!((lpath == "*") || (lpath == lname))) { - // no match here - return found; - } - } - if (path.substr(pathdot) == SCP_LOG_LEVEL_PARAM_NAME) { - // Found it - set = true; - } - - if (set) { - found++; - scp::set_logger_level()(m, level); - } - std::vector children; - if (m) { - children = m->get_child_objects(); - } else { - children = sc_core::sc_get_top_level_objects(); - } - - for (auto c : children) { - if (lpath == "*") { - found += set_log_levels(path, level, c, set); - } - if (pathdot != std::string::npos) { - found += set_log_levels(path.substr(pathdot), level, c, set); - } - } - return found; -}; - -void cci_enable_logging(cci::cci_broker_handle broker) { - std::string pname = std::string(".") + SCP_LOG_LEVEL_PARAM_NAME; - int plen = std::string(SCP_LOG_LEVEL_PARAM_NAME).length(); - std::vector logging_paths; - for (auto path : broker.get_unconsumed_preset_values( - [&plen](const std::pair& iv) { - if (iv.first.length() >= plen) { - return (0 == iv.first.compare(iv.first.length() - plen, - plen, - SCP_LOG_LEVEL_PARAM_NAME)); - } else { - return false; - } - })) { - logging_paths.push_back(path); - } - - std::sort(logging_paths.begin(), logging_paths.end(), - [&](cci::cci_name_value_pair& s1, cci::cci_name_value_pair& s2) { - return std::count(s1.first.begin(), s1.first.end(), '.') > - std::count(s2.first.begin(), s2.first.end(), '.'); - }); - for (auto path : logging_paths) { - int found = set_log_levels( - path.first, (sc_core::sc_verbosity)(path.second.get_int())); - if (found == 0) { - SCP_WARN()("No logger named {} found", path.first); - } else { - SCP_INFO()("{} loggers enabled from name {}", found, path.first); - } - } -} -#endif - } // namespace scp #endif \ No newline at end of file diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h index 85db29e..380fc34 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/scp/sc_report.h @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ - +/* + * + * THIS FILE IS INTENDED TO BE UP-STREAMED + */ #ifndef _SCP_REPORT_H_ #define _SCP_REPORT_H_ @@ -32,10 +35,6 @@ #include #include -#ifdef FMT_SHARED -#include -#endif - #if defined(_MSC_VER) && defined(ERROR) #undef ERROR #endif @@ -77,22 +76,10 @@ static const char* _SCP_FMT_EMPTY_STR = ""; //! @brief reporting utilities namespace scp { //! \brief array holding string representations of log levels -static std::array buffer = { - { "NONE", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", - "TRACEALL" } -}; +static std::array buffer = { { "NONE", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", + "TRACEALL" } }; //! \brief enum defining the log levels -enum class log { - NONE, - FATAL, - ERROR, - WARNING, - INFO, - DEBUG, - TRACE, - TRACEALL, - DBGTRACE = TRACEALL -}; +enum class log { NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE, TRACEALL, DBGTRACE = TRACEALL }; /** * @fn log as_log(int) @@ -101,12 +88,11 @@ enum class log { * @param logLevel the logging level * @return the log level */ -inline log as_log(int logLevel) { - assert(logLevel >= static_cast(log::NONE) && - logLevel <= static_cast(log::TRACEALL)); - std::array m = { { log::NONE, log::FATAL, log::ERROR, - log::WARNING, log::INFO, log::DEBUG, - log::TRACE, log::TRACEALL } }; +inline log as_log(int logLevel) +{ + assert(logLevel >= static_cast(log::NONE) && logLevel <= static_cast(log::TRACEALL)); + std::array m = { { log::NONE, log::FATAL, log::ERROR, log::WARNING, log::INFO, log::DEBUG, log::TRACE, + log::TRACEALL } }; return m[logLevel]; } /** @@ -117,7 +103,8 @@ inline log as_log(int logLevel) { * @param val the value holding the resulting value * @return the input stream */ -inline std::istream& operator>>(std::istream& is, log& val) { +inline std::istream& operator>>(std::istream& is, log& val) +{ std::string buf; is >> buf; for (auto i = 0U; i <= static_cast(log::TRACEALL); ++i) { @@ -136,7 +123,8 @@ inline std::istream& operator>>(std::istream& is, log& val) { * @param val logging level * @return reference to the stream for chaining */ -inline std::ostream& operator<<(std::ostream& os, log const& val) { +inline std::ostream& operator<<(std::ostream& os, log const& val) +{ os << buffer[static_cast(val)]; return os; } @@ -158,15 +146,14 @@ struct scp_logger_cache { sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); }; -struct scp_global_logger_handler : sc_core::sc_object { - virtual sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, - const char* scname, - const char* tname) const =0; +struct scp_global_logger_handler : sc_core::sc_object { + virtual sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, const char* scname, + const char* tname) const = 0; }; -inline sc_core::sc_verbosity get_log_verbosity() { - return static_cast( - ::sc_core::sc_report_handler::get_verbosity_level()); +inline sc_core::sc_verbosity get_log_verbosity() +{ + return static_cast(::sc_core::sc_report_handler::get_verbosity_level()); } /** * @fn sc_core::sc_verbosity get_log_verbosity(const char*) @@ -191,9 +178,7 @@ sc_core::sc_verbosity get_log_verbosity(char const* t); * @param t the SystemC hierarchy scope name * @return the verbosity level */ -inline sc_core::sc_verbosity get_log_verbosity(std::string const& t) { - return get_log_verbosity(t.c_str()); -} +inline sc_core::sc_verbosity get_log_verbosity(std::string const& t) { return get_log_verbosity(t.c_str()); } /** * @brief Return list of logging parameters that have been used @@ -220,8 +205,10 @@ struct ScLogger { * @param line number where the log entry originates * @param verbosity the log level */ - ScLogger(const char* file, int line, int verbosity = sc_core::SC_MEDIUM): - t(nullptr), file(file), line(line), level(verbosity){}; + ScLogger(const char* file, int line, int verbosity = sc_core::SC_MEDIUM) + : t(nullptr), file(file), line(line), level(verbosity) + { + } ScLogger() = delete; @@ -237,9 +224,9 @@ struct ScLogger { * @brief the destructor generating the SystemC report * */ - virtual ~ScLogger() { - ::sc_core::sc_report_handler::report( - SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); + virtual ~ScLogger() + { + ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); } /** * @fn ScLogger& type() @@ -247,7 +234,8 @@ struct ScLogger { * * @return reference to self for chaining */ - inline ScLogger& type() { + inline ScLogger& type() + { this->t = nullptr; return *this; } @@ -258,7 +246,8 @@ struct ScLogger { * @param t type of th elog entry * @return reference to self for chaining */ - inline ScLogger& type(char const* t) { + inline ScLogger& type(char const* t) + { this->t = const_cast(t); return *this; } @@ -269,7 +258,8 @@ struct ScLogger { * @param t type of th elog entry * @return reference to self for chaining */ - inline ScLogger& type(std::string const& t) { + inline ScLogger& type(std::string const& t) + { this->t = const_cast(t.c_str()); return *this; } @@ -324,25 +314,21 @@ struct ScLogger { /* User interface macros */ #define SCMOD this->sc_core::sc_module::name() -#define SCP_LOGGER(...) \ - scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ - SCP_LOGGER_NAME()) = { sc_core::SC_UNSET, \ - "", \ - { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ - POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } - -#define SCP_LOGGER_VECTOR(NAME) \ - std::vector SCP_LOGGER_NAME(NAME) +#define SCP_LOGGER(...) \ + scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ + SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ + SCP_LOGGER_NAME()) = { sc_core::SC_UNSET, \ + "", \ + { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))(POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } + +#define SCP_LOGGER_VECTOR(NAME) std::vector SCP_LOGGER_NAME(NAME) #define SCP_LOGGER_VECTOR_PUSH_BACK(NAME, ...) \ - SCP_LOGGER_NAME(NAME).push_back( \ - { sc_core::SC_UNSET, "", { __VA_ARGS__ } }); + SCP_LOGGER_NAME(NAME).push_back({ sc_core::SC_UNSET, "", { __VA_ARGS__ } }); class call_sc_name_fn { template - static auto test(T* p) - -> decltype(p->sc_core::sc_module::name(), std::true_type()); + static auto test(T* p) -> decltype(p->sc_core::sc_module::name(), std::true_type()); template static auto test(...) -> decltype(std::false_type()); @@ -352,15 +338,15 @@ class call_sc_name_fn public: // define a function IF the method exists template - auto operator()(TYPE* p) const - -> std::enable_if_t, const char*> { + auto operator()(TYPE* p) const -> std::enable_if_t, const char*> + { return p->sc_core::sc_module::name(); } // define a function IF NOT the method exists template - auto operator()(TYPE* p) const - -> std::enable_if_t, const char*> { + auto operator()(TYPE* p) const -> std::enable_if_t, const char*> + { return nullptr; } }; @@ -371,26 +357,20 @@ class call_sc_name_fn // or a cache'd level /*** Helper macros for SCP_ report macros ****/ -#define SCP_VBSTY_CHECK_CACHED(lvl, features, cached, ...) \ - (cached.level >= lvl) && \ - (cached.get_log_verbosity_cached(scp::call_sc_name_fn()(this), \ - typeid(*this).name()) >= lvl) - -#define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) \ - (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) - -#define SCP_VBSTY_CHECK(lvl, ...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (SCP_VBSTY_CHECK_CACHED( \ - lvl, FIRST_ARG(__VA_ARGS__), \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ +#define SCP_VBSTY_CHECK_CACHED(lvl, features, cached, ...) \ + (cached.level >= lvl) && \ + (cached.get_log_verbosity_cached(scp::call_sc_name_fn()(this), typeid(*this).name()) >= lvl) + +#define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) + +#define SCP_VBSTY_CHECK(lvl, ...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (SCP_VBSTY_CHECK_CACHED(lvl, FIRST_ARG(__VA_ARGS__), SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ SCP_VBSTY_CHECK_UNCACHED(lvl, ##__VA_ARGS__)) -#define SCP_GET_FEATURES(...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (FIRST_ARG EXPAND((POP_ARG( \ - __VA_ARGS__, \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ +#define SCP_GET_FEATURES(...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (FIRST_ARG EXPAND((POP_ARG(__VA_ARGS__, SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ __VA_ARGS__) #ifdef FMT_SHARED @@ -399,60 +379,47 @@ class call_sc_name_fn #define _SCP_FMT_EMPTY_STR(...) "Please add FMT library for FMT support." #endif -#define SCP_LOG(lvl, ...) \ - ::scp::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, lvl / 10) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ +#define SCP_LOG(lvl, ...) \ + ::scp::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, lvl / 10).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ << _SCP_FMT_EMPTY_STR /*** End HELPER Macros *******/ //! macro for debug trace level output -#define SCP_TRACEALL(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_DEBUG, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_DEBUG, __VA_ARGS__) +#define SCP_TRACEALL(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_DEBUG, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_DEBUG, __VA_ARGS__) //! macro for trace level output -#define SCP_TRACE(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_FULL, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_FULL, __VA_ARGS__) +#define SCP_TRACE(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_FULL, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_FULL, __VA_ARGS__) //! macro for debug level output -#define SCP_DEBUG(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_HIGH, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_HIGH, __VA_ARGS__) +#define SCP_DEBUG(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_HIGH, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_HIGH, __VA_ARGS__) //! macro for info level output -#define SCP_INFO(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_MEDIUM, ##__VA_ARGS__)) \ - SCP_LOG(sc_core::SC_MEDIUM, __VA_ARGS__) +#define SCP_INFO(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_MEDIUM, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_MEDIUM, __VA_ARGS__) //! macro for warning level output -#define SCP_WARN(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_LOW, ##__VA_ARGS__)) \ - ::scp::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, \ - sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ +#define SCP_WARN(...) \ + if (SCP_VBSTY_CHECK(sc_core::SC_LOW, ##__VA_ARGS__)) \ + ::scp::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, sc_core::SC_MEDIUM) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ << _SCP_FMT_EMPTY_STR //! macro for error level output -#define SCP_ERR(...) \ - ::scp::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, \ - sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ +#define SCP_ERR(...) \ + ::scp::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, sc_core::SC_MEDIUM) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ << _SCP_FMT_EMPTY_STR //! macro for fatal message output -#define SCP_FATAL(...) \ - ::scp::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, \ - sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ +#define SCP_FATAL(...) \ + ::scp::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, sc_core::SC_MEDIUM) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ << _SCP_FMT_EMPTY_STR #ifdef NDEBUG #define SCP_ASSERT(expr) ((void)0) #else -#define SCP_ASSERT(expr) \ - ((void)((expr) ? 0 \ - : (SC_REPORT_FATAL(::sc_core::SC_ID_ASSERTION_FAILED_, \ - #expr), \ - 0))) +#define SCP_ASSERT(expr) ((void)((expr) ? 0 : (SC_REPORT_FATAL(::sc_core::SC_ID_ASSERTION_FAILED_, #expr), 0))) #endif } // namespace scp diff --git a/report/src/logger.cpp b/report/src/logger.cpp index 1014d6a..ab9c606 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -26,11 +26,6 @@ #include #include #include -#ifdef HAS_CCI -#include -#include -#include "scp/report_cci_setter.h" -#endif #include #include #include @@ -68,7 +63,8 @@ struct ExtLogConfig : public scp::LogConfig { std::shared_ptr console_logger; std::regex reg_ex; sc_core::sc_time cycle_base{ 0, sc_core::SC_NS }; - auto operator=(const scp::LogConfig& o) -> ExtLogConfig& { + auto operator=(const scp::LogConfig& o) -> ExtLogConfig& + { scp::LogConfig::operator=(o); return *this; } @@ -85,15 +81,13 @@ ExtLogConfig log_cfg; thread_local ExtLogConfig log_cfg; #endif -inline std::string padded(std::string str, size_t width, - bool show_ellipsis = true) { - if (width < 7) - return str; +inline std::string padded(std::string str, size_t width, bool show_ellipsis = true) +{ + if (width < 7) return str; if (str.length() > width) { if (show_ellipsis) { auto pos = str.size() - (width - 6); - return str.substr(0, 3) + "..." + - str.substr(pos, str.size() - pos); + return str.substr(0, 3) + "..." + str.substr(pos, str.size() - pos); } else return str.substr(0, width); } else { @@ -101,8 +95,8 @@ inline std::string padded(std::string str, size_t width, } } -auto get_tuple(const sc_core::sc_time& t) - -> std::tuple { +auto get_tuple(const sc_core::sc_time& t) -> std::tuple +{ auto val = t.value(); auto tr = (uint64_t)(sc_core::sc_time::from_value(1).to_seconds() * 1E15); auto scale = 0U; @@ -118,21 +112,19 @@ auto get_tuple(const sc_core::sc_time& t) scale++; tu += (0 == (scale % 3)); } - for (scale %= 3; scale != 0; scale--) - val *= 10; + for (scale %= 3; scale != 0; scale--) val *= 10; return std::make_tuple(val, static_cast(tu)); } -auto time2string(const sc_core::sc_time& t) -> std::string { - const std::array time_units{ "fs", "ps", "ns", - "us", "ms", "s " }; +auto time2string(const sc_core::sc_time& t) -> std::string +{ + const std::array time_units{ "fs", "ps", "ns", "us", "ms", "s " }; const std::array multiplier{ 1ULL, 1000ULL, 1000ULL * 1000, 1000ULL * 1000 * 1000, 1000ULL * 1000 * 1000 * 1000, - 1000ULL * 1000 * 1000 * 1000 * - 1000 }; + 1000ULL * 1000 * 1000 * 1000 * 1000 }; std::ostringstream oss; if (!t.value()) { oss << "0 s "; @@ -145,8 +137,7 @@ auto time2string(const sc_core::sc_time& t) -> std::string { if (fs_val >= multiplier[j]) { const auto i = val / multiplier[j - scale]; const auto f = val % multiplier[j - scale]; - oss << i << '.' << std::setw(3 * (j - scale)) - << std::setfill('0') << std::right << f << ' ' + oss << i << '.' << std::setw(3 * (j - scale)) << std::setfill('0') << std::right << f << ' ' << time_units[j]; break; } @@ -154,59 +145,46 @@ auto time2string(const sc_core::sc_time& t) -> std::string { } return oss.str(); } -auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) - -> const std::string { - if (rep.get_severity() > sc_core::SC_INFO || - cfg.log_filter_regex.length() == 0 || - rep.get_verbosity() == sc_core::SC_MEDIUM || - log_cfg.match(rep.get_msg_type())) { +auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) -> const std::string +{ + if (rep.get_severity() > sc_core::SC_INFO || cfg.log_filter_regex.length() == 0 || + rep.get_verbosity() == sc_core::SC_MEDIUM || log_cfg.match(rep.get_msg_type())) { std::stringstream os; if (likely(cfg.print_sim_time)) { if (unlikely(log_cfg.cycle_base.value())) { if (unlikely(cfg.print_delta)) os << "[" << std::setw(7) << std::setfill(' ') - << sc_core::sc_time_stamp().value() / - log_cfg.cycle_base.value() - << "(" << std::setw(5) << sc_core::sc_delta_count() - << ")]"; + << sc_core::sc_time_stamp().value() / log_cfg.cycle_base.value() << "(" << std::setw(5) + << sc_core::sc_delta_count() << ")]"; else os << "[" << std::setw(7) << std::setfill(' ') - << sc_core::sc_time_stamp().value() / - log_cfg.cycle_base.value() - << "]"; + << sc_core::sc_time_stamp().value() / log_cfg.cycle_base.value() << "]"; } else { auto t = time2string(sc_core::sc_time_stamp()); if (unlikely(cfg.print_delta)) - os << "[" << std::setw(20) << std::setfill(' ') << t << "(" - << std::setw(5) << sc_core::sc_delta_count() << ")]"; + os << "[" << std::setw(20) << std::setfill(' ') << t << "(" << std::setw(5) + << sc_core::sc_delta_count() << ")]"; else - os << "[" << std::setw(20) << std::setfill(' ') << t - << "]"; + os << "[" << std::setw(20) << std::setfill(' ') << t << "]"; } } if (unlikely(rep.get_id() >= 0)) os << "(" - << "IWEF"[rep.get_severity()] << rep.get_id() << ") " - << rep.get_msg_type() << ": "; + << "IWEF"[rep.get_severity()] << rep.get_id() << ") " << rep.get_msg_type() << ": "; else if (cfg.msg_type_field_width) { - if (cfg.msg_type_field_width == - std::numeric_limits::max()) + if (cfg.msg_type_field_width == std::numeric_limits::max()) os << rep.get_msg_type() << ": "; else - os << padded(rep.get_msg_type(), cfg.msg_type_field_width) - << ": "; + os << padded(rep.get_msg_type(), cfg.msg_type_field_width) << ": "; } - if (*rep.get_msg()) - os << rep.get_msg(); + if (*rep.get_msg()) os << rep.get_msg(); if (rep.get_severity() >= cfg.file_info_from) { if (rep.get_line_number()) - os << "\n [FILE:" << rep.get_file_name() << ":" - << rep.get_line_number() << "]"; + os << "\n [FILE:" << rep.get_file_name() << ":" << rep.get_line_number() << "]"; sc_core::sc_simcontext* simc = sc_core::sc_get_curr_simcontext(); if (simc && sc_core::sc_is_running()) { const char* proc_name = rep.get_process_name(); - if (proc_name) - os << "\n [PROCESS:" << proc_name << "]"; + if (proc_name) os << "\n [PROCESS:" << proc_name << "]"; } } return os.str(); @@ -214,18 +192,16 @@ auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) return ""; } -inline auto get_verbosity(const sc_core::sc_report& rep) -> int { - return rep.get_verbosity() > sc_core::SC_NONE && - rep.get_verbosity() < sc_core::SC_LOW - ? rep.get_verbosity() * 10 - : rep.get_verbosity(); +inline auto get_verbosity(const sc_core::sc_report& rep) -> int +{ + return rep.get_verbosity() > sc_core::SC_NONE && rep.get_verbosity() < sc_core::SC_LOW ? rep.get_verbosity() * 10 + : rep.get_verbosity(); } -inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, - const scp::LogConfig& cfg) { +inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, const scp::LogConfig& cfg) +{ auto msg = compose_message(rep, cfg); - if (!msg.size()) - return; + if (!msg.size()) return; switch (rep.get_severity()) { case sc_core::SC_INFO: switch (get_verbosity(rep)) { @@ -255,8 +231,8 @@ inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, } } -inline void log2logger(spdlog::logger& logger, scp::log lvl, - const std::string& msg) { +inline void log2logger(spdlog::logger& logger, scp::log lvl, const std::string& msg) +{ switch (lvl) { case scp::log::DBGTRACE: case scp::log::TRACE: @@ -282,47 +258,39 @@ inline void log2logger(spdlog::logger& logger, scp::log lvl, } } -void report_handler(const sc_core::sc_report& rep, - const sc_core::sc_actions& actions) { +void report_handler(const sc_core::sc_report& rep, const sc_core::sc_actions& actions) +{ thread_local bool sc_stop_called = false; - if (actions & sc_core::SC_DO_NOTHING) - return; - if (rep.get_severity() == sc_core::SC_INFO || - !log_cfg.report_only_first_error || + if (actions & sc_core::SC_DO_NOTHING) return; + if (rep.get_severity() == sc_core::SC_INFO || !log_cfg.report_only_first_error || sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) < 2) { - if ((actions & sc_core::SC_DISPLAY) && - (!log_cfg.file_logger || get_verbosity(rep) < sc_core::SC_HIGH)) + if ((actions & sc_core::SC_DISPLAY) && (!log_cfg.file_logger || get_verbosity(rep) < sc_core::SC_HIGH)) log2logger(*log_cfg.console_logger, rep, log_cfg); if ((actions & sc_core::SC_LOG) && log_cfg.file_logger) { scp::LogConfig lcfg(log_cfg); lcfg.print_sim_time = true; - if (!lcfg.msg_type_field_width) - lcfg.msg_type_field_width = 24; + if (!lcfg.msg_type_field_width) lcfg.msg_type_field_width = 24; log2logger(*log_cfg.file_logger, rep, lcfg); } } if (actions & sc_core::SC_STOP) { - std::this_thread::sleep_for(std::chrono::milliseconds( - static_cast(log_cfg.level) * 10)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(log_cfg.level) * 10)); if (sc_core::sc_is_running() && !sc_stop_called) { sc_core::sc_stop(); sc_stop_called = true; } } if (actions & sc_core::SC_ABORT) { - std::this_thread::sleep_for(std::chrono::milliseconds( - static_cast(log_cfg.level) * 20)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(log_cfg.level) * 20)); abort(); } if (actions & sc_core::SC_THROW) { - std::this_thread::sleep_for(std::chrono::milliseconds( - static_cast(log_cfg.level) * 20)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(log_cfg.level) * 20)); throw rep; } if (sc_core::sc_time_stamp().value() && !sc_core::sc_is_running()) { log_cfg.console_logger->flush(); - if (log_cfg.file_logger) - log_cfg.file_logger->flush(); + if (log_cfg.file_logger) log_cfg.file_logger->flush(); } } @@ -339,30 +307,20 @@ void report_handler(const sc_core::sc_report& rep, } // namespace static std::mutex cfg_guard; -static void configure_logging() { +static void configure_logging() +{ std::lock_guard lock(cfg_guard); static bool spdlog_initialized = false; - sc_core::sc_report_handler::set_actions( - sc_core::SC_ERROR, - sc_core::SC_DEFAULT_ERROR_ACTIONS | sc_core::SC_DISPLAY); - sc_core::sc_report_handler::set_actions(sc_core::SC_FATAL, - sc_core::SC_DEFAULT_FATAL_ACTIONS); - sc_core::sc_report_handler::set_verbosity_level( - verbosity[static_cast(log_cfg.level)]); + sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, sc_core::SC_DEFAULT_ERROR_ACTIONS | sc_core::SC_DISPLAY); + sc_core::sc_report_handler::set_actions(sc_core::SC_FATAL, sc_core::SC_DEFAULT_FATAL_ACTIONS); + sc_core::sc_report_handler::set_verbosity_level(verbosity[static_cast(log_cfg.level)]); sc_core::sc_report_handler::set_handler(report_handler); if (!spdlog_initialized) { - spdlog::init_thread_pool( - 1024U, - log_cfg.log_file_name.size() - ? 2U - : 1U); // queue with 8k items and 1 backing thread. - log_cfg.console_logger = log_cfg.log_async - ? spdlog::stdout_color_mt< - spdlog::async_factory>( - "console_logger") - : spdlog::stdout_color_mt( - "console_logger"); + spdlog::init_thread_pool(1024U, + log_cfg.log_file_name.size() ? 2U : 1U); // queue with 8k items and 1 backing thread. + log_cfg.console_logger = log_cfg.log_async ? spdlog::stdout_color_mt("console_logger") + : spdlog::stdout_color_mt("console_logger"); auto logger_fmt = log_cfg.print_severity ? "[%L] %v" : "%v"; if (log_cfg.colored_output) { std::ostringstream os; @@ -375,17 +333,11 @@ static void configure_logging() { if (log_cfg.log_file_name.size()) { { std::ofstream ofs; - ofs.open(log_cfg.log_file_name, - std::ios::out | std::ios::trunc); + ofs.open(log_cfg.log_file_name, std::ios::out | std::ios::trunc); } - log_cfg.file_logger = log_cfg.log_async - ? spdlog::basic_logger_mt< - spdlog::async_factory>( - "file_logger", - log_cfg.log_file_name) - : spdlog::basic_logger_mt( - "file_logger", - log_cfg.log_file_name); + log_cfg.file_logger = log_cfg.log_async ? spdlog::basic_logger_mt( + "file_logger", log_cfg.log_file_name) + : spdlog::basic_logger_mt("file_logger", log_cfg.log_file_name); if (log_cfg.print_severity) log_cfg.file_logger->set_pattern("[%8l] %v"); else @@ -396,118 +348,126 @@ static void configure_logging() { spdlog_initialized = true; } else { log_cfg.console_logger = spdlog::get("console_logger"); - if (log_cfg.log_file_name.size()) - log_cfg.file_logger = spdlog::get("file_logger"); + if (log_cfg.log_file_name.size()) log_cfg.file_logger = spdlog::get("file_logger"); } if (log_cfg.log_filter_regex.size()) { - log_cfg.reg_ex = std::regex(log_cfg.log_filter_regex, - std::regex::extended | std::regex::icase); + log_cfg.reg_ex = std::regex(log_cfg.log_filter_regex, std::regex::extended | std::regex::icase); } } -void scp::reinit_logging(scp::log level) { +void scp::reinit_logging(scp::log level) +{ sc_core::sc_report_handler::set_handler(report_handler); log_cfg.level = level; lut.clear(); } -void scp::init_logging(scp::log level, unsigned type_field_width, - bool print_time) { +void scp::init_logging(scp::log level, unsigned type_field_width, bool print_time) +{ log_cfg.msg_type_field_width = type_field_width; log_cfg.print_sys_time = print_time; log_cfg.level = level; configure_logging(); } -void scp::init_logging(const scp::LogConfig& log_config) { +void scp::init_logging(const scp::LogConfig& log_config) +{ log_cfg = log_config; configure_logging(); } -void scp::set_logging_level(scp::log level) { +void scp::set_logging_level(scp::log level) +{ log_cfg.level = level; - sc_core::sc_report_handler::set_verbosity_level( - verbosity[static_cast(level)]); + sc_core::sc_report_handler::set_verbosity_level(verbosity[static_cast(level)]); log_cfg.console_logger->set_level(static_cast( - SPDLOG_LEVEL_OFF - - std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); + SPDLOG_LEVEL_OFF - std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); } -auto scp::get_logging_level() -> scp::log { - return log_cfg.level; -} +auto scp::get_logging_level() -> scp::log { return log_cfg.level; } -void scp::set_cycle_base(sc_core::sc_time period) { - log_cfg.cycle_base = period; -} +void scp::set_cycle_base(sc_core::sc_time period) { log_cfg.cycle_base = period; } -auto scp::LogConfig::logLevel(scp::log level) -> scp::LogConfig& { +auto scp::LogConfig::logLevel(scp::log level) -> scp::LogConfig& +{ this->level = level; return *this; } -auto scp::LogConfig::msgTypeFieldWidth(unsigned width) -> scp::LogConfig& { +auto scp::LogConfig::msgTypeFieldWidth(unsigned width) -> scp::LogConfig& +{ this->msg_type_field_width = width; return *this; } -auto scp::LogConfig::printSysTime(bool enable) -> scp::LogConfig& { +auto scp::LogConfig::printSysTime(bool enable) -> scp::LogConfig& +{ this->print_sys_time = enable; return *this; } -auto scp::LogConfig::printSimTime(bool enable) -> scp::LogConfig& { +auto scp::LogConfig::printSimTime(bool enable) -> scp::LogConfig& +{ this->print_sim_time = enable; return *this; } -auto scp::LogConfig::printDelta(bool enable) -> scp::LogConfig& { +auto scp::LogConfig::printDelta(bool enable) -> scp::LogConfig& +{ this->print_delta = enable; return *this; } -auto scp::LogConfig::printSeverity(bool enable) -> scp::LogConfig& { +auto scp::LogConfig::printSeverity(bool enable) -> scp::LogConfig& +{ this->print_severity = enable; return *this; } -auto scp::LogConfig::logFileName(std::string&& name) -> scp::LogConfig& { +auto scp::LogConfig::logFileName(std::string&& name) -> scp::LogConfig& +{ this->log_file_name = name; return *this; } -auto scp::LogConfig::logFileName(const std::string& name) -> scp::LogConfig& { +auto scp::LogConfig::logFileName(const std::string& name) -> scp::LogConfig& +{ this->log_file_name = name; return *this; } -auto scp::LogConfig::coloredOutput(bool enable) -> scp::LogConfig& { +auto scp::LogConfig::coloredOutput(bool enable) -> scp::LogConfig& +{ this->colored_output = enable; return *this; } -auto scp::LogConfig::logFilterRegex(std::string&& expr) -> scp::LogConfig& { +auto scp::LogConfig::logFilterRegex(std::string&& expr) -> scp::LogConfig& +{ this->log_filter_regex = expr; return *this; } -auto scp::LogConfig::logFilterRegex(const std::string& expr) - -> scp::LogConfig& { +auto scp::LogConfig::logFilterRegex(const std::string& expr) -> scp::LogConfig& +{ this->log_filter_regex = expr; return *this; } -auto scp::LogConfig::logAsync(bool v) -> scp::LogConfig& { +auto scp::LogConfig::logAsync(bool v) -> scp::LogConfig& +{ this->log_async = v; return *this; } -auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& { +auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& +{ this->report_only_first_error = v; return *this; } -auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { +auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& +{ this->file_info_from = v; return *this; } \ No newline at end of file diff --git a/report/src/report.cpp b/report/src/sc_report.cpp similarity index 85% rename from report/src/report.cpp rename to report/src/sc_report.cpp index 50d1d93..0e7f8ec 100644 --- a/report/src/report.cpp +++ b/report/src/sc_report.cpp @@ -14,10 +14,12 @@ * limitations under the License. *******************************************************************************/ /* - * report.cpp + * sc_report.cpp * * Created on: 19.09.2017 * Author: eyck@minres.com + * + * THIS FILE IS INTENDED TO BE UP-STREAMED */ #include @@ -47,9 +49,9 @@ std::unordered_map lut; thread_local std::unordered_map lut; #endif - // BKDR hash algorithm -auto char_hash(char const* str) -> uint64_t { +auto char_hash(char const* str) -> uint64_t +{ constexpr unsigned int seed = 131; // 31 131 1313 13131131313 etc// uint64_t hash = 0; while (*str) { @@ -60,16 +62,14 @@ auto char_hash(char const* str) -> uint64_t { } } // namespace -sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( - const char* scname, const char* tname = "") { +sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached(const char* scname, const char* tname = "") +{ if (level != sc_core::SC_UNSET) { return level; } - if (!scname && features.size()) - scname = features[0].c_str(); - if (!scname) - scname = ""; + if (!scname && features.size()) scname = features[0].c_str(); + if (!scname) scname = ""; type = std::string(scname); @@ -82,15 +82,14 @@ sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( } } - return level = static_cast( - ::sc_core::sc_report_handler::get_verbosity_level()); + return level = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); } -auto scp::get_log_verbosity(char const* str) -> sc_core::sc_verbosity { +auto scp::get_log_verbosity(char const* str) -> sc_core::sc_verbosity +{ auto k = char_hash(str); auto it = lut.find(k); - if (it != lut.end()) - return it->second; + if (it != lut.end()) return it->second; scp::scp_logger_cache tmp; lut[k] = tmp.get_log_verbosity_cached(str); diff --git a/report/tests/CMakeLists.txt b/report/tests/CMakeLists.txt new file mode 100644 index 0000000..1b66c6e --- /dev/null +++ b/report/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.14) +project(scp-tests VERSION 1.0 LANGUAGES CXX C) + +macro(run_test test) + add_executable(${test} ${test}.cc) + target_link_libraries(${test} scp::reporting SystemC::systemc SystemC::cci) + add_test(NAME ${test} COMMAND ${test}) + set_tests_properties(${test} PROPERTIES TIMEOUT 10) +endmacro() + +run_test(logger) diff --git a/report/tests/logger.cc b/report/tests/logger.cc new file mode 100644 index 0000000..2d37c46 --- /dev/null +++ b/report/tests/logger.cc @@ -0,0 +1,250 @@ +/***************************************************************************** + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +SC_MODULE (test4) { + SC_CTOR (test4) { + SCP_INFO(()) << " . T4 Logger() 1"; + SCP_WARN(()) << " . T4 Logger() 1"; + SCP_INFO(()) << " . T4 Logger() 2"; + SCP_WARN(()) << " . T4 Logger() 2"; + } + SCP_LOGGER(); +}; + +SC_MODULE (test3) { + SC_CTOR (test3) { + SCP_INFO((D)) << " . T3 D Logger \"other\" \"feature.one\""; + SCP_WARN((D)) << " . T3 D Logger \"other\" \"feature.one\""; + SCP_INFO(()) << " . T3 Logger ()"; + SCP_WARN(()) << " . T3 Logger ()"; + } + SCP_LOGGER((D), "other", "feature.one"); + SCP_LOGGER(()); +}; + +SC_MODULE (test2) { + SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") + { + SCP_INFO(()) << " T2 Logger()"; + SCP_WARN(()) << " T2 Logger()"; + } + SCP_LOGGER(); + test3 t31, t32; + test4 t4; +}; + +SC_MODULE (test1) { + SC_CTOR (test1) : t2("t2") + { + SCP_WARN((), "My.Name") << " T1 My.Name typed log"; + SCP_INFO(()) << " T1 Logger()"; + SCP_WARN(()) << " T1 Logger()"; + + SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing1"); + SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing2"); + + SCP_INFO((vec[0])) << "Thing1?"; + SCP_WARN((vec[0])) << "Thing1?"; + SCP_INFO((vec[1])) << "Thing2?"; + SCP_WARN((vec[1])) << "Thing2?"; + } + SCP_LOGGER("something", "else"); + SCP_LOGGER_VECTOR(vec); + test2 t2; +}; + +class outside_class +{ + SCP_LOGGER("out.class", "thing1"); + +public: + outside_class() + { + SCP_INFO(())("constructor"); + SCP_WARN(())("constructor"); + } +}; + +SC_MODULE (test) { + outside_class oc; + SC_CTOR (test) { + SCP_DEBUG(SCMOD) << "First part"; + + SCP_INFO() << "Uncached version empty"; + SCP_INFO(())("FMT String : Cached version default"); + SCP_INFO(SCMOD) << "UnCached version feature using SCMOD macro"; + SCP_INFO((m_my_logger)) << "Cached version using (m_my_logger)"; + SCP_INFO((D)) << "Cached version with D"; + } + + SCP_LOGGER((m_my_logger)); + SCP_LOGGER(()); + SCP_LOGGER((1), "other"); + SCP_LOGGER((D), "other", "feature.one"); +}; + +int sc_main(int argc, char** argv) +{ + cci_utils::consuming_broker broker("global_broker"); + cci_register_broker(broker); + cci::cci_originator orig("config"); + broker.set_preset_cci_value("log_level", cci::cci_value(1), orig); + broker.set_preset_cci_value("top.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("feature.log_level", cci::cci_value(5), orig); + + broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); + broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); + + std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); + scp::scp_logger_from_cci cci_logger; + scp::init_logging(scp::LogConfig() + .logLevel(scp::log::DEBUG) // set log level to debug + .msgTypeFieldWidth(20) + .fileInfoFrom(5) + .logAsync(false) + .printSimTime(false) + .logFileName(logfile)); // make the msg type column a bit tighter + SCP_INFO() << "Constructing design"; + test toptest("top"); + test1 t1("t1"); + for (auto n : cci_logger.get_logging_parameters()) { + SCP_INFO()("{}", n); + } + SCP_INFO() << "Starting simulation"; + sc_core::sc_start(); + SCP_WARN() << "Ending simulation"; + +#ifdef FMT_SHARED + std::string fmtstr = "FMT String : Cached version default"; +#else + std::string fmtstr = "Please add FMT library for FMT support."; +#endif + + std::string expected = + R"([ info] [ 0 s ]SystemC : Constructing design +[ info] [ 0 s ]out.class : constructor +[ warning] [ 0 s ]out.class : constructor +[ debug] [ 0 s ]top : First part +[ info] [ 0 s ]SystemC : Uncached version empty +[ info] [ 0 s ]top : FMT String : Cached version default +[ info] [ 0 s ]top : UnCached version feature using SCMOD macro +[ info] [ 0 s ]top : Cached version using (m_my_logger) +[ info] [ 0 s ]top : Cached version with D +[ info] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" +[ warning] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" +[ info] [ 0 s ]t1.t2.t3_1 : . T3 Logger () +[ warning] [ 0 s ]t1.t2.t3_1 : . T3 Logger () +[ info] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" +[ warning] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" +[ warning] [ 0 s ]t1.t2.t3_2 : . T3 Logger () +[ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 +[ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 +[ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 +[ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 +[ warning] [ 0 s ]t1.t2 : T2 Logger() +[ warning] [ 0 s ]My.Name : T1 My.Name typed log +[ warning] [ 0 s ]t1 : T1 Logger() +[ info] [ 0 s ]t1 : Thing1? +[ warning] [ 0 s ]t1 : Thing1? +[ warning] [ 0 s ]t1 : Thing2? +[ info] [ 0 s ]SystemC : .log_level +[ info] [ 0 s ]SystemC : else.log_level +[ info] [ 0 s ]SystemC : feature.log_level +[ info] [ 0 s ]SystemC : feature.one.log_level +[ info] [ 0 s ]SystemC : other.log_level +[ info] [ 0 s ]SystemC : out.class.log_level +[ info] [ 0 s ]SystemC : out.class.out.class.log_level +[ info] [ 0 s ]SystemC : out.class.out.log_level +[ info] [ 0 s ]SystemC : out.class.outside_class.log_level +[ info] [ 0 s ]SystemC : out.class.thing1.log_level +[ info] [ 0 s ]SystemC : out.log_level +[ info] [ 0 s ]SystemC : out.out.class.log_level +[ info] [ 0 s ]SystemC : out.out.log_level +[ info] [ 0 s ]SystemC : out.outside_class.log_level +[ info] [ 0 s ]SystemC : out.thing1.log_level +[ info] [ 0 s ]SystemC : outside_class.log_level +[ info] [ 0 s ]SystemC : some.log_level +[ info] [ 0 s ]SystemC : something.log_level +[ info] [ 0 s ]SystemC : t1.else.log_level +[ info] [ 0 s ]SystemC : t1.feature.log_level +[ info] [ 0 s ]SystemC : t1.feature.one.log_level +[ info] [ 0 s ]SystemC : t1.log_level +[ info] [ 0 s ]SystemC : t1.other.log_level +[ info] [ 0 s ]SystemC : t1.some.log_level +[ info] [ 0 s ]SystemC : t1.something.log_level +[ info] [ 0 s ]SystemC : t1.t2.feature.log_level +[ info] [ 0 s ]SystemC : t1.t2.feature.one.log_level +[ info] [ 0 s ]SystemC : t1.t2.log_level +[ info] [ 0 s ]SystemC : t1.t2.other.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_1.feature.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_1.feature.one.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_1.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_1.other.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_1.test3.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_2.feature.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_2.feature.one.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_2.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_2.other.log_level +[ info] [ 0 s ]SystemC : t1.t2.t3_2.test3.log_level +[ info] [ 0 s ]SystemC : t1.t2.t4.log_level +[ info] [ 0 s ]SystemC : t1.t2.t4.test4.log_level +[ info] [ 0 s ]SystemC : t1.t2.test2.log_level +[ info] [ 0 s ]SystemC : t1.t2.test3.log_level +[ info] [ 0 s ]SystemC : t1.t2.test4.log_level +[ info] [ 0 s ]SystemC : t1.test1.log_level +[ info] [ 0 s ]SystemC : t1.test2.log_level +[ info] [ 0 s ]SystemC : t1.test3.log_level +[ info] [ 0 s ]SystemC : t1.test4.log_level +[ info] [ 0 s ]SystemC : t1.thing1.log_level +[ info] [ 0 s ]SystemC : t1.thing2.log_level +[ info] [ 0 s ]SystemC : test.log_level +[ info] [ 0 s ]SystemC : test1.log_level +[ info] [ 0 s ]SystemC : test2.log_level +[ info] [ 0 s ]SystemC : test3.log_level +[ info] [ 0 s ]SystemC : test4.log_level +[ info] [ 0 s ]SystemC : thing1.log_level +[ info] [ 0 s ]SystemC : thing2.log_level +[ info] [ 0 s ]SystemC : top..log_level +[ info] [ 0 s ]SystemC : top.feature.log_level +[ info] [ 0 s ]SystemC : top.feature.one.log_level +[ info] [ 0 s ]SystemC : top.log_level +[ info] [ 0 s ]SystemC : top.other.log_level +[ info] [ 0 s ]SystemC : top.test.log_level +[ info] [ 0 s ]SystemC : Starting simulation +[ warning] [ 0 s ]SystemC : Ending simulation +)"; + + std::ifstream lf(logfile); + std::string out((std::istreambuf_iterator(lf)), std::istreambuf_iterator()); + + std::cout << "out file\n" << out << "\n"; + std::cout << "expected\n" << expected << "\n"; + std::cout << "Number of difference: " << out.compare(expected) << "\n"; + + std::remove(logfile.c_str()); + return out.compare(expected); +} diff --git a/tlm_extensions/initiator_id/include/scp/tlm_extensions/initiator_id.h b/tlm_extensions/initiator_id/include/scp/tlm_extensions/initiator_id.h index ee11efd..988a790 100644 --- a/tlm_extensions/initiator_id/include/scp/tlm_extensions/initiator_id.h +++ b/tlm_extensions/initiator_id/include/scp/tlm_extensions/initiator_id.h @@ -38,21 +38,21 @@ class initiator_id : public tlm::tlm_extension initiator_id(uint64_t id) { m_id = id; } initiator_id(const initiator_id&) = default; - virtual tlm_extension_base* clone() const override { - return new initiator_id(*this); - } + virtual tlm_extension_base* clone() const override { return new initiator_id(*this); } - virtual void copy_from(const tlm_extension_base& ext) override { + virtual void copy_from(const tlm_extension_base& ext) override + { const initiator_id& other = static_cast(ext); *this = other; } operator uint64_t() { return m_id; }; -#define overload(_OP) \ - initiator_id& operator _OP(const uint64_t id) { \ - this->m_id _OP id; \ - return *this; \ +#define overload(_OP) \ + initiator_id& operator _OP(const uint64_t id) \ + { \ + this->m_id _OP id; \ + return *this; \ } overload(+=); overload(-=); @@ -65,7 +65,8 @@ class initiator_id : public tlm::tlm_extension overload(<<=); overload(>>=); - initiator_id& operator=(const uint64_t id) { + initiator_id& operator=(const uint64_t id) + { m_id = id; return *this; } diff --git a/tlm_extensions/initiator_id/tests/smoke.cc b/tlm_extensions/initiator_id/tests/smoke.cc index f6ea4f0..c102fe3 100644 --- a/tlm_extensions/initiator_id/tests/smoke.cc +++ b/tlm_extensions/initiator_id/tests/smoke.cc @@ -34,7 +34,8 @@ SC_MODULE (test) { } }; -int sc_main(int argc, char** argv) { +int sc_main(int argc, char** argv) +{ test test1("test"); sc_core::sc_start(); diff --git a/tlm_extensions/path_trace/include/scp/tlm_extensions/path_trace.h b/tlm_extensions/path_trace/include/scp/tlm_extensions/path_trace.h index 05d6f9e..a3d32c0 100644 --- a/tlm_extensions/path_trace/include/scp/tlm_extensions/path_trace.h +++ b/tlm_extensions/path_trace/include/scp/tlm_extensions/path_trace.h @@ -40,11 +40,10 @@ class path_trace : public tlm::tlm_extension path_trace() = default; path_trace(const path_trace&) = default; - virtual tlm_extension_base* clone() const override { - return new path_trace(*this); - } + virtual tlm_extension_base* clone() const override { return new path_trace(*this); } - virtual void copy_from(const tlm_extension_base& ext) override { + virtual void copy_from(const tlm_extension_base& ext) override + { const path_trace& other = static_cast(ext); *this = other; } @@ -66,7 +65,8 @@ class path_trace : public tlm::tlm_extension * @return a string consisting of the names of each object stamped into the * path separated with the separator provided. */ - std::string to_string(std::string separator = "->") { + std::string to_string(std::string separator = "->") + { std::stringstream info; std::string s; for (auto o : m_path) { diff --git a/tlm_extensions/path_trace/tests/smoke.cc b/tlm_extensions/path_trace/tests/smoke.cc index 8958eab..7b899d6 100644 --- a/tlm_extensions/path_trace/tests/smoke.cc +++ b/tlm_extensions/path_trace/tests/smoke.cc @@ -39,7 +39,8 @@ SC_MODULE (test) { } }; -int sc_main(int argc, char** argv) { +int sc_main(int argc, char** argv) +{ test test1("test"); sc_core::sc_start(); From fef79a1a6a0669061f8081db864536851b10dea5 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 3 Dec 2024 17:06:22 +0100 Subject: [PATCH 10/17] Rename SCP_LOGGER to SCP_REPORTER Signed-off-by: Mark Burton --- examples/smoke_logger.cc | 27 +++++++++++----------- report/include/scp/report.h | 5 ++++ report/include/scp/report_cci_setter.h | 2 +- report/include/scp/sc_report.h | 32 +++++++++++++------------- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/examples/smoke_logger.cc b/examples/smoke_logger.cc index 27d0e04..5ffb7a6 100644 --- a/examples/smoke_logger.cc +++ b/examples/smoke_logger.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,7 @@ SC_MODULE (test4) { SCP_INFO(()) << " . T4 Logger() 2"; SCP_WARN(()) << " . T4 Logger() 2"; } - SCP_LOGGER(); + SCP_REPORTER(); }; SC_MODULE (test3) { @@ -44,8 +45,8 @@ SC_MODULE (test3) { SCP_INFO(()) << " . T3 Logger ()"; SCP_WARN(()) << " . T3 Logger ()"; } - SCP_LOGGER((D), "other", "feature.one"); - SCP_LOGGER(()); + SCP_REPORTER((D), "other", "feature.one"); + SCP_REPORTER(()); }; SC_MODULE (test2) { @@ -54,7 +55,7 @@ SC_MODULE (test2) { SCP_INFO(()) << " T2 Logger()"; SCP_WARN(()) << " T2 Logger()"; } - SCP_LOGGER(); + SCP_REPORTER(); test3 t31, t32; test4 t4; }; @@ -66,22 +67,22 @@ SC_MODULE (test1) { SCP_INFO(()) << " T1 Logger()"; SCP_WARN(()) << " T1 Logger()"; - SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing1"); - SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing2"); + SCP_REPORTER_VECTOR_PUSH_BACK(vec, "some", "thing1"); + SCP_REPORTER_VECTOR_PUSH_BACK(vec, "some", "thing2"); SCP_INFO((vec[0])) << "Thing1?"; SCP_WARN((vec[0])) << "Thing1?"; SCP_INFO((vec[1])) << "Thing2?"; SCP_WARN((vec[1])) << "Thing2?"; } - SCP_LOGGER("something", "else"); - SCP_LOGGER_VECTOR(vec); + SCP_REPORTER("something", "else"); + SCP_REPORTER_VECTOR(vec); test2 t2; }; class outside_class { - SCP_LOGGER("out.class", "thing1"); + SCP_REPORTER("out.class", "thing1"); public: outside_class() @@ -127,10 +128,10 @@ SC_MODULE (test) { SCP_INFO((D)) << "Locally cached version with D"; } - SCP_LOGGER((m_my_logger)); - SCP_LOGGER(()); - SCP_LOGGER((1), "other"); - SCP_LOGGER((D), "other", "feature.one"); + SCP_REPORTER((m_my_logger)); + SCP_REPORTER(()); + SCP_REPORTER((1), "other"); + SCP_REPORTER((D), "other", "feature.one"); }; int sc_main(int argc, char** argv) diff --git a/report/include/scp/report.h b/report/include/scp/report.h index 42c3b59..011c90a 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -4,6 +4,11 @@ #include "scp/helpers.h" #include "scp/logger.h" +#define SCP_LOGGER(...) SCP_REPORTER(__VA_ARGS__) +#define SCP_LOGGER_NAME(...) SCP_REPORTER_NAME(__VA_ARGS__) +#define SCP_LOGGER_VECTOR(...) SCP_REPORTER_VECTOR(__VA_ARGS__) +#define SCP_LOGGER_VECTOR_PUSH_BACK(...) SCP_REPORTER_VECTOR_PUSH_BACK(__VA_ARGS__) + #ifdef FMT_SHARED #ifndef _FMT_CONVENIENCE_DEFINED #define _FMT_CONVENIENCE_DEFINED diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h index 01ba463..7881da3 100644 --- a/report/include/scp/report_cci_setter.h +++ b/report/include/scp/report_cci_setter.h @@ -16,7 +16,7 @@ #ifndef _SCP_REPORT_CCI_SETTER_H_ #define _SCP_REPORT_CCI_SETTER_H_ -#include +#include #include #include #include diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h index 380fc34..2c3e00d 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/scp/sc_report.h @@ -310,20 +310,20 @@ struct ScLogger { /********/ /* default logger cache name */ -#define SCP_LOGGER_NAME(x) CAT(_m_scp_log_level_cache_, x) +#define SCP_REPORTER_NAME(x) CAT(_m_scp_log_level_cache_, x) /* User interface macros */ #define SCMOD this->sc_core::sc_module::name() -#define SCP_LOGGER(...) \ - scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ - SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ - SCP_LOGGER_NAME()) = { sc_core::SC_UNSET, \ - "", \ - { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))(POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } +#define SCP_REPORTER(...) \ + scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ + SCP_REPORTER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ + SCP_REPORTER_NAME()) = { sc_core::SC_UNSET, \ + "", \ + { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))(POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } -#define SCP_LOGGER_VECTOR(NAME) std::vector SCP_LOGGER_NAME(NAME) -#define SCP_LOGGER_VECTOR_PUSH_BACK(NAME, ...) \ - SCP_LOGGER_NAME(NAME).push_back({ sc_core::SC_UNSET, "", { __VA_ARGS__ } }); +#define SCP_REPORTER_VECTOR(NAME) std::vector SCP_REPORTER_NAME(NAME) +#define SCP_REPORTER_VECTOR_PUSH_BACK(NAME, ...) \ + SCP_REPORTER_NAME(NAME).push_back({ sc_core::SC_UNSET, "", { __VA_ARGS__ } }); class call_sc_name_fn { @@ -363,14 +363,14 @@ class call_sc_name_fn #define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) -#define SCP_VBSTY_CHECK(lvl, ...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (SCP_VBSTY_CHECK_CACHED(lvl, FIRST_ARG(__VA_ARGS__), SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ +#define SCP_VBSTY_CHECK(lvl, ...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (SCP_VBSTY_CHECK_CACHED(lvl, FIRST_ARG(__VA_ARGS__), SCP_REPORTER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ SCP_VBSTY_CHECK_UNCACHED(lvl, ##__VA_ARGS__)) -#define SCP_GET_FEATURES(...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (FIRST_ARG EXPAND((POP_ARG(__VA_ARGS__, SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ +#define SCP_GET_FEATURES(...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (FIRST_ARG EXPAND((POP_ARG(__VA_ARGS__, SCP_REPORTER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ __VA_ARGS__) #ifdef FMT_SHARED From 28d29a1809869a87b4ca401cb9ab5ebfc180e246 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 11 Dec 2024 15:05:26 +0100 Subject: [PATCH 11/17] Mark ScLogger destructor as potentially throwing an exception Signed-off-by: Mark Burton --- report/include/scp/sc_report.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h index 2c3e00d..966e76a 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/scp/sc_report.h @@ -224,7 +224,7 @@ struct ScLogger { * @brief the destructor generating the SystemC report * */ - virtual ~ScLogger() + virtual ~ScLogger() noexcept(false) { ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); } From 077fe80185dafbff30f9159abd14573c9891b03e Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 17 Dec 2024 15:16:57 +0100 Subject: [PATCH 12/17] Depricate SC_THROW, and mask it out in the ScLogger destructor. Signed-off-by: Mark Burton --- report/README.md | 7 +++++++ report/include/scp/sc_report.h | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/report/README.md b/report/README.md index 3bcfc50..ae5b7ff 100644 --- a/report/README.md +++ b/report/README.md @@ -1,4 +1,11 @@ +NB the TROW actions in sc_report handler should be marked as deprecated, and users encouraged to calling throw as appropriate in their user code. This removes the ambiguity about whether and what a report handler would throw. +# Overview +The Logging interface provides a short lived streaming object which collects the information required for logging, and will then pass that to a sc_report_handler. This object should not be used directly, rather the macros described below should be preferred. + +***The logging interface should _NOT_ be used to cause exceptions to be thrown, this should be handled in user code (The underlying sc_report_handler SC_THROW action is deprecated and will be ignored). *** + +A set of convenience macros are provided. ## Reporting macros diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h index 966e76a..3dbf77e 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/scp/sc_report.h @@ -223,10 +223,15 @@ struct ScLogger { * @fn ~ScLogger() * @brief the destructor generating the SystemC report * + * NB a destructor should not throw an exception, here we attempt to prevent the sc_report_handler from throwing + * The ScLogging interface is _ONLY_ for logging, simulation control should happen in user code. */ - virtual ~ScLogger() noexcept(false) + virtual ~ScLogger() noexcept(true) { + auto old = sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR); + sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old &= !sc_core::SC_THROW); ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); + sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old); } /** * @fn ScLogger& type() From 319f643632d0b4d6a6ecfec6e2c1a81ffc9c999e Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 24 Jan 2025 12:40:05 +0100 Subject: [PATCH 13/17] Remove all actions and clean up Signed-off-by: Mark Burton --- examples/smoke_logger.cc | 12 +- examples/smoke_report.cc | 12 +- report/README.md | 35 +++-- report/include/scp/logger.h | 10 +- report/include/scp/report_cci_setter.h | 8 +- report/include/scp/sc_report.h | 175 ++++++++++++++----------- report/src/logger.cpp | 49 +++---- report/tests/logger.cc | 12 +- 8 files changed, 172 insertions(+), 141 deletions(-) diff --git a/examples/smoke_logger.cc b/examples/smoke_logger.cc index 5ffb7a6..246984c 100644 --- a/examples/smoke_logger.cc +++ b/examples/smoke_logger.cc @@ -139,13 +139,13 @@ int sc_main(int argc, char** argv) cci_utils::consuming_broker broker("global_broker"); cci_register_broker(broker); cci::cci_originator orig("config"); - broker.set_preset_cci_value("log_level", cci::cci_value(1), orig); - broker.set_preset_cci_value("top.log_level", cci::cci_value(5), orig); - broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(5), orig); - broker.set_preset_cci_value("feature.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("log_level", cci::cci_value(100), orig); + broker.set_preset_cci_value("top.log_level", cci::cci_value(500), orig); + broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(500), orig); + broker.set_preset_cci_value("feature.log_level", cci::cci_value(500), orig); - broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); - broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("test4.log_level", cci::cci_value(400), orig); + broker.set_preset_cci_value("thing1.log_level", cci::cci_value(500), orig); std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); scp::scp_logger_from_cci cci_logger; diff --git a/examples/smoke_report.cc b/examples/smoke_report.cc index 9b2ee5c..20390c9 100644 --- a/examples/smoke_report.cc +++ b/examples/smoke_report.cc @@ -136,13 +136,13 @@ int sc_main(int argc, char** argv) cci_utils::consuming_broker broker("global_broker"); cci_register_broker(broker); cci::cci_originator orig("config"); - broker.set_preset_cci_value("log_level", cci::cci_value(1), orig); - broker.set_preset_cci_value("top.log_level", cci::cci_value(5), orig); - broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(5), orig); - broker.set_preset_cci_value("feature.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("log_level", cci::cci_value(100), orig); + broker.set_preset_cci_value("top.log_level", cci::cci_value(500), orig); + broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(500), orig); + broker.set_preset_cci_value("feature.log_level", cci::cci_value(500), orig); - broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); - broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("test4.log_level", cci::cci_value(400), orig); + broker.set_preset_cci_value("thing1.log_level", cci::cci_value(500), orig); std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); SCP_INFO() << "Constructing design"; diff --git a/report/README.md b/report/README.md index ae5b7ff..dcfa8f9 100644 --- a/report/README.md +++ b/report/README.md @@ -1,11 +1,21 @@ NB the TROW actions in sc_report handler should be marked as deprecated, and users encouraged to calling throw as appropriate in their user code. This removes the ambiguity about whether and what a report handler would throw. -# Overview -The Logging interface provides a short lived streaming object which collects the information required for logging, and will then pass that to a sc_report_handler. This object should not be used directly, rather the macros described below should be preferred. +#Problem Statement and proposed Solution + +This part of the library is intended to provide a convenient way to log information, such that it's easy to adopt and, in doing so, eases the path to code-reuse, (typically "logging libraries" are one of the key common parts which need to be included from each different code base). + +The goals are: +1/ A simple interface for model writes that supports both "{fmt}" style syntax ("Hello {}","world") and also streaming syntax (<<"Hello "<<"world"). +2/ At the 'back end' an interface should be provided to enable run-time enabling of logging. +3/ The interface mechanism should ensure that a single "if" is checked against the logging level prior to evaluating the full contents of the logging message, such that computationally expensive calls can be used to build the message, and will have no effect on simulation speed if they are not logged. + +This interface is independent of SystemC, however it works with the CCI parameter mechanism, and takes care to avoid name collisions with existing entities in SystemC. -***The logging interface should _NOT_ be used to cause exceptions to be thrown, this should be handled in user code (The underlying sc_report_handler SC_THROW action is deprecated and will be ignored). *** -A set of convenience macros are provided. +# Implementation details +The current implementation of the Logging interface provides a short lived streaming object which collects the information required for logging, and will then pass that to a sc_report_handler. This object should not be used directly, rather the macros described below should be preferred. + +***The logging interface should _NOT_ be used to cause exceptions to be thrown, this should be handled in user code (The underlying sc_report_handler SC_THROW action is deprecated and will be ignored). *** ## Reporting macros @@ -23,15 +33,14 @@ The Log levels used by the scp library are as follows : | SCP log
level value | SCP_ report macro | Log levels name | Print Level | Equivelent sc_core | | --- | --- | --- | --- | --- | | 0 | NONE | | sc_core::SC_NONE | -| 1 | SCP_FATAL() | FATAL | sc_core::SC_LOW | `sc_core::SC_FATAL` (Always printed) -| 1 | SCP_ERROR() | ERROR | sc_core::SC_LOW | `sc_core::SC_ERROR` (Always printed) -| 1 | SCP_WARNING() | WARNING | sc_core::SC_LOW | `sc_core::SC_WARNING` -| 4 | SCP_INFO() | INFO | sc_core::SC_MEDIUM| `sc_core::SC_MEDIUM` -| 5 | SCP_DEBUG() | DEBUG | sc_core::SC_HIGH | `sc_core::SC_HIGH` -| 6 | SCP_TRACE() | TRACE | sc_core::SC_FULL | `sc_core::SC_FULL` -| 7 | SCP_TRACEALL() | TRACEAL | sc_core::SC_DEBUG | `sc_core::SC_DEBUG` - -Hence WARNINGS will be printed if the log level is set above 1. Hence setting a log_level of 3 will print Fatal, Error and Warning messages only. +| 1 | LOG_CRITICAL() | CRITICAL | sc_core::SC_LOW | `sc_core::SC_FATAL` (Always printed) +| 1 | LOG_WARN() | NOTE | sc_core::SC_LOW | `sc_core::SC_WARNING` +| 4 | LOG_INFO() | INFO | sc_core::SC_MEDIUM| `sc_core::SC_MEDIUM` +| 5 | LOG_TRACE() | DEBUG | sc_core::SC_HIGH | `sc_core::SC_HIGH` +| 6 | LOG_FULL () | TRACE | sc_core::SC_FULL | `sc_core::SC_FULL` + + +Hence NOTES will be printed if the log level is set above 1. Hence setting a log_level of 3 will print Fatal, Error and Warning messages only. ## SCP_ report macros diff --git a/report/include/scp/logger.h b/report/include/scp/logger.h index c44095d..7bd8992 100644 --- a/report/include/scp/logger.h +++ b/report/include/scp/logger.h @@ -26,7 +26,7 @@ //! @brief reporting backend utilities namespace scp { /** - * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) + * @fn void init_logging(log=log::WARN, unsigned=24, bool=false) * @brief initializes the SystemC logging system with a particular logging * level * @@ -34,9 +34,9 @@ namespace scp { * @param type_field_width the with of the type field in the output * @param print_time whether to print the system time stamp */ -void init_logging(log level = log::WARNING, unsigned type_field_width = 24, bool print_time = false); +void init_logging(log level = log::WARN, unsigned type_field_width = 24, bool print_time = false); /** - * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) + * @fn void init_logging(log=log::WARN, unsigned=24, bool=false) * @brief initializes the SystemC logging system with a particular logging * level * @@ -44,7 +44,7 @@ void init_logging(log level = log::WARNING, unsigned type_field_width = 24, bool * @param type_field_width the with of the type field in the output * @param print_time whether to print the system time stamp */ -void reinit_logging(log level = log::WARNING); +void reinit_logging(log level = log::WARN); /** * @struct LogConfig * @brief the configuration class for the logging setup @@ -53,7 +53,7 @@ void reinit_logging(log level = log::WARNING); * class follows the builder pattern. */ struct LogConfig { - log level{ log::WARNING }; + log level{ log::WARN }; unsigned msg_type_field_width{ 24 }; bool print_sys_time{ false }; bool print_sim_time{ true }; diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h index 7881da3..aa3ea80 100644 --- a/report/include/scp/report_cci_setter.h +++ b/report/include/scp/report_cci_setter.h @@ -61,13 +61,17 @@ class scp_logger_from_cci : public scp_global_logger_handler auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME : name + "." SCP_LOG_LEVEL_PARAM_NAME; auto h = broker.get_param_handle(param_name); if (h.is_valid()) { - return verbosity.at(std::min(h.get_cci_value().get_int(), verbosity.size() - 1)); + return static_cast(h.get_cci_value().get_int()); } else { auto val = broker.get_preset_cci_value(param_name); if (val.is_int()) { broker.lock_preset_value(param_name); - return verbosity.at(std::min(val.get_int(), verbosity.size() - 1)); + return static_cast(val.get_int()); + } + if (val.is_string()) { + broker.lock_preset_value(param_name); + return static_cast(scp::as_log(val.get_string())); } } return sc_core::SC_UNSET; diff --git a/report/include/scp/sc_report.h b/report/include/scp/sc_report.h index 3dbf77e..961404b 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/scp/sc_report.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifdef __GNUG__ @@ -38,26 +39,16 @@ #if defined(_MSC_VER) && defined(ERROR) #undef ERROR #endif -static const std::array severity = { - sc_core::SC_FATAL, // scp::log::NONE - sc_core::SC_FATAL, // scp::log::FATAL - sc_core::SC_ERROR, // scp::log::ERROR - sc_core::SC_WARNING, // scp::log::WARNING - sc_core::SC_INFO, // scp::log::INFO - sc_core::SC_INFO, // scp::log::DEBUG - sc_core::SC_INFO, // scp::log::TRACE - sc_core::SC_INFO // scp::log::TRACEALL -}; -static const std::array verbosity = { - sc_core::SC_NONE, // scp::log::NONE - sc_core::SC_LOW, // scp::log::FATAL - sc_core::SC_LOW, // scp::log::ERROR - sc_core::SC_LOW, // scp::log::WARNING - sc_core::SC_MEDIUM, // scp::log::INFO - sc_core::SC_HIGH, // scp::log::DEBUG - sc_core::SC_FULL, // scp::log::TRACE - sc_core::SC_DEBUG // scp::log::TRACEALL -}; + +/* In SystemC there are 2 'scales' the severity which is INFO, WARNING, ERROR and FATAL. + * And Verbosity which is a sub-division of INFO (NONE, LOW, MEDIUM, HIGH, FULL and DEBUG) + * + * Here we add Loging levels: + * CRITICAL, WARN, INFO, TRACE and FULL. + * Which correspond to the Verbosity levels + * SC_NONE, SC_LOW, SC_MEDIUM, SC_HIGH and SC_FULL + */ + namespace sc_core { const sc_core::sc_verbosity SC_UNSET = (sc_core::sc_verbosity)INT_MAX; } @@ -75,25 +66,64 @@ static const char* _SCP_FMT_EMPTY_STR = ""; /**@{*/ //! @brief reporting utilities namespace scp { -//! \brief array holding string representations of log levels -static std::array buffer = { { "NONE", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", - "TRACEALL" } }; -//! \brief enum defining the log levels -enum class log { NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE, TRACEALL, DBGTRACE = TRACEALL }; + +/************************ + * Provide a set of names and conversions that are suitable for logging levels based on + * SystemC "verbosity's" + ************************/ + +enum class log { + NONE = sc_core::SC_NONE, + CRITICAL = sc_core::SC_NONE, + WARN = sc_core::SC_LOW, + INFO = sc_core::SC_MEDIUM, + TRACE = sc_core::SC_HIGH, + FULL = sc_core::SC_DEBUG, + + DEBUG = sc_core::SC_HIGH, + DBGTRACE = sc_core::SC_DEBUG // Only for backward compatibility +}; +inline std::map log_map() +{ + static std::map m = { + { log::NONE, "NONE" }, { log::CRITICAL, "CRITICAL" }, { log::WARN, "WARN" }, + { log::INFO, "INFO" }, { log::TRACE, "TRACE" }, { log::FULL, "FULL" } + }; + return m; +} /** - * @fn log as_log(int) - * @brief safely convert an integer into a log level + * @fn log as_log(sc_verbosity) + * @brief safely convert an sc_verbosity (integer) into a log level * * @param logLevel the logging level * @return the log level */ -inline log as_log(int logLevel) +inline log as_log(sc_core::sc_verbosity logLevel) +{ + auto m = log_map(); + for (auto l : m) { + if (logLevel <= static_cast(l.first)) { + return l.first; + } + } + return log::FULL; +} + +/** + * @fn log as_log(std::string) + * @brief safely convert a string into a log level + * + * @param logName the string name for the log level + * @return the log level + */ +inline log as_log(std::string logName) { - assert(logLevel >= static_cast(log::NONE) && logLevel <= static_cast(log::TRACEALL)); - std::array m = { { log::NONE, log::FATAL, log::ERROR, log::WARNING, log::INFO, log::DEBUG, log::TRACE, - log::TRACEALL } }; - return m[logLevel]; + auto m = log_map(); + for (auto l : m) { + if (logName == l.second) return l.first; + } + sc_assert(false); } /** * @fn std::istream& operator >>(std::istream&, log&) @@ -107,12 +137,7 @@ inline std::istream& operator>>(std::istream& is, log& val) { std::string buf; is >> buf; - for (auto i = 0U; i <= static_cast(log::TRACEALL); ++i) { - if (std::strcmp(buf.c_str(), buffer[i]) == 0) { - val = as_log(i); - return is; - } - } + val = as_log(buf); return is; } /** @@ -125,10 +150,13 @@ inline std::istream& operator>>(std::istream& is, log& val) */ inline std::ostream& operator<<(std::ostream& os, log const& val) { - os << buffer[static_cast(val)]; + auto m = log_map(); + os << m[val]; return os; } +/******************/ + /** * @brief cached logging information used in the (logger) form. * @@ -195,7 +223,7 @@ std::vector get_logging_parameters(); * * @tparam SEVERITY */ -template +template struct ScLogger { /** * @fn ScLogger(const char*, int, int=sc_core::SC_MEDIUM) @@ -228,10 +256,13 @@ struct ScLogger { */ virtual ~ScLogger() noexcept(true) { - auto old = sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR); - sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old &= !sc_core::SC_THROW); + auto old = sc_core::sc_report_handler::set_actions(SEVERITY); + if (WITH_ACTIONS == false) { + sc_core::sc_report_handler::set_actions( + SEVERITY, old & ~(sc_core::SC_THROW | sc_core::SC_INTERRUPT | sc_core::SC_STOP | sc_core::SC_ABORT)); + } ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); - sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old); + sc_core::sc_report_handler::set_actions(SEVERITY, old); } /** * @fn ScLogger& type() @@ -384,48 +415,32 @@ class call_sc_name_fn #define _SCP_FMT_EMPTY_STR(...) "Please add FMT library for FMT support." #endif -#define SCP_LOG(lvl, ...) \ - ::scp::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, lvl / 10).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ +#define SCP_MSG(lvl, ...) \ + ::scp::ScLogger<::sc_core::SC_INFO, false>(__FILE__, __LINE__, lvl).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ << _SCP_FMT_EMPTY_STR /*** End HELPER Macros *******/ -//! macro for debug trace level output -#define SCP_TRACEALL(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_DEBUG, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_DEBUG, __VA_ARGS__) -//! macro for trace level output -#define SCP_TRACE(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_FULL, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_FULL, __VA_ARGS__) -//! macro for debug level output -#define SCP_DEBUG(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_HIGH, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_HIGH, __VA_ARGS__) -//! macro for info level output -#define SCP_INFO(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_MEDIUM, ##__VA_ARGS__)) SCP_LOG(sc_core::SC_MEDIUM, __VA_ARGS__) -//! macro for warning level output -#define SCP_WARN(...) \ - if (SCP_VBSTY_CHECK(sc_core::SC_LOW, ##__VA_ARGS__)) \ - ::scp::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ - << _SCP_FMT_EMPTY_STR -//! macro for error level output -#define SCP_ERR(...) \ - ::scp::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ +#define SCP_LOG(lvl, ...) \ + if (SCP_VBSTY_CHECK(lvl, ##__VA_ARGS__)) SCP_MSG(lvl, __VA_ARGS__) + +#define SCCRITICAL(...) SCP_LOG(log::CRITICAL, ##__VA_ARGS__) +#define SCWARN(...) SCP_LOG(log::WARN, ##__VA_ARGS__) +#define SCINFO(...) SCP_LOG(log::INFO, ##__VA_ARGS__) +#define SCTRACE(...) SCP_LOG(log::TRACE, ##__VA_ARGS__) +#define SCFULL(...) SCP_LOG(log::FULL, ##__VA_ARGS__) + +/* Only for backwards compatibility with SCP library */ +#define SCP_FATAL(...) \ + ::scp::ScLogger<::sc_core::SC_FATAL, true>(__FILE__, __LINE__, sc_core::SC_NONE).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ << _SCP_FMT_EMPTY_STR -//! macro for fatal message output -#define SCP_FATAL(...) \ - ::scp::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, sc_core::SC_MEDIUM) \ - .type(SCP_GET_FEATURES(__VA_ARGS__)) \ - .get() \ +#define SCP_ERR(...) \ + ::scp::ScLogger<::sc_core::SC_ERROR, true>(__FILE__, __LINE__, sc_core::SC_NONE).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ << _SCP_FMT_EMPTY_STR - -#ifdef NDEBUG -#define SCP_ASSERT(expr) ((void)0) -#else -#define SCP_ASSERT(expr) ((void)((expr) ? 0 : (SC_REPORT_FATAL(::sc_core::SC_ID_ASSERTION_FAILED_, #expr), 0))) -#endif +#define SCP_WARN(...) SCP_LOG(sc_core::SC_LOW, ##__VA_ARGS__) +#define SCP_INFO(...) SCP_LOG(sc_core::SC_MEDIUM, ##__VA_ARGS__) +#define SCP_DEBUG(...) SCP_LOG(sc_core::SC_HIGH, ##__VA_ARGS__) +#define SCP_TRACE(...) SCP_LOG(sc_core::SC_FULL, ##__VA_ARGS__) +#define SCP_TRACEALL(...) SCP_LOG(sc_core::SC_DEBUG, ##__VA_ARGS__) } // namespace scp /** @} */ // end of scp-report diff --git a/report/src/logger.cpp b/report/src/logger.cpp index ab9c606..0d30fb6 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -192,31 +192,37 @@ auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) - return ""; } -inline auto get_verbosity(const sc_core::sc_report& rep) -> int -{ - return rep.get_verbosity() > sc_core::SC_NONE && rep.get_verbosity() < sc_core::SC_LOW ? rep.get_verbosity() * 10 - : rep.get_verbosity(); -} - inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, const scp::LogConfig& cfg) { auto msg = compose_message(rep, cfg); if (!msg.size()) return; switch (rep.get_severity()) { case sc_core::SC_INFO: - switch (get_verbosity(rep)) { - case sc_core::SC_DEBUG: - case sc_core::SC_FULL: + { + int v = rep.get_verbosity(); + if (v >= sc_core::SC_DEBUG) { logger.trace(msg); break; - case sc_core::SC_HIGH: + } + if (v >= sc_core::SC_HIGH) { logger.debug(msg); break; - default: + } + if (v >= sc_core::SC_MEDIUM) { logger.info(msg); break; } + if (v >= sc_core::SC_LOW) { + logger.warn(msg); + break; + } + if (v >= sc_core::SC_NONE) { + logger.error(msg); + break; + } + logger.critical(msg); break; + } case sc_core::SC_WARNING: logger.warn(msg); break; @@ -234,26 +240,23 @@ inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, co inline void log2logger(spdlog::logger& logger, scp::log lvl, const std::string& msg) { switch (lvl) { - case scp::log::DBGTRACE: - case scp::log::TRACE: + case scp::log::FULL: logger.trace(msg); return; - case scp::log::DEBUG: + case scp::log::TRACE: logger.debug(msg); return; case scp::log::INFO: logger.info(msg); return; - case scp::log::WARNING: + case scp::log::WARN: logger.warn(msg); return; - case scp::log::ERROR: + case scp::log::CRITICAL: logger.error(msg); return; - case scp::log::FATAL: - logger.critical(msg); - return; default: + logger.critical(msg); break; } } @@ -264,7 +267,7 @@ void report_handler(const sc_core::sc_report& rep, const sc_core::sc_actions& ac if (actions & sc_core::SC_DO_NOTHING) return; if (rep.get_severity() == sc_core::SC_INFO || !log_cfg.report_only_first_error || sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) < 2) { - if ((actions & sc_core::SC_DISPLAY) && (!log_cfg.file_logger || get_verbosity(rep) < sc_core::SC_HIGH)) + if ((actions & sc_core::SC_DISPLAY) && (!log_cfg.file_logger || rep.get_verbosity() < sc_core::SC_HIGH)) log2logger(*log_cfg.console_logger, rep, log_cfg); if ((actions & sc_core::SC_LOG) && log_cfg.file_logger) { scp::LogConfig lcfg(log_cfg); @@ -286,7 +289,7 @@ void report_handler(const sc_core::sc_report& rep, const sc_core::sc_actions& ac } if (actions & sc_core::SC_THROW) { std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(log_cfg.level) * 20)); - throw rep; + sc_core::sc_stop(); } if (sc_core::sc_time_stamp().value() && !sc_core::sc_is_running()) { log_cfg.console_logger->flush(); @@ -314,7 +317,7 @@ static void configure_logging() sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, sc_core::SC_DEFAULT_ERROR_ACTIONS | sc_core::SC_DISPLAY); sc_core::sc_report_handler::set_actions(sc_core::SC_FATAL, sc_core::SC_DEFAULT_FATAL_ACTIONS); - sc_core::sc_report_handler::set_verbosity_level(verbosity[static_cast(log_cfg.level)]); + sc_core::sc_report_handler::set_verbosity_level(static_cast(log_cfg.level)); sc_core::sc_report_handler::set_handler(report_handler); if (!spdlog_initialized) { spdlog::init_thread_pool(1024U, @@ -379,7 +382,7 @@ void scp::init_logging(const scp::LogConfig& log_config) void scp::set_logging_level(scp::log level) { log_cfg.level = level; - sc_core::sc_report_handler::set_verbosity_level(verbosity[static_cast(level)]); + sc_core::sc_report_handler::set_verbosity_level(static_cast(level)); log_cfg.console_logger->set_level(static_cast( SPDLOG_LEVEL_OFF - std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); } diff --git a/report/tests/logger.cc b/report/tests/logger.cc index 2d37c46..3866484 100644 --- a/report/tests/logger.cc +++ b/report/tests/logger.cc @@ -111,13 +111,13 @@ int sc_main(int argc, char** argv) cci_utils::consuming_broker broker("global_broker"); cci_register_broker(broker); cci::cci_originator orig("config"); - broker.set_preset_cci_value("log_level", cci::cci_value(1), orig); - broker.set_preset_cci_value("top.log_level", cci::cci_value(5), orig); - broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(5), orig); - broker.set_preset_cci_value("feature.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("log_level", cci::cci_value("WARN"), orig); + broker.set_preset_cci_value("top.log_level", cci::cci_value(500), orig); + broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(500), orig); + broker.set_preset_cci_value("feature.log_level", cci::cci_value(500), orig); - broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); - broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); + broker.set_preset_cci_value("test4.log_level", cci::cci_value(400), orig); + broker.set_preset_cci_value("thing1.log_level", cci::cci_value(500), orig); std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); scp::scp_logger_from_cci cci_logger; From 393fab81ee9b0d42bf8f91df49ac2caef9a354c8 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 26 Mar 2025 12:41:09 +0100 Subject: [PATCH 14/17] Re-factor to create sc_log separate from SCP Signed-off-by: Mark Burton --- examples/smoke_logger.cc | 94 +++---- report/README.md | 234 ++++++++++-------- .../{scp/sc_report.h => sc_log/sc_log.h} | 153 +++++------- report/include/scp/logger.h | 21 +- report/include/scp/report.h | 65 ++++- report/include/scp/report_cci_setter.h | 31 +-- report/src/logger.cpp | 69 +++--- report/src/sc_report.cpp | 16 +- report/tests/logger.cc | 2 +- 9 files changed, 368 insertions(+), 317 deletions(-) rename report/include/{scp/sc_report.h => sc_log/sc_log.h} (67%) diff --git a/examples/smoke_logger.cc b/examples/smoke_logger.cc index 246984c..28bed98 100644 --- a/examples/smoke_logger.cc +++ b/examples/smoke_logger.cc @@ -30,32 +30,32 @@ SC_MODULE (test4) { SC_CTOR (test4) { - SCP_INFO(()) << " . T4 Logger() 1"; - SCP_WARN(()) << " . T4 Logger() 1"; - SCP_INFO(()) << " . T4 Logger() 2"; - SCP_WARN(()) << " . T4 Logger() 2"; + SC_INFO(()) << " . T4 Logger() 1"; + SC_WARN(()) << " . T4 Logger() 1"; + SC_INFO(()) << " . T4 Logger() 2"; + SC_WARN(()) << " . T4 Logger() 2"; } - SCP_REPORTER(); + SC_LOG_HANDLE(); }; SC_MODULE (test3) { SC_CTOR (test3) { - SCP_INFO((D)) << " . T3 D Logger \"other\" \"feature.one\""; - SCP_WARN((D)) << " . T3 D Logger \"other\" \"feature.one\""; - SCP_INFO(()) << " . T3 Logger ()"; - SCP_WARN(()) << " . T3 Logger ()"; + SC_INFO((D)) << " . T3 D Logger \"other\" \"feature.one\""; + SC_WARN((D)) << " . T3 D Logger \"other\" \"feature.one\""; + SC_INFO(()) << " . T3 Logger ()"; + SC_WARN(()) << " . T3 Logger ()"; } - SCP_REPORTER((D), "other", "feature.one"); - SCP_REPORTER(()); + SC_LOG_HANDLE((D), "other", "feature.one"); + SC_LOG_HANDLE(()); }; SC_MODULE (test2) { SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") { - SCP_INFO(()) << " T2 Logger()"; - SCP_WARN(()) << " T2 Logger()"; + SC_INFO(()) << " T2 Logger()"; + SC_WARN(()) << " T2 Logger()"; } - SCP_REPORTER(); + SC_LOG_HANDLE(); test3 t31, t32; test4 t4; }; @@ -63,52 +63,52 @@ SC_MODULE (test2) { SC_MODULE (test1) { SC_CTOR (test1) : t2("t2") { - SCP_WARN((), "My.Name") << " T1 My.Name typed log"; - SCP_INFO(()) << " T1 Logger()"; - SCP_WARN(()) << " T1 Logger()"; + SC_WARN((), "My.Name") << " T1 My.Name typed log"; + SC_INFO(()) << " T1 Logger()"; + SC_WARN(()) << " T1 Logger()"; - SCP_REPORTER_VECTOR_PUSH_BACK(vec, "some", "thing1"); - SCP_REPORTER_VECTOR_PUSH_BACK(vec, "some", "thing2"); + SC_LOG_HANDLE_VECTOR_PUSH_BACK(vec, "some", "thing1"); + SC_LOG_HANDLE_VECTOR_PUSH_BACK(vec, "some", "thing2"); - SCP_INFO((vec[0])) << "Thing1?"; - SCP_WARN((vec[0])) << "Thing1?"; - SCP_INFO((vec[1])) << "Thing2?"; - SCP_WARN((vec[1])) << "Thing2?"; + SC_INFO((vec[0])) << "Thing1?"; + SC_WARN((vec[0])) << "Thing1?"; + SC_INFO((vec[1])) << "Thing2?"; + SC_WARN((vec[1])) << "Thing2?"; } - SCP_REPORTER("something", "else"); - SCP_REPORTER_VECTOR(vec); + SC_LOG_HANDLE("something", "else"); + SC_LOG_HANDLE_VECTOR(vec); test2 t2; }; class outside_class { - SCP_REPORTER("out.class", "thing1"); + SC_LOG_HANDLE("out.class", "thing1"); public: outside_class() { - SCP_INFO(())("constructor"); - SCP_WARN(())("constructor"); + SC_INFO(())("constructor"); + SC_WARN(())("constructor"); } }; SC_MODULE (test) { outside_class oc; SC_CTOR (test) { - SCP_DEBUG(SCMOD) << "First part"; + SC_DEBUG(SCMOD) << "First part"; scp::tlm_extensions::path_trace ext; ext.stamp(this); - SCP_INFO(SCMOD) << ext.to_string(); + SC_INFO(SCMOD) << ext.to_string(); ext.reset(); ext.stamp(this); ext.stamp(this); ext.stamp(this); - SCP_INFO(SCMOD) << ext.to_string(); + SC_INFO(SCMOD) << ext.to_string(); ext.reset(); - SCP_DEBUG(SCMOD) << "Second part"; + SC_DEBUG(SCMOD) << "Second part"; scp::tlm_extensions::initiator_id mid(0x1234); mid = 0x2345; mid &= 0xff; @@ -121,17 +121,17 @@ SC_MODULE (test) { SC_REPORT_INFO("ext test", "Failour"); } - SCP_INFO() << "Globally cached version empty"; - SCP_INFO(())("FMT String : Locally cached version default"); - SCP_INFO(SCMOD) << "Globally cached version feature using SCMOD macro"; - SCP_INFO((m_my_logger)) << "Locally cached version using (m_my_logger)"; - SCP_INFO((D)) << "Locally cached version with D"; + SC_INFO() << "Globally cached version empty"; + SC_INFO(())("FMT String : Locally cached version default"); + SC_INFO(SCMOD) << "Globally cached version feature using SCMOD macro"; + SC_INFO((m_my_logger)) << "Locally cached version using (m_my_logger)"; + SC_INFO((D)) << "Locally cached version with D"; } - SCP_REPORTER((m_my_logger)); - SCP_REPORTER(()); - SCP_REPORTER((1), "other"); - SCP_REPORTER((D), "other", "feature.one"); + SC_LOG_HANDLE((m_my_logger)); + SC_LOG_HANDLE(()); + SC_LOG_HANDLE((1), "other"); + SC_LOG_HANDLE((D), "other", "feature.one"); }; int sc_main(int argc, char** argv) @@ -147,22 +147,22 @@ int sc_main(int argc, char** argv) broker.set_preset_cci_value("test4.log_level", cci::cci_value(400), orig); broker.set_preset_cci_value("thing1.log_level", cci::cci_value(500), orig); - std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); + std::string logfile = "/tmp/sc_log_smoke_report_test." + std::to_string(getpid()); scp::scp_logger_from_cci cci_logger; - scp::init_logging(scp::LogConfig() - .logLevel(scp::log::DEBUG) // set log level to debug + sc_log::init_logging(sc_log::LogConfig() + .logLevel(sc_log::log_levels::DEBUG) // set log level to debug .msgTypeFieldWidth(20) .fileInfoFrom(5) .logAsync(false) .printSimTime(false) .logFileName(logfile)); // make the msg type column a bit tighter - SCP_INFO() << "Constructing design"; + SC_INFO() << "Constructing design"; test toptest("top"); test1 t1("t1"); - SCP_INFO() << "Starting simulation"; + SC_INFO() << "Starting simulation"; sc_core::sc_start(); - SCP_WARN() << "Ending simulation"; + SC_WARN() << "Ending simulation"; #ifdef FMT_SHARED std::string fmtstr = "FMT String : Locally cached version default"; diff --git a/report/README.md b/report/README.md index dcfa8f9..a16d984 100644 --- a/report/README.md +++ b/report/README.md @@ -1,145 +1,163 @@ + +*** NB the TROW actions in sc_report handler should be marked as deprecated, and users encouraged to calling throw as appropriate in their user code. This removes the ambiguity about whether and what a report handler would throw. +*** #Problem Statement and proposed Solution -This part of the library is intended to provide a convenient way to log information, such that it's easy to adopt and, in doing so, eases the path to code-reuse, (typically "logging libraries" are one of the key common parts which need to be included from each different code base). +This part of the library is intended to provide a convenient way to log information, such that it is easy to adopt and, in doing so, eases the path to code-reuse, (typically "logging libraries" are one of the key common parts which need to be included from each different code base). The goals are: -1/ A simple interface for model writes that supports both "{fmt}" style syntax ("Hello {}","world") and also streaming syntax (<<"Hello "<<"world"). -2/ At the 'back end' an interface should be provided to enable run-time enabling of logging. -3/ The interface mechanism should ensure that a single "if" is checked against the logging level prior to evaluating the full contents of the logging message, such that computationally expensive calls can be used to build the message, and will have no effect on simulation speed if they are not logged. - -This interface is independent of SystemC, however it works with the CCI parameter mechanism, and takes care to avoid name collisions with existing entities in SystemC. - +1/ A simple interface for model writers that supports both "{std::format}" style syntax, available in C++20, such as `"Hello {}","world"` and also streaming syntax `<<"Hello "<<"world"`. +2/ Provided a mechanism to allow run-time enabling of logging, which can be (for instance) connected to the SystemC CCI standard for configuration. +3/ The interface should be efficient, to encourage model writers to be able to use as much logging as they require, without the need to remove it for production code. Hence a single `if` should be used to checked against the logging level prior to evaluating the full contents of the logging message, such that computationally expensive calls can be used to build the message, and will have no effect on simulation speed if they are not reported. # Implementation details -The current implementation of the Logging interface provides a short lived streaming object which collects the information required for logging, and will then pass that to a sc_report_handler. This object should not be used directly, rather the macros described below should be preferred. - -***The logging interface should _NOT_ be used to cause exceptions to be thrown, this should be handled in user code (The underlying sc_report_handler SC_THROW action is deprecated and will be ignored). *** +The implementation of the Logging interface provides a short lived streaming object which collects the information required for logging, and will then pass that to a sc_report_handler. This object should not be used directly, rather the macros described below should be preferred. -## Reporting macros +***The logging interface can _NOT_ be used to cause exceptions to be thrown, this should be handled in user code (The underlying sc_report_handler sc_core::SC_THROW, sc_core::SC_INTERRUPT, sc_core::SC_STOP and sc_core::SC_ABORT actions will be masked). *** -The library offers the following macros. These macros ensure that, in general, a single 'if' is used to guard against output, so they can be used liberally throughout model code. +## Loggin interface -The library uses the Cmake Package Manager to fetch SystemC, CCI, RapidJSON, FMT Library, Spdlog. -For SystemC and CCI by default we use the "Master" Branch. Use a package lock to set a specific version if you need to. +the following levels of logging are pre-defined: + `CRITICAL` : Equivalent to SystemC verbosity `sc_core::SC_NONE` + `WARN` : Equivalent to SystemC verbosity `sc_core::SC_LOW` + `INFO` : Equivalent to SystemC verbosity `sc_core::SC_MEDIUM` + `DEBUG` : Equivalent to SystemC verbosity `sc_core::SC_HIGH` + `TRACE` : Equivalent to SystemC verbosity `sc_core::SC_DEBUG` -see: https://github.com/cpm-cmake/CPM.cmake +The following macros are provided: ----- +`SCMOD` : Convenience for `this->sc_core::sc_module::name()` +`SC_LOG_HANDLE(...)` : Define a log handle, that can be used in subsequent LOG macros. +`SC_LOG_HANDLE_VECTOR(NAME)` : Define a vector of handles. +`SC_LOG_HANDLE_VECTOR_PUSH_BACK(NAME, ...)` : Add to a vector of handles. -The Log levels used by the scp library are as follows : +`SC_LOG_AT(lvl, ...)` : Log at level `lvl` +`SC_CRITICAL(...)` : Log at level `CRITICAL` +`SC_WARN(...)` : Log at level `WARN` +`SC_INFO(...)` : Log at level `INFO` +`SC_DEBUG(...)` : Log at level `DEBUG` +`SC_TRACE(...)` : Log at level `TRACE` -| SCP log
level value | SCP_ report macro | Log levels name | Print Level | Equivelent sc_core | -| --- | --- | --- | --- | --- | -| 0 | NONE | | sc_core::SC_NONE | -| 1 | LOG_CRITICAL() | CRITICAL | sc_core::SC_LOW | `sc_core::SC_FATAL` (Always printed) -| 1 | LOG_WARN() | NOTE | sc_core::SC_LOW | `sc_core::SC_WARNING` -| 4 | LOG_INFO() | INFO | sc_core::SC_MEDIUM| `sc_core::SC_MEDIUM` -| 5 | LOG_TRACE() | DEBUG | sc_core::SC_HIGH | `sc_core::SC_HIGH` -| 6 | LOG_FULL () | TRACE | sc_core::SC_FULL | `sc_core::SC_FULL` +## sc_log macros -Hence NOTES will be printed if the log level is set above 1. Hence setting a log_level of 3 will print Fatal, Error and Warning messages only. - -## SCP_ report macros - -The following SCP_ report macros can process an [{FMT}](https://github.com/fmtlib/fmt) formatter, or operate as a normal stream (accepting normal operators for output). +The following SC_ report macros can process an `{std::format}` formatter, or operate on a stream ```C - SCP_TRACE() << "My trace message"; - SCP_TRACE()("The answer is {}.", 42); + SC_TRACE() << "My trace message"; + SC_TRACE()("The answer is {}.", 42); ``` -The macros can take the following options: +The macros can take the following options (`SC_TRACE` is used as an example, but the forms apply to all macros `SC_LOG_AT(lvl, ...)`, `SC_CRITICAL(...)`, `SC_WARN(...)`, `SC_INFO(...)`, `SC_DEBUG(...)` and `SC_TRACE(...)`): ```C - SCP_TRACE() + SC_TRACE() ``` -Uses the global default report level set up during initialization to determine whether the message is printed. (Defaults to 'SC_WARNING' in the absence of any initialization). No 'feature' information will be printed with the message. +Uses the global default report level as returned by ::sc_core::sc_report_handler::get_verbosity_level() to determine whether the message is printed. (This typically defaults to `SC_LOW` in the absence of any initialization). No 'feature' information will be included with the message. ```C - SCP_TRACE("string") + SC_TRACE("string") ``` -The string represents a `feature` that is being reported upon. The message will be tagged with the feature name, and the feature name will be printed along with the message. The name will also be used to look up a `CCI` parameter with the extension `log_level`. -Hence: -```C - SCP_TRACE("top.mymodel") -``` -will check for, in order of priority: - `top.mymodel.log_level` - `top.log_level` - `log_level` -The first matching parameter will be used. Hence it is possible to set a top level `top.log_level` and overwrite that for specific models in the hierarchy (`top.mymodel.log_level`). -If no parameters with matching names are found, the global default report level set up during initialization will be used (Defaults to 'SC_WARNING' in the absence of any initialization). +The string represents a `feature` that is being reported upon. The message will be tagged with the feature name, and the feature name will be included along with the message. The name will also be used to look up the log level, in order to determine whether the message should be reported or not. -Any string can be used, and it maybe a `std::string` or a `const char*`. Hence, users may create hierarchies of reporting features outside of the SystemC hierarchy itself. None the less, a convenience macro `SCMOD` is provided to use the current `SC_MODULE` name. Hence a typical example would be +Any string can be used, and it maybe a `std::string` or a `const char*`. Hence, users may create hierarchies of reporting features outside of the SystemC hierarchy itself. The convenience macro `SCMOD` is provided to use the current `SC_MODULE` name. Hence a typical example could be ```C - SCP_TRACE(SCMOD) << "My trace message"; + SC_TRACE(SCMOD) << "My trace message"; ``` Having established whether the feature should be printed or not, the result is cached in a lookup table. This lookup table will be used on all subsequent calls to any macro using the same feature string. (see thread safety below) -This form of `SCP_TRACE` uses a global lookup table. This means there is a look-up 'cost' each time an SCP_ report function is used. Also see below for thread safety concerns. (Only one string is permitted in this form, because it will be 'hashed' and used to look up in the table) +**NOTE** Nonetheless, there is a cost of this (string based) lookup. Hence other forms are preferred for critical code. ```C - SCP_TRACE((logger)) + SC_TRACE((handle)) ``` -In this form, the `logger` is expected to be within scope of the macro, it should be instantiated using the `SCP_LOGGER` macro. It will be used to store the debug level at which printing should occur and feature information which will be shared by all users of the `logger`. An alternate form makes use of the default logger (see below) : `SCP_TRACE(())`. +In this form, the `handle` is expected to be within scope when the macro is used, it should be instantiated using the `SC_LOG_HANDLE` macro (see below). It will be used to store the debug level at which printing should occur and feature information which will be shared by all users of the `handle`. + +**NOTE** For both thread safety and critical code regions, this form is preferred. + +For convenience, a "default" handle is provided, and the alternate form makes use of the default handle (see below) : `SC_TRACE(())`. ```C - SCP_TRACE((logger),"string") + SC_TRACE((handle),"string") ``` -Both forms can be used together, in which case the logging type used in the output will be the feature string, while the logger will be used to determine if the +Both forms can be used together, in which case the logging type used in the output will be the feature string, while the handle will be used to determine if the message should be reported. ```C - SCP_LOGGER() + SC_LOG_HANDLE() ``` -The `SCP_LOGGER` macro is used to instantiate a logger for use in an SCP_ report macro. It is expected to be used in a class definition and the logger is expected to be used within that class. It should be constructed with the 'features' of logging for which it will be used. There are several forms of the SCP_LOGGER macro. With no arguments, the macro will construct a logger with the default name in the current scope. It is an error to use the macro more than once with no arguments. +The `SC_LOG_HANDLE` macro is used to instantiate a handle for use in the logging macros. It is expected to be used in a class definition and the handle is expected to be used within that class. It should be constructed with the "features" of logging for which it will be used. There are several forms of the SC_LOG_HANDLE macro. With no arguments, the macro will construct a handle with the "default" name in the current scope. It is an error to use the macro more than once with no arguments. -By default, the logger will be initiated with some default features on the first use of any SCP_ report macro. This MUST happen within the SystemC context (on the SystemC thread) - it is safest to use an `SC_TRACE` macro (for instance) in the sc_module constructor. +By default, the handle will be initiated on the first use of any SC_ report macro, and the log level at which messages are reported will be evaluated at this point (and remain constant from then on). ThFor thread safety, this *MUST* happen within the SystemC context (on the SystemC thread) - it is safest to use an `SC_TRACE` macro (for instance) in the sc_module constructor. The default features are the SystemC hierarchial name (`this->name()`) and the C++ type name. The C++ type name is demangled, and will be pre-pended with the SystemC hierarchical name. -Hence an sc_module `"my_mod"` instanced with the hierarchical name `top.a.b.mod` will automatically include the feature `top.a.b.mod.my_mod` and may be enabled using the parameter `top.a.b.mod.m_mod.log_level`. (See below for wildcard options). +Hence an sc_module `"my_mod"` instanced with the hierarchical name `top.a.b.mod` will automatically include the feature `top.a.b.mod.my_mod`. The CCI interface mechanism (see below) can be used to enable this feature, by using the parameter `top.a.b.mod.m_mod.log_level`. ```C - SCP_LOGGER("string"...) + SC_LOG_HANDLE("string"...) ``` -In this variant, the variable umber of feature strings passes will be *prepended* to the list of default features such that the features listed take precedence over the default features. The strings may be either `std::string`'s or `const char*`'s. +In this variant, the variable number of feature strings passes will be *prepended* to the list of default features such that the features listed take precedence over the default features. The strings may be either `std::string`'s or `const char*`'s. + +The feature names will be pre-pended with the SystemC hierarchical name (at the point the first SC_ report macro is used). -The feature names will be pre-pended with the SystemC hierarchical name (at the point the first SCP_ report macro is used). +Hence a string `"spacial"` used in model `top.a.b` will be inserted as feature `top.a.b.special` (and using CCI may be enabled using the parameter `top.a.b.special.log_level`). -Hence a string `"spacial"` used in model `top.a.b` will be inserted interpreted as feature `top.a.b.special` and may be enabled using the parameter `top.a.b.special.log_level`. (See below for wildcard options). +```C + SC_LOG_HANDLE((my_handle)) +``` +In this form, `my_handle` will be used as the handle name, which should also be used as the handle name for the SC_ report macros. The actual name of the instantiated variable will be 'mangled' such that there is no danger of name collision, hence short handle names are perfectly permissible, they may even be single digits (e.g. `SC_LOG_HANDLE((1))` which would allow the use of report functions such as `SC_TRACE((1))`). Omitting the handle name will be equivalent of the previous macros (hence `SC_LOG_HANDLE(())` is the same as `SC_LOG_HANDLE()`). These variants may be combined e.g. `SC_LOG_HANDLE((1),"feature", "feature.sub_feature")` + +## Report setters and CCI Integration +A special sc_object is defined called sc_log_global_logger_handler ```C - SCP_LOGGER((my_logger)) +struct sc_log_global_logger_handler : sc_core::sc_object { + virtual log_levels operator()(struct sc_log_logger_cache& logger, const char* scname, + const char* tname) const = 0; +}; ``` -In this form, `my_logger` will be used as the logger name, which should also be used as the logger name for the SCP_ report macros. The actual name of the instantiated variable will be 'mangled' such that there is no danger of name collision, hence short logger names are perfectly permissable, they may even be single digits (e.g. `SCP_LOGGER((1))` which would allow the use of report functions such as `SCP_TRACE((1))`. Omitting the logger name will be equivalent of the previous macros (hence `SCP_LOGGER(())` is the same as `SCP_LOGGER()`). These variants may be combined e.g. `SCP_LOGGER((1),"feature", "feature.sub_feature")` +Calls to this function will return the log level for a specific log handle, a systemc hierarchical name, and a type name. Users may implement their own derived instances of this class to determine whether messages should be reported. + +The SCP library contains an instance of this class which uses SyetemC::CCI parameters to determine this information. The following documentation is included here for convenience. -## feature matching rules +## CCI Integration (in thr SCP library) + +The SCP implementation of the global logger handler makes use of CCI parameters suffixed with the extension `log_level`. +Hence: +```C + SC_TRACE("top.mymodel") +``` +will check for, in order of priority: + `top.mymodel.log_level` + `top.log_level` + `log_level` +The first matching parameter will be used. Hence it is possible to set a top level `top.log_level` and overwrite that for specific models in the hierarchy (`top.mymodel.log_level`). +If no parameters with matching names are found, the global default report level set up during initialization will be used (Defaults to 'WARN' in the absence of any initialization). -A logger can be initialized with a variable number of feature strings, each of which may be used to identify features that can then be enabled using CCI parameters. The hierarchical SystemC decomposition is used to find the best match for a feature. The feature (and corresponding log level) that best matches (i.e is the closest in the hierarchy to the feature) will be used. In addition, CCI parameters who's name starts with `*.` can be used to match several levels of hierarchy. +A handle can be initialized with a variable number of feature strings, each of which may be used to identify features that can then be enabled using CCI parameters. The hierarchical SystemC decomposition is used to find the best match for a feature. The feature (and corresponding log level) that best matches (i.e is the closest in the hierarchy to the feature) will be used. In addition, CCI parameters who's name starts with `*.` can be used to match several levels of hierarchy. Hence a module of type `mymod`, instanced with hierarchical name `top.foo` with feature `a.b` will search in order for: -| Priority | | -| --- | --- | -| 4 |`top.foo.a.b.log_level` | -| 3 |`top.foo.a.log_level` | -| 2 |`top.foo.log_level` | -| 4 |`*.foo.a.b.log_level` | -| 3 |`*.foo.a.log_level` | -| 2 |`*.foo.log_level` | -| 3 |`top.a.b.log_level` | -| 2 |`top.a.log_level` | -| 1 |`top.log_level` | -| 2 |`a.b.log_level` | -| 2 |`*.b.log_level` | -| 1 |`mymod.log_level` | -| 1 |`*.log_level` | -| 0 |`log_level` | +| Priority | | +| -------- | ----------------------- | +| 4 | `top.foo.a.b.log_level` | +| 3 | `top.foo.a.log_level` | +| 2 | `top.foo.log_level` | +| 4 | `*.foo.a.b.log_level` | +| 3 | `*.foo.a.log_level` | +| 2 | `*.foo.log_level` | +| 3 | `top.a.b.log_level` | +| 2 | `top.a.log_level` | +| 1 | `top.log_level` | +| 2 | `a.b.log_level` | +| 2 | `*.b.log_level` | +| 1 | `mymod.log_level` | +| 1 | `*.log_level` | +| 0 | `log_level` | @@ -166,44 +184,44 @@ Convenience functions are provided on a configuration structure that return a mo .logFileName(logfile)); ``` -| Use | method | Default -| ---- | ---- | --- | -| set the logging level | `logLevel(int)` | WARNING (3) | -| define the width of the message field, 0 to disable,
`std::numeric_limits::max()` for arbitrary width | ` msgTypeFieldWidth(unsigned)` | | -| enable/disable printing of system time | `printSysTime(bool)` | true | -| enable/disable printing of simulation time | `printSimTime(bool)` | true | -| enable/disable printing delta cycles | `printDelta(bool)` | true | -| enable/disable printing of severity level | `printSeverity(bool)` | true | -| enable/disable colored output | `coloredOutput(bool)` | true | -| set the file name for the log output file | `logFileName([const] std::string&)` | | -| set the regular expression to filter the output | `logFilterRegex([const] std::string&)` | | -| enable/disable asynchronous output (write to file in separate thread | `logAsync(bool)` | true | -| print the file name from this log level | `fileInfoFrom(int)` | sc_core::SC_INFO (4) | -| disable/enable the suppression of all error messages after the first | `reportOnlyFirstError(bool)` | true | +| Use | method | Default | +| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -------------------- | +| set the logging level | `logLevel(int)` | WARNING (3) | +| define the width of the message field, 0 to disable,
`std::numeric_limits::max()` for arbitrary width | ` msgTypeFieldWidth(unsigned)` | | +| enable/disable printing of system time | `printSysTime(bool)` | true | +| enable/disable printing of simulation time | `printSimTime(bool)` | true | +| enable/disable printing delta cycles | `printDelta(bool)` | true | +| enable/disable printing of severity level | `printSeverity(bool)` | true | +| enable/disable colored output | `coloredOutput(bool)` | true | +| set the file name for the log output file | `logFileName([const] std::string&)` | | +| set the regular expression to filter the output | `logFilterRegex([const] std::string&)` | | +| enable/disable asynchronous output (write to file in separate thread | `logAsync(bool)` | true | +| print the file name from this log level | `fileInfoFrom(int)` | sc_core::SC_INFO (4) | +| disable/enable the suppression of all error messages after the first | `reportOnlyFirstError(bool)` | true | ## Thread safety -None of the macro's are thread safe. SCP_LOGGER *must* be used within a SystemC module context. The SCP_ report macros MAY be used outside of a SystemC module context, and may be used on separate threads. However they *must* first be used on the SystemC thread within a module context. +None of the macro's are thread safe. SC_LOG_HANDLE *must* be used within a SystemC module context. The SC_ report macros MAY be used outside of a SystemC module context, and may be used on separate threads. However they *must* first be used on the SystemC thread within a module context. Hence it is recommended that every sc_module constructor includes something like: ```C - SCP_TRACE(()) << "Constructor"; + SC_TRACE(()) << "Constructor"; ``` (This will print the module hierarchy name as well as other information so the short message string is still useful.) -This is equally true whether using a local 'logger' or the global lookup table. When using the global lookup table, in separate threads, care has to be taken that NO logger is added once reporting starts on the non SystemC thread as this could potentially corrupt the lookup table (which is only thread safe for multiple reads). In general, it is highly recommended to use the `(logger)` form for such cases. +This is equally true whether using a local 'handle' or the global lookup table. When using the global lookup table, in separate threads, care has to be taken that NO handle is added once reporting starts on the non SystemC thread as this could potentially corrupt the lookup table (which is only thread safe for multiple reads). In general, it is highly recommended to use the `(handle)` form for such cases. ## Recommendations The recommended way to use this library is: -For Systems that are not using CCI parameters, use the SCP_ report macros with no parameters, either with or without a top level initialization. e.g. `SCP_TRACE() << "your message";` +For Systems that are not using CCI parameters, use the SC_ report macros with no parameters, either with or without a top level initialization. e.g. `SC_TRACE() << "your message";` -For modules that need very occasional reporting can use the "string" form of the SCP_ report macros, ideally using SCMOD. e.g. `SCP_TRACE(SCMOD) << "your message";` +For modules that need very occasional reporting can use the "string" form of the SC_ report macros, ideally using SCMOD. e.g. `SC_TRACE(SCMOD) << "your message";` -For modules that either use a lot of reporting, or require multiple threads, use the `(logger)` form, e.g. `SCP_TRACE(()) << "your message";`. This will require instantiating the logger which can be done with `SCP_LOGGER(())` in the class. +For modules that either use a lot of reporting, or require multiple threads, use the `(handle)` form, e.g. `SC_TRACE(()) << "your message";`. This will require instantiating the handle which can be done with `SC_LOG_HANDLE(())` in the class. -For Systems and modules that have specific features which do not align with the module hierarchy, the `(logger)` form should be used, with additional feature strings. +For Systems and modules that have specific features which do not align with the module hierarchy, the `(handle)` form should be used, with additional feature strings. For the user, reporting can be enabled using CCI parameters. This can be achieved in most cases on the command line. To enable or disable specific modules in the hierarchy the full hierarchy name can be used e.g. `-p top.a.b.my_module.log_level=5`. To enable all instances of a specific model the wildcard can be used e.g. `-p *.model.log_level=5`. A global 'default' can be provided at the top level. @@ -213,15 +231,15 @@ For the user, reporting can be enabled using CCI parameters. This can be achieve Sometimes it's important to use both a 'cached' approach, and to allow the cache to be (locally) dynamic. For instance as now client devices are added to a tlm multi-port, it may be important to log messages per client. To achieve this 2 macros are provided: ```C - SCP_LOGGER_VECTOR(NAME) + SC_LOG_HANDLE_VECTOR(NAME) ``` -This instantiates a vector of loggers (with the base name `NAME`). +This instantiates a vector of handles (with the base name `NAME`). ```C - SCP_LOGGER_VECTOR_PUSH_BACK(NAME, "features"... ) + SC_LOG_HANDLE_VECTOR_PUSH_BACK(NAME, "features"... ) ``` -This will push_back a new logger to the logger vector, initialized with the features listed. -From this point on any of the SCP_ reporting macro's can be used with the form `SCP_INFO((NAME[i]))` +This will push_back a new handle to the handle vector, initialized with the features listed. +From this point on any of the SC_ reporting macro's can be used with the form `SC_INFO((NAME[i]))` ## Utilities diff --git a/report/include/scp/sc_report.h b/report/include/sc_log/sc_log.h similarity index 67% rename from report/include/scp/sc_report.h rename to report/include/sc_log/sc_log.h index 961404b..1d95e28 100644 --- a/report/include/scp/sc_report.h +++ b/report/include/sc_log/sc_log.h @@ -17,8 +17,8 @@ * * THIS FILE IS INTENDED TO BE UP-STREAMED */ -#ifndef _SCP_REPORT_H_ -#define _SCP_REPORT_H_ +#ifndef _SC_LOG_REPORT_H_ +#define _SC_LOG_REPORT_H_ #include #include @@ -49,57 +49,51 @@ * SC_NONE, SC_LOW, SC_MEDIUM, SC_HIGH and SC_FULL */ -namespace sc_core { -const sc_core::sc_verbosity SC_UNSET = (sc_core::sc_verbosity)INT_MAX; -} - //! the name of the CCI property to attach to modules to control logging of //! this module -#define SCP_LOG_LEVEL_PARAM_NAME "log_level" +#define SC_LOG_LEVEL_PARAM_NAME "log_level" // must be global for macro to work. static const char* _SCP_FMT_EMPTY_STR = ""; -/** \ingroup scp-report +/** \ingroup sc_log-report * @{ */ /**@{*/ //! @brief reporting utilities -namespace scp { +namespace sc_log { /************************ * Provide a set of names and conversions that are suitable for logging levels based on * SystemC "verbosity's" ************************/ -enum class log { +enum class log_levels { NONE = sc_core::SC_NONE, CRITICAL = sc_core::SC_NONE, WARN = sc_core::SC_LOW, INFO = sc_core::SC_MEDIUM, - TRACE = sc_core::SC_HIGH, - FULL = sc_core::SC_DEBUG, - DEBUG = sc_core::SC_HIGH, - DBGTRACE = sc_core::SC_DEBUG // Only for backward compatibility + TRACE = sc_core::SC_DEBUG, + + UNSET = INT_MAX }; -inline std::map log_map() +inline std::map log_map() { - static std::map m = { - { log::NONE, "NONE" }, { log::CRITICAL, "CRITICAL" }, { log::WARN, "WARN" }, - { log::INFO, "INFO" }, { log::TRACE, "TRACE" }, { log::FULL, "FULL" } - }; + static std::map m = { { log_levels::NONE, "NONE" }, { log_levels::CRITICAL, "CRITICAL" }, + { log_levels::WARN, "WARN" }, { log_levels::INFO, "INFO" }, + { log_levels::DEBUG, "DEBUG" }, { log_levels::TRACE, "TRACE" } }; return m; } /** - * @fn log as_log(sc_verbosity) - * @brief safely convert an sc_verbosity (integer) into a log level + * @fn log as_log(int) + * @brief safely convert an integer into a log level * * @param logLevel the logging level * @return the log level */ -inline log as_log(sc_core::sc_verbosity logLevel) +inline log_levels as_log(int logLevel) { auto m = log_map(); for (auto l : m) { @@ -107,7 +101,7 @@ inline log as_log(sc_core::sc_verbosity logLevel) return l.first; } } - return log::FULL; + return log_levels::TRACE; } /** @@ -117,13 +111,13 @@ inline log as_log(sc_core::sc_verbosity logLevel) * @param logName the string name for the log level * @return the log level */ -inline log as_log(std::string logName) +inline log_levels as_log(std::string logName) { auto m = log_map(); for (auto l : m) { - if (logName == l.second) return l.first; + if (logName <= l.second) return l.first; } - sc_assert(false); + return log_levels::TRACE; } /** * @fn std::istream& operator >>(std::istream&, log&) @@ -133,7 +127,7 @@ inline log as_log(std::string logName) * @param val the value holding the resulting value * @return the input stream */ -inline std::istream& operator>>(std::istream& is, log& val) +inline std::istream& operator>>(std::istream& is, log_levels& val) { std::string buf; is >> buf; @@ -148,7 +142,7 @@ inline std::istream& operator>>(std::istream& is, log& val) * @param val logging level * @return reference to the stream for chaining */ -inline std::ostream& operator<<(std::ostream& os, log const& val) +inline std::ostream& operator<<(std::ostream& os, log_levels const& val) { auto m = log_map(); os << m[val]; @@ -161,27 +155,26 @@ inline std::ostream& operator<<(std::ostream& os, log const& val) * @brief cached logging information used in the (logger) form. * */ -struct scp_logger_cache { - sc_core::sc_verbosity level = sc_core::SC_UNSET; +struct sc_log_logger_cache { + log_levels level = log_levels::UNSET; std::string type; std::vector features; /** * @brief Initialize the verbosity cache and/or return the cached value. * - * @return sc_core::sc_verbosity + * @return log */ - sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); + log_levels get_log_verbosity_cached(const char*, const char*); }; -struct scp_global_logger_handler : sc_core::sc_object { - virtual sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, const char* scname, - const char* tname) const = 0; +struct sc_log_global_logger_handler : sc_core::sc_object { + virtual log_levels operator()(struct sc_log_logger_cache& logger, const char* scname, const char* tname) const = 0; }; -inline sc_core::sc_verbosity get_log_verbosity() +inline log_levels get_log_verbosity() { - return static_cast(::sc_core::sc_report_handler::get_verbosity_level()); + return static_cast(::sc_core::sc_report_handler::get_verbosity_level()); } /** * @fn sc_core::sc_verbosity get_log_verbosity(const char*) @@ -194,7 +187,8 @@ inline sc_core::sc_verbosity get_log_verbosity() * @param t the SystemC hierarchy scope name * @return the verbosity level */ -sc_core::sc_verbosity get_log_verbosity(char const* t); + +log_levels get_log_verbosity(char const* t); /** * @fn sc_core::sc_verbosity get_log_verbosity(const char*) * @brief get the scope-based verbosity level @@ -206,7 +200,7 @@ sc_core::sc_verbosity get_log_verbosity(char const* t); * @param t the SystemC hierarchy scope name * @return the verbosity level */ -inline sc_core::sc_verbosity get_log_verbosity(std::string const& t) { return get_log_verbosity(t.c_str()); } +inline log_levels get_log_verbosity(std::string const& t) { return get_log_verbosity(t.c_str()); } /** * @brief Return list of logging parameters that have been used @@ -233,7 +227,7 @@ struct ScLogger { * @param line number where the log entry originates * @param verbosity the log level */ - ScLogger(const char* file, int line, int verbosity = sc_core::SC_MEDIUM) + ScLogger(const char* file, int line, log_levels verbosity = sc_log::log_levels::INFO) : t(nullptr), file(file), line(line), level(verbosity) { } @@ -261,7 +255,8 @@ struct ScLogger { sc_core::sc_report_handler::set_actions( SEVERITY, old & ~(sc_core::SC_THROW | sc_core::SC_INTERRUPT | sc_core::SC_STOP | sc_core::SC_ABORT)); } - ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); + ::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), + static_cast(level), file, line); sc_core::sc_report_handler::set_actions(SEVERITY, old); } /** @@ -312,7 +307,7 @@ struct ScLogger { char* t{ nullptr }; const char* file; const int line; - const int level; + const log_levels level; }; /** @@ -346,20 +341,20 @@ struct ScLogger { /********/ /* default logger cache name */ -#define SCP_REPORTER_NAME(x) CAT(_m_scp_log_level_cache_, x) +#define SC_LOG_HANDLE_NAME(x) CAT(_m_sc_log_log_level_cache_, x) /* User interface macros */ #define SCMOD this->sc_core::sc_module::name() -#define SCP_REPORTER(...) \ - scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ - SCP_REPORTER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ - SCP_REPORTER_NAME()) = { sc_core::SC_UNSET, \ - "", \ - { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))(POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } +#define SC_LOG_HANDLE(...) \ + sc_log::sc_log_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ + SC_LOG_HANDLE_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ + SC_LOG_HANDLE_NAME()) = { sc_log::log_levels::UNSET, \ + "", \ + { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))(POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } -#define SCP_REPORTER_VECTOR(NAME) std::vector SCP_REPORTER_NAME(NAME) -#define SCP_REPORTER_VECTOR_PUSH_BACK(NAME, ...) \ - SCP_REPORTER_NAME(NAME).push_back({ sc_core::SC_UNSET, "", { __VA_ARGS__ } }); +#define SC_LOG_HANDLE_VECTOR(NAME) std::vector SC_LOG_HANDLE_NAME(NAME) +#define SC_LOG_HANDLE_VECTOR_PUSH_BACK(NAME, ...) \ + SC_LOG_HANDLE_NAME(NAME).push_back({ sc_log::log_levels::UNSET, "", { __VA_ARGS__ } }); class call_sc_name_fn { @@ -395,18 +390,19 @@ class call_sc_name_fn /*** Helper macros for SCP_ report macros ****/ #define SCP_VBSTY_CHECK_CACHED(lvl, features, cached, ...) \ (cached.level >= lvl) && \ - (cached.get_log_verbosity_cached(scp::call_sc_name_fn()(this), typeid(*this).name()) >= lvl) + (cached.get_log_verbosity_cached(sc_log::call_sc_name_fn()(this), typeid(*this).name()) >= lvl) -#define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) +#define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) (::sc_log::get_log_verbosity(__VA_ARGS__) >= lvl) -#define SCP_VBSTY_CHECK(lvl, ...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (SCP_VBSTY_CHECK_CACHED(lvl, FIRST_ARG(__VA_ARGS__), SCP_REPORTER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ +#define SCP_VBSTY_CHECK(lvl, ...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (SCP_VBSTY_CHECK_CACHED(lvl, FIRST_ARG(__VA_ARGS__), \ + SC_LOG_HANDLE_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ SCP_VBSTY_CHECK_UNCACHED(lvl, ##__VA_ARGS__)) -#define SCP_GET_FEATURES(...) \ - IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ - (FIRST_ARG EXPAND((POP_ARG(__VA_ARGS__, SCP_REPORTER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ +#define SCP_GET_FEATURES(...) \ + IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ + (FIRST_ARG EXPAND((POP_ARG(__VA_ARGS__, SC_LOG_HANDLE_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ __VA_ARGS__) #ifdef FMT_SHARED @@ -415,33 +411,20 @@ class call_sc_name_fn #define _SCP_FMT_EMPTY_STR(...) "Please add FMT library for FMT support." #endif -#define SCP_MSG(lvl, ...) \ - ::scp::ScLogger<::sc_core::SC_INFO, false>(__FILE__, __LINE__, lvl).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ +#define SCP_MSG(lvl, ...) \ + ::sc_log::ScLogger<::sc_core::SC_INFO, false>(__FILE__, __LINE__, lvl).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ << _SCP_FMT_EMPTY_STR /*** End HELPER Macros *******/ -#define SCP_LOG(lvl, ...) \ - if (SCP_VBSTY_CHECK(lvl, ##__VA_ARGS__)) SCP_MSG(lvl, __VA_ARGS__) +#define SC_LOG_AT(lvl, ...) \ + if (SCP_VBSTY_CHECK(lvl, __VA_ARGS__)) SCP_MSG(lvl, __VA_ARGS__) -#define SCCRITICAL(...) SCP_LOG(log::CRITICAL, ##__VA_ARGS__) -#define SCWARN(...) SCP_LOG(log::WARN, ##__VA_ARGS__) -#define SCINFO(...) SCP_LOG(log::INFO, ##__VA_ARGS__) -#define SCTRACE(...) SCP_LOG(log::TRACE, ##__VA_ARGS__) -#define SCFULL(...) SCP_LOG(log::FULL, ##__VA_ARGS__) +#define SC_CRITICAL(...) SC_LOG_AT(sc_log::log_levels::CRITICAL, _VA_ARGS__) +#define SC_WARN(...) SC_LOG_AT(sc_log::log_levels::WARN, __VA_ARGS__) +#define SC_INFO(...) SC_LOG_AT(sc_log::log_levels::INFO, __VA_ARGS__) +#define SC_DEBUG(...) SC_LOG_AT(sc_log::log_levels::DEBUG, __VA_ARGS__) +#define SC_TRACE(...) SC_LOG_AT(sc_log::log_levels::TRACE, __VA_ARGS__) -/* Only for backwards compatibility with SCP library */ -#define SCP_FATAL(...) \ - ::scp::ScLogger<::sc_core::SC_FATAL, true>(__FILE__, __LINE__, sc_core::SC_NONE).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ - << _SCP_FMT_EMPTY_STR -#define SCP_ERR(...) \ - ::scp::ScLogger<::sc_core::SC_ERROR, true>(__FILE__, __LINE__, sc_core::SC_NONE).type(SCP_GET_FEATURES(__VA_ARGS__)).get() \ - << _SCP_FMT_EMPTY_STR -#define SCP_WARN(...) SCP_LOG(sc_core::SC_LOW, ##__VA_ARGS__) -#define SCP_INFO(...) SCP_LOG(sc_core::SC_MEDIUM, ##__VA_ARGS__) -#define SCP_DEBUG(...) SCP_LOG(sc_core::SC_HIGH, ##__VA_ARGS__) -#define SCP_TRACE(...) SCP_LOG(sc_core::SC_FULL, ##__VA_ARGS__) -#define SCP_TRACEALL(...) SCP_LOG(sc_core::SC_DEBUG, ##__VA_ARGS__) - -} // namespace scp -/** @} */ // end of scp-report -#endif /* _SCP_REPORT_H_ */ +} // namespace sc_log +/** @} */ // end of sc_log-report +#endif /* _SC_LOG_REPORT_H_ */ diff --git a/report/include/scp/logger.h b/report/include/scp/logger.h index 7bd8992..bdb1c8f 100644 --- a/report/include/scp/logger.h +++ b/report/include/scp/logger.h @@ -17,16 +17,16 @@ #ifndef _SCP_LOGGER_H_ #define _SCP_LOGGER_H_ -#include "sc_report.h" +#include "sc_log/sc_log.h" /** \ingroup scp-report * @{ */ /**@{*/ //! @brief reporting backend utilities -namespace scp { +namespace sc_log { /** - * @fn void init_logging(log=log::WARN, unsigned=24, bool=false) + * @fn void init_logging(log_levels=log_levels::WARN, unsigned=24, bool=false) * @brief initializes the SystemC logging system with a particular logging * level * @@ -34,7 +34,7 @@ namespace scp { * @param type_field_width the with of the type field in the output * @param print_time whether to print the system time stamp */ -void init_logging(log level = log::WARN, unsigned type_field_width = 24, bool print_time = false); +void init_logging(log_levels level = log_levels::WARN, unsigned type_field_width = 24, bool print_time = false); /** * @fn void init_logging(log=log::WARN, unsigned=24, bool=false) * @brief initializes the SystemC logging system with a particular logging @@ -44,7 +44,7 @@ void init_logging(log level = log::WARN, unsigned type_field_width = 24, bool pr * @param type_field_width the with of the type field in the output * @param print_time whether to print the system time stamp */ -void reinit_logging(log level = log::WARN); +void reinit_logging(log_levels level = log_levels::WARN); /** * @struct LogConfig * @brief the configuration class for the logging setup @@ -53,7 +53,7 @@ void reinit_logging(log level = log::WARN); * class follows the builder pattern. */ struct LogConfig { - log level{ log::WARN }; + log_levels level{ log_levels::WARN }; unsigned msg_type_field_width{ 24 }; bool print_sys_time{ false }; bool print_sim_time{ true }; @@ -67,7 +67,8 @@ struct LogConfig { int file_info_from{ sc_core::SC_INFO }; //! set the logging level - LogConfig& logLevel(log); + LogConfig& logLevel(log_levels); + LogConfig& logLevel(int); //! define the width of the message field, 0 to disable, //! std::numeric_limits::max() for arbitrary width LogConfig& msgTypeFieldWidth(unsigned); @@ -111,14 +112,14 @@ void init_logging(const LogConfig& log_config); * * @param level the logging level */ -void set_logging_level(log level); +void set_logging_level(log_levels level); /** * @fn log get_logging_level() * @brief get the SystemC logging level * * @return the logging level */ -log get_logging_level(); +log_levels get_logging_level(); /** * @fn void set_cycle_base(sc_core::sc_time) * @brief sets the cycle base for cycle based logging @@ -136,6 +137,6 @@ void set_cycle_base(sc_core::sc_time period); * @return the global verbosity level */ -} // namespace scp +} // namespace sc_log /** @} */ // end of scp logger #endif /* _SCP_LOGGER_H_ */ diff --git a/report/include/scp/report.h b/report/include/scp/report.h index 011c90a..e967d80 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -1,13 +1,58 @@ -/* this is merely a convenience to maintain the old API's */ -#include "scp/sc_report.h" +/* this is merely a convenience to maintain the old API's used by SCP. It should be removed once the logger library is + * upstreamed */ + +#ifndef _SCP_BW_REPORT_H_ +#define _SCP_BW_REPORT_H_ + +#include "sc_log/sc_log.h" #include "scp/helpers.h" #include "scp/logger.h" -#define SCP_LOGGER(...) SCP_REPORTER(__VA_ARGS__) -#define SCP_LOGGER_NAME(...) SCP_REPORTER_NAME(__VA_ARGS__) -#define SCP_LOGGER_VECTOR(...) SCP_REPORTER_VECTOR(__VA_ARGS__) -#define SCP_LOGGER_VECTOR_PUSH_BACK(...) SCP_REPORTER_VECTOR_PUSH_BACK(__VA_ARGS__) +/* Only for backwards compatibility with SCP library */ + +#define SCP_LOG_LEVEL_PARAM_NAME SC_LOG_LEVEL_PARAM_NAME + +#define SCP_FATAL(...) \ + ::sc_log::ScLogger<::sc_core::SC_FATAL, true>(__FILE__, __LINE__, sc_log::log_levels::NONE) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ + << _SCP_FMT_EMPTY_STR +#define SCP_ERR(...) \ + ::sc_log::ScLogger<::sc_core::SC_ERROR, true>(__FILE__, __LINE__, sc_log::log_levels::NONE) \ + .type(SCP_GET_FEATURES(__VA_ARGS__)) \ + .get() \ + << _SCP_FMT_EMPTY_STR +#define SCP_WARN(...) SC_LOG_AT(sc_log::log_levels::WARN, __VA_ARGS__) +#define SCP_INFO(...) SC_LOG_AT(sc_log::log_levels::INFO, __VA_ARGS__) +#define SCP_DEBUG(...) SC_LOG_AT(sc_log::log_levels::DEBUG, __VA_ARGS__) +#define SCP_TRACE(...) SC_LOG_AT(sc_log::log_levels::TRACE, __VA_ARGS__) +#define SCP_TRACEALL(...) SC_LOG_AT(sc_log::log_levels::TRACE, __VA_ARGS__) +#define SCP_FULL(...) SC_LOG_AT(sc_log::log_levels::TRACE, __VA_ARGS__) + +#define SCP_LOGGER(...) SC_LOG_HANDLE(__VA_ARGS__) +#define SCP_LOGGER_NAME(...) SC_LOG_HANDLE_NAME(__VA_ARGS__) +#define SCP_LOGGER_VECTOR(NAME) SC_LOG_HANDLE_VECTOR(NAME) +#define SCP_LOGGER_VECTOR_PUSH_BACK(NAME, ...) SC_LOG_HANDLE_VECTOR_PUSH_BACK(NAME, __VA_ARGS__) + +namespace scp { +/* provide weekly typed enum constants for backwards compatibility */ +enum log { + NONE = sc_core::SC_NONE, + CRITICAL = sc_core::SC_NONE, + WARN = sc_core::SC_LOW, + INFO = sc_core::SC_MEDIUM, + DEBUG = sc_core::SC_HIGH, + TRACE = sc_core::SC_DEBUG, + DBGTRACE = sc_core::SC_DEBUG, + FULL = sc_core::SC_DEBUG, +}; +using scp_logger_cache = sc_log::sc_log_logger_cache; +using LogConfig = sc_log::LogConfig; +inline namespace sc_log { +using namespace ::sc_log; +} +} // namespace scp #ifdef FMT_SHARED #ifndef _FMT_CONVENIENCE_DEFINED @@ -29,9 +74,11 @@ struct fmt::formatter>, char> #endif #ifdef HAS_CCI -#ifndef _GLOBAL_SCP_LOGGER_FROM_CCI_DEFINED -#define _GLOBAL_SCP_LOGGER_FROM_CCI_DEFINED +#ifndef _GLOBAL_SC_LOG_LOGGER_FROM_CCI_DEFINED +#define _GLOBAL_SC_LOG_LOGGER_FROM_CCI_DEFINED #include "scp/report_cci_setter.h" -static scp::scp_logger_from_cci _global_scp_logger_from_cci; +static scp::scp_logger_from_cci _global_sc_log_logger_from_cci; #endif // _GLOBAL_SCP_LOGGER_FROM_CCI_DEFINED #endif + +#endif // _SCP_BW_REPORT_H_ \ No newline at end of file diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h index aa3ea80..5d6eac0 100644 --- a/report/include/scp/report_cci_setter.h +++ b/report/include/scp/report_cci_setter.h @@ -16,7 +16,7 @@ #ifndef _SCP_REPORT_CCI_SETTER_H_ #define _SCP_REPORT_CCI_SETTER_H_ -#include +#include #include #include #include @@ -25,7 +25,7 @@ namespace scp { static std::set logging_parameters; -class scp_logger_from_cci : public scp_global_logger_handler +class scp_logger_from_cci : public sc_log::sc_log_global_logger_handler { std::vector split(const std::string& s) const { @@ -53,28 +53,30 @@ class scp_logger_from_cci : public scp_global_logger_handler map.insert(make_pair(n, s)); if (interesting) { - logging_parameters.insert(s + "." SCP_LOG_LEVEL_PARAM_NAME); + logging_parameters.insert(s + "." SC_LOG_LEVEL_PARAM_NAME); } } - sc_core::sc_verbosity cci_lookup(cci::cci_broker_handle broker, std::string name) const + sc_log::log_levels cci_lookup(cci::cci_broker_handle broker, std::string name) const { - auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME : name + "." SCP_LOG_LEVEL_PARAM_NAME; + auto param_name = (name.empty()) ? SC_LOG_LEVEL_PARAM_NAME : name + "." SC_LOG_LEVEL_PARAM_NAME; auto h = broker.get_param_handle(param_name); if (h.is_valid()) { - return static_cast(h.get_cci_value().get_int()); + return static_cast(h.get_cci_value().get_int()); } else { auto val = broker.get_preset_cci_value(param_name); if (val.is_int()) { broker.lock_preset_value(param_name); - return static_cast(val.get_int()); + if (val.get_int() < 100) + return static_cast(val.get_int() * 100); // For 'old' SCP support + return static_cast(val.get_int()); } if (val.is_string()) { broker.lock_preset_value(param_name); - return static_cast(scp::as_log(val.get_string())); + return static_cast(sc_log::as_log(val.get_string())); } } - return sc_core::SC_UNSET; + return sc_log::log_levels::UNSET; } #ifdef __GNUG__ std::string demangle(const char* name) const @@ -92,13 +94,14 @@ class scp_logger_from_cci : public scp_global_logger_handler std::string demangle(const char* name) { return name; } #endif public: - sc_core::sc_verbosity operator()(struct scp_logger_cache& logger, const char* scname, const char* tname) const + sc_log::log_levels operator()(struct sc_log::sc_log_logger_cache& logger, const char* scname, + const char* tname) const { try { // we rely on there being a broker, allow this to throw if not auto broker = sc_core::sc_get_current_object() ? cci::cci_get_broker() - : cci::cci_get_global_broker(cci::cci_originator("scp_reporting_global")); + : cci::cci_get_global_broker(cci::cci_originator("sc_log_reporting_global")); std::multimap> allfeatures; @@ -129,8 +132,8 @@ class scp_logger_from_cci : public scp_global_logger_handler insert(allfeatures, "", false); for (std::pair f : allfeatures) { - sc_core::sc_verbosity v = cci_lookup(broker, f.second); - if (v != sc_core::SC_UNSET) { + sc_log::log_levels v = cci_lookup(broker, f.second); + if (v != sc_log::log_levels::UNSET) { logger.level = v; return v; } @@ -139,7 +142,7 @@ class scp_logger_from_cci : public scp_global_logger_handler // If there is no global broker, revert to initialized verbosity // level } - return logger.level = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); + return logger.level = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); } static std::vector get_logging_parameters() { diff --git a/report/src/logger.cpp b/report/src/logger.cpp index 0d30fb6..1e4c257 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -58,14 +58,14 @@ std::unordered_map lut; thread_local std::unordered_map lut; #endif -struct ExtLogConfig : public scp::LogConfig { +struct ExtLogConfig : public sc_log::LogConfig { std::shared_ptr file_logger; std::shared_ptr console_logger; std::regex reg_ex; sc_core::sc_time cycle_base{ 0, sc_core::SC_NS }; - auto operator=(const scp::LogConfig& o) -> ExtLogConfig& + auto operator=(const sc_log::LogConfig& o) -> ExtLogConfig& { - scp::LogConfig::operator=(o); + sc_log::LogConfig::operator=(o); return *this; } auto match(const char* type) -> bool { return regex_search(type, reg_ex); } @@ -145,7 +145,7 @@ auto time2string(const sc_core::sc_time& t) -> std::string } return oss.str(); } -auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) -> const std::string +auto compose_message(const sc_core::sc_report& rep, const sc_log::LogConfig& cfg) -> const std::string { if (rep.get_severity() > sc_core::SC_INFO || cfg.log_filter_regex.length() == 0 || rep.get_verbosity() == sc_core::SC_MEDIUM || log_cfg.match(rep.get_msg_type())) { @@ -192,13 +192,12 @@ auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) - return ""; } -inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, const scp::LogConfig& cfg) +inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, const sc_log::LogConfig& cfg) { auto msg = compose_message(rep, cfg); if (!msg.size()) return; switch (rep.get_severity()) { - case sc_core::SC_INFO: - { + case sc_core::SC_INFO: { int v = rep.get_verbosity(); if (v >= sc_core::SC_DEBUG) { logger.trace(msg); @@ -237,22 +236,22 @@ inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, co } } -inline void log2logger(spdlog::logger& logger, scp::log lvl, const std::string& msg) +inline void log2logger(spdlog::logger& logger, sc_log::log_levels lvl, const std::string& msg) { switch (lvl) { - case scp::log::FULL: + case sc_log::log_levels::TRACE: logger.trace(msg); return; - case scp::log::TRACE: + case sc_log::log_levels::DEBUG: logger.debug(msg); return; - case scp::log::INFO: + case sc_log::log_levels::INFO: logger.info(msg); return; - case scp::log::WARN: + case sc_log::log_levels::WARN: logger.warn(msg); return; - case scp::log::CRITICAL: + case sc_log::log_levels::CRITICAL: logger.error(msg); return; default: @@ -270,7 +269,7 @@ void report_handler(const sc_core::sc_report& rep, const sc_core::sc_actions& ac if ((actions & sc_core::SC_DISPLAY) && (!log_cfg.file_logger || rep.get_verbosity() < sc_core::SC_HIGH)) log2logger(*log_cfg.console_logger, rep, log_cfg); if ((actions & sc_core::SC_LOG) && log_cfg.file_logger) { - scp::LogConfig lcfg(log_cfg); + sc_log::LogConfig lcfg(log_cfg); lcfg.print_sim_time = true; if (!lcfg.msg_type_field_width) lcfg.msg_type_field_width = 24; log2logger(*log_cfg.file_logger, rep, lcfg); @@ -358,14 +357,14 @@ static void configure_logging() } } -void scp::reinit_logging(scp::log level) +void sc_log::reinit_logging(sc_log::log_levels level) { sc_core::sc_report_handler::set_handler(report_handler); log_cfg.level = level; lut.clear(); } -void scp::init_logging(scp::log level, unsigned type_field_width, bool print_time) +void sc_log::init_logging(sc_log::log_levels level, unsigned type_field_width, bool print_time) { log_cfg.msg_type_field_width = type_field_width; log_cfg.print_sys_time = print_time; @@ -373,13 +372,13 @@ void scp::init_logging(scp::log level, unsigned type_field_width, bool print_tim configure_logging(); } -void scp::init_logging(const scp::LogConfig& log_config) +void sc_log::init_logging(const sc_log::LogConfig& log_config) { log_cfg = log_config; configure_logging(); } -void scp::set_logging_level(scp::log level) +void sc_log::set_logging_level(sc_log::log_levels level) { log_cfg.level = level; sc_core::sc_report_handler::set_verbosity_level(static_cast(level)); @@ -387,89 +386,89 @@ void scp::set_logging_level(scp::log level) SPDLOG_LEVEL_OFF - std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); } -auto scp::get_logging_level() -> scp::log { return log_cfg.level; } +auto sc_log::get_logging_level() -> sc_log::log_levels { return log_cfg.level; } -void scp::set_cycle_base(sc_core::sc_time period) { log_cfg.cycle_base = period; } +void sc_log::set_cycle_base(sc_core::sc_time period) { log_cfg.cycle_base = period; } -auto scp::LogConfig::logLevel(scp::log level) -> scp::LogConfig& +auto sc_log::LogConfig::logLevel(sc_log::log_levels level) -> sc_log::LogConfig& { this->level = level; return *this; } - -auto scp::LogConfig::msgTypeFieldWidth(unsigned width) -> scp::LogConfig& +auto sc_log::LogConfig::logLevel(int level) -> sc_log::LogConfig& { return logLevel(as_log(level)); } +auto sc_log::LogConfig::msgTypeFieldWidth(unsigned width) -> sc_log::LogConfig& { this->msg_type_field_width = width; return *this; } -auto scp::LogConfig::printSysTime(bool enable) -> scp::LogConfig& +auto sc_log::LogConfig::printSysTime(bool enable) -> sc_log::LogConfig& { this->print_sys_time = enable; return *this; } -auto scp::LogConfig::printSimTime(bool enable) -> scp::LogConfig& +auto sc_log::LogConfig::printSimTime(bool enable) -> sc_log::LogConfig& { this->print_sim_time = enable; return *this; } -auto scp::LogConfig::printDelta(bool enable) -> scp::LogConfig& +auto sc_log::LogConfig::printDelta(bool enable) -> sc_log::LogConfig& { this->print_delta = enable; return *this; } -auto scp::LogConfig::printSeverity(bool enable) -> scp::LogConfig& +auto sc_log::LogConfig::printSeverity(bool enable) -> sc_log::LogConfig& { this->print_severity = enable; return *this; } -auto scp::LogConfig::logFileName(std::string&& name) -> scp::LogConfig& +auto sc_log::LogConfig::logFileName(std::string&& name) -> sc_log::LogConfig& { this->log_file_name = name; return *this; } -auto scp::LogConfig::logFileName(const std::string& name) -> scp::LogConfig& +auto sc_log::LogConfig::logFileName(const std::string& name) -> sc_log::LogConfig& { this->log_file_name = name; return *this; } -auto scp::LogConfig::coloredOutput(bool enable) -> scp::LogConfig& +auto sc_log::LogConfig::coloredOutput(bool enable) -> sc_log::LogConfig& { this->colored_output = enable; return *this; } -auto scp::LogConfig::logFilterRegex(std::string&& expr) -> scp::LogConfig& +auto sc_log::LogConfig::logFilterRegex(std::string&& expr) -> sc_log::LogConfig& { this->log_filter_regex = expr; return *this; } -auto scp::LogConfig::logFilterRegex(const std::string& expr) -> scp::LogConfig& +auto sc_log::LogConfig::logFilterRegex(const std::string& expr) -> sc_log::LogConfig& { this->log_filter_regex = expr; return *this; } -auto scp::LogConfig::logAsync(bool v) -> scp::LogConfig& +auto sc_log::LogConfig::logAsync(bool v) -> sc_log::LogConfig& { this->log_async = v; return *this; } -auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& +auto sc_log::LogConfig::reportOnlyFirstError(bool v) -> sc_log::LogConfig& { this->report_only_first_error = v; return *this; } -auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& +auto sc_log::LogConfig::fileInfoFrom(int v) -> sc_log::LogConfig& { this->file_info_from = v; return *this; diff --git a/report/src/sc_report.cpp b/report/src/sc_report.cpp index 0e7f8ec..fc72974 100644 --- a/report/src/sc_report.cpp +++ b/report/src/sc_report.cpp @@ -44,9 +44,9 @@ namespace { // races in the unordered_map #ifdef DISABLE_REPORT_THREAD_LOCAL -std::unordered_map lut; +std::unordered_map lut; #else -thread_local std::unordered_map lut; +thread_local std::unordered_map lut; #endif // BKDR hash algorithm @@ -62,9 +62,9 @@ auto char_hash(char const* str) -> uint64_t } } // namespace -sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached(const char* scname, const char* tname = "") +sc_log::log_levels sc_log::sc_log_logger_cache::get_log_verbosity_cached(const char* scname, const char* tname = "") { - if (level != sc_core::SC_UNSET) { + if (level != sc_log::log_levels::UNSET) { return level; } @@ -75,23 +75,23 @@ sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached(const char // find the first suitable registered sc_object that can handle the lookup for (auto o : sc_core::sc_get_top_level_objects()) { - auto* h = dynamic_cast(o); + auto* h = dynamic_cast(o); if (h) { auto& h_ref = *h; return h_ref(*this, scname, tname); } } - return level = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); + return level = static_cast(::sc_core::sc_report_handler::get_verbosity_level()); } -auto scp::get_log_verbosity(char const* str) -> sc_core::sc_verbosity +auto sc_log::get_log_verbosity(char const* str) -> sc_log::log_levels { auto k = char_hash(str); auto it = lut.find(k); if (it != lut.end()) return it->second; - scp::scp_logger_cache tmp; + sc_log::sc_log_logger_cache tmp; lut[k] = tmp.get_log_verbosity_cached(str); return lut[k]; } diff --git a/report/tests/logger.cc b/report/tests/logger.cc index 3866484..92340be 100644 --- a/report/tests/logger.cc +++ b/report/tests/logger.cc @@ -122,7 +122,7 @@ int sc_main(int argc, char** argv) std::string logfile = "/tmp/scp_smoke_report_test." + std::to_string(getpid()); scp::scp_logger_from_cci cci_logger; scp::init_logging(scp::LogConfig() - .logLevel(scp::log::DEBUG) // set log level to debug + .logLevel(scp::log_levels::DEBUG) // set log level to debug .msgTypeFieldWidth(20) .fileInfoFrom(5) .logAsync(false) From 6c29456bd67cbff96d4e9ce1daf8d220a7e6db2b Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 4 Apr 2025 08:20:57 +0200 Subject: [PATCH 15/17] Align to SystemC/sc_log proposal Signed-off-by: Mark Burton --- report/include/sc_log/sc_log.h | 45 +++++++------------------- report/include/scp/logger.h | 1 + report/include/scp/report_cci_setter.h | 12 +++++-- report/src/logger.cpp | 2 +- report/src/sc_report.cpp | 5 +-- 5 files changed, 27 insertions(+), 38 deletions(-) diff --git a/report/include/sc_log/sc_log.h b/report/include/sc_log/sc_log.h index 1d95e28..612e4a1 100644 --- a/report/include/sc_log/sc_log.h +++ b/report/include/sc_log/sc_log.h @@ -17,8 +17,11 @@ * * THIS FILE IS INTENDED TO BE UP-STREAMED */ -#ifndef _SC_LOG_REPORT_H_ -#define _SC_LOG_REPORT_H_ +#ifndef _SCP_LOG_REPORT_H_ +#define _SCP_LOG_REPORT_H_ + +#include +#ifndef SC_HAS_SC_LOG #include #include @@ -27,32 +30,6 @@ #include #include -#ifdef __GNUG__ -#include -#include -#endif - -#include -#include -#include - -#if defined(_MSC_VER) && defined(ERROR) -#undef ERROR -#endif - -/* In SystemC there are 2 'scales' the severity which is INFO, WARNING, ERROR and FATAL. - * And Verbosity which is a sub-division of INFO (NONE, LOW, MEDIUM, HIGH, FULL and DEBUG) - * - * Here we add Loging levels: - * CRITICAL, WARN, INFO, TRACE and FULL. - * Which correspond to the Verbosity levels - * SC_NONE, SC_LOW, SC_MEDIUM, SC_HIGH and SC_FULL - */ - -//! the name of the CCI property to attach to modules to control logging of -//! this module -#define SC_LOG_LEVEL_PARAM_NAME "log_level" - // must be global for macro to work. static const char* _SCP_FMT_EMPTY_STR = ""; @@ -80,9 +57,10 @@ enum class log_levels { }; inline std::map log_map() { - static std::map m = { { log_levels::NONE, "NONE" }, { log_levels::CRITICAL, "CRITICAL" }, - { log_levels::WARN, "WARN" }, { log_levels::INFO, "INFO" }, - { log_levels::DEBUG, "DEBUG" }, { log_levels::TRACE, "TRACE" } }; + static std::map m = { + { log_levels::CRITICAL, "CRITICAL" }, { log_levels::NONE, "NONE" }, { log_levels::WARN, "WARN" }, + { log_levels::INFO, "INFO" }, { log_levels::DEBUG, "DEBUG" }, { log_levels::TRACE, "TRACE" } + }; return m; } @@ -115,7 +93,7 @@ inline log_levels as_log(std::string logName) { auto m = log_map(); for (auto l : m) { - if (logName <= l.second) return l.first; + if (logName == l.second) return l.first; } return log_levels::TRACE; } @@ -169,7 +147,7 @@ struct sc_log_logger_cache { }; struct sc_log_global_logger_handler : sc_core::sc_object { - virtual log_levels operator()(struct sc_log_logger_cache& logger, const char* scname, const char* tname) const = 0; + virtual log_levels operator()(struct sc_log_logger_cache& logger, std::string_view scname, const char* tname) const = 0; }; inline log_levels get_log_verbosity() @@ -427,4 +405,5 @@ class call_sc_name_fn } // namespace sc_log /** @} */ // end of sc_log-report +#endif // SCP_HAS_SC_LOG #endif /* _SC_LOG_REPORT_H_ */ diff --git a/report/include/scp/logger.h b/report/include/scp/logger.h index bdb1c8f..6bb8941 100644 --- a/report/include/scp/logger.h +++ b/report/include/scp/logger.h @@ -17,6 +17,7 @@ #ifndef _SCP_LOGGER_H_ #define _SCP_LOGGER_H_ +#include #include "sc_log/sc_log.h" /** \ingroup scp-report diff --git a/report/include/scp/report_cci_setter.h b/report/include/scp/report_cci_setter.h index 5d6eac0..acc870a 100644 --- a/report/include/scp/report_cci_setter.h +++ b/report/include/scp/report_cci_setter.h @@ -16,12 +16,20 @@ #ifndef _SCP_REPORT_CCI_SETTER_H_ #define _SCP_REPORT_CCI_SETTER_H_ +#include #include #include #include #include #include +#ifdef __GNUG__ +#include +#include +#endif + +#define SC_LOG_LEVEL_PARAM_NAME "log_level" + namespace scp { static std::set logging_parameters; @@ -94,7 +102,7 @@ class scp_logger_from_cci : public sc_log::sc_log_global_logger_handler std::string demangle(const char* name) { return name; } #endif public: - sc_log::log_levels operator()(struct sc_log::sc_log_logger_cache& logger, const char* scname, + sc_log::log_levels operator()(struct sc_log::sc_log_logger_cache& logger, std::string_view scname, const char* tname) const { try { @@ -106,7 +114,7 @@ class scp_logger_from_cci : public sc_log::sc_log_global_logger_handler std::multimap> allfeatures; /* initialize */ - for (auto scn = split(scname); scn.size(); scn.pop_back()) { + for (auto scn = split(std::string(scname)); scn.size(); scn.pop_back()) { for (int first = 0; first < scn.size(); first++) { auto f = scn.begin() + first; std::vector p(f, scn.end()); diff --git a/report/src/logger.cpp b/report/src/logger.cpp index 1e4c257..8968aaa 100644 --- a/report/src/logger.cpp +++ b/report/src/logger.cpp @@ -20,11 +20,11 @@ * Author: eyck@minres.com */ -#include #include #include #include #include +#include #include #include #include diff --git a/report/src/sc_report.cpp b/report/src/sc_report.cpp index fc72974..e6a47be 100644 --- a/report/src/sc_report.cpp +++ b/report/src/sc_report.cpp @@ -21,9 +21,9 @@ * * THIS FILE IS INTENDED TO BE UP-STREAMED */ - -#include #include +#ifndef SC_HAS_SC_LOG +#include #include #if defined(__GNUC__) || defined(__clang__) @@ -95,3 +95,4 @@ auto sc_log::get_log_verbosity(char const* str) -> sc_log::log_levels lut[k] = tmp.get_log_verbosity_cached(str); return lut[k]; } +#endif // SC_HAS_SC_LOG \ No newline at end of file From 8cc36a866f84aede040902301d3e3ed3f5794547 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 8 Apr 2025 09:20:03 +0200 Subject: [PATCH 16/17] Adjust cmake to be cleaner and remove conflict with AMS Signed-off-by: Mark Burton --- CMakeLists.txt | 13 +++++-------- report/CMakeLists.txt | 4 +++- report/include/scp/report.h | 3 +++ tlm_extensions/initiator_id/CMakeLists.txt | 13 +++++-------- tlm_extensions/path_trace/CMakeLists.txt | 13 +++++-------- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f060b7e..c16fd52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,15 +8,12 @@ set(GITHUB "https://github.com/" CACHE STRING "github base url") include(FetchContent) include(CTest) -FetchContent_Declare( - cpm-cmake - GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git - GIT_SHALLOW True - GIT_TAG v0.31.1 +file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.5/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake ) - -FetchContent_MakeAvailable(cpm-cmake) -include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) +include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") diff --git a/report/CMakeLists.txt b/report/CMakeLists.txt index 8497c59..f714f37 100644 --- a/report/CMakeLists.txt +++ b/report/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(reporting VERSION 1.0 LANGUAGES CXX C) +project(scp_logging VERSION 1.0 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to build all targets.") @@ -102,6 +102,8 @@ enable_testing() add_subdirectory(tests) endif() add_library("scp::report::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) +add_library("scp::reporting" ALIAS "${PROJECT_NAME}") + packageproject( NAME "${PROJECT_NAME}" VERSION ${PROJECT_VERSION} diff --git a/report/include/scp/report.h b/report/include/scp/report.h index e967d80..5f03c9c 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -10,6 +10,9 @@ #include "scp/logger.h" /* Only for backwards compatibility with SCP library */ +#ifdef SC_HAS_SC_LOG +#define _SCP_FMT_EMPTY_STR _SC_LOG_FMT_EMPTY_STR +#endif #define SCP_LOG_LEVEL_PARAM_NAME SC_LOG_LEVEL_PARAM_NAME diff --git a/tlm_extensions/initiator_id/CMakeLists.txt b/tlm_extensions/initiator_id/CMakeLists.txt index ec7fd50..60555be 100644 --- a/tlm_extensions/initiator_id/CMakeLists.txt +++ b/tlm_extensions/initiator_id/CMakeLists.txt @@ -8,15 +8,12 @@ set(GITHUB "https://github.com/" CACHE STRING "github base url") include(FetchContent) include(CTest) -FetchContent_Declare( - cpm-cmake - GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git - GIT_SHALLOW True - GIT_TAG v0.31.1 +file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.5/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake ) - -FetchContent_MakeAvailable(cpm-cmake) -include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) +include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") diff --git a/tlm_extensions/path_trace/CMakeLists.txt b/tlm_extensions/path_trace/CMakeLists.txt index bbd0a76..9555b4e 100644 --- a/tlm_extensions/path_trace/CMakeLists.txt +++ b/tlm_extensions/path_trace/CMakeLists.txt @@ -8,15 +8,12 @@ set(GITHUB "https://github.com/" CACHE STRING "github base url") include(FetchContent) include(CTest) -FetchContent_Declare( - cpm-cmake - GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git - GIT_SHALLOW True - GIT_TAG v0.31.1 +file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.5/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake ) - -FetchContent_MakeAvailable(cpm-cmake) -include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) +include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") From c7d6775520e308607ba5f0300f84e616286c363c Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 9 Apr 2025 08:57:07 +0200 Subject: [PATCH 17/17] Add an Audio Example Signed-off-by: Mark Burton --- examples/audio_example/.clang-format | 44 +++++ examples/audio_example/CMakeLists.txt | 78 ++++++++ examples/audio_example/include/argparser.h | 75 ++++++++ examples/audio_example/include/async_event.h | 129 +++++++++++++ examples/audio_example/include/audiooutput.h | 179 +++++++++++++++++++ examples/audio_example/include/midiplayer.h | 127 +++++++++++++ examples/audio_example/src/main.cc | 68 +++++++ 7 files changed, 700 insertions(+) create mode 100644 examples/audio_example/.clang-format create mode 100644 examples/audio_example/CMakeLists.txt create mode 100644 examples/audio_example/include/argparser.h create mode 100644 examples/audio_example/include/async_event.h create mode 100644 examples/audio_example/include/audiooutput.h create mode 100644 examples/audio_example/include/midiplayer.h create mode 100644 examples/audio_example/src/main.cc diff --git a/examples/audio_example/.clang-format b/examples/audio_example/.clang-format new file mode 100644 index 0000000..ea0ba51 --- /dev/null +++ b/examples/audio_example/.clang-format @@ -0,0 +1,44 @@ +--- +Language: Cpp +BasedOnStyle: Google + +ColumnLimit: 120 +UseTab: Never +IndentWidth: 4 +IndentCaseLabels: false + +PointerAlignment: Left +DerivePointerAlignment: false + +AccessModifierOffset: -4 + +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AlignConsecutiveAssignments: false + +AllowAllArgumentsOnNextLine: false +AllowShortFunctionsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AllowShortLambdasOnASingleLine: true + +BreakConstructorInitializers: BeforeComma +BreakBeforeBinaryOperators: None +BreakStringLiterals: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterFunction: true +# PackConstructorInitializers: Never # When we have clang14 + +SpaceBeforeCtorInitializerColon: false +SpacesBeforeTrailingComments: 1 +AlignTrailingComments: true + +SortIncludes: false +SortUsingDeclarations: false + +Cpp11BracedListStyle: false +PenaltyBreakAssignment: 2000 + +ForEachMacros: ['SC_MODULE', 'SC_CTOR'] diff --git a/examples/audio_example/CMakeLists.txt b/examples/audio_example/CMakeLists.txt new file mode 100644 index 0000000..e22e1bc --- /dev/null +++ b/examples/audio_example/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +project(audioexample VERSION 1.0 LANGUAGES CXX C) + +set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to build all targets.") + +set(GITHUB "https://github.com/" CACHE STRING "github base url") + +include(FetchContent) +include(CTest) + +# download CPM.cmake +file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.2/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake +) +include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + +cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") + +cpmaddpackage( + NAME SystemCLanguage + GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git + GIT_SHALLOW True + GIT_TAG 3.0.1 +) + +set(SYSTEMC_HOME ${SystemCLanguage_SOURCE_DIR}) +include_directories(${SystemCLanguage_SOURCE_DIR}/src) +include_directories(${SystemCAMS_SOURCE_DIR}/src) +cpmaddpackage( + NAME SystemCAMS + GIT_REPOSITORY ${GITHUB}/Risto97/systemc-ams.git + GIT_SHALLOW True + GIT_TAG master +) +message("including ${SystemCAMS_SOURCE_DIR}/src") +target_include_directories(systemc-ams PRIVATE ${SystemCAMS_SOURCE_DIR}/src) + + +cpmaddpackage( + NAME SystemCCCI + GIT_REPOSITORY ${GITHUB}accellera-official/cci.git + GIT_SHALLOW True + GIT_TAG main +) + +cpmaddpackage( + NAME SCP + GIT_REPOSITORY https://github.com/accellera-official/systemc-common-practices.git + GIT_TAG main + GIT_SHALLOW TRUE +) + +cpmaddpackage( + NAME MidiParser + GIT_REPOSITORY https://github.com/MStefan99/Midi-Parser.git + GIT_TAG master + GIT_SHALLOW TRUE +) + +file(DOWNLOAD + https://www.midiworld.com/midis/other/bach/bwv972.mid + ${CMAKE_CURRENT_BINARY_DIR}/bwv972.mid + SHOW_PROGRESS +) + +include_directories(${PORTAUDIO_INCLUDE_DIRS}) +include_directories(include) +add_executable(${PROJECT_NAME} + src/main.cc +) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(PORTAUDIO REQUIRED IMPORTED_TARGET GLOBAL portaudio-2.0) +#include_directories(${PORTAUDIO_INCLUDE_DIRS}) + +target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::systemc SystemC::cci systemc-ams scp::reporting PkgConfig::PORTAUDIO libParser) diff --git a/examples/audio_example/include/argparser.h b/examples/audio_example/include/argparser.h new file mode 100644 index 0000000..6b15fc5 --- /dev/null +++ b/examples/audio_example/include/argparser.h @@ -0,0 +1,75 @@ + +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __ARG_PARSER_H__ +#define __ARG_PARSER_H__ +#include +#include +#include +#include + +std::pair get_key_val_args(const std::string& arg) +{ + std::stringstream ss(arg); + std::string key, value; + + if (!std::getline(ss, key, '=')) { + SCP_FATAL("Parser") << "parameter name not found!" << std::endl; + } + if (!std::getline(ss, value)) { + SCP_FATAL("Parser") << "parameter value not found!" << std::endl; + } + + SCP_INFO("Parser") << "Setting param " << key << " to value " << value; + + return std::make_pair(key, value); +} +void parseCommandLineWithGetOpt(const int argc, const char* const* argv) +{ + SCP_INFO("Parser") << "Parse command line (" << argc << " arguments)"; + + // getopt permutes argv array, so copy it to argv_cp + std::vector> argv_cp; + char* argv_cp_raw[argc]; + for (int i = 0; i < argc; i++) { + size_t len = strlen(argv[i]) + 1; // count \0 + argv_cp.emplace_back(std::make_unique(len)); + strcpy(argv_cp[i].get(), argv[i]); + argv_cp_raw[i] = argv_cp[i].get(); + } + + // configure getopt + optind = 0; // reset of getopt + opterr = 0; // avoid error message for not recognized option + + // Don't add 'i' here. It must be specified as a long option. + const char* optstring = "p:"; + + struct option long_options[] = { { "param", required_argument, 0, 'p' }, // --param foo.baa=10 + { 0, 0, 0, 0 } }; + + while (1) { + int c = getopt_long(argc, argv_cp_raw, optstring, long_options, 0); + if (c == EOF) break; + + switch (c) { + case 'p': // -p and --param + { + auto param = get_key_val_args(std::string(optarg)); + cci::cci_get_global_broker(cci::cci_originator("ArgumentParser")) + .set_preset_cci_value(param.first, cci::cci_value(cci::cci_value::from_json(param.second))); + break; + } + + default: + /* unrecognized option */ + break; + } + } +} + +#endif \ No newline at end of file diff --git a/examples/audio_example/include/async_event.h b/examples/audio_example/include/async_event.h new file mode 100644 index 0000000..a3516dd --- /dev/null +++ b/examples/audio_example/include/async_event.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Author: GreenSocs 2022 + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ASYNC_EVENT +#define ASYNC_EVENT + +#include +#define SC_HAS_SUSPENDING +#define SC_HAS_ASYNC_ATTACH_SUSPENDING +#include +#include +#include +#include + +namespace gs { +class async_event : public sc_core::sc_prim_channel, public sc_core::sc_event +{ +private: + sc_core::sc_time m_delay; + std::thread::id tid; + std::mutex mutex; // Belt and braces + bool outstanding = false; + enum { none, attach, detach } attach_pending_state = none; + +public: + async_event(bool start_attached = true): outstanding(0) + { + tid = std::this_thread::get_id(); + enable_attach_suspending(start_attached); + } + + void async_notify() { notify(); } + + void notify() + { + if (tid == std::this_thread::get_id()) { + sc_core::sc_event::notify(); + } else { + notify(sc_core::SC_ZERO_TIME); + } + } + void notify(double d, sc_core::sc_time_unit u) { notify(sc_core::sc_time(d, u)); } + void notify(sc_core::sc_time delay) + { + if (tid == std::this_thread::get_id()) { + sc_core::sc_event::notify(delay); + } else { + mutex.lock(); + m_delay = delay; + outstanding = true; + mutex.unlock(); + async_request_update(); +#ifndef SC_HAS_SUSPENDING + sc_core::sc_internal_async_wakeup(); +#endif + } + } + + void async_attach_suspending() + { +#ifndef SC_HAS_ASYNC_ATTACH_SUSPENDING + sc_core::async_attach_suspending(this); +#else + if (tid == std::this_thread::get_id()) { + this->sc_core::sc_prim_channel::async_attach_suspending(); + } else { + mutex.lock(); + attach_pending_state = attach; + mutex.unlock(); + async_request_update(); + } +#endif + } + + void async_detach_suspending() + { +#ifndef SC_HAS_ASYNC_ATTACH_SUSPENDING + sc_core::async_detach_suspending(this); +#else + if (tid == std::this_thread::get_id()) { + this->sc_core::sc_prim_channel::async_detach_suspending(); + } else { + mutex.lock(); + attach_pending_state = detach; + mutex.unlock(); + async_request_update(); + } +#endif + } + + void enable_attach_suspending(bool e) { e ? this->async_attach_suspending() : this->async_detach_suspending(); } + +private: + void update(void) + { + mutex.lock(); + // we should be in SystemC thread + if (outstanding) { + sc_event::notify(m_delay); + outstanding = false; + } + switch (attach_pending_state) { + case attach: + this->async_attach_suspending(); + break; + case detach: + this->async_detach_suspending(); + break; + default: + break; + } + attach_pending_state = none; + mutex.unlock(); + } + void start_of_simulation() + { + // we should be in SystemC thread + if (outstanding) { + request_update(); + } + } +}; +} // namespace gs + +#endif // ASYNC_EVENT diff --git a/examples/audio_example/include/audiooutput.h b/examples/audio_example/include/audiooutput.h new file mode 100644 index 0000000..7a4eff6 --- /dev/null +++ b/examples/audio_example/include/audiooutput.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __AUDIOOUTPUT__ +#define __AUDIOOUTPUT__ + +#include +#include +#include +#include +#include "tlm.h" +#include "tlm_utils/simple_target_socket.h" + +#include "async_event.h" + +static int paGlobalCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, + void* userData); + +SC_MODULE (audiooutput) { + SCP_LOGGER(); + + tlm_utils::simple_target_socket socket; + + cci::cci_param p_sample_rate; + cci::cci_param p_frames_per_buffer; + cci::cci_param p_buffer_frames; + + std::queue> frames; + + struct noteinfo { + double frequency; + int channel; + int note; + }; + std::vector notes; + + struct channel { + std::unordered_map notes; + }; + std::unordered_map channels; + + void noteOn(bool on, int midinote, int midichannel) + { + if (on) { + if (channels[midichannel].notes.count(midinote)) { + return; + } + + float a = 442; // at least it is in my orchestra! + float f = (a / 32) * pow(2, ((midinote - 9) / 12.0)); + SCP_INFO(())("Note {} channel {} on", midinote, midichannel); + channels[midichannel].notes[midinote] = { f, midichannel, midinote }; + } else { + SCP_INFO(())("Note {} channel {} off", midinote, midichannel); + channels[midichannel].notes.erase(midinote); + } + } + + void b_transport(tlm::tlm_generic_payload & trans, sc_core::sc_time & delay) + { + auto midi = *reinterpret_cast*>(trans.get_data_ptr()); + noteOn(std::get<0>(midi), std::get<1>(midi), std::get<2>(midi)); + } + + PaStream* stream = nullptr; + + gs::async_event draining; + + void handle_err(PaError err) + { + if (err != paNoError) { + Pa_Terminate(); + SCP_ERR(())( + "An error occurred while using the portaudio stream\n" + "Error number: {}\n" + "Error message: {}", + err, Pa_GetErrorText(err)); + throw std::runtime_error("pa error"); + } + } + SC_CTOR (audiooutput) + : p_sample_rate("sample_rate", 44100, "frames per second") + , p_frames_per_buffer("frames_per_buffer", 1024, "frames per frame") + , p_buffer_frames("buffer_frames", 10, "Number of frames to buffer") + { + SCP_TRACE(())("audio output constructor"); + + handle_err(Pa_Initialize()); + handle_err(Pa_OpenDefaultStream(&stream, 0, /* no input channels */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + p_sample_rate, p_frames_per_buffer, /* frames per buffer */ + paGlobalCallback, this)); + + SC_THREAD(sampler); + + SC_METHOD(drain_control); + sensitive << draining; + dont_initialize(); + + socket.register_b_transport(this, &audiooutput::b_transport); + } + + ~audiooutput() + { + handle_err(Pa_StopStream(stream)); + handle_err(Pa_CloseStream(stream)); + Pa_Terminate(); + } + + void drain_control() + { + if (frames.size() > (p_buffer_frames * p_frames_per_buffer)) { + if (Pa_IsStreamStopped(stream) == 1) { + handle_err(Pa_StartStream(stream)); + } + sc_core::sc_suspend_all(); + } else { + sc_core::sc_unsuspend_all(); + } + } + void sampler() + { + while (1) { + wait(1.0f / p_sample_rate, sc_core::SC_SEC); + + double time = sc_time_stamp().to_seconds(); + double frequency = 440; + double amplitude = 0.1; + double v = 0; + for (auto c : channels) { + for (auto n : c.second.notes) { + v += amplitude * std::sin(2 * M_PI * n.second.frequency * time); + } + } + frames.push({ v, v }); + draining.notify(); + } + } + +public: + /* This routine will be called by the PortAudio engine when audio is needed. + * It may called at interrupt level on some machines so don't do anything + * that could mess up the system like calling malloc() or free(). + */ + int paCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags) + { + float* out = (float*)outputBuffer; + (void)inputBuffer; /* Prevent unused variable warning. */ + + if (frames.size() < framesPerBuffer) { + draining.notify(); + return 1; + } + for (auto i = 0; i < framesPerBuffer; i++) { + assert(frames.size() >= 1); + auto sample = frames.front(); + frames.pop(); + *out++ = sample.first; + *out++ = sample.second; + } + draining.notify(); + return 0; + } +}; + +static int paGlobalCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData) +{ + audiooutput* a = static_cast(userData); + return a->paCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); +} + +#endif diff --git a/examples/audio_example/include/midiplayer.h b/examples/audio_example/include/midiplayer.h new file mode 100644 index 0000000..f5e38d3 --- /dev/null +++ b/examples/audio_example/include/midiplayer.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __MIDIPLAYER__ +#define __MIDIPLAYER__ + +#include +#include +#include +#include +#include "tlm.h" +#include "tlm_utils/simple_initiator_socket.h" + +#include "Midi.h" + +SC_MODULE (midiplayer) { + cci::cci_param midifile; + SCP_LOGGER(); + tlm_utils::simple_initiator_socket socket; + + SC_CTOR (midiplayer) : + midifile("midifile", "bwv972.mid", "Midi file to play") + { + SCP_TRACE(())("Constructor"); + SC_THREAD(reader); + } + + void reader() + { + Midi f{ midifile.get_value().c_str() }; + + auto& header = f.getHeader(); + auto& tracks = f.getTracks(); + + SCP_DEBUG(()) << "File read"; + SCP_DEBUG(()) << "File contents:"; + SCP_DEBUG(()) << " Header:"; + SCP_DEBUG(()) << " File format: " << (int)header.getFormat(); + SCP_DEBUG(()) << " Number of tracks: " << header.getNTracks(); + SCP_DEBUG(()) << " Time division: " << header.getDivision(); + + for (const auto& track : tracks) { + SCP_DEBUG(()) << " Track events:"; + auto& events = track.getEvents(); + + for (const auto& trackEvent : events) { + auto* event = trackEvent.getEvent(); + uint8_t* data; + if (event->getType() == MidiType::EventType::MidiEvent) { + auto* midiEvent = (MidiEvent*)event; + + SCP_DEBUG(()) << " Midi event:"; + auto status = midiEvent->getStatus(); + + if (status == MidiType::MidiMessageStatus::NoteOn) { + if (trackEvent.getDeltaTime().getData() > 0) { + SCP_DEBUG(()) << "\t\t\tLength: " << trackEvent.getDeltaTime().getData(); + wait(trackEvent.getDeltaTime().getData(), sc_core::SC_MS); + } + + SCP_DEBUG(()) << "\t\t\t" << "Note " << (midiEvent->getVelocity() ? "on " : "off ") + << (int)midiEvent->getNote() << " on channel " << (int)midiEvent->getChannel(); + auto n = std::make_tuple(midiEvent->getVelocity(), (int)midiEvent->getNote(), + (int)midiEvent->getChannel()); + tlm::tlm_generic_payload txn; + txn.set_command(tlm::TLM_IGNORE_COMMAND); + txn.set_data_ptr(reinterpret_cast(&n)); + txn.set_data_length(sizeof(n)); + txn.set_streaming_width(sizeof(n)); + txn.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + sc_core::sc_time delta; + socket->b_transport(txn, delta); + } else if (status == MidiType::MidiMessageStatus::NoteOff) { + if (trackEvent.getDeltaTime().getData() > 0) { + SCP_DEBUG(()) << "\t\t\tLength: " << trackEvent.getDeltaTime().getData(); + wait(trackEvent.getDeltaTime().getData(), sc_core::SC_MS); + } + SCP_DEBUG(()) << "\t\t\t" << "Note off " << (int)midiEvent->getNote() << " on channel " + << (int)midiEvent->getChannel(); + auto n = std::make_tuple(false, (int)midiEvent->getNote(), + (int)midiEvent->getChannel()); + tlm::tlm_generic_payload txn; + txn.set_command(tlm::TLM_IGNORE_COMMAND); + txn.set_data_ptr(reinterpret_cast(&n)); + txn.set_data_length(sizeof(n)); + txn.set_streaming_width(sizeof(n)); + txn.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + sc_core::sc_time delta; + socket->b_transport(txn, delta); + } else { + SCP_DEBUG(()) << "\t\t\tStatus: 0x" << hex << (int)midiEvent->getStatus(); + SCP_DEBUG(()) << "\t\t\tData: 0x" << midiEvent->getData() << dec; + } + } else if (event->getType() == MidiType::EventType::SysExEvent) { + SCP_DEBUG(()) << "\t\tSystem exclusive event:"; + SCP_DEBUG(()) << "\t\t\tStatus: 0x" << hex << ((MetaEvent*)event)->getStatus(); + SCP_DEBUG(()) << "\t\t\tData: 0x"; + + data = ((MetaEvent*)event)->getData(); + for (int i{ 0 }; i < ((MetaEvent*)event)->getLength(); ++i) { + SCP_DEBUG(()) << (int)data[i]; + } + SCP_DEBUG(()) << dec; + } else { // event->getType() == MidiType::EventType::MetaEvent + SCP_DEBUG(()) << "\t\tMeta event:"; + SCP_DEBUG(()) << "\t\t\tStatus: 0x" << hex << ((MetaEvent*)event)->getStatus(); + SCP_DEBUG(()) << "\t\t\tData: 0x"; + + data = ((MetaEvent*)event)->getData(); + for (int i{ 0 }; i < ((MetaEvent*)event)->getLength(); ++i) { + SCP_DEBUG(()) << (int)data[i]; + } + if (!((MetaEvent*)event)->getLength()) { + SCP_DEBUG(()) << "0"; + } + SCP_DEBUG(()) << dec; + } + } + } + sc_core::sc_stop(); + } +}; + +#endif \ No newline at end of file diff --git a/examples/audio_example/src/main.cc b/examples/audio_example/src/main.cc new file mode 100644 index 0000000..a8c0932 --- /dev/null +++ b/examples/audio_example/src/main.cc @@ -0,0 +1,68 @@ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include +#include +#define HAS_CCI +#include +#include "argparser.h" +#include "audiooutput.h" +#include "midiplayer.h" + +int sc_main(int argc, char* argv[]) +{ + cci_utils::consuming_broker m_broker("Broker"); + cci_register_broker(m_broker); + parseCommandLineWithGetOpt(argc, argv); + scp::init_logging(scp::LogConfig() + .fileInfoFrom(sc_core::SC_ERROR) + .logAsync(true) + .logLevel(scp::log::DBGTRACE) // set log level to DBGTRACE = TRACEALL + .msgTypeFieldWidth(30)); // make the msg type column a bit tighter + + audiooutput m_audio("MyAudio"); + midiplayer m_player("MyMidiPlayer"); + m_audio.socket(m_player.socket); + sc_core::sc_start(); + + return 0; +}