diff options
Diffstat (limited to 'mozglue/misc/AutoProfilerLabel.cpp')
-rw-r--r-- | mozglue/misc/AutoProfilerLabel.cpp | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/mozglue/misc/AutoProfilerLabel.cpp b/mozglue/misc/AutoProfilerLabel.cpp new file mode 100644 index 0000000000..c07ea084dc --- /dev/null +++ b/mozglue/misc/AutoProfilerLabel.cpp @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "mozilla/AutoProfilerLabel.h" + +#include "mozilla/Assertions.h" +#include "mozilla/PlatformMutex.h" + +namespace mozilla { + +// RAII class that encapsulates all shared static data, and enforces locking +// when accessing this data. +class MOZ_RAII AutoProfilerLabelData { + public: + AutoProfilerLabelData() { sAPLMutex.Lock(); } + + ~AutoProfilerLabelData() { sAPLMutex.Unlock(); } + + AutoProfilerLabelData(const AutoProfilerLabelData&) = delete; + void operator=(const AutoProfilerLabelData&) = delete; + + const ProfilerLabelEnter& EnterCRef() const { return sEnter; } + ProfilerLabelEnter& EnterRef() { return sEnter; } + + const ProfilerLabelExit& ExitCRef() const { return sExit; } + ProfilerLabelExit& ExitRef() { return sExit; } + + const uint32_t& GenerationCRef() const { return sGeneration; } + uint32_t& GenerationRef() { return sGeneration; } + + static bool RacyIsProfilerPresent() { return !!sGeneration; } + + private: + // Thin shell around mozglue PlatformMutex, for local internal use. + // Does not preserve behavior in JS record/replay. + class Mutex : private mozilla::detail::MutexImpl { + public: + Mutex() : mozilla::detail::MutexImpl() {} + void Lock() { mozilla::detail::MutexImpl::lock(); } + void Unlock() { mozilla::detail::MutexImpl::unlock(); } + }; + + // Mutex protecting access to the following static members. + static Mutex sAPLMutex MOZ_UNANNOTATED; + + static ProfilerLabelEnter sEnter; + static ProfilerLabelExit sExit; + + // Current "generation" of RegisterProfilerLabelEnterExit calls. + static uint32_t sGeneration; +}; + +/* static */ AutoProfilerLabelData::Mutex AutoProfilerLabelData::sAPLMutex; +/* static */ ProfilerLabelEnter AutoProfilerLabelData::sEnter = nullptr; +/* static */ ProfilerLabelExit AutoProfilerLabelData::sExit = nullptr; +/* static */ uint32_t AutoProfilerLabelData::sGeneration = 0; + +void RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter, + ProfilerLabelExit aExit) { + MOZ_ASSERT(!aEnter == !aExit, "Must provide both null or both non-null"); + + AutoProfilerLabelData data; + MOZ_ASSERT(!aEnter != !data.EnterRef(), + "Must go from null to non-null, or from non-null to null"); + data.EnterRef() = aEnter; + data.ExitRef() = aExit; + ++data.GenerationRef(); +} + +bool IsProfilerPresent() { + return AutoProfilerLabelData::RacyIsProfilerPresent(); +} + +ProfilerLabel ProfilerLabelBegin(const char* aLabelName, + const char* aDynamicString, void* aSp) { + const AutoProfilerLabelData data; + void* entryContext = (data.EnterCRef()) + ? data.EnterCRef()(aLabelName, aDynamicString, aSp) + : nullptr; + uint32_t generation = data.GenerationCRef(); + + return MakeTuple(entryContext, generation); +} + +void ProfilerLabelEnd(const ProfilerLabel& aLabel) { + if (!IsValidProfilerLabel(aLabel)) { + return; + } + + const AutoProfilerLabelData data; + if (data.ExitCRef() && (Get<1>(aLabel) == data.GenerationCRef())) { + data.ExitCRef()(Get<0>(aLabel)); + } +} + +AutoProfilerLabel::AutoProfilerLabel(const char* aLabel, + const char* aDynamicString) { + Tie(mEntryContext, mGeneration) = + ProfilerLabelBegin(aLabel, aDynamicString, this); +} + +AutoProfilerLabel::~AutoProfilerLabel() { + ProfilerLabelEnd(MakeTuple(mEntryContext, mGeneration)); +} + +} // namespace mozilla |