1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
|