summaryrefslogtreecommitdiff
path: root/libtiutils/DebugUtils.h
diff options
context:
space:
mode:
Diffstat (limited to 'libtiutils/DebugUtils.h')
-rw-r--r--libtiutils/DebugUtils.h385
1 files changed, 373 insertions, 12 deletions
diff --git a/libtiutils/DebugUtils.h b/libtiutils/DebugUtils.h
index f421252..a05ba8d 100644
--- a/libtiutils/DebugUtils.h
+++ b/libtiutils/DebugUtils.h
@@ -14,23 +14,384 @@
* limitations under the License.
*/
-
-
#ifndef DEBUG_UTILS_H
#define DEBUG_UTILS_H
-///Defines for debug statements - Macro LOG_TAG needs to be defined in the respective files
-#define DBGUTILS_LOGVA(str) ALOGV("%s:%d %s - " str,__FILE__, __LINE__,__FUNCTION__);
-#define DBGUTILS_LOGVB(str,...) ALOGV("%s:%d %s - " str,__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__);
-#define DBGUTILS_LOGDA(str) ALOGD("%s:%d %s - " str,__FILE__, __LINE__,__FUNCTION__);
-#define DBGUTILS_LOGDB(str, ...) ALOGD("%s:%d %s - " str,__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__);
-#define DBGUTILS_LOGEA(str) ALOGE("%s:%d %s - " str,__FILE__, __LINE__, __FUNCTION__);
-#define DBGUTILS_LOGEB(str, ...) ALOGE("%s:%d %s - " str,__FILE__, __LINE__,__FUNCTION__, __VA_ARGS__);
-#define LOG_FUNCTION_NAME ALOGV("%d: %s() ENTER", __LINE__, __FUNCTION__);
-#define LOG_FUNCTION_NAME_EXIT ALOGV("%d: %s() EXIT", __LINE__, __FUNCTION__);
+#include <android/log.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
-#endif //DEBUG_UTILS_H
+namespace Ti {
+
+
+
+
+// use 2 space characters for call stack indent
+static const int kFunctionLoggerIndentSize = 2;
+
+
+
+
+template <int Size = kFunctionLoggerIndentSize>
+class IndentString
+{
+public:
+ IndentString(int length);
+
+ const char * string() const;
+
+private:
+ int calculateOffset(int length) const;
+
+private:
+ const int mOffset;
+};
+
+
+
+
+class Debug
+{
+public:
+ static Debug * instance();
+
+ int offsetForCurrentThread();
+ void log(int priority, const char * format, ...);
+
+private:
+ class ThreadInfo
+ {
+ public:
+ ThreadInfo() :
+ threadId(0), callOffset(0)
+ {}
+
+ volatile int32_t threadId;
+ int callOffset;
+ };
+
+ class Data : public android::RefBase
+ {
+ public:
+ android::Vector<ThreadInfo*> threads;
+ };
+
+private:
+ // called from FunctionLogger
+ void increaseOffsetForCurrentThread();
+ void decreaseOffsetForCurrentThread();
+
+private:
+ Debug();
+
+ void grow();
+ ThreadInfo * registerThread(Data * data, int32_t threadId);
+ ThreadInfo * findCurrentThreadInfo();
+ void addOffsetForCurrentThread(int offset);
+
+private:
+ static Debug sInstance;
+
+ mutable android::Mutex mMutex;
+ android::sp<Data> mData;
+
+ friend class FunctionLogger;
+};
+
+
+
+
+class FunctionLogger
+{
+public:
+ FunctionLogger(const char * file, int line, const char * function);
+ ~FunctionLogger();
+
+ void setExitLine(int line);
+
+private:
+ const char * const mFile;
+ const int mLine;
+ const char * const mFunction;
+ const void * const mThreadId;
+ int mExitLine;
+};
+
+
+
+
+#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
+# define LOG_FUNCTION_NAME Ti::FunctionLogger __function_logger_instance(__FILE__, __LINE__, __FUNCTION__);
+# define LOG_FUNCTION_NAME_EXIT __function_logger_instance.setExitLine(__LINE__);
+#else
+# define LOG_FUNCTION_NAME int __function_logger_instance;
+# define LOG_FUNCTION_NAME_EXIT (void*)__function_logger_instance;
+#endif
+
+#ifdef TI_UTILS_DEBUG_USE_TIMESTAMPS
+ // truncate timestamp to 1000 seconds to fit into 6 characters
+# define TI_UTILS_DEBUG_TIMESTAMP_TOKEN "[%06d] "
+# define TI_UTILS_DEBUG_TIMESTAMP_VARIABLE static_cast<int>(nanoseconds_to_milliseconds(systemTime()) % 1000000),
+#else
+# define TI_UTILS_DEBUG_TIMESTAMP_TOKEN
+# define TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
+#endif
+
+
+
+
+#define DBGUTILS_LOGV_FULL(priority, file, line, function, format, ...) \
+ do \
+ { \
+ Ti::Debug * const debug = Ti::Debug::instance(); \
+ debug->log(priority, format, \
+ TI_UTILS_DEBUG_TIMESTAMP_VARIABLE \
+ reinterpret_cast<int>(androidGetThreadId()), \
+ Ti::IndentString<>(debug->offsetForCurrentThread()).string(), \
+ file, line, function, __VA_ARGS__); \
+ } while (0)
+
+#define DBGUTILS_LOGV(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_VERBOSE, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - " __VA_ARGS__, "")
+#define DBGUTILS_LOGD(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - " __VA_ARGS__, "")
+#define DBGUTILS_LOGI(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_INFO, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - " __VA_ARGS__, "")
+#define DBGUTILS_LOGW(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_WARN, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - " __VA_ARGS__, "")
+#define DBGUTILS_LOGE(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - " __VA_ARGS__, "")
+#define DBGUTILS_LOGF(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_FATAL, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - " __VA_ARGS__, "")
+
+#define DBGUTILS_LOGVA DBGUTILS_LOGV
+#define DBGUTILS_LOGVB DBGUTILS_LOGV
+
+#define DBGUTILS_LOGDA DBGUTILS_LOGD
+#define DBGUTILS_LOGDB DBGUTILS_LOGD
+
+#define DBGUTILS_LOGEA DBGUTILS_LOGE
+#define DBGUTILS_LOGEB DBGUTILS_LOGE
+
+// asserts
+#define _DBGUTILS_PLAIN_ASSERT(condition) \
+ do \
+ { \
+ if ( !(condition) ) \
+ { \
+ __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug", \
+ "Condition failed: " #condition); \
+ __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug", \
+ "Aborting process..."); \
+ abort(); \
+ } \
+ } while (0)
+
+#define _DBGUTILS_PLAIN_ASSERT_X(condition, ...) \
+ do \
+ { \
+ if ( !(condition) ) \
+ { \
+ __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug", \
+ "Condition failed: " #condition ": " __VA_ARGS__); \
+ __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug", \
+ "Aborting process..."); \
+ abort(); \
+ } \
+ } while (0)
+
+#define DBGUTILS_ASSERT(condition) \
+ do \
+ { \
+ if ( !(condition) ) \
+ { \
+ DBGUTILS_LOGF("Condition failed: " #condition); \
+ DBGUTILS_LOGF("Aborting process..."); \
+ abort(); \
+ } \
+ } while (0)
+#define DBGUTILS_ASSERT_X(condition, ...) \
+ do \
+ { \
+ if ( !(condition) ) \
+ { \
+ DBGUTILS_LOGF("Condition failed: " #condition ": " __VA_ARGS__); \
+ DBGUTILS_LOGF("Aborting process..."); \
+ abort(); \
+ } \
+ } while (0)
+
+
+
+
+static const int kIndentStringMaxLength = 128;
+
+template <int Size>
+inline int IndentString<Size>::calculateOffset(const int length) const
+{
+ const int offset = kIndentStringMaxLength - length*Size;
+ return offset < 0 ? 0 : offset;
+}
+
+template <int Size>
+inline IndentString<Size>::IndentString(const int length) :
+ mOffset(calculateOffset(length))
+{}
+
+template <int Size>
+inline const char * IndentString<Size>::string() const
+{
+ extern const char sIndentStringBuffer[];
+ return sIndentStringBuffer + mOffset;
+}
+
+
+
+
+inline Debug * Debug::instance()
+{ return &sInstance; }
+
+
+inline Debug::ThreadInfo * Debug::findCurrentThreadInfo()
+{
+ // retain reference to threads data
+ android::sp<Data> data = mData;
+
+ // iterate over threads to locate thread id,
+ // this is safe from race conditions because each thread
+ // is able to modify only his own ThreadInfo structure
+ const int32_t threadId = reinterpret_cast<int32_t>(androidGetThreadId());
+ const int size = int(data->threads.size());
+ for ( int i = 0; i < size; ++i )
+ {
+ ThreadInfo * const threadInfo = data->threads.itemAt(i);
+ if ( threadInfo->threadId == threadId )
+ return threadInfo;
+ }
+
+ // this thread has not been registered yet,
+ // try to fing empty thread info slot
+ while ( true )
+ {
+ ThreadInfo * const threadInfo = registerThread(data.get(), threadId);
+ if ( threadInfo )
+ return threadInfo;
+
+ // failed registering thread, because all slots are occupied
+ // grow the data and try again
+ grow();
+
+ data = mData;
+ }
+
+ // should never reach here
+ _DBGUTILS_PLAIN_ASSERT(false);
+ return 0;
+}
+
+
+inline void Debug::addOffsetForCurrentThread(const int offset)
+{
+ if ( offset == 0 )
+ return;
+
+ ThreadInfo * const threadInfo = findCurrentThreadInfo();
+ _DBGUTILS_PLAIN_ASSERT(threadInfo);
+
+ threadInfo->callOffset += offset;
+
+ if ( threadInfo->callOffset == 0 )
+ {
+ // thread call stack has dropped to zero, unregister it
+ android_atomic_acquire_store(0, &threadInfo->threadId);
+ }
+}
+
+
+inline int Debug::offsetForCurrentThread()
+{
+#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
+ ThreadInfo * const threadInfo = findCurrentThreadInfo();
+ _DBGUTILS_PLAIN_ASSERT(threadInfo);
+
+ return threadInfo->callOffset;
+#else
+ return 0;
+#endif
+}
+
+
+inline void Debug::increaseOffsetForCurrentThread()
+{
+#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
+ addOffsetForCurrentThread(1);
+#endif
+}
+
+
+inline void Debug::decreaseOffsetForCurrentThread()
+{
+#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
+ addOffsetForCurrentThread(-1);
+#endif
+}
+
+
+inline void Debug::log(const int priority, const char * const format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ __android_log_vprint(priority, LOG_TAG, format, args);
+ va_end(args);
+}
+
+
+
+
+inline FunctionLogger::FunctionLogger(const char * const file, const int line, const char * const function) :
+ mFile(file), mLine(line), mFunction(function), mThreadId(androidGetThreadId()), mExitLine(-1)
+{
+ Debug * const debug = Debug::instance();
+ debug->increaseOffsetForCurrentThread();
+ android_printLog(ANDROID_LOG_DEBUG, LOG_TAG,
+ TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s+ %s:%d %s - ENTER",
+ TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
+ (int)mThreadId, IndentString<>(debug->offsetForCurrentThread()).string(),
+ mFile, mLine, mFunction);
+}
+
+
+inline FunctionLogger::~FunctionLogger()
+{
+ Debug * const debug = Debug::instance();
+ android_printLog(ANDROID_LOG_DEBUG, LOG_TAG,
+ TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s- %s:%d %s - EXIT",
+ TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
+ (int)mThreadId, IndentString<>(debug->offsetForCurrentThread()).string(),
+ mFile, mExitLine == -1 ? mLine : mExitLine, mFunction);
+ debug->decreaseOffsetForCurrentThread();
+}
+
+
+inline void FunctionLogger::setExitLine(const int line)
+{
+ if ( mExitLine != -1 )
+ {
+ Debug * const debug = Debug::instance();
+ android_printLog(ANDROID_LOG_DEBUG, LOG_TAG,
+ TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s %s:%d %s - Double function exit trace detected. Previous: %d",
+ TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
+ (int)mThreadId, IndentString<>(debug->offsetForCurrentThread()).string(),
+ mFile, line, mFunction, mExitLine);
+ }
+
+ mExitLine = line;
+}
+
+
+
+
+} // namespace Ti
+
+
+
+
+#endif //DEBUG_UTILS_H