|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include <string> |
|
7 #include <sstream> |
|
8 #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
|
9 #include "EventTracer.h" |
|
10 #endif |
|
11 #include "GeckoProfiler.h" |
|
12 #include "nsProfiler.h" |
|
13 #include "nsMemory.h" |
|
14 #include "nsString.h" |
|
15 #include "mozilla/Services.h" |
|
16 #include "nsIObserverService.h" |
|
17 #include "nsIInterfaceRequestor.h" |
|
18 #include "nsILoadContext.h" |
|
19 #include "nsIWebNavigation.h" |
|
20 #include "nsIInterfaceRequestorUtils.h" |
|
21 #include "shared-libraries.h" |
|
22 #include "js/Value.h" |
|
23 |
|
24 using std::string; |
|
25 |
|
26 NS_IMPL_ISUPPORTS(nsProfiler, nsIProfiler) |
|
27 |
|
28 nsProfiler::nsProfiler() |
|
29 : mLockedForPrivateBrowsing(false) |
|
30 { |
|
31 } |
|
32 |
|
33 nsProfiler::~nsProfiler() |
|
34 { |
|
35 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); |
|
36 if (observerService) { |
|
37 observerService->RemoveObserver(this, "chrome-document-global-created"); |
|
38 observerService->RemoveObserver(this, "last-pb-context-exited"); |
|
39 } |
|
40 } |
|
41 |
|
42 nsresult |
|
43 nsProfiler::Init() { |
|
44 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); |
|
45 if (observerService) { |
|
46 observerService->AddObserver(this, "chrome-document-global-created", false); |
|
47 observerService->AddObserver(this, "last-pb-context-exited", false); |
|
48 } |
|
49 return NS_OK; |
|
50 } |
|
51 |
|
52 NS_IMETHODIMP |
|
53 nsProfiler::Observe(nsISupports *aSubject, |
|
54 const char *aTopic, |
|
55 const char16_t *aData) |
|
56 { |
|
57 if (strcmp(aTopic, "chrome-document-global-created") == 0) { |
|
58 nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryInterface(aSubject); |
|
59 nsCOMPtr<nsIWebNavigation> parentWebNav = do_GetInterface(requestor); |
|
60 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(parentWebNav); |
|
61 if (loadContext && loadContext->UsePrivateBrowsing() && !mLockedForPrivateBrowsing) { |
|
62 mLockedForPrivateBrowsing = true; |
|
63 profiler_lock(); |
|
64 } |
|
65 } else if (strcmp(aTopic, "last-pb-context-exited") == 0) { |
|
66 mLockedForPrivateBrowsing = false; |
|
67 profiler_unlock(); |
|
68 } |
|
69 return NS_OK; |
|
70 } |
|
71 |
|
72 NS_IMETHODIMP |
|
73 nsProfiler::StartProfiler(uint32_t aEntries, double aInterval, |
|
74 const char** aFeatures, uint32_t aFeatureCount, |
|
75 const char** aThreadNameFilters, uint32_t aFilterCount) |
|
76 { |
|
77 if (mLockedForPrivateBrowsing) { |
|
78 return NS_ERROR_NOT_AVAILABLE; |
|
79 } |
|
80 |
|
81 profiler_start(aEntries, aInterval, |
|
82 aFeatures, aFeatureCount, |
|
83 aThreadNameFilters, aFilterCount); |
|
84 #ifdef MOZ_INSTRUMENT_EVENT_LOOP |
|
85 bool printToConsole = false; |
|
86 mozilla::InitEventTracing(printToConsole); |
|
87 #endif |
|
88 return NS_OK; |
|
89 } |
|
90 |
|
91 NS_IMETHODIMP |
|
92 nsProfiler::StopProfiler() |
|
93 { |
|
94 profiler_stop(); |
|
95 return NS_OK; |
|
96 } |
|
97 |
|
98 NS_IMETHODIMP |
|
99 nsProfiler::IsPaused(bool *aIsPaused) |
|
100 { |
|
101 *aIsPaused = profiler_is_paused(); |
|
102 return NS_OK; |
|
103 } |
|
104 |
|
105 NS_IMETHODIMP |
|
106 nsProfiler::PauseSampling() |
|
107 { |
|
108 profiler_pause(); |
|
109 return NS_OK; |
|
110 } |
|
111 |
|
112 NS_IMETHODIMP |
|
113 nsProfiler::ResumeSampling() |
|
114 { |
|
115 profiler_resume(); |
|
116 return NS_OK; |
|
117 } |
|
118 |
|
119 NS_IMETHODIMP |
|
120 nsProfiler::AddMarker(const char *aMarker) |
|
121 { |
|
122 PROFILER_MARKER(aMarker); |
|
123 return NS_OK; |
|
124 } |
|
125 |
|
126 NS_IMETHODIMP |
|
127 nsProfiler::GetProfile(char **aProfile) |
|
128 { |
|
129 char *profile = profiler_get_profile(); |
|
130 if (profile) { |
|
131 size_t len = strlen(profile); |
|
132 char *profileStr = static_cast<char *> |
|
133 (nsMemory::Clone(profile, (len + 1) * sizeof(char))); |
|
134 profileStr[len] = '\0'; |
|
135 *aProfile = profileStr; |
|
136 free(profile); |
|
137 } |
|
138 return NS_OK; |
|
139 } |
|
140 |
|
141 static void |
|
142 AddSharedLibraryInfoToStream(std::ostream& aStream, const SharedLibrary& aLib) |
|
143 { |
|
144 aStream << "{"; |
|
145 aStream << "\"start\":" << aLib.GetStart(); |
|
146 aStream << ",\"end\":" << aLib.GetEnd(); |
|
147 aStream << ",\"offset\":" << aLib.GetOffset(); |
|
148 aStream << ",\"name\":\"" << aLib.GetName() << "\""; |
|
149 const std::string &breakpadId = aLib.GetBreakpadId(); |
|
150 aStream << ",\"breakpadId\":\"" << breakpadId << "\""; |
|
151 #ifdef XP_WIN |
|
152 // FIXME: remove this XP_WIN code when the profiler plugin has switched to |
|
153 // using breakpadId. |
|
154 std::string pdbSignature = breakpadId.substr(0, 32); |
|
155 std::string pdbAgeStr = breakpadId.substr(32, breakpadId.size() - 1); |
|
156 |
|
157 std::stringstream stream; |
|
158 stream << pdbAgeStr; |
|
159 |
|
160 unsigned pdbAge; |
|
161 stream << std::hex; |
|
162 stream >> pdbAge; |
|
163 |
|
164 #ifdef DEBUG |
|
165 std::ostringstream oStream; |
|
166 oStream << pdbSignature << std::hex << std::uppercase << pdbAge; |
|
167 MOZ_ASSERT(breakpadId == oStream.str()); |
|
168 #endif |
|
169 |
|
170 aStream << ",\"pdbSignature\":\"" << pdbSignature << "\""; |
|
171 aStream << ",\"pdbAge\":" << pdbAge; |
|
172 aStream << ",\"pdbName\":\"" << aLib.GetName() << "\""; |
|
173 #endif |
|
174 aStream << "}"; |
|
175 } |
|
176 |
|
177 std::string |
|
178 GetSharedLibraryInfoString() |
|
179 { |
|
180 SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf(); |
|
181 if (info.GetSize() == 0) |
|
182 return "[]"; |
|
183 |
|
184 std::ostringstream os; |
|
185 os << "["; |
|
186 AddSharedLibraryInfoToStream(os, info.GetEntry(0)); |
|
187 |
|
188 for (size_t i = 1; i < info.GetSize(); i++) { |
|
189 os << ","; |
|
190 AddSharedLibraryInfoToStream(os, info.GetEntry(i)); |
|
191 } |
|
192 |
|
193 os << "]"; |
|
194 return os.str(); |
|
195 } |
|
196 |
|
197 NS_IMETHODIMP |
|
198 nsProfiler::GetSharedLibraryInformation(nsAString& aOutString) |
|
199 { |
|
200 aOutString.Assign(NS_ConvertUTF8toUTF16(GetSharedLibraryInfoString().c_str())); |
|
201 return NS_OK; |
|
202 } |
|
203 |
|
204 NS_IMETHODIMP nsProfiler::GetProfileData(JSContext* aCx, |
|
205 JS::MutableHandle<JS::Value> aResult) |
|
206 { |
|
207 JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx)); |
|
208 if (!obj) { |
|
209 return NS_ERROR_FAILURE; |
|
210 } |
|
211 aResult.setObject(*obj); |
|
212 return NS_OK; |
|
213 } |
|
214 |
|
215 NS_IMETHODIMP |
|
216 nsProfiler::IsActive(bool *aIsActive) |
|
217 { |
|
218 *aIsActive = profiler_is_active(); |
|
219 return NS_OK; |
|
220 } |
|
221 |
|
222 NS_IMETHODIMP |
|
223 nsProfiler::GetResponsivenessTimes(uint32_t *aCount, double **aResult) |
|
224 { |
|
225 unsigned int len = 100; |
|
226 const double* times = profiler_get_responsiveness(); |
|
227 if (!times) { |
|
228 *aCount = 0; |
|
229 *aResult = nullptr; |
|
230 return NS_OK; |
|
231 } |
|
232 |
|
233 double *fs = static_cast<double *> |
|
234 (nsMemory::Clone(times, len * sizeof(double))); |
|
235 |
|
236 *aCount = len; |
|
237 *aResult = fs; |
|
238 |
|
239 return NS_OK; |
|
240 } |
|
241 |
|
242 NS_IMETHODIMP |
|
243 nsProfiler::GetFeatures(uint32_t *aCount, char ***aFeatures) |
|
244 { |
|
245 uint32_t len = 0; |
|
246 |
|
247 const char **features = profiler_get_features(); |
|
248 if (!features) { |
|
249 *aCount = 0; |
|
250 *aFeatures = nullptr; |
|
251 return NS_OK; |
|
252 } |
|
253 |
|
254 while (features[len]) { |
|
255 len++; |
|
256 } |
|
257 |
|
258 char **featureList = static_cast<char **> |
|
259 (nsMemory::Alloc(len * sizeof(char*))); |
|
260 |
|
261 for (size_t i = 0; i < len; i++) { |
|
262 size_t strLen = strlen(features[i]); |
|
263 featureList[i] = static_cast<char *> |
|
264 (nsMemory::Clone(features[i], (strLen + 1) * sizeof(char))); |
|
265 } |
|
266 |
|
267 *aFeatures = featureList; |
|
268 *aCount = len; |
|
269 return NS_OK; |
|
270 } |