Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions
5 // are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in
10 // the documentation and/or other materials provided with the
11 // distribution.
12 // * Neither the name of Google, Inc. nor the names of its contributors
13 // may be used to endorse or promote products derived from this
14 // software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 // SUCH DAMAGE.
29 #include <windows.h>
30 #include <mmsystem.h>
31 #include <process.h>
32 #include "platform.h"
33 #include "TableTicker.h"
34 #include "ProfileEntry.h"
35 #include "UnwinderThread2.h"
37 class PlatformData : public Malloced {
38 public:
39 // Get a handle to the calling thread. This is the thread that we are
40 // going to profile. We need to make a copy of the handle because we are
41 // going to use it in the sampler thread. Using GetThreadHandle() will
42 // not work in this case. We're using OpenThread because DuplicateHandle
43 // for some reason doesn't work in Chrome's sandbox.
44 PlatformData(int aThreadId) : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
45 THREAD_SUSPEND_RESUME |
46 THREAD_QUERY_INFORMATION,
47 false,
48 aThreadId)) {}
50 ~PlatformData() {
51 if (profiled_thread_ != NULL) {
52 CloseHandle(profiled_thread_);
53 profiled_thread_ = NULL;
54 }
55 }
57 HANDLE profiled_thread() { return profiled_thread_; }
59 private:
60 HANDLE profiled_thread_;
61 };
63 /* static */ PlatformData*
64 Sampler::AllocPlatformData(int aThreadId)
65 {
66 return new PlatformData(aThreadId);
67 }
69 /* static */ void
70 Sampler::FreePlatformData(PlatformData* aData)
71 {
72 delete aData;
73 }
75 uintptr_t
76 Sampler::GetThreadHandle(PlatformData* aData)
77 {
78 return (uintptr_t) aData->profiled_thread();
79 }
81 class SamplerThread : public Thread {
82 public:
83 SamplerThread(double interval, Sampler* sampler)
84 : Thread("SamplerThread")
85 , interval_(interval)
86 , sampler_(sampler)
87 {
88 interval_ = floor(interval + 0.5);
89 if (interval_ <= 0) {
90 interval_ = 1;
91 }
92 }
94 static void StartSampler(Sampler* sampler) {
95 if (instance_ == NULL) {
96 instance_ = new SamplerThread(sampler->interval(), sampler);
97 instance_->Start();
98 } else {
99 ASSERT(instance_->interval_ == sampler->interval());
100 }
101 }
103 static void StopSampler() {
104 instance_->Join();
105 delete instance_;
106 instance_ = NULL;
107 }
109 // Implement Thread::Run().
110 virtual void Run() {
112 // By default we'll not adjust the timer resolution which tends to be around
113 // 16ms. However, if the requested interval is sufficiently low we'll try to
114 // adjust the resolution to match.
115 if (interval_ < 10)
116 ::timeBeginPeriod(interval_);
118 while (sampler_->IsActive()) {
119 if (!sampler_->IsPaused()) {
120 mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
121 std::vector<ThreadInfo*> threads =
122 sampler_->GetRegisteredThreads();
123 for (uint32_t i = 0; i < threads.size(); i++) {
124 ThreadInfo* info = threads[i];
126 // This will be null if we're not interested in profiling this thread.
127 if (!info->Profile())
128 continue;
130 PseudoStack::SleepState sleeping = info->Stack()->observeSleeping();
131 if (sleeping == PseudoStack::SLEEPING_AGAIN) {
132 info->Profile()->DuplicateLastSample();
133 //XXX: This causes flushes regardless of jank-only mode
134 info->Profile()->flush();
135 continue;
136 }
138 ThreadProfile* thread_profile = info->Profile();
140 SampleContext(sampler_, thread_profile);
141 }
142 }
143 OS::Sleep(interval_);
144 }
146 // disable any timer resolution changes we've made
147 if (interval_ < 10)
148 ::timeEndPeriod(interval_);
149 }
151 void SampleContext(Sampler* sampler, ThreadProfile* thread_profile) {
152 uintptr_t thread = Sampler::GetThreadHandle(
153 thread_profile->GetPlatformData());
154 HANDLE profiled_thread = reinterpret_cast<HANDLE>(thread);
155 if (profiled_thread == NULL)
156 return;
158 // Context used for sampling the register state of the profiled thread.
159 CONTEXT context;
160 memset(&context, 0, sizeof(context));
162 TickSample sample_obj;
163 TickSample* sample = &sample_obj;
165 // Grab the timestamp before pausing the thread, to avoid deadlocks.
166 sample->timestamp = mozilla::TimeStamp::Now();
167 sample->threadProfile = thread_profile;
169 static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
170 if (SuspendThread(profiled_thread) == kSuspendFailed)
171 return;
173 context.ContextFlags = CONTEXT_CONTROL;
174 if (GetThreadContext(profiled_thread, &context) != 0) {
175 #if V8_HOST_ARCH_X64
176 sample->pc = reinterpret_cast<Address>(context.Rip);
177 sample->sp = reinterpret_cast<Address>(context.Rsp);
178 sample->fp = reinterpret_cast<Address>(context.Rbp);
179 #else
180 sample->pc = reinterpret_cast<Address>(context.Eip);
181 sample->sp = reinterpret_cast<Address>(context.Esp);
182 sample->fp = reinterpret_cast<Address>(context.Ebp);
183 #endif
184 sample->context = &context;
185 sampler->Tick(sample);
186 }
187 ResumeThread(profiled_thread);
188 }
190 Sampler* sampler_;
191 int interval_; // units: ms
193 // Protects the process wide state below.
194 static SamplerThread* instance_;
196 DISALLOW_COPY_AND_ASSIGN(SamplerThread);
197 };
199 SamplerThread* SamplerThread::instance_ = NULL;
202 Sampler::Sampler(double interval, bool profiling, int entrySize)
203 : interval_(interval),
204 profiling_(profiling),
205 paused_(false),
206 active_(false),
207 entrySize_(entrySize) {
208 }
210 Sampler::~Sampler() {
211 ASSERT(!IsActive());
212 }
214 void Sampler::Start() {
215 ASSERT(!IsActive());
216 SetActive(true);
217 SamplerThread::StartSampler(this);
218 }
220 void Sampler::Stop() {
221 ASSERT(IsActive());
222 SetActive(false);
223 SamplerThread::StopSampler();
224 }
227 static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
229 static unsigned int __stdcall ThreadEntry(void* arg) {
230 Thread* thread = reinterpret_cast<Thread*>(arg);
231 thread->Run();
232 return 0;
233 }
235 // Initialize a Win32 thread object. The thread has an invalid thread
236 // handle until it is started.
237 Thread::Thread(const char* name)
238 : stack_size_(0) {
239 thread_ = kNoThread;
240 set_name(name);
241 }
243 void Thread::set_name(const char* name) {
244 strncpy(name_, name, sizeof(name_));
245 name_[sizeof(name_) - 1] = '\0';
246 }
248 // Close our own handle for the thread.
249 Thread::~Thread() {
250 if (thread_ != kNoThread) CloseHandle(thread_);
251 }
253 // Create a new thread. It is important to use _beginthreadex() instead of
254 // the Win32 function CreateThread(), because the CreateThread() does not
255 // initialize thread specific structures in the C runtime library.
256 void Thread::Start() {
257 thread_ = reinterpret_cast<HANDLE>(
258 _beginthreadex(NULL,
259 static_cast<unsigned>(stack_size_),
260 ThreadEntry,
261 this,
262 0,
263 (unsigned int*) &thread_id_));
264 }
266 // Wait for thread to terminate.
267 void Thread::Join() {
268 if (thread_id_ != GetCurrentId()) {
269 WaitForSingleObject(thread_, INFINITE);
270 }
271 }
273 /* static */ Thread::tid_t
274 Thread::GetCurrentId()
275 {
276 return GetCurrentThreadId();
277 }
279 void OS::Startup() {
280 }
282 void OS::Sleep(int milliseconds) {
283 ::Sleep(milliseconds);
284 }
286 bool Sampler::RegisterCurrentThread(const char* aName,
287 PseudoStack* aPseudoStack,
288 bool aIsMainThread, void* stackTop)
289 {
290 if (!Sampler::sRegisteredThreadsMutex)
291 return false;
294 mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
296 int id = GetCurrentThreadId();
298 for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
299 ThreadInfo* info = sRegisteredThreads->at(i);
300 if (info->ThreadId() == id) {
301 // Thread already registered. This means the first unregister will be
302 // too early.
303 ASSERT(false);
304 return false;
305 }
306 }
308 set_tls_stack_top(stackTop);
310 ThreadInfo* info = new ThreadInfo(aName, id,
311 aIsMainThread, aPseudoStack, stackTop);
313 if (sActiveSampler) {
314 sActiveSampler->RegisterThread(info);
315 }
317 sRegisteredThreads->push_back(info);
319 uwt__register_thread_for_profiling(stackTop);
320 return true;
321 }
323 void Sampler::UnregisterCurrentThread()
324 {
325 if (!Sampler::sRegisteredThreadsMutex)
326 return;
328 tlsStackTop.set(nullptr);
330 mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
332 int id = GetCurrentThreadId();
334 for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
335 ThreadInfo* info = sRegisteredThreads->at(i);
336 if (info->ThreadId() == id) {
337 delete info;
338 sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
339 break;
340 }
341 }
342 }
344 void TickSample::PopulateContext(void* aContext)
345 {
346 MOZ_ASSERT(aContext);
347 CONTEXT* pContext = reinterpret_cast<CONTEXT*>(aContext);
348 context = pContext;
349 RtlCaptureContext(pContext);
351 #if defined(SPS_PLAT_amd64_windows)
353 pc = reinterpret_cast<Address>(pContext->Rip);
354 sp = reinterpret_cast<Address>(pContext->Rsp);
355 fp = reinterpret_cast<Address>(pContext->Rbp);
357 #elif defined(SPS_PLAT_x86_windows)
359 pc = reinterpret_cast<Address>(pContext->Eip);
360 sp = reinterpret_cast<Address>(pContext->Esp);
361 fp = reinterpret_cast<Address>(pContext->Ebp);
363 #endif
364 }