Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; 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/HangAnnotations.h"
8 :
9 : #include <vector>
10 :
11 : #include "MainThreadUtils.h"
12 : #include "mozilla/DebugOnly.h"
13 : #include "nsXULAppAPI.h"
14 :
15 : namespace mozilla {
16 : namespace HangMonitor {
17 :
18 : // Chrome hang annotators. This can go away once BHR has completely replaced
19 : // ChromeHangs.
20 3 : static StaticAutoPtr<Observer::Annotators> gChromehangAnnotators;
21 :
22 : class BrowserHangAnnotations : public HangAnnotations
23 : {
24 : public:
25 : BrowserHangAnnotations();
26 : ~BrowserHangAnnotations();
27 :
28 : void AddAnnotation(const nsAString& aName, const int32_t aData) override;
29 : void AddAnnotation(const nsAString& aName, const double aData) override;
30 : void AddAnnotation(const nsAString& aName, const nsAString& aData) override;
31 : void AddAnnotation(const nsAString& aName, const nsACString& aData) override;
32 : void AddAnnotation(const nsAString& aName, const bool aData) override;
33 :
34 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
35 : bool IsEmpty() const override;
36 : UniquePtr<Enumerator> GetEnumerator() override;
37 :
38 : typedef std::pair<nsString, nsString> AnnotationType;
39 : typedef std::vector<AnnotationType> VectorType;
40 : typedef VectorType::const_iterator IteratorType;
41 :
42 : private:
43 : VectorType mAnnotations;
44 : };
45 :
46 0 : BrowserHangAnnotations::BrowserHangAnnotations()
47 : {
48 0 : MOZ_COUNT_CTOR(BrowserHangAnnotations);
49 0 : }
50 :
51 0 : BrowserHangAnnotations::~BrowserHangAnnotations()
52 : {
53 0 : MOZ_COUNT_DTOR(BrowserHangAnnotations);
54 0 : }
55 :
56 : void
57 0 : BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData)
58 : {
59 0 : nsString dataString;
60 0 : dataString.AppendInt(aData);
61 0 : AnnotationType annotation = std::make_pair(nsString(aName), dataString);
62 0 : mAnnotations.push_back(annotation);
63 0 : }
64 :
65 : void
66 0 : BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const double aData)
67 : {
68 0 : nsString dataString;
69 0 : dataString.AppendFloat(aData);
70 0 : AnnotationType annotation = std::make_pair(nsString(aName), dataString);
71 0 : mAnnotations.push_back(annotation);
72 0 : }
73 :
74 : void
75 0 : BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
76 : {
77 0 : AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData));
78 0 : mAnnotations.push_back(annotation);
79 0 : }
80 :
81 : void
82 0 : BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData)
83 : {
84 0 : nsString dataString;
85 0 : AppendUTF8toUTF16(aData, dataString);
86 0 : AnnotationType annotation = std::make_pair(nsString(aName), dataString);
87 0 : mAnnotations.push_back(annotation);
88 0 : }
89 :
90 : void
91 0 : BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const bool aData)
92 : {
93 0 : nsString dataString;
94 0 : dataString += aData ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false");
95 0 : AnnotationType annotation = std::make_pair(nsString(aName), dataString);
96 0 : mAnnotations.push_back(annotation);
97 0 : }
98 :
99 : /**
100 : * This class itself does not use synchronization but it (and its parent object)
101 : * should be protected by mutual exclusion in some way. In Telemetry the chrome
102 : * hang data is protected via TelemetryImpl::mHangReportsMutex.
103 : */
104 : class ChromeHangAnnotationEnumerator : public HangAnnotations::Enumerator
105 : {
106 : public:
107 : explicit ChromeHangAnnotationEnumerator(const BrowserHangAnnotations::VectorType& aAnnotations);
108 : ~ChromeHangAnnotationEnumerator();
109 :
110 : virtual bool Next(nsAString& aOutName, nsAString& aOutValue);
111 :
112 : private:
113 : BrowserHangAnnotations::IteratorType mIterator;
114 : BrowserHangAnnotations::IteratorType mEnd;
115 : };
116 :
117 0 : ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator(
118 0 : const BrowserHangAnnotations::VectorType& aAnnotations)
119 : : mIterator(aAnnotations.begin())
120 0 : , mEnd(aAnnotations.end())
121 : {
122 0 : MOZ_COUNT_CTOR(ChromeHangAnnotationEnumerator);
123 0 : }
124 :
125 0 : ChromeHangAnnotationEnumerator::~ChromeHangAnnotationEnumerator()
126 : {
127 0 : MOZ_COUNT_DTOR(ChromeHangAnnotationEnumerator);
128 0 : }
129 :
130 : bool
131 0 : ChromeHangAnnotationEnumerator::Next(nsAString& aOutName, nsAString& aOutValue)
132 : {
133 0 : aOutName.Truncate();
134 0 : aOutValue.Truncate();
135 0 : if (mIterator == mEnd) {
136 0 : return false;
137 : }
138 0 : aOutName = mIterator->first;
139 0 : aOutValue = mIterator->second;
140 0 : ++mIterator;
141 0 : return true;
142 : }
143 :
144 : bool
145 0 : BrowserHangAnnotations::IsEmpty() const
146 : {
147 0 : return mAnnotations.empty();
148 : }
149 :
150 : size_t
151 0 : BrowserHangAnnotations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
152 : {
153 : size_t result = sizeof(mAnnotations) +
154 0 : mAnnotations.capacity() * sizeof(AnnotationType);
155 0 : for (IteratorType i = mAnnotations.begin(), e = mAnnotations.end(); i != e;
156 : ++i) {
157 0 : result += i->first.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
158 0 : result += i->second.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
159 : }
160 :
161 0 : return result;
162 : }
163 :
164 : UniquePtr<HangAnnotations::Enumerator>
165 0 : BrowserHangAnnotations::GetEnumerator()
166 : {
167 0 : if (mAnnotations.empty()) {
168 0 : return nullptr;
169 : }
170 0 : return MakeUnique<ChromeHangAnnotationEnumerator>(mAnnotations);
171 : }
172 :
173 : namespace Observer {
174 :
175 1 : Annotators::Annotators()
176 1 : : mMutex("HangMonitor::Annotators::mMutex")
177 : {
178 1 : MOZ_COUNT_CTOR(Annotators);
179 1 : }
180 :
181 0 : Annotators::~Annotators()
182 : {
183 0 : MOZ_ASSERT(mAnnotators.empty());
184 0 : MOZ_COUNT_DTOR(Annotators);
185 0 : }
186 :
187 : bool
188 1 : Annotators::Register(Annotator& aAnnotator)
189 : {
190 2 : MutexAutoLock lock(mMutex);
191 1 : auto result = mAnnotators.insert(&aAnnotator);
192 2 : return result.second;
193 : }
194 :
195 : bool
196 0 : Annotators::Unregister(Annotator& aAnnotator)
197 : {
198 0 : MutexAutoLock lock(mMutex);
199 0 : DebugOnly<std::set<Annotator*>::size_type> numErased;
200 0 : numErased = mAnnotators.erase(&aAnnotator);
201 0 : MOZ_ASSERT(numErased == 1);
202 0 : return mAnnotators.empty();
203 : }
204 :
205 : UniquePtr<HangAnnotations>
206 0 : Annotators::GatherAnnotations()
207 : {
208 0 : auto annotations = MakeUnique<BrowserHangAnnotations>();
209 : { // Scope for lock
210 0 : MutexAutoLock lock(mMutex);
211 0 : for (std::set<Annotator*>::iterator i = mAnnotators.begin(),
212 0 : e = mAnnotators.end();
213 : i != e; ++i) {
214 0 : (*i)->AnnotateHang(*annotations);
215 : }
216 : }
217 0 : if (annotations->IsEmpty()) {
218 0 : return nullptr;
219 : }
220 0 : return Move(annotations);
221 : }
222 :
223 : } // namespace Observer
224 :
225 : void
226 3 : RegisterAnnotator(Annotator& aAnnotator)
227 : {
228 3 : BackgroundHangMonitor::RegisterAnnotator(aAnnotator);
229 : // We still register annotators for ChromeHangs
230 6 : if (NS_IsMainThread() &&
231 3 : GeckoProcessType_Default == XRE_GetProcessType()) {
232 1 : if (!gChromehangAnnotators) {
233 1 : gChromehangAnnotators = new Observer::Annotators();
234 : }
235 1 : gChromehangAnnotators->Register(aAnnotator);
236 : }
237 3 : }
238 :
239 : void
240 0 : UnregisterAnnotator(Annotator& aAnnotator)
241 : {
242 0 : BackgroundHangMonitor::UnregisterAnnotator(aAnnotator);
243 : // We still register annotators for ChromeHangs
244 0 : if (NS_IsMainThread() &&
245 0 : GeckoProcessType_Default == XRE_GetProcessType()) {
246 0 : if (gChromehangAnnotators->Unregister(aAnnotator)) {
247 0 : gChromehangAnnotators = nullptr;
248 : }
249 : }
250 0 : }
251 :
252 : UniquePtr<HangAnnotations>
253 0 : ChromeHangAnnotatorCallout()
254 : {
255 0 : if (!gChromehangAnnotators) {
256 0 : return nullptr;
257 : }
258 0 : return gChromehangAnnotators->GatherAnnotations();
259 : }
260 :
261 : } // namespace HangMonitor
262 : } // namespace mozilla
|