diff options
Diffstat (limited to 'tools/profiler/tasktracer')
-rw-r--r-- | tools/profiler/tasktracer/GeckoTaskTracer.cpp | 472 | ||||
-rw-r--r-- | tools/profiler/tasktracer/GeckoTaskTracer.h | 92 | ||||
-rw-r--r-- | tools/profiler/tasktracer/GeckoTaskTracerImpl.h | 102 | ||||
-rw-r--r-- | tools/profiler/tasktracer/SourceEventTypeMap.h | 11 | ||||
-rw-r--r-- | tools/profiler/tasktracer/TracedTaskCommon.cpp | 169 | ||||
-rw-r--r-- | tools/profiler/tasktracer/TracedTaskCommon.h | 73 |
6 files changed, 919 insertions, 0 deletions
diff --git a/tools/profiler/tasktracer/GeckoTaskTracer.cpp b/tools/profiler/tasktracer/GeckoTaskTracer.cpp new file mode 100644 index 000000000..ada695614 --- /dev/null +++ b/tools/profiler/tasktracer/GeckoTaskTracer.cpp @@ -0,0 +1,472 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GeckoTaskTracer.h" +#include "GeckoTaskTracerImpl.h" + +#include "mozilla/MathAlgorithms.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/ThreadLocal.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Unused.h" + +#include "nsString.h" +#include "nsThreadUtils.h" +#include "prtime.h" + +#include <stdarg.h> + +// We need a definition of gettid(), but glibc doesn't provide a +// wrapper for it. +#if defined(__GLIBC__) +#include <unistd.h> +#include <sys/syscall.h> +static inline pid_t gettid() +{ + return (pid_t) syscall(SYS_gettid); +} +#elif defined(XP_MACOSX) +#include <unistd.h> +#include <sys/syscall.h> +static inline pid_t gettid() +{ + return (pid_t) syscall(SYS_thread_selfid); +} +#elif defined(LINUX) +#include <sys/types.h> +pid_t gettid(); +#endif + +// NS_ENSURE_TRUE_VOID() without the warning on the debug build. +#define ENSURE_TRUE_VOID(x) \ + do { \ + if (MOZ_UNLIKELY(!(x))) { \ + return; \ + } \ + } while(0) + +// NS_ENSURE_TRUE() without the warning on the debug build. +#define ENSURE_TRUE(x, ret) \ + do { \ + if (MOZ_UNLIKELY(!(x))) { \ + return ret; \ + } \ + } while(0) + +namespace mozilla { +namespace tasktracer { + +static MOZ_THREAD_LOCAL(TraceInfo*) sTraceInfoTLS; +static mozilla::StaticMutex sMutex; + +// The generation of TraceInfo. It will be > 0 if the Task Tracer is started and +// <= 0 if stopped. +static mozilla::Atomic<bool> sStarted; +static nsTArray<UniquePtr<TraceInfo>>* sTraceInfos = nullptr; +static PRTime sStartTime; + +static const char sJSLabelPrefix[] = "#tt#"; + +namespace { + +static PRTime +GetTimestamp() +{ + return PR_Now() / 1000; +} + +static TraceInfo* +AllocTraceInfo(int aTid) +{ + StaticMutexAutoLock lock(sMutex); + + auto* info = sTraceInfos->AppendElement(MakeUnique<TraceInfo>(aTid)); + + return info->get(); +} + +static void +SaveCurTraceInfo() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + info->mSavedCurTraceSourceId = info->mCurTraceSourceId; + info->mSavedCurTraceSourceType = info->mCurTraceSourceType; + info->mSavedCurTaskId = info->mCurTaskId; +} + +static void +RestoreCurTraceInfo() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + info->mCurTraceSourceId = info->mSavedCurTraceSourceId; + info->mCurTraceSourceType = info->mSavedCurTraceSourceType; + info->mCurTaskId = info->mSavedCurTaskId; +} + +static void +CreateSourceEvent(SourceEventType aType) +{ + // Save the currently traced source event info. + SaveCurTraceInfo(); + + // Create a new unique task id. + uint64_t newId = GenNewUniqueTaskId(); + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + info->mCurTraceSourceId = newId; + info->mCurTraceSourceType = aType; + info->mCurTaskId = newId; + + uintptr_t* namePtr; +#define SOURCE_EVENT_NAME(type) \ + case SourceEventType::type: \ + { \ + static int CreateSourceEvent##type; \ + namePtr = (uintptr_t*)&CreateSourceEvent##type; \ + break; \ + } + + switch (aType) { +#include "SourceEventTypeMap.h" + default: + MOZ_CRASH("Unknown SourceEvent."); + } +#undef CREATE_SOURCE_EVENT_NAME + + // Log a fake dispatch and start for this source event. + LogDispatch(newId, newId, newId, aType); + LogVirtualTablePtr(newId, newId, namePtr); + LogBegin(newId, newId); +} + +static void +DestroySourceEvent() +{ + // Log a fake end for this source event. + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + LogEnd(info->mCurTraceSourceId, info->mCurTraceSourceId); + + // Restore the previously saved source event info. + RestoreCurTraceInfo(); +} + +inline static bool +IsStartLogging() +{ + return sStarted; +} + +static void +SetLogStarted(bool aIsStartLogging) +{ + MOZ_ASSERT(aIsStartLogging != IsStartLogging()); + sStarted = aIsStartLogging; + + StaticMutexAutoLock lock(sMutex); + if (!aIsStartLogging) { + for (uint32_t i = 0; i < sTraceInfos->Length(); ++i) { + (*sTraceInfos)[i]->mObsolete = true; + } + } +} + +static void +CleanUp() +{ + SetLogStarted(false); + StaticMutexAutoLock lock(sMutex); + + if (sTraceInfos) { + delete sTraceInfos; + sTraceInfos = nullptr; + } +} + +inline static void +ObsoleteCurrentTraceInfos() +{ + // Note that we can't and don't need to acquire sMutex here because this + // function is called before the other threads are recreated. + for (uint32_t i = 0; i < sTraceInfos->Length(); ++i) { + (*sTraceInfos)[i]->mObsolete = true; + } +} + +} // namespace anonymous + +nsCString* +TraceInfo::AppendLog() +{ + MutexAutoLock lock(mLogsMutex); + return mLogs.AppendElement(); +} + +void +TraceInfo::MoveLogsInto(TraceInfoLogsType& aResult) +{ + MutexAutoLock lock(mLogsMutex); + aResult.AppendElements(Move(mLogs)); +} + +void +InitTaskTracer(uint32_t aFlags) +{ + if (aFlags & FORKED_AFTER_NUWA) { + ObsoleteCurrentTraceInfos(); + return; + } + + MOZ_ASSERT(!sTraceInfos); + sTraceInfos = new nsTArray<UniquePtr<TraceInfo>>(); + + if (!sTraceInfoTLS.initialized()) { + Unused << sTraceInfoTLS.init(); + } +} + +void +ShutdownTaskTracer() +{ + CleanUp(); +} + +static void +FreeTraceInfo(TraceInfo* aTraceInfo) +{ + StaticMutexAutoLock lock(sMutex); + if (aTraceInfo) { + sTraceInfos->RemoveElement(aTraceInfo); + } +} + +void FreeTraceInfo() +{ + FreeTraceInfo(sTraceInfoTLS.get()); +} + +TraceInfo* +GetOrCreateTraceInfo() +{ + ENSURE_TRUE(sTraceInfoTLS.initialized(), nullptr); + ENSURE_TRUE(IsStartLogging(), nullptr); + + TraceInfo* info = sTraceInfoTLS.get(); + if (info && info->mObsolete) { + // TraceInfo is obsolete: remove it. + FreeTraceInfo(info); + info = nullptr; + } + + if (!info) { + info = AllocTraceInfo(gettid()); + sTraceInfoTLS.set(info); + } + + return info; +} + +uint64_t +GenNewUniqueTaskId() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE(info, 0); + + pid_t tid = gettid(); + uint64_t taskid = ((uint64_t)tid << 32) | ++info->mLastUniqueTaskId; + return taskid; +} + +AutoSaveCurTraceInfo::AutoSaveCurTraceInfo() +{ + SaveCurTraceInfo(); +} + +AutoSaveCurTraceInfo::~AutoSaveCurTraceInfo() +{ + RestoreCurTraceInfo(); +} + +void +SetCurTraceInfo(uint64_t aSourceEventId, uint64_t aParentTaskId, + SourceEventType aSourceEventType) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + info->mCurTraceSourceId = aSourceEventId; + info->mCurTaskId = aParentTaskId; + info->mCurTraceSourceType = aSourceEventType; +} + +void +GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId, + SourceEventType* aOutSourceEventType) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + *aOutSourceEventId = info->mCurTraceSourceId; + *aOutParentTaskId = info->mCurTaskId; + *aOutSourceEventType = info->mCurTraceSourceType; +} + +void +LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, uint64_t aSourceEventId, + SourceEventType aSourceEventType) +{ + LogDispatch(aTaskId, aParentTaskId, aSourceEventId, aSourceEventType, 0); +} + +void +LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, uint64_t aSourceEventId, + SourceEventType aSourceEventType, int aDelayTimeMs) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + // aDelayTimeMs is the expected delay time in milliseconds, thus the dispatch + // time calculated of it might be slightly off in the real world. + uint64_t time = (aDelayTimeMs <= 0) ? GetTimestamp() : + GetTimestamp() + aDelayTimeMs; + + // Log format: + // [0 taskId dispatchTime sourceEventId sourceEventType parentTaskId] + nsCString* log = info->AppendLog(); + if (log) { + log->AppendPrintf("%d %lld %lld %lld %d %lld", + ACTION_DISPATCH, aTaskId, time, aSourceEventId, + aSourceEventType, aParentTaskId); + } +} + +void +LogBegin(uint64_t aTaskId, uint64_t aSourceEventId) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + // Log format: + // [1 taskId beginTime processId threadId] + nsCString* log = info->AppendLog(); + if (log) { + log->AppendPrintf("%d %lld %lld %d %d", + ACTION_BEGIN, aTaskId, GetTimestamp(), getpid(), gettid()); + } +} + +void +LogEnd(uint64_t aTaskId, uint64_t aSourceEventId) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + // Log format: + // [2 taskId endTime] + nsCString* log = info->AppendLog(); + if (log) { + log->AppendPrintf("%d %lld %lld", ACTION_END, aTaskId, GetTimestamp()); + } +} + +void +LogVirtualTablePtr(uint64_t aTaskId, uint64_t aSourceEventId, uintptr_t* aVptr) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + // Log format: + // [4 taskId address] + nsCString* log = info->AppendLog(); + if (log) { + log->AppendPrintf("%d %lld %p", ACTION_GET_VTABLE, aTaskId, aVptr); + } +} + +AutoSourceEvent::AutoSourceEvent(SourceEventType aType) +{ + CreateSourceEvent(aType); +} + +AutoSourceEvent::~AutoSourceEvent() +{ + DestroySourceEvent(); +} + +void AddLabel(const char* aFormat, ...) +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + va_list args; + va_start(args, aFormat); + nsAutoCString buffer; + buffer.AppendPrintf(aFormat, args); + va_end(args); + + // Log format: + // [3 taskId "label"] + nsCString* log = info->AppendLog(); + if (log) { + log->AppendPrintf("%d %lld %lld \"%s\"", ACTION_ADD_LABEL, info->mCurTaskId, + GetTimestamp(), buffer.get()); + } +} + +// Functions used by GeckoProfiler. + +void +StartLogging() +{ + sStartTime = GetTimestamp(); + SetLogStarted(true); +} + +void +StopLogging() +{ + SetLogStarted(false); +} + +UniquePtr<TraceInfoLogsType> +GetLoggedData(TimeStamp aTimeStamp) +{ + auto result = MakeUnique<TraceInfoLogsType>(); + + // TODO: This is called from a signal handler. Use semaphore instead. + StaticMutexAutoLock lock(sMutex); + + for (uint32_t i = 0; i < sTraceInfos->Length(); ++i) { + (*sTraceInfos)[i]->MoveLogsInto(*result); + } + + return result; +} + +const PRTime +GetStartTime() +{ + return sStartTime; +} + +const char* +GetJSLabelPrefix() +{ + return sJSLabelPrefix; +} + +#undef ENSURE_TRUE_VOID +#undef ENSURE_TRUE + +} // namespace tasktracer +} // namespace mozilla diff --git a/tools/profiler/tasktracer/GeckoTaskTracer.h b/tools/profiler/tasktracer/GeckoTaskTracer.h new file mode 100644 index 000000000..9e36b3f0b --- /dev/null +++ b/tools/profiler/tasktracer/GeckoTaskTracer.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GECKO_TASK_TRACER_H +#define GECKO_TASK_TRACER_H + +#include "mozilla/UniquePtr.h" +#include "nsCOMPtr.h" +#include "nsTArrayForwardDeclare.h" + +/** + * TaskTracer provides a way to trace the correlation between different tasks + * across threads and processes. Unlike sampling based profilers, TaskTracer can + * tell you where a task is dispatched from, what its original source was, how + * long it waited in the event queue, and how long it took to execute. + * + * Source Events are usually some kinds of I/O events we're interested in, such + * as touch events, timer events, network events, etc. When a source event is + * created, TaskTracer records the entire chain of Tasks and nsRunnables as they + * are dispatched to different threads and processes. It records latency, + * execution time, etc. for each Task and nsRunnable that chains back to the + * original source event. + */ + +class Task; +class nsIRunnable; +class nsCString; + +namespace mozilla { + +class TimeStamp; + +namespace tasktracer { + +enum { + FORKED_AFTER_NUWA = 1 << 0 +}; + +enum SourceEventType { + Unknown = 0, + Touch, + Mouse, + Key, + Bluetooth, + Unixsocket, + Wifi +}; + +class AutoSourceEvent +{ +public: + AutoSourceEvent(SourceEventType aType); + ~AutoSourceEvent(); +}; + +void InitTaskTracer(uint32_t aFlags = 0); +void ShutdownTaskTracer(); + +// Add a label to the currently running task, aFormat is the message to log, +// followed by corresponding parameters. +void AddLabel(const char* aFormat, ...); + +void StartLogging(); +void StopLogging(); +UniquePtr<nsTArray<nsCString>> GetLoggedData(TimeStamp aStartTime); + +// Returns the timestamp when Task Tracer is enabled in this process. +const PRTime GetStartTime(); + +/** + * Internal functions. + */ + +Task* CreateTracedTask(Task* aTask); + +already_AddRefed<nsIRunnable> +CreateTracedRunnable(already_AddRefed<nsIRunnable>&& aRunnable); + +// Free the TraceInfo allocated on a thread's TLS. Currently we are wrapping +// tasks running on nsThreads and base::thread, so FreeTraceInfo is called at +// where nsThread and base::thread release themselves. +void FreeTraceInfo(); + +const char* GetJSLabelPrefix(); + +} // namespace tasktracer +} // namespace mozilla. + +#endif diff --git a/tools/profiler/tasktracer/GeckoTaskTracerImpl.h b/tools/profiler/tasktracer/GeckoTaskTracerImpl.h new file mode 100644 index 000000000..5b748fb96 --- /dev/null +++ b/tools/profiler/tasktracer/GeckoTaskTracerImpl.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GECKO_TASK_TRACER_IMPL_H +#define GECKO_TASK_TRACER_IMPL_H + +#include "GeckoTaskTracer.h" +#include "mozilla/Mutex.h" +#include "nsTArray.h" + +namespace mozilla { +namespace tasktracer { + +typedef nsTArray<nsCString> TraceInfoLogsType; + +struct TraceInfo +{ + TraceInfo(uint32_t aThreadId) + : mCurTraceSourceId(0) + , mCurTaskId(0) + , mSavedCurTraceSourceId(0) + , mSavedCurTaskId(0) + , mCurTraceSourceType(Unknown) + , mSavedCurTraceSourceType(Unknown) + , mThreadId(aThreadId) + , mLastUniqueTaskId(0) + , mObsolete(false) + , mLogsMutex("TraceInfoMutex") + { + MOZ_COUNT_CTOR(TraceInfo); + } + + ~TraceInfo() { MOZ_COUNT_DTOR(TraceInfo); } + + nsCString* AppendLog(); + void MoveLogsInto(TraceInfoLogsType& aResult); + + uint64_t mCurTraceSourceId; + uint64_t mCurTaskId; + uint64_t mSavedCurTraceSourceId; + uint64_t mSavedCurTaskId; + SourceEventType mCurTraceSourceType; + SourceEventType mSavedCurTraceSourceType; + uint32_t mThreadId; + uint32_t mLastUniqueTaskId; + mozilla::Atomic<bool> mObsolete; + + // This mutex protects the following log array because MoveLogsInto() might + // be called on another thread. + mozilla::Mutex mLogsMutex; + TraceInfoLogsType mLogs; +}; + +// Return the TraceInfo of current thread, allocate a new one if not exit. +TraceInfo* GetOrCreateTraceInfo(); + +uint64_t GenNewUniqueTaskId(); + +class AutoSaveCurTraceInfo +{ +public: + AutoSaveCurTraceInfo(); + ~AutoSaveCurTraceInfo(); +}; + +void SetCurTraceInfo(uint64_t aSourceEventId, uint64_t aParentTaskId, + SourceEventType aSourceEventType); + +void GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId, + SourceEventType* aOutSourceEventType); + +/** + * Logging functions of different trace actions. + */ +enum ActionType { + ACTION_DISPATCH = 0, + ACTION_BEGIN, + ACTION_END, + ACTION_ADD_LABEL, + ACTION_GET_VTABLE +}; + +void LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, + uint64_t aSourceEventId, SourceEventType aSourceEventType); + +void LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, + uint64_t aSourceEventId, SourceEventType aSourceEventType, + int aDelayTimeMs); + +void LogBegin(uint64_t aTaskId, uint64_t aSourceEventId); + +void LogEnd(uint64_t aTaskId, uint64_t aSourceEventId); + +void LogVirtualTablePtr(uint64_t aTaskId, uint64_t aSourceEventId, uintptr_t* aVptr); + +} // namespace mozilla +} // namespace tasktracer + +#endif diff --git a/tools/profiler/tasktracer/SourceEventTypeMap.h b/tools/profiler/tasktracer/SourceEventTypeMap.h new file mode 100644 index 000000000..77dbc8330 --- /dev/null +++ b/tools/profiler/tasktracer/SourceEventTypeMap.h @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +SOURCE_EVENT_NAME(Unknown) +SOURCE_EVENT_NAME(Touch) +SOURCE_EVENT_NAME(Mouse) +SOURCE_EVENT_NAME(Key) +SOURCE_EVENT_NAME(Bluetooth) +SOURCE_EVENT_NAME(Unixsocket) +SOURCE_EVENT_NAME(Wifi) diff --git a/tools/profiler/tasktracer/TracedTaskCommon.cpp b/tools/profiler/tasktracer/TracedTaskCommon.cpp new file mode 100644 index 000000000..770eb202c --- /dev/null +++ b/tools/profiler/tasktracer/TracedTaskCommon.cpp @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GeckoTaskTracerImpl.h" +#include "TracedTaskCommon.h" + +// NS_ENSURE_TRUE_VOID() without the warning on the debug build. +#define ENSURE_TRUE_VOID(x) \ + do { \ + if (MOZ_UNLIKELY(!(x))) { \ + return; \ + } \ + } while(0) + +namespace mozilla { +namespace tasktracer { + +TracedTaskCommon::TracedTaskCommon() + : mSourceEventType(SourceEventType::Unknown) + , mSourceEventId(0) + , mParentTaskId(0) + , mTaskId(0) + , mIsTraceInfoInit(false) +{ +} + +TracedTaskCommon::~TracedTaskCommon() +{ +} + +void +TracedTaskCommon::Init() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + mTaskId = GenNewUniqueTaskId(); + mSourceEventId = info->mCurTraceSourceId; + mSourceEventType = info->mCurTraceSourceType; + mParentTaskId = info->mCurTaskId; + mIsTraceInfoInit = true; +} + +void +TracedTaskCommon::DispatchTask(int aDelayTimeMs) +{ + LogDispatch(mTaskId, mParentTaskId, mSourceEventId, mSourceEventType, + aDelayTimeMs); +} + +void +TracedTaskCommon::GetTLSTraceInfo() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + mSourceEventType = info->mCurTraceSourceType; + mSourceEventId = info->mCurTraceSourceId; + mTaskId = info->mCurTaskId; + mIsTraceInfoInit = true; +} + +void +TracedTaskCommon::SetTLSTraceInfo() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + if (mIsTraceInfoInit) { + info->mCurTraceSourceId = mSourceEventId; + info->mCurTraceSourceType = mSourceEventType; + info->mCurTaskId = mTaskId; + } +} + +void +TracedTaskCommon::ClearTLSTraceInfo() +{ + TraceInfo* info = GetOrCreateTraceInfo(); + ENSURE_TRUE_VOID(info); + + info->mCurTraceSourceId = 0; + info->mCurTraceSourceType = SourceEventType::Unknown; + info->mCurTaskId = 0; +} + +/** + * Implementation of class TracedRunnable. + */ +TracedRunnable::TracedRunnable(already_AddRefed<nsIRunnable>&& aOriginalObj) + : TracedTaskCommon() + , mOriginalObj(Move(aOriginalObj)) +{ + Init(); + LogVirtualTablePtr(mTaskId, mSourceEventId, reinterpret_cast<uintptr_t*>(mOriginalObj.get())); +} + +TracedRunnable::~TracedRunnable() +{ +} + +NS_IMETHODIMP +TracedRunnable::Run() +{ + SetTLSTraceInfo(); + LogBegin(mTaskId, mSourceEventId); + nsresult rv = mOriginalObj->Run(); + LogEnd(mTaskId, mSourceEventId); + ClearTLSTraceInfo(); + + return rv; +} + +/** + * Implementation of class TracedTask. + */ +TracedTask::TracedTask(Task* aOriginalObj) + : TracedTaskCommon() + , mOriginalObj(aOriginalObj) +{ + Init(); + LogVirtualTablePtr(mTaskId, mSourceEventId, reinterpret_cast<uintptr_t*>(aOriginalObj)); +} + +TracedTask::~TracedTask() +{ + if (mOriginalObj) { + delete mOriginalObj; + mOriginalObj = nullptr; + } +} + +void +TracedTask::Run() +{ + SetTLSTraceInfo(); + LogBegin(mTaskId, mSourceEventId); + mOriginalObj->Run(); + LogEnd(mTaskId, mSourceEventId); + ClearTLSTraceInfo(); +} + +/** + * CreateTracedRunnable() returns a TracedRunnable wrapping the original + * nsIRunnable object, aRunnable. + */ +already_AddRefed<nsIRunnable> +CreateTracedRunnable(already_AddRefed<nsIRunnable>&& aRunnable) +{ + nsCOMPtr<nsIRunnable> runnable = new TracedRunnable(Move(aRunnable)); + return runnable.forget(); +} + +/** + * CreateTracedTask() returns a TracedTask wrapping the original Task object, + * aTask. + */ +Task* +CreateTracedTask(Task* aTask) +{ + Task* task = new TracedTask(aTask); + return task; +} + +} // namespace tasktracer +} // namespace mozilla diff --git a/tools/profiler/tasktracer/TracedTaskCommon.h b/tools/profiler/tasktracer/TracedTaskCommon.h new file mode 100644 index 000000000..3594b8e9e --- /dev/null +++ b/tools/profiler/tasktracer/TracedTaskCommon.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TRACED_TASK_COMMON_H +#define TRACED_TASK_COMMON_H + +#include "base/task.h" +#include "GeckoTaskTracer.h" +#include "nsCOMPtr.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace tasktracer { + +class TracedTaskCommon +{ +public: + TracedTaskCommon(); + virtual ~TracedTaskCommon(); + + void DispatchTask(int aDelayTimeMs = 0); + + void SetTLSTraceInfo(); + void GetTLSTraceInfo(); + void ClearTLSTraceInfo(); + +protected: + void Init(); + + // TraceInfo of TLS will be set by the following parameters, including source + // event type, source event ID, parent task ID, and task ID of this traced + // task/runnable. + SourceEventType mSourceEventType; + uint64_t mSourceEventId; + uint64_t mParentTaskId; + uint64_t mTaskId; + bool mIsTraceInfoInit; +}; + +class TracedRunnable : public TracedTaskCommon + , public nsRunnable +{ +public: + NS_DECL_NSIRUNNABLE + + TracedRunnable(already_AddRefed<nsIRunnable>&& aOriginalObj); + +private: + virtual ~TracedRunnable(); + + nsCOMPtr<nsIRunnable> mOriginalObj; +}; + +class TracedTask : public TracedTaskCommon + , public Task +{ +public: + TracedTask(Task* aOriginalObj); + ~TracedTask(); + + virtual void Run(); + +private: + Task* mOriginalObj; +}; + +} // namespace tasktracer +} // namespace mozilla + +#endif |