|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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 #ifndef TableTicker_h |
|
7 #define TableTicker_h |
|
8 |
|
9 #include "platform.h" |
|
10 #include "ProfileEntry.h" |
|
11 #include "mozilla/Mutex.h" |
|
12 #include "IntelPowerGadget.h" |
|
13 |
|
14 static bool |
|
15 hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature) { |
|
16 for(size_t i = 0; i < aFeatureCount; i++) { |
|
17 if (strcmp(aFeatures[i], aFeature) == 0) |
|
18 return true; |
|
19 } |
|
20 return false; |
|
21 } |
|
22 |
|
23 static bool |
|
24 threadSelected(ThreadInfo* aInfo, char** aThreadNameFilters, uint32_t aFeatureCount) { |
|
25 if (aFeatureCount == 0) { |
|
26 return true; |
|
27 } |
|
28 |
|
29 for (uint32_t i = 0; i < aFeatureCount; ++i) { |
|
30 const char* filterPrefix = aThreadNameFilters[i]; |
|
31 if (strncmp(aInfo->Name(), filterPrefix, strlen(filterPrefix)) == 0) { |
|
32 return true; |
|
33 } |
|
34 } |
|
35 |
|
36 return false; |
|
37 } |
|
38 |
|
39 extern TimeStamp sLastTracerEvent; |
|
40 extern int sFrameNumber; |
|
41 extern int sLastFrameNumber; |
|
42 extern unsigned int sCurrentEventGeneration; |
|
43 extern unsigned int sLastSampledEventGeneration; |
|
44 |
|
45 class BreakpadSampler; |
|
46 |
|
47 class TableTicker: public Sampler { |
|
48 public: |
|
49 TableTicker(double aInterval, int aEntrySize, |
|
50 const char** aFeatures, uint32_t aFeatureCount, |
|
51 const char** aThreadNameFilters, uint32_t aFilterCount) |
|
52 : Sampler(aInterval, true, aEntrySize) |
|
53 , mPrimaryThreadProfile(nullptr) |
|
54 , mSaveRequested(false) |
|
55 , mUnwinderThread(false) |
|
56 , mFilterCount(aFilterCount) |
|
57 #if defined(XP_WIN) |
|
58 , mIntelPowerGadget(nullptr) |
|
59 #endif |
|
60 { |
|
61 mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk"); |
|
62 |
|
63 //XXX: It's probably worth splitting the jank profiler out from the regular profiler at some point |
|
64 mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank"); |
|
65 mProfileJS = hasFeature(aFeatures, aFeatureCount, "js"); |
|
66 mProfileJava = hasFeature(aFeatures, aFeatureCount, "java"); |
|
67 mProfilePower = hasFeature(aFeatures, aFeatureCount, "power"); |
|
68 mProfileThreads = hasFeature(aFeatures, aFeatureCount, "threads"); |
|
69 mUnwinderThread = hasFeature(aFeatures, aFeatureCount, "unwinder") || sps_version2(); |
|
70 mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf"); |
|
71 mPrivacyMode = hasFeature(aFeatures, aFeatureCount, "privacy"); |
|
72 mAddMainThreadIO = hasFeature(aFeatures, aFeatureCount, "mainthreadio"); |
|
73 |
|
74 #if defined(XP_WIN) |
|
75 if (mProfilePower) { |
|
76 mIntelPowerGadget = new IntelPowerGadget(); |
|
77 mProfilePower = mIntelPowerGadget->Init(); |
|
78 } |
|
79 #endif |
|
80 |
|
81 // Deep copy aThreadNameFilters |
|
82 mThreadNameFilters = new char*[aFilterCount]; |
|
83 for (uint32_t i = 0; i < aFilterCount; ++i) { |
|
84 mThreadNameFilters[i] = strdup(aThreadNameFilters[i]); |
|
85 } |
|
86 |
|
87 sStartTime = TimeStamp::Now(); |
|
88 |
|
89 { |
|
90 mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex); |
|
91 |
|
92 // Create ThreadProfile for each registered thread |
|
93 for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { |
|
94 ThreadInfo* info = sRegisteredThreads->at(i); |
|
95 |
|
96 RegisterThread(info); |
|
97 } |
|
98 |
|
99 SetActiveSampler(this); |
|
100 } |
|
101 } |
|
102 |
|
103 ~TableTicker() { |
|
104 if (IsActive()) |
|
105 Stop(); |
|
106 |
|
107 SetActiveSampler(nullptr); |
|
108 |
|
109 // Destroy ThreadProfile for all threads |
|
110 { |
|
111 mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex); |
|
112 |
|
113 for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { |
|
114 ThreadInfo* info = sRegisteredThreads->at(i); |
|
115 ThreadProfile* profile = info->Profile(); |
|
116 if (profile) { |
|
117 delete profile; |
|
118 info->SetProfile(nullptr); |
|
119 } |
|
120 } |
|
121 } |
|
122 #if defined(XP_WIN) |
|
123 delete mIntelPowerGadget; |
|
124 #endif |
|
125 } |
|
126 |
|
127 void RegisterThread(ThreadInfo* aInfo) { |
|
128 if (!aInfo->IsMainThread() && !mProfileThreads) { |
|
129 return; |
|
130 } |
|
131 |
|
132 if (!threadSelected(aInfo, mThreadNameFilters, mFilterCount)) { |
|
133 return; |
|
134 } |
|
135 |
|
136 ThreadProfile* profile = new ThreadProfile(aInfo->Name(), |
|
137 EntrySize(), |
|
138 aInfo->Stack(), |
|
139 aInfo->ThreadId(), |
|
140 aInfo->GetPlatformData(), |
|
141 aInfo->IsMainThread(), |
|
142 aInfo->StackTop()); |
|
143 aInfo->SetProfile(profile); |
|
144 } |
|
145 |
|
146 // Called within a signal. This function must be reentrant |
|
147 virtual void Tick(TickSample* sample); |
|
148 |
|
149 // Immediately captures the calling thread's call stack and returns it. |
|
150 virtual SyncProfile* GetBacktrace(); |
|
151 |
|
152 // Called within a signal. This function must be reentrant |
|
153 virtual void RequestSave() |
|
154 { |
|
155 mSaveRequested = true; |
|
156 } |
|
157 |
|
158 virtual void HandleSaveRequest(); |
|
159 |
|
160 ThreadProfile* GetPrimaryThreadProfile() |
|
161 { |
|
162 if (!mPrimaryThreadProfile) { |
|
163 mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex); |
|
164 |
|
165 for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { |
|
166 ThreadInfo* info = sRegisteredThreads->at(i); |
|
167 if (info->IsMainThread()) { |
|
168 mPrimaryThreadProfile = info->Profile(); |
|
169 break; |
|
170 } |
|
171 } |
|
172 } |
|
173 |
|
174 return mPrimaryThreadProfile; |
|
175 } |
|
176 |
|
177 void ToStreamAsJSON(std::ostream& stream); |
|
178 virtual JSObject *ToJSObject(JSContext *aCx); |
|
179 void StreamMetaJSCustomObject(JSStreamWriter& b); |
|
180 bool HasUnwinderThread() const { return mUnwinderThread; } |
|
181 bool ProfileJS() const { return mProfileJS; } |
|
182 bool ProfileJava() const { return mProfileJava; } |
|
183 bool ProfilePower() const { return mProfilePower; } |
|
184 bool ProfileThreads() const { return mProfileThreads; } |
|
185 bool InPrivacyMode() const { return mPrivacyMode; } |
|
186 bool AddMainThreadIO() const { return mAddMainThreadIO; } |
|
187 |
|
188 protected: |
|
189 // Called within a signal. This function must be reentrant |
|
190 virtual void UnwinderTick(TickSample* sample); |
|
191 |
|
192 // Called within a signal. This function must be reentrant |
|
193 virtual void InplaceTick(TickSample* sample); |
|
194 |
|
195 // Not implemented on platforms which do not support backtracing |
|
196 void doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample); |
|
197 |
|
198 void StreamJSObject(JSStreamWriter& b); |
|
199 |
|
200 // This represent the application's main thread (SAMPLER_INIT) |
|
201 ThreadProfile* mPrimaryThreadProfile; |
|
202 bool mSaveRequested; |
|
203 bool mAddLeafAddresses; |
|
204 bool mUseStackWalk; |
|
205 bool mJankOnly; |
|
206 bool mProfileJS; |
|
207 bool mProfileThreads; |
|
208 bool mUnwinderThread; |
|
209 bool mProfileJava; |
|
210 bool mProfilePower; |
|
211 |
|
212 // Keep the thread filter to check against new thread that |
|
213 // are started while profiling |
|
214 char** mThreadNameFilters; |
|
215 uint32_t mFilterCount; |
|
216 bool mPrivacyMode; |
|
217 bool mAddMainThreadIO; |
|
218 #if defined(XP_WIN) |
|
219 IntelPowerGadget* mIntelPowerGadget; |
|
220 #endif |
|
221 }; |
|
222 |
|
223 #endif |
|
224 |