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 "ProfilerParent.h"
8 :
9 : #include "mozilla/ClearOnShutdown.h"
10 : #include "mozilla/RefPtr.h"
11 : #include "mozilla/Unused.h"
12 :
13 : #include "nsProfiler.h"
14 : #include "nsTArray.h"
15 : #include "nsThreadUtils.h"
16 :
17 : namespace mozilla {
18 :
19 : using namespace ipc;
20 :
21 : class ProfilerParentTracker final {
22 : public:
23 : static void StartTracking(ProfilerParent* aParent);
24 : static void StopTracking(ProfilerParent* aParent);
25 :
26 : template<typename FuncType>
27 : static void Enumerate(FuncType aIterFunc);
28 :
29 : ProfilerParentTracker();
30 : ~ProfilerParentTracker();
31 :
32 : private:
33 : nsTArray<ProfilerParent*> mProfilerParents;
34 : static UniquePtr<ProfilerParentTracker> sInstance;
35 : };
36 :
37 3 : UniquePtr<ProfilerParentTracker> ProfilerParentTracker::sInstance;
38 :
39 : /* static */ void
40 2 : ProfilerParentTracker::StartTracking(ProfilerParent* aProfilerParent)
41 : {
42 2 : if (!sInstance) {
43 1 : sInstance = MakeUnique<ProfilerParentTracker>();
44 1 : ClearOnShutdown(&sInstance);
45 : }
46 2 : sInstance->mProfilerParents.AppendElement(aProfilerParent);
47 2 : }
48 :
49 : /* static */ void
50 0 : ProfilerParentTracker::StopTracking(ProfilerParent* aParent)
51 : {
52 0 : if (sInstance) {
53 0 : sInstance->mProfilerParents.RemoveElement(aParent);
54 : }
55 0 : }
56 :
57 : template<typename FuncType>
58 : /* static */ void
59 0 : ProfilerParentTracker::Enumerate(FuncType aIterFunc)
60 : {
61 0 : if (sInstance) {
62 0 : for (ProfilerParent* profilerParent : sInstance->mProfilerParents) {
63 0 : if (!profilerParent->mDestroyed) {
64 0 : aIterFunc(profilerParent);
65 : }
66 : }
67 : }
68 0 : }
69 :
70 1 : ProfilerParentTracker::ProfilerParentTracker()
71 : {
72 1 : MOZ_COUNT_CTOR(ProfilerParentTracker);
73 1 : }
74 :
75 0 : ProfilerParentTracker::~ProfilerParentTracker()
76 : {
77 0 : MOZ_COUNT_DTOR(ProfilerParentTracker);
78 :
79 0 : nsTArray<ProfilerParent*> parents;
80 0 : parents = mProfilerParents;
81 : // Close the channels of any profiler parents that haven't been destroyed.
82 0 : for (ProfilerParent* profilerParent : parents) {
83 0 : if (!profilerParent->mDestroyed) {
84 : // Keep the object alive until the call to Close() has completed.
85 : // Close() will trigger a call to DeallocPProfilerParent.
86 0 : RefPtr<ProfilerParent> actor = profilerParent;
87 0 : actor->Close();
88 : }
89 : }
90 0 : }
91 :
92 : /* static */ Endpoint<PProfilerChild>
93 2 : ProfilerParent::CreateForProcess(base::ProcessId aOtherPid)
94 : {
95 2 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
96 4 : Endpoint<PProfilerParent> parent;
97 2 : Endpoint<PProfilerChild> child;
98 2 : nsresult rv = PProfiler::CreateEndpoints(base::GetCurrentProcId(),
99 : aOtherPid,
100 2 : &parent, &child);
101 :
102 2 : if (NS_FAILED(rv)) {
103 0 : MOZ_CRASH("Failed to create top level actor for PProfiler!");
104 : }
105 :
106 4 : RefPtr<ProfilerParent> actor = new ProfilerParent();
107 2 : if (!parent.Bind(actor)) {
108 0 : MOZ_CRASH("Failed to bind parent actor for PProfiler!");
109 : }
110 :
111 : // mSelfRef will be cleared in DeallocPProfilerParent.
112 2 : actor->mSelfRef = actor;
113 2 : actor->Init();
114 :
115 4 : return child;
116 : }
117 :
118 2 : ProfilerParent::ProfilerParent()
119 2 : : mDestroyed(false)
120 : {
121 2 : MOZ_COUNT_CTOR(ProfilerParent);
122 :
123 2 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
124 2 : }
125 :
126 : void
127 2 : ProfilerParent::Init()
128 : {
129 2 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
130 :
131 2 : ProfilerParentTracker::StartTracking(this);
132 :
133 2 : if (profiler_is_active()) {
134 : // If the profiler is already running in this process, start it in the
135 : // child process immediately.
136 0 : int entries = 0;
137 0 : double interval = 0;
138 0 : mozilla::Vector<const char*> filters;
139 : uint32_t features;
140 0 : profiler_get_start_params(&entries, &interval, &features, &filters);
141 :
142 0 : ProfilerInitParams ipcParams;
143 0 : ipcParams.enabled() = true;
144 0 : ipcParams.entries() = entries;
145 0 : ipcParams.interval() = interval;
146 0 : ipcParams.features() = features;
147 :
148 0 : for (uint32_t i = 0; i < filters.length(); ++i) {
149 0 : ipcParams.filters().AppendElement(filters[i]);
150 : }
151 :
152 0 : Unused << SendStart(ipcParams);
153 : }
154 2 : }
155 :
156 0 : ProfilerParent::~ProfilerParent()
157 : {
158 0 : MOZ_COUNT_DTOR(ProfilerParent);
159 :
160 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
161 0 : ProfilerParentTracker::StopTracking(this);
162 0 : }
163 :
164 : /* static */ nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>>
165 0 : ProfilerParent::GatherProfiles()
166 : {
167 0 : if (!NS_IsMainThread()) {
168 0 : return nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>>();
169 : }
170 :
171 0 : nsTArray<RefPtr<SingleProcessProfilePromise>> results;
172 0 : ProfilerParentTracker::Enumerate([&](ProfilerParent* profilerParent) {
173 0 : results.AppendElement(profilerParent->SendGatherProfile());
174 0 : });
175 0 : return results;
176 : }
177 :
178 : /* static */ void
179 0 : ProfilerParent::ProfilerStarted(nsIProfilerStartParams* aParams)
180 : {
181 0 : if (!NS_IsMainThread()) {
182 0 : return;
183 : }
184 :
185 0 : ProfilerInitParams ipcParams;
186 0 : ipcParams.enabled() = true;
187 0 : aParams->GetEntries(&ipcParams.entries());
188 0 : aParams->GetInterval(&ipcParams.interval());
189 0 : aParams->GetFeatures(&ipcParams.features());
190 0 : ipcParams.filters() = aParams->GetFilters();
191 :
192 0 : ProfilerParentTracker::Enumerate([&](ProfilerParent* profilerParent) {
193 0 : Unused << profilerParent->SendStart(ipcParams);
194 0 : });
195 : }
196 :
197 : /* static */ void
198 0 : ProfilerParent::ProfilerStopped()
199 : {
200 0 : if (!NS_IsMainThread()) {
201 0 : return;
202 : }
203 :
204 0 : ProfilerParentTracker::Enumerate([](ProfilerParent* profilerParent) {
205 0 : Unused << profilerParent->SendStop();
206 0 : });
207 : }
208 :
209 : /* static */ void
210 0 : ProfilerParent::ProfilerPaused()
211 : {
212 0 : if (!NS_IsMainThread()) {
213 0 : return;
214 : }
215 :
216 0 : ProfilerParentTracker::Enumerate([](ProfilerParent* profilerParent) {
217 0 : Unused << profilerParent->SendPause();
218 0 : });
219 : }
220 :
221 : /* static */ void
222 0 : ProfilerParent::ProfilerResumed()
223 : {
224 0 : if (!NS_IsMainThread()) {
225 0 : return;
226 : }
227 :
228 0 : ProfilerParentTracker::Enumerate([](ProfilerParent* profilerParent) {
229 0 : Unused << profilerParent->SendResume();
230 0 : });
231 : }
232 :
233 : void
234 0 : ProfilerParent::ActorDestroy(ActorDestroyReason aActorDestroyReason)
235 : {
236 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
237 0 : mDestroyed = true;
238 0 : }
239 :
240 : void
241 0 : ProfilerParent::DeallocPProfilerParent()
242 : {
243 0 : mSelfRef = nullptr;
244 0 : }
245 :
246 : } // namespace mozilla
|