1+ /* ******************************************************************************
2+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ *******************************************************************************/
16+ #ifndef _SCP_REPORT_CCI_SETTER_H_
17+ #define _SCP_REPORT_CCI_SETTER_H_
18+
19+ #include < scp/report.h>
20+ #include < cci_configuration>
21+ #include < type_traits>
22+ #include < regex>
23+
24+ namespace scp {
25+ static std::set<std::string> logging_parameters;
26+
27+ class scp_logger_from_cci
28+ {
29+ std::vector<std::string> split (const std::string& s) const {
30+ std::vector<std::string> result;
31+ std::istringstream iss (s);
32+ std::string item;
33+ while (std::getline (iss, item, ' .' )) {
34+ result.push_back (item);
35+ }
36+ return result;
37+ }
38+
39+ std::string join (std::vector<std::string> vec) const {
40+ if (vec.empty ())
41+ return " " ;
42+ return std::accumulate (
43+ vec.begin (), vec.end (), std::string (),
44+ [](const std::string& a, const std::string& b) -> std::string {
45+ return a + (a.length () > 0 ? " ." : " " ) + b;
46+ });
47+ }
48+
49+ void insert (std::multimap<int , std::string, std::greater<int >>& map,
50+ std::string s, bool interesting) const {
51+ int n = std::count (s.begin (), s.end (), ' .' );
52+ map.insert (make_pair (n, s));
53+
54+ if (interesting) {
55+ logging_parameters.insert (s + " ." SCP_LOG_LEVEL_PARAM_NAME);
56+ }
57+ }
58+ sc_core::sc_verbosity cci_lookup (cci::cci_broker_handle broker,
59+ std::string name) const {
60+ auto param_name = (name.empty ()) ? SCP_LOG_LEVEL_PARAM_NAME
61+ : name + " ." SCP_LOG_LEVEL_PARAM_NAME;
62+ auto h = broker.get_param_handle (param_name);
63+ if (h.is_valid ()) {
64+ return verbosity.at (std::min<unsigned >(h.get_cci_value ().get_int (),
65+ verbosity.size () - 1 ));
66+ } else {
67+ auto val = broker.get_preset_cci_value (param_name);
68+
69+ if (val.is_int ()) {
70+ broker.lock_preset_value (param_name);
71+ return verbosity.at (
72+ std::min<unsigned >(val.get_int (), verbosity.size () - 1 ));
73+ }
74+ }
75+ return sc_core::SC_UNSET;
76+ }
77+ #ifdef __GNUG__
78+ std::string demangle (const char * name) const {
79+ int status = -4 ; // some arbitrary value to eliminate the compiler
80+ // warning
81+
82+ // enable c++11 by passing the flag -std=c++11 to g++
83+ std::unique_ptr<char , void (*)(void *)> res{
84+ abi::__cxa_demangle (name, NULL , NULL , &status), std::free
85+ };
86+
87+ return (status == 0 ) ? res.get () : name;
88+ }
89+ #else
90+ // does nothing if not GNUG
91+ std::string demangle (const char * name) { return name; }
92+ #endif
93+ public:
94+ sc_core::sc_verbosity operator ()(struct scp_logger_cache & logger,
95+ const char * scname,
96+ const char * tname) const {
97+ try {
98+ // we rely on there being a broker, allow this to throw if not
99+ auto broker = sc_core::sc_get_current_object ()
100+ ? cci::cci_get_broker ()
101+ : cci::cci_get_global_broker (cci::cci_originator (
102+ " scp_reporting_global" ));
103+
104+ std::multimap<int , std::string, std::greater<int >> allfeatures;
105+
106+ /* initialize */
107+ for (auto scn = split (scname); scn.size (); scn.pop_back ()) {
108+ for (int first = 0 ; first < scn.size (); first++) {
109+ auto f = scn.begin () + first;
110+ std::vector<std::string> p (f, scn.end ());
111+ auto scn_str = ((first > 0 ) ? " *." : " " ) + join (p);
112+
113+ for (auto ft : logger.features ) {
114+ for (auto ftn = split (ft); ftn.size ();
115+ ftn.pop_back ()) {
116+ insert (allfeatures, scn_str + " ." + join (ftn),
117+ first == 0 );
118+ }
119+ }
120+ insert (allfeatures, scn_str + " ." + demangle (tname),
121+ first == 0 );
122+ insert (allfeatures, scn_str, first == 0 );
123+ }
124+ }
125+ for (auto ft : logger.features ) {
126+ for (auto ftn = split (ft); ftn.size (); ftn.pop_back ()) {
127+ insert (allfeatures, join (ftn), true );
128+ insert (allfeatures, " *." + join (ftn), false );
129+ }
130+ }
131+ insert (allfeatures, demangle (tname), true );
132+ insert (allfeatures, " *" , false );
133+ insert (allfeatures, " " , false );
134+
135+ for (std::pair<int , std::string> f : allfeatures) {
136+ sc_core::sc_verbosity v = cci_lookup (broker, f.second );
137+ if (v != sc_core::SC_UNSET) {
138+ logger.level = v;
139+ return v;
140+ }
141+ }
142+ } catch (const std::exception&) {
143+ // If there is no global broker, revert to initialized verbosity
144+ // level
145+ }
146+ return logger.level = static_cast <sc_core::sc_verbosity>(
147+ ::sc_core::sc_report_handler::get_verbosity_level ());
148+ }
149+ static std::vector<std::string> get_logging_parameters () {
150+ return std::vector<std::string>(logging_parameters.begin (),
151+ logging_parameters.end ());
152+ }
153+ };
154+
155+ #if 0
156+
157+ /*template <typename T, typename = int>
158+ struct HasLogger : std::false_type { };
159+
160+ template <typename T>
161+ struct HasLogger <T, decltype((void) T::SCP_LOGGER_NAME(), 0)> : std::true_type
162+ { };
163+ */
164+
165+ class set_logger_level
166+ {
167+ template <class T>
168+ static auto test(T* p) -> decltype(p->SCP_LOGGER_NAME(), std::true_type());
169+ template <class T>
170+ static auto test(...) -> decltype(std::false_type());
171+
172+ template <class T>
173+ static constexpr bool has_logger = decltype(test<T>(nullptr))::value;
174+
175+ public:
176+ // define a function IF the method exists
177+ template <class TYPE>
178+ auto operator()(TYPE* p, sc_core::sc_verbosity level) const
179+ -> std::enable_if_t<has_logger<TYPE>> {
180+ p->SCP_LOGGER_NAME().level = level;
181+ }
182+
183+ // define a function IF NOT the method exists
184+ template <class TYPE>
185+ auto operator()(TYPE* p, sc_core::sc_verbosity level) const
186+ -> std::enable_if_t<!has_logger<TYPE>> {}
187+ };
188+
189+ int set_log_levels(std::string path, sc_core::sc_verbosity level,
190+ sc_core::sc_object* m = nullptr, bool set = false) {
191+ int found = 0;
192+ auto pathdot = path.find_first_of('.');
193+ auto lpath = (pathdot != std::string::npos) ? path.substr(pathdot) : path;
194+
195+ if (m) {
196+ std::string mname = std::string(m->name());
197+ auto namedot = mname.find_last_of('.');
198+ auto lname = (namedot != std::string::npos) ? mname.substr(namedot)
199+ : mname;
200+
201+ if (!((lpath == "*") || (lpath == lname))) {
202+ // no match here
203+ return found;
204+ }
205+ }
206+ if (path.substr(pathdot) == SCP_LOG_LEVEL_PARAM_NAME) {
207+ // Found it
208+ set = true;
209+ }
210+
211+ if (set) {
212+ found++;
213+ scp::set_logger_level()(m, level);
214+ }
215+ std::vector<sc_core::sc_object*> children;
216+ if (m) {
217+ children = m->get_child_objects();
218+ } else {
219+ children = sc_core::sc_get_top_level_objects();
220+ }
221+
222+ for (auto c : children) {
223+ if (lpath == "*") {
224+ found += set_log_levels(path, level, c, set);
225+ }
226+ if (pathdot != std::string::npos) {
227+ found += set_log_levels(path.substr(pathdot), level, c, set);
228+ }
229+ }
230+ return found;
231+ };
232+
233+ void cci_enable_logging(cci::cci_broker_handle broker) {
234+ std::string pname = std::string(".") + SCP_LOG_LEVEL_PARAM_NAME;
235+ int plen = std::string(SCP_LOG_LEVEL_PARAM_NAME).length();
236+ std::vector<cci::cci_name_value_pair> logging_paths;
237+ for (auto path : broker.get_unconsumed_preset_values(
238+ [&plen](const std::pair<std::string, cci::cci_value>& iv) {
239+ if (iv.first.length() >= plen) {
240+ return (0 == iv.first.compare(iv.first.length() - plen,
241+ plen,
242+ SCP_LOG_LEVEL_PARAM_NAME));
243+ } else {
244+ return false;
245+ }
246+ })) {
247+ logging_paths.push_back(path);
248+ }
249+
250+ std::sort(logging_paths.begin(), logging_paths.end(),
251+ [&](cci::cci_name_value_pair& s1, cci::cci_name_value_pair& s2) {
252+ return std::count(s1.first.begin(), s1.first.end(), '.') >
253+ std::count(s2.first.begin(), s2.first.end(), '.');
254+ });
255+ for (auto path : logging_paths) {
256+ int found = set_log_levels(
257+ path.first, (sc_core::sc_verbosity)(path.second.get_int()));
258+ if (found == 0) {
259+ SCP_WARN()("No logger named {} found", path.first);
260+ } else {
261+ SCP_INFO()("{} loggers enabled from name {}", found, path.first);
262+ }
263+ }
264+ }
265+ #endif
266+
267+ } // namespace scp
268+
269+ #endif
0 commit comments