From 73b8fe58c6fb985898d2bbf431926f0628e2b0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Sat, 11 Apr 2015 11:44:49 +0200 Subject: Async: add runtime executor tracing for easier debugging --- async/src/CMakeLists.txt | 1 + async/src/async.cpp | 6 +++- async/src/async.h | 20 ++++++++++++ async/src/debug.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++ async/src/debug.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 async/src/debug.cpp create mode 100644 async/src/debug.h (limited to 'async') diff --git a/async/src/CMakeLists.txt b/async/src/CMakeLists.txt index 6f8ab63..becc8ee 100644 --- a/async/src/CMakeLists.txt +++ b/async/src/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(async_SRCS async.cpp future.cpp + debug.cpp ) add_library(${PROJECT_NAME} SHARED ${async_SRCS}) diff --git a/async/src/async.cpp b/async/src/async.cpp index 6f28084..e92d333 100644 --- a/async/src/async.cpp +++ b/async/src/async.cpp @@ -21,7 +21,6 @@ #include #include - using namespace Async; Private::Execution::Execution(const Private::ExecutorBasePtr &executor) @@ -45,6 +44,11 @@ void Private::Execution::setFinished() { isFinished = true; //executor.clear(); +#ifndef QT_NO_DEBUG + if (tracer) { + delete tracer; + } +#endif } void Private::Execution::releaseFuture() diff --git a/async/src/async.h b/async/src/async.h index 2243046..73eeaa0 100644 --- a/async/src/async.h +++ b/async/src/async.h @@ -25,6 +25,7 @@ #include #include "future.h" +#include "debug.h" #include "async_impl.h" #include @@ -115,8 +116,13 @@ struct Execution { bool isFinished; ExecutionPtr prevExecution; + +#ifndef QT_NO_DEBUG + Tracer *tracer; +#endif }; + typedef QSharedPointer ExecutionPtr; class ExecutorBase @@ -128,6 +134,7 @@ class ExecutorBase friend class Async::Job; friend class Execution; + friend class Async::Tracer; public: virtual ~ExecutorBase(); @@ -143,6 +150,10 @@ protected: virtual bool handleError(const ExecutionPtr &execution) = 0; ExecutorBasePtr mPrev; + +#ifndef QT_NO_DEBUG + QString mExecutorName; +#endif }; template @@ -581,6 +592,9 @@ ExecutionPtr Executor::exec(const ExecutorBasePtr &self) // Passing 'self' to execution ensures that the Executor chain remains // valid until the entire execution is finished ExecutionPtr execution = ExecutionPtr::create(self); +#ifndef QT_NO_DEBUG + execution->tracer = new Tracer(execution.data()); // owned by execution +#endif // chainup execution->prevExecution = mPrev ? mPrev->exec(mPrev) : ExecutionPtr(); @@ -667,6 +681,7 @@ ThenExecutor::ThenExecutor(ThenTask then, ErrorHandler : Executor::type, Out, In ...>(error, parent) , mFunc(then) { + STORE_EXECUTOR_NAME("ThenExecutor", Out, In ...); } template @@ -686,6 +701,7 @@ EachExecutor::EachExecutor(EachTask each, ErrorHandle : Executor(error, parent) , mFunc(each) { + STORE_EXECUTOR_NAME("EachExecutor", PrevOut, Out, In); } template @@ -727,6 +743,7 @@ template ReduceExecutor::ReduceExecutor(ReduceTask reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent) : ThenExecutor(reduce, errorFunc, parent) { + STORE_EXECUTOR_NAME("ReduceExecutor", Out, In); } template @@ -734,6 +751,7 @@ SyncThenExecutor::SyncThenExecutor(SyncThenTask then, : Executor::type, Out, In ...>(errorFunc, parent) , mFunc(then) { + STORE_EXECUTOR_NAME("SyncThenExecutor", Out, In ...); } template @@ -775,6 +793,7 @@ SyncEachExecutor::SyncEachExecutor(SyncEachTask each, : Executor(errorFunc, parent) , mFunc(each) { + STORE_EXECUTOR_NAME("SyncEachExecutor", PrevOut, Out, In); } template @@ -812,6 +831,7 @@ template SyncReduceExecutor::SyncReduceExecutor(SyncReduceTask reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent) : SyncThenExecutor(reduce, errorFunc, parent) { + STORE_EXECUTOR_NAME("SyncReduceExecutor", Out, In); } diff --git a/async/src/debug.cpp b/async/src/debug.cpp new file mode 100644 index 0000000..9dfad1a --- /dev/null +++ b/async/src/debug.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library. If not, see . + */ + +#include "debug.h" +#include "async.h" + +#include + +#ifdef __GNUG__ +#include +#include +#endif + +namespace Async +{ + +Q_LOGGING_CATEGORY(Debug, "org.kde.async", QtWarningMsg); +Q_LOGGING_CATEGORY(Trace, "org.kde.async.trace", QtWarningMsg); + +QString demangleName(const char *name) +{ +#ifdef __GNUG__ + int status = 1; // uses -3 to 0 error codes + std::unique_ptr demangled(abi::__cxa_demangle(name, 0, 0, &status), std::free); + if (status == 0) { + return QString(demangled.get()); + } +#endif + return QString(name); +} + +} + +using namespace Async; + +int Tracer::lastId = 0; + +Tracer::Tracer(Private::Execution *execution) + : mId(lastId++) + , mExecution(execution) +{ + msg(Async::Tracer::Start); +} + +Tracer::~Tracer() +{ + msg(Async::Tracer::End); + // FIXME: Does this work on parallel executions? + --lastId; + --mId; +} + +void Tracer::msg(Tracer::MsgType msgType) +{ + qCDebug(Trace).nospace() << (QString().fill(QLatin1Char(' '), mId * 2) % + (msgType == Async::Tracer::Start ? " START " : " END ") % + QString::number(mId) % " " % + mExecution->executor->mExecutorName); +} diff --git a/async/src/debug.h b/async/src/debug.h new file mode 100644 index 0000000..c453eb3 --- /dev/null +++ b/async/src/debug.h @@ -0,0 +1,80 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library. If not, see . + */ + +#ifndef ASYNC_DEBUG_H +#define ASYNC_DEBUG_H + +#include +#include + +#ifndef QT_NO_DEBUG +#include +#endif + +namespace Async +{ + +Q_DECLARE_LOGGING_CATEGORY(Debug) +Q_DECLARE_LOGGING_CATEGORY(Trace) + +QString demangleName(const char *name); + +namespace Private +{ +class Execution; +} + +class Tracer +{ +public: + Tracer(Private::Execution *execution); + ~Tracer(); + +private: + enum MsgType { + Start, + End + }; + void msg(MsgType); + + int mId; + Private::Execution *mExecution; + + static int lastId; +}; + +} + +#ifndef QT_NO_DEBUG + template + QString storeExecutorNameExpanded() { + return Async::demangleName(typeid(T).name()); + } + + template + typename std::enable_if::type + storeExecutorNameExpanded() { + return storeExecutorNameExpanded() % QStringLiteral(", ") % storeExecutorNameExpanded(); + } + + #define STORE_EXECUTOR_NAME(name, ...) \ + ExecutorBase::mExecutorName = QStringLiteral(name) % QStringLiteral("<") % storeExecutorNameExpanded<__VA_ARGS__>() % QStringLiteral(">") +#else + #define STORE_EXECUTOR_NAME(...) +#endif + +#endif // ASYNC_DEBUG_H \ No newline at end of file -- cgit v1.2.3