michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "GeckoTaskTracer.h" michael@0: #include "GeckoTaskTracerImpl.h" michael@0: michael@0: #include "mozilla/StaticMutex.h" michael@0: #include "mozilla/ThreadLocal.h" michael@0: #include "mozilla/unused.h" michael@0: michael@0: #include "nsClassHashtable.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #if defined(__GLIBC__) michael@0: // glibc doesn't implement gettid(2). michael@0: #include michael@0: static pid_t gettid() michael@0: { michael@0: return (pid_t) syscall(SYS_gettid); michael@0: } michael@0: #endif michael@0: michael@0: #define MAX_USER_LABEL_LEN 512 michael@0: michael@0: namespace mozilla { michael@0: namespace tasktracer { michael@0: michael@0: static mozilla::ThreadLocal sTraceInfoTLS; michael@0: static StaticMutex sMutex; michael@0: static nsClassHashtable* sTraceInfos = nullptr; michael@0: michael@0: namespace { michael@0: michael@0: static TraceInfo* michael@0: AllocTraceInfo(int aTid) michael@0: { michael@0: StaticMutexAutoLock lock(sMutex); michael@0: michael@0: sTraceInfos->Put(aTid, new TraceInfo(aTid)); michael@0: return sTraceInfos->Get(aTid); michael@0: } michael@0: michael@0: static void michael@0: FreeTraceInfo(int aTid) michael@0: { michael@0: StaticMutexAutoLock lock(sMutex); michael@0: michael@0: sTraceInfos->Remove(aTid); michael@0: } michael@0: michael@0: static bool michael@0: IsInitialized() michael@0: { michael@0: return sTraceInfoTLS.initialized(); michael@0: } michael@0: michael@0: static void michael@0: SaveCurTraceInfo() michael@0: { michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: NS_ENSURE_TRUE_VOID(info); michael@0: michael@0: info->mSavedCurTraceSourceId = info->mCurTraceSourceId; michael@0: info->mSavedCurTraceSourceType = info->mCurTraceSourceType; michael@0: info->mSavedCurTaskId = info->mCurTaskId; michael@0: } michael@0: michael@0: static void michael@0: RestoreCurTraceInfo() michael@0: { michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: NS_ENSURE_TRUE_VOID(info); michael@0: michael@0: info->mCurTraceSourceId = info->mSavedCurTraceSourceId; michael@0: info->mCurTraceSourceType = info->mSavedCurTraceSourceType; michael@0: info->mCurTaskId = info->mSavedCurTaskId; michael@0: } michael@0: michael@0: static void michael@0: CreateSourceEvent(SourceEventType aType) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized()); michael@0: michael@0: // Save the currently traced source event info. michael@0: SaveCurTraceInfo(); michael@0: michael@0: // Create a new unique task id. michael@0: uint64_t newId = GenNewUniqueTaskId(); michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: info->mCurTraceSourceId = newId; michael@0: info->mCurTraceSourceType = aType; michael@0: info->mCurTaskId = newId; michael@0: michael@0: // Log a fake dispatch and start for this source event. michael@0: LogDispatch(newId, newId,newId, aType); michael@0: LogBegin(newId, newId); michael@0: } michael@0: michael@0: static void michael@0: DestroySourceEvent() michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized()); michael@0: michael@0: // Log a fake end for this source event. michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: LogEnd(info->mCurTraceSourceId, info->mCurTraceSourceId); michael@0: michael@0: // Restore the previously saved source event info. michael@0: RestoreCurTraceInfo(); michael@0: } michael@0: michael@0: } // namespace anonymous michael@0: michael@0: void michael@0: InitTaskTracer() michael@0: { michael@0: MOZ_ASSERT(!sTraceInfos); michael@0: michael@0: sTraceInfos = new nsClassHashtable(); michael@0: michael@0: if (!sTraceInfoTLS.initialized()) { michael@0: unused << sTraceInfoTLS.init(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ShutdownTaskTracer() michael@0: { michael@0: delete sTraceInfos; michael@0: sTraceInfos = nullptr; michael@0: } michael@0: michael@0: TraceInfo* michael@0: GetOrCreateTraceInfo() michael@0: { michael@0: NS_ENSURE_TRUE(IsInitialized(), nullptr); michael@0: michael@0: TraceInfo* info = sTraceInfoTLS.get(); michael@0: if (!info) { michael@0: info = AllocTraceInfo(gettid()); michael@0: sTraceInfoTLS.set(info); michael@0: } michael@0: michael@0: return info; michael@0: } michael@0: michael@0: uint64_t michael@0: GenNewUniqueTaskId() michael@0: { michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: NS_ENSURE_TRUE(info, 0); michael@0: michael@0: pid_t tid = gettid(); michael@0: uint64_t taskid = ((uint64_t)tid << 32) | ++info->mLastUniqueTaskId; michael@0: return taskid; michael@0: } michael@0: michael@0: AutoSaveCurTraceInfo::AutoSaveCurTraceInfo() michael@0: { michael@0: SaveCurTraceInfo(); michael@0: } michael@0: michael@0: AutoSaveCurTraceInfo::~AutoSaveCurTraceInfo() michael@0: { michael@0: RestoreCurTraceInfo(); michael@0: } michael@0: michael@0: void michael@0: SetCurTraceInfo(uint64_t aSourceEventId, uint64_t aParentTaskId, michael@0: SourceEventType aSourceEventType) michael@0: { michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: NS_ENSURE_TRUE_VOID(info); michael@0: michael@0: info->mCurTraceSourceId = aSourceEventId; michael@0: info->mCurTaskId = aParentTaskId; michael@0: info->mCurTraceSourceType = aSourceEventType; michael@0: } michael@0: michael@0: void michael@0: GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId, michael@0: SourceEventType* aOutSourceEventType) michael@0: { michael@0: TraceInfo* info = GetOrCreateTraceInfo(); michael@0: NS_ENSURE_TRUE_VOID(info); michael@0: michael@0: *aOutSourceEventId = info->mCurTraceSourceId; michael@0: *aOutParentTaskId = info->mCurTaskId; michael@0: *aOutSourceEventType = info->mCurTraceSourceType; michael@0: } michael@0: michael@0: void michael@0: LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, uint64_t aSourceEventId, michael@0: SourceEventType aSourceEventType) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); michael@0: michael@0: // Log format: michael@0: // [0 taskId dispatchTime sourceEventId sourceEventType parentTaskId] michael@0: } michael@0: michael@0: void michael@0: LogBegin(uint64_t aTaskId, uint64_t aSourceEventId) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); michael@0: michael@0: // Log format: michael@0: // [1 taskId beginTime processId threadId] michael@0: } michael@0: michael@0: void michael@0: LogEnd(uint64_t aTaskId, uint64_t aSourceEventId) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); michael@0: michael@0: // Log format: michael@0: // [2 taskId endTime] michael@0: } michael@0: michael@0: void michael@0: LogVirtualTablePtr(uint64_t aTaskId, uint64_t aSourceEventId, int* aVptr) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized() && aSourceEventId); michael@0: michael@0: // Log format: michael@0: // [4 taskId address] michael@0: } michael@0: michael@0: void michael@0: FreeTraceInfo() michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized()); michael@0: michael@0: FreeTraceInfo(gettid()); michael@0: } michael@0: michael@0: AutoSourceEvent::AutoSourceEvent(SourceEventType aType) michael@0: { michael@0: CreateSourceEvent(aType); michael@0: } michael@0: michael@0: AutoSourceEvent::~AutoSourceEvent() michael@0: { michael@0: DestroySourceEvent(); michael@0: } michael@0: michael@0: void AddLabel(const char* aFormat, ...) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(IsInitialized()); michael@0: michael@0: va_list args; michael@0: va_start(args, aFormat); michael@0: char buffer[MAX_USER_LABEL_LEN] = {0}; michael@0: vsnprintf(buffer, MAX_USER_LABEL_LEN, aFormat, args); michael@0: va_end(args); michael@0: michael@0: // Log format: michael@0: // [3 taskId "label"] michael@0: } michael@0: michael@0: } // namespace tasktracer michael@0: } // namespace mozilla