From 179b764f064a4028f5ce2cb257bdb70adffe5e4a Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 20 Mar 2024 20:34:57 +0100 Subject: [PATCH] Split the CCI mechanism from the rest of remote.h Signed-off-by: Mark Burton --- examples/smoke_report.cc | 67 +----- report/CMakeLists.txt | 10 +- report/include/scp/report.h | 29 ++- report/include/scp/report_cci_setter.h | 269 +++++++++++++++++++++++++ report/src/report.cpp | 157 +-------------- 5 files changed, 316 insertions(+), 216 deletions(-) create mode 100644 report/include/scp/report_cci_setter.h diff --git a/examples/smoke_report.cc b/examples/smoke_report.cc index 3a86de7..6353c03 100644 --- a/examples/smoke_report.cc +++ b/examples/smoke_report.cc @@ -144,14 +144,12 @@ 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::init_logging(scp::LogConfig() + .logLevel(scp::log::DEBUG) // set log level to debug + .msgTypeFieldWidth(20) + .fileInfoFrom(5) + .logAsync(false) + .printSimTime(false)); SCP_INFO() << "Constructing design"; test toptest("top"); test1 t1("t1"); @@ -160,56 +158,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/CMakeLists.txt b/report/CMakeLists.txt index 7a51f63..62fdf17 100644 --- a/report/CMakeLists.txt +++ b/report/CMakeLists.txt @@ -97,17 +97,15 @@ 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() +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( diff --git a/report/include/scp/report.h b/report/include/scp/report.h index 4ba6f9a..c190dd6 100644 --- a/report/include/scp/report.h +++ b/report/include/scp/report.h @@ -44,7 +44,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; } @@ -168,6 +187,10 @@ struct LogConfig { bool report_only_first_error{ false }; int file_info_from{ sc_core::SC_INFO }; + std::function + log_level_lookup_fn; + //! set the logging level LogConfig& logLevel(log); //! define the width of the message field, 0 to disable, @@ -197,6 +220,10 @@ struct LogConfig { LogConfig& fileInfoFrom(int); //! disable/enable the supression of all error messages after the first LogConfig& reportOnlyFirstError(bool = true); + //! register log level function + LogConfig& registerLogLevelFn( + std::function); }; /** 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/report.cpp b/report/src/report.cpp index f5a87a7..7195fe9 100644 --- a/report/src/report.cpp +++ b/report/src/report.cpp @@ -25,9 +25,6 @@ #include #include #include -#ifdef HAS_CCI -#include -#endif #include #include #include @@ -60,11 +57,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; struct ExtLogConfig : public scp::LogConfig { std::shared_ptr file_logger; @@ -341,26 +333,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 -}; static std::mutex cfg_guard; static void configure_logging() { std::lock_guard lock(cfg_guard); @@ -534,79 +506,12 @@ 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; - 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); - } +auto scp::LogConfig::registerLogLevelFn( + std::function + fn) -> scp::LogConfig& { + this->log_level_lookup_fn = fn; + return *this; } sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( @@ -622,56 +527,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()); }