Merge "Sync UTC harness" into devel/master
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.h
1 #ifndef DALI_INTEGRATION_DEBUG_H
2 #define DALI_INTEGRATION_DEBUG_H
3
4 /*
5  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23 #include <cstring>
24 #include <iostream>
25 #include <list>
26 #include <sstream>
27 #include <string>
28
29 #include <dali/public-api/common/vector-wrapper.h>
30 #include <dali/public-api/object/property-map.h>
31
32 // INTERNAL INCLUDES
33 #include <dali/public-api/common/dali-common.h>
34
35 // Using Debug namespace alias shortens the log usage significantly
36 namespace Dali
37 {
38 namespace Integration
39 {
40 namespace Log
41 {
42 }
43 } // namespace Integration
44 } // namespace Dali
45 namespace Debug = Dali::Integration::Log;
46
47 namespace Dali
48 {
49 struct Vector2;
50 struct Vector3;
51 struct Vector4;
52 class Matrix3;
53 class Matrix;
54 class Quaternion;
55
56 #if defined(DEBUG_ENABLED)
57
58 // Less opaque types for debugger
59 typedef std::vector<Dali::Property::Value> DebugPropertyValueArray;
60 using DebugIndexValuePair       = std::pair<Property::Index, Property::Value>;
61 using DebugStringValueContainer = std::vector<Dali::StringValuePair>;
62 using DebugIndexValueContainer  = std::vector<DebugIndexValuePair>;
63
64 struct DebugPropertyValueMap
65 {
66   DebugStringValueContainer stringValues;
67   DebugIndexValueContainer  intValues;
68 };
69
70 // Fake globals for gdb typedefs
71 extern Dali::DebugPropertyValueArray gValueArray;
72 extern Dali::DebugPropertyValueMap   gValueMap;
73
74 #endif
75
76 namespace Integration
77 {
78 namespace Log
79 {
80 enum DebugPriority
81 {
82   DEBUG,
83   INFO,
84   WARNING,
85   ERROR
86 };
87
88 /**
89  * Used by logging macros to log a message
90  * @param level debug level
91  * @param format string format
92  */
93 DALI_CORE_API void LogMessage(enum DebugPriority level, const char* format, ...);
94
95 /**
96  * Prefix macros to sync with dlog logger format
97  * __MODULE__ macro also defined at dlog-internal.h
98  */
99 #ifndef DALI_LOG_FORMAT_PREFIX
100 #ifndef __MODULE__
101 #define __MODULE__ (std::strrchr(__FILE__, '/') ? std::strrchr(__FILE__, '/') + 1 : __FILE__)
102 #endif
103 #define DALI_LOG_FORMAT_PREFIX "%s: %s(%d) > "
104 #define DALI_LOG_FORMAT_PREFIX_ARGS __MODULE__, __func__, __LINE__
105 #endif
106
107 /**
108  * Global logging macros to log a message along with function/class name and line
109  * @param level debug level
110  * @param format string format
111  */
112 #define LogMessageWithFunctionLine(level, format, ...)                            \
113   LogMessage(level,                                                               \
114              (std::string(DALI_LOG_FORMAT_PREFIX) + std::string(format)).c_str(), \
115              DALI_LOG_FORMAT_PREFIX_ARGS,                                         \
116              ##__VA_ARGS__)
117
118 /**
119  * typedef for the logging function.
120  */
121 using LogFunction = void (*)(DebugPriority, std::string&);
122
123 /**
124  * A log function has to be installed for every thread that wants to use logging.
125  * This should be done by the adaptor.
126  * The log function can be different for each thread.
127  * @param logFunction the log function to install
128  * @param logOpts the log options to save in thread
129  */
130 DALI_CORE_API void InstallLogFunction(const LogFunction& logFunction);
131
132 /**
133  * A log function has to be uninstalled for every thread that wants to use logging.
134  * The log function can be different for each thread.
135  */
136 DALI_CORE_API void UninstallLogFunction();
137
138 /********************************************************************************
139  *                            Error/Warning  macros.                            *
140  ********************************************************************************/
141
142 /**
143  * Provides unfiltered logging for global error level messages
144  */
145 #define DALI_LOG_ERROR(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::ERROR, format, ##__VA_ARGS__)
146
147 #define DALI_LOG_ERROR_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::ERROR, format, ##__VA_ARGS__)
148
149 #define DALI_LOG_WARNING_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::WARNING, format, ##__VA_ARGS__)
150
151 /**
152  * Provides unfiltered logging for fps monitor
153  */
154 #define DALI_LOG_FPS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
155
156 /**
157  * Provides unfiltered logging for update status
158  */
159 #define DALI_LOG_UPDATE_STATUS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
160
161 /**
162  * Provides unfiltered logging for render information
163  */
164 #define DALI_LOG_RENDER_INFO(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
165
166 /**
167  * Provides unfiltered logging for release
168  */
169 #define DALI_LOG_RELEASE_INFO(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
170
171 /**
172  * Provides unfiltered logging for debuf information
173  */
174 #define DALI_LOG_DEBUG_INFO(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::DEBUG, format, ##__VA_ARGS__)
175
176 #ifdef DEBUG_ENABLED
177
178 /**
179  * Provides unfiltered logging for global warning level messages
180  */
181 #define DALI_LOG_WARNING(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::WARNING, "%s " format, ASSERT_LOCATION, ##__VA_ARGS__)
182
183 #else // DEBUG_ENABLED
184
185 // Don't warn on release build
186 #define DALI_LOG_WARNING(format, ...)
187
188 #endif
189
190 /********************************************************************************
191  *                                    Filter                                    *
192  ********************************************************************************/
193
194 #ifdef DEBUG_ENABLED
195
196 /**
197  * Enumeration of logging levels.
198  * Used by the filters to provide multiple log levels.
199  * In general, the higher the value, the more debug is available for that filter.
200  */
201 enum LogLevel
202 {
203   NoLogging = 0,
204   Concise   = 1,
205   General   = 2,
206   Verbose   = 3
207 };
208
209 /**
210  * The Filter object is used by the DALI_LOG_INFO macro and others to determine if the logging
211  * should take place, and routes the logging via the platform abstraction's LogMessage.
212  *
213  * It provides a logging level. If this is set to zero, then DALI_LOG_INFO won't log anything.
214  * It provides the ability to turn tracing on or off.
215  *
216  */
217 class DALI_CORE_API Filter
218 {
219 public:
220   using FilterList = std::list<Filter*>;
221   using FilterIter = std::list<Filter*>::iterator;
222
223 public:
224   /**
225    * Test if the filter is enabled for the given logging level
226    * @param[in] level - the level to test.
227    * @return true if this level of logging is enabled.
228    */
229   bool IsEnabledFor(LogLevel level)
230   {
231     return level != Debug::NoLogging && level <= mLoggingLevel;
232   }
233
234   /**
235    * Test if trace is enabled for this filter.
236    * @return true if trace is enabled;
237    */
238   bool IsTraceEnabled()
239   {
240     return mTraceEnabled;
241   }
242
243   /**
244    * Enable tracing on this filter.
245    */
246   void EnableTrace()
247   {
248     mTraceEnabled = true;
249   }
250
251   /**
252    * Disable tracing on this filter.
253    */
254   void DisableTrace()
255   {
256     mTraceEnabled = false;
257   }
258
259   /**
260    * Set the log level for this filter. Setting to a higher value than Debug::General also
261    * enables General;
262    */
263   void SetLogLevel(LogLevel level)
264   {
265     mLoggingLevel = level;
266   }
267
268   /**
269    * Perform the logging for this filter.
270    */
271   void Log(LogLevel level, const char* format, ...);
272
273   /**
274    * Create a new filter whose debug level and trace can be modified through the use of an
275    * environment variable.
276    *
277    * @param[in] level The default log level
278    * @param[in] trace The default trace level. If true, function tracing is on.
279    * @param[in] environmentVariableName The environment variable name used in order to change the
280    *                                    log level or trace.
281    *
282    * @info To modify logg level/trace at runtime, you can should define your filter as shown below:
283    *
284    * @code
285    * Debug::Filter* filter = Debug::Filter::New( Debug::NoLogging, false, "FILTER_ENV" );
286    * @endcode
287    *
288    * And to use it when running an executable:
289    * @code
290    * FILTER_ENV=3 dali-demo        // LogLevel Verbose,   Trace using default
291    * FILTER_ENV=1,true dali-demo   // LogLevel Concise,   Trace ON
292    * FILTER_ENV=2,false dali-demo  // LogLevel General,   Trace OFF
293    * FILTER_ENV=0,true dali-demo   // LogLevel NoLogging, Trace ON
294    * @endcode
295    */
296   static Filter* New(LogLevel level, bool trace, const char* environmentVariableName);
297
298   /**
299    * Enable trace on all filters.
300    */
301   static void EnableGlobalTrace();
302
303   /**
304    * Disable trace on all filters.
305    */
306   static void DisableGlobalTrace();
307
308   /**
309    * Set log level for all filters.
310    *
311    * @param[in] level The log level
312    */
313   static void SetGlobalLogLevel(LogLevel level);
314
315 private:
316   /**
317    * Constructor.
318    * @param[in] level - the highest log level.
319    * @param[in] trace - whether this filter allows tracing.
320    */
321   Filter(LogLevel level, bool trace)
322   : mLoggingLevel(level),
323     mTraceEnabled(trace),
324     mNesting(0)
325   {
326   }
327
328   static FilterList* GetActiveFilters();
329
330 public:
331   // High level filters. If these filters are too broad for your current requirement, then
332   // you can add a filter to your own class or source file. If you do, use Filter::New()
333   // to tell this class about it.
334
335   static Filter* gRender;
336   static Filter* gResource;
337   static Filter* gGLResource;
338   static Filter* gObject;
339   static Filter* gImage;
340   static Filter* gModel;
341   static Filter* gNode;
342   static Filter* gElement;
343   static Filter* gActor;
344   static Filter* gShader;
345
346 private:
347   LogLevel mLoggingLevel;
348   bool     mTraceEnabled;
349
350 public:
351   int mNesting;
352 };
353
354 #define DALI_LOG_FILTER_SET_LEVEL(filter, level) filter->SetLogLevel(level)
355 #define DALI_LOG_FILTER_ENABLE_TRACE(filter) filter->EnableTrace()
356 #define DALI_LOG_FILTER_DISABLE_TRACE(filter) filter->DisableTrace()
357
358 #else
359
360 #define DALI_LOG_FILTER_SET_LEVEL(filter, level)
361 #define DALI_LOG_FILTER_ENABLE_TRACE(filter)
362 #define DALI_LOG_FILTER_DISABLE_TRACE(filter)
363
364 #endif
365
366 /********************************************************************************
367  *                            General Logging macros                            *
368  ********************************************************************************/
369
370 #ifdef DEBUG_ENABLED
371
372 #define DALI_LOG_INFO(filter, level, format, ...)                                    \
373   if(filter && filter->IsEnabledFor(level))                                          \
374   {                                                                                  \
375     filter->Log(level,                                                               \
376                 (std::string(DALI_LOG_FORMAT_PREFIX) + std::string(format)).c_str(), \
377                 DALI_LOG_FORMAT_PREFIX_ARGS,                                         \
378                 ##__VA_ARGS__);                                                      \
379   }
380
381 #define DALI_LOG_STREAM(filter, level, stream) \
382   if(filter && filter->IsEnabledFor(level))    \
383   {                                            \
384     std::ostringstream o;                      \
385     o << stream << std::endl;                  \
386     filter->Log(level, "%s", o.str().c_str()); \
387   }
388
389 #else // DEBUG_ENABLED
390
391 #define DALI_LOG_INFO(filter, level, format, ...)
392 #define DALI_LOG_STREAM(filter, level, stream)
393
394 #endif // DEBUG_ENABLED
395
396 /********************************************************************************
397  *                                  Trace Macros                                *
398  ********************************************************************************/
399
400 /*
401  * These macros allow the instrumentation of methods. These translate into calls
402  * to LogMessage(INFO).
403  */
404
405 #ifdef DEBUG_ENABLED
406
407 class DALI_CORE_API TraceObj
408 {
409 public:
410   TraceObj(Filter* filter, const char* fmt, ...);
411   ~TraceObj();
412
413 public:
414   std::string mMessage;
415   Filter*     mFilter;
416 };
417
418 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...) \
419   Dali::Integration::Log::TraceObj debugTraceObj(filter, "%s: " format, ASSERT_LOCATION, ##__VA_ARGS__)
420
421 #define DALI_LOG_TRACE_METHOD(filter) \
422   Dali::Integration::Log::TraceObj debugTraceObj(filter, ASSERT_LOCATION)
423
424 #else // DEBUG_ENABLED
425
426 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...)
427 #define DALI_LOG_TRACE_METHOD(filter)
428
429 #endif
430
431 /********************************************************************************
432  *                              Extra object debug                              *
433  ********************************************************************************/
434
435 #ifdef DEBUG_ENABLED
436
437 /**
438  * Warning, this macro changes the current scope, so should usually be put at the
439  * end of the class definition.
440  *
441  * Suggest that the value is usually set to the object's name.
442  * Warning - this will increase the size of the object for a debug build.
443  */
444 #define DALI_LOG_OBJECT_STRING_DECLARATION \
445 public:                                    \
446   std::string mDebugString;
447
448 /**
449  * Print all the actor tree names
450  **/
451 #define DALI_LOG_ACTOR_TREE(node)                                  \
452   {                                                                \
453     std::stringstream branch;                                      \
454     Node*             tempNode = node;                             \
455     while(tempNode)                                                \
456     {                                                              \
457       branch << "<" << tempNode->mDebugString << ">::";            \
458       tempNode = tempNode->GetParent();                            \
459     }                                                              \
460     DALI_LOG_ERROR_NOFN("Actor tree: %s\n", branch.str().c_str()); \
461   }
462
463 /**
464  * Allows one object to set another object's debug string
465  */
466 #define DALI_LOG_SET_OBJECT_STRING(object, string) (object->mDebugString = string)
467
468 /**
469  * Allows one object to set another object's std::string easily
470  */
471 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...) (object->mDebugString = FormatToString(fmt, ##__VA_ARGS__))
472
473 /**
474  * Allows one object to get another object's debug string
475  */
476 #define DALI_LOG_GET_OBJECT_STRING(object) (object->mDebugString)
477
478 /**
479  * Get the C string (for use in formatted logging)
480  */
481 #define DALI_LOG_GET_OBJECT_C_STR(object) (object->mDebugString.c_str())
482
483 /**
484  * Filtered logging of the object's debug string
485  */
486 #define DALI_LOG_OBJECT(filter, object) DALI_LOG_INFO(filter, Debug::General, object->mDebugString)
487
488 #else // DEBUG_ENABLED
489
490 #define DALI_LOG_OBJECT_STRING_DECLARATION
491 #define DALI_LOG_ACTOR_TREE(node)
492 #define DALI_LOG_SET_OBJECT_STRING(object, string)
493 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...)
494 #define DALI_LOG_GET_OBJECT_STRING(object)
495 #define DALI_LOG_GET_OBJECT_C_STR(object) ""
496 #define DALI_LOG_OBJECT(filter, object)
497
498 #endif
499
500 /********************************************************************************
501  *                            Time instrumentation                              *
502  ********************************************************************************/
503 #if defined(DEBUG_ENABLED)
504
505 /**
506   * @brief Get the monotonic time since the clock's epoch.
507   *
508   * @param[out]  timeInNanoseconds  The time in nanoseconds since the reference point.
509   *
510   * @note The maximum value timeInNanoseconds can hold is 0xFFFFFFFFFFFFFFFF which is 1.844674407e+19. Therefore, this can overflow after approximately 584 years.
511   */
512 void GetNanoseconds(uint64_t& timeInNanoseconds);
513
514 #define DALI_LOG_TIMER_START(timeVariable) \
515   uint64_t timeVariable##1;                \
516   Debug::GetNanoseconds(timeVariable##1);
517
518 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString) \
519   uint64_t timeVariable##2;                                        \
520   Debug::GetNanoseconds(timeVariable##2);                          \
521   DALI_LOG_INFO(filter, level, preString " %ld uSec\n", ((timeVariable##2 - timeVariable##1) / 1000));
522
523 #else // DEBUG_ENABLED
524
525 #define DALI_LOG_TIMER_START(timeVariable)
526 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString)
527
528 #endif
529
530 } // namespace Log
531 } // namespace Integration
532 } // namespace Dali
533
534 #endif // DALI_INTEGRATION_DEBUG_H