AutoProfilerLabel.cpp (3739B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/AutoProfilerLabel.h" 8 9 #include "mozilla/Assertions.h" 10 #include "mozilla/PlatformMutex.h" 11 12 namespace mozilla { 13 14 // RAII class that encapsulates all shared static data, and enforces locking 15 // when accessing this data. 16 class MOZ_RAII AutoProfilerLabelData { 17 public: 18 AutoProfilerLabelData() { sAPLMutex.Lock(); } 19 20 ~AutoProfilerLabelData() { sAPLMutex.Unlock(); } 21 22 AutoProfilerLabelData(const AutoProfilerLabelData&) = delete; 23 void operator=(const AutoProfilerLabelData&) = delete; 24 25 const ProfilerLabelEnter& EnterCRef() const { return sEnter; } 26 ProfilerLabelEnter& EnterRef() { return sEnter; } 27 28 const ProfilerLabelExit& ExitCRef() const { return sExit; } 29 ProfilerLabelExit& ExitRef() { return sExit; } 30 31 const uint32_t& GenerationCRef() const { return sGeneration; } 32 uint32_t& GenerationRef() { return sGeneration; } 33 34 static bool RacyIsProfilerPresent() { return !!sGeneration; } 35 36 private: 37 // Thin shell around mozglue PlatformMutex, for local internal use. 38 // Does not preserve behavior in JS record/replay. 39 class Mutex : private mozilla::detail::MutexImpl { 40 public: 41 Mutex() = default; 42 void Lock() { mozilla::detail::MutexImpl::lock(); } 43 void Unlock() { mozilla::detail::MutexImpl::unlock(); } 44 }; 45 46 // Mutex protecting access to the following static members. 47 static Mutex sAPLMutex MOZ_UNANNOTATED; 48 49 static ProfilerLabelEnter sEnter; 50 static ProfilerLabelExit sExit; 51 52 // Current "generation" of RegisterProfilerLabelEnterExit calls. 53 static uint32_t sGeneration; 54 }; 55 56 MOZ_RUNINIT /* static */ AutoProfilerLabelData::Mutex 57 AutoProfilerLabelData::sAPLMutex; 58 /* static */ ProfilerLabelEnter AutoProfilerLabelData::sEnter = nullptr; 59 /* static */ ProfilerLabelExit AutoProfilerLabelData::sExit = nullptr; 60 /* static */ uint32_t AutoProfilerLabelData::sGeneration = 0; 61 62 void RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter, 63 ProfilerLabelExit aExit) { 64 MOZ_ASSERT(!aEnter == !aExit, "Must provide both null or both non-null"); 65 66 AutoProfilerLabelData data; 67 MOZ_ASSERT(!aEnter != !data.EnterRef(), 68 "Must go from null to non-null, or from non-null to null"); 69 data.EnterRef() = aEnter; 70 data.ExitRef() = aExit; 71 ++data.GenerationRef(); 72 } 73 74 bool IsProfilerPresent() { 75 return AutoProfilerLabelData::RacyIsProfilerPresent(); 76 } 77 78 ProfilerLabel ProfilerLabelBegin(const char* aLabelName, 79 const char* aDynamicString, void* aSp) { 80 const AutoProfilerLabelData data; 81 void* entryContext = (data.EnterCRef()) 82 ? data.EnterCRef()(aLabelName, aDynamicString, aSp) 83 : nullptr; 84 uint32_t generation = data.GenerationCRef(); 85 86 return std::make_tuple(entryContext, generation); 87 } 88 89 void ProfilerLabelEnd(const ProfilerLabel& aLabel) { 90 if (!IsValidProfilerLabel(aLabel)) { 91 return; 92 } 93 94 const AutoProfilerLabelData data; 95 if (data.ExitCRef() && (std::get<1>(aLabel) == data.GenerationCRef())) { 96 data.ExitCRef()(std::get<0>(aLabel)); 97 } 98 } 99 100 AutoProfilerLabel::AutoProfilerLabel(const char* aLabel, 101 const char* aDynamicString) { 102 std::tie(mEntryContext, mGeneration) = 103 ProfilerLabelBegin(aLabel, aDynamicString, this); 104 } 105 106 AutoProfilerLabel::~AutoProfilerLabel() { 107 ProfilerLabelEnd(std::make_tuple(mEntryContext, mGeneration)); 108 } 109 110 } // namespace mozilla