Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(527)

Side by Side Diff: profiler/native_stack_sampler_win.cc

Issue 2043183002: Update to Chromium //base at Chromium commit 01cb97b2e09618bbc3a60c7348f0a844eea20547. (Closed) Base URL: https://github.com/domokit/base.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « process/process_util_unittest.cc ('k') | profiler/win32_stack_frame_unwinder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <objbase.h> 5 #include <objbase.h>
6 #include <windows.h> 6 #include <windows.h>
7 7
8 #include <map> 8 #include <map>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/profiler/native_stack_sampler.h" 12 #include "base/profiler/native_stack_sampler.h"
13 #include "base/profiler/win32_stack_frame_unwinder.h"
13 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h" 17 #include "base/time/time.h"
17 #include "base/win/pe_image.h" 18 #include "base/win/pe_image.h"
18 #include "base/win/scoped_handle.h" 19 #include "base/win/scoped_handle.h"
19 20
20 namespace base { 21 namespace base {
21 22
23 // Stack recording functions --------------------------------------------------
24
22 namespace { 25 namespace {
23 26
24 // Walks the stack represented by |context| from the current frame downwards, 27 // Walks the stack represented by |context| from the current frame downwards,
25 // recording the instruction pointers for each frame in |instruction_pointers|. 28 // recording the instruction pointers for each frame in |instruction_pointers|.
26 int RecordStack(CONTEXT* context, 29 int RecordStack(CONTEXT* context,
27 int max_stack_size, 30 int max_stack_size,
28 const void* instruction_pointers[], 31 const void* instruction_pointers[],
29 bool* last_frame_is_unknown_function) { 32 Win32StackFrameUnwinder* frame_unwinder) {
30 #ifdef _WIN64 33 #ifdef _WIN64
31 *last_frame_is_unknown_function = false;
32
33 int i = 0; 34 int i = 0;
34 for (; (i < max_stack_size) && context->Rip; ++i) { 35 for (; (i < max_stack_size) && context->Rip; ++i) {
35 // Try to look up unwind metadata for the current function.
36 ULONG64 image_base;
37 PRUNTIME_FUNCTION runtime_function =
38 RtlLookupFunctionEntry(context->Rip, &image_base, nullptr);
39
40 instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip); 36 instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
41 37 if (!frame_unwinder->TryUnwind(context))
42 if (runtime_function) { 38 return i + 1;
43 KNONVOLATILE_CONTEXT_POINTERS nvcontext = {};
44 void* handler_data;
45 ULONG64 establisher_frame;
46 RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
47 &handler_data, &establisher_frame, &nvcontext);
48 } else {
49 // If we don't have a RUNTIME_FUNCTION, then in theory this should be a
50 // leaf function whose frame contains only a return address, at
51 // RSP. However, crash data also indicates that some third party libraries
52 // do not provide RUNTIME_FUNCTION information for non-leaf functions. We
53 // could manually unwind the stack in the former case, but attempting to
54 // do so in the latter case would produce wrong results and likely crash,
55 // so just bail out.
56 //
57 // Ad hoc runs with instrumentation show that ~5% of stack traces end with
58 // a valid leaf function. To avoid selectively omitting these traces it
59 // makes sense to ultimately try to distinguish these two cases and
60 // selectively unwind the stack for legitimate leaf functions. For the
61 // purposes of avoiding crashes though, just ignore them all for now.
62 return i;
63 }
64 } 39 }
65 return i; 40 return i;
66 #else 41 #else
67 return 0; 42 return 0;
68 #endif 43 #endif
69 } 44 }
70 45
71 // Fills in |module_handles| corresponding to the pointers to code in 46 // Fills in |module_handles| corresponding to the pointers to code in
72 // |addresses|. The module handles are returned with reference counts 47 // |addresses|. The module handles are returned with reference counts
73 // incremented and should be freed with FreeModuleHandles. See note in 48 // incremented and should be freed with FreeModuleHandles. See note in
74 // SuspendThreadAndRecordStack for why |addresses| and |module_handles| are 49 // SuspendThreadAndRecordStack for why |addresses| and |module_handles| are
75 // arrays. 50 // arrays.
76 void FindModuleHandlesForAddresses(const void* const addresses[], 51 void FindModuleHandlesForAddresses(const void* const addresses[],
77 HMODULE module_handles[], 52 HMODULE module_handles[],
78 int stack_depth, 53 int stack_depth) {
79 bool last_frame_is_unknown_function) { 54 for (int i = 0; i < stack_depth; ++i) {
80 const int module_frames =
81 last_frame_is_unknown_function ? stack_depth - 1 : stack_depth;
82 for (int i = 0; i < module_frames; ++i) {
83 HMODULE module_handle = NULL; 55 HMODULE module_handle = NULL;
84 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, 56 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
85 reinterpret_cast<LPCTSTR>(addresses[i]), 57 reinterpret_cast<LPCTSTR>(addresses[i]),
86 &module_handle)) { 58 &module_handle)) {
87 // HMODULE actually represents the base address of the module, so we can 59 // HMODULE actually represents the base address of the module, so we can
88 // use it directly as an address. 60 // use it directly as an address.
89 DCHECK_LE(reinterpret_cast<const void*>(module_handle), addresses[i]); 61 DCHECK_LE(reinterpret_cast<const void*>(module_handle), addresses[i]);
90 module_handles[i] = module_handle; 62 module_handles[i] = module_handle;
91 } 63 }
92 } 64 }
(...skipping 29 matching lines...) Expand all
122 std::wstring build_id; 94 std::wstring build_id;
123 int result = 95 int result =
124 ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize); 96 ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize);
125 if (result != kGUIDSize) 97 if (result != kGUIDSize)
126 return std::string(); 98 return std::string();
127 RemoveChars(build_id, L"{}-", &build_id); 99 RemoveChars(build_id, L"{}-", &build_id);
128 build_id += StringPrintf(L"%d", age); 100 build_id += StringPrintf(L"%d", age);
129 return WideToUTF8(build_id); 101 return WideToUTF8(build_id);
130 } 102 }
131 103
104 // ScopedDisablePriorityBoost -------------------------------------------------
105
132 // Disables priority boost on a thread for the lifetime of the object. 106 // Disables priority boost on a thread for the lifetime of the object.
133 class ScopedDisablePriorityBoost { 107 class ScopedDisablePriorityBoost {
134 public: 108 public:
135 ScopedDisablePriorityBoost(HANDLE thread_handle); 109 ScopedDisablePriorityBoost(HANDLE thread_handle);
136 ~ScopedDisablePriorityBoost(); 110 ~ScopedDisablePriorityBoost();
137 111
138 private: 112 private:
139 HANDLE thread_handle_; 113 HANDLE thread_handle_;
140 BOOL got_previous_boost_state_; 114 BOOL got_previous_boost_state_;
141 BOOL boost_state_was_disabled_; 115 BOOL boost_state_was_disabled_;
(...skipping 22 matching lines...) Expand all
164 // |instruction_pointers|, then resumes the thread. Returns the size of the 138 // |instruction_pointers|, then resumes the thread. Returns the size of the
165 // stack. 139 // stack.
166 // 140 //
167 // IMPORTANT NOTE: No heap allocations may occur between SuspendThread and 141 // IMPORTANT NOTE: No heap allocations may occur between SuspendThread and
168 // ResumeThread. Otherwise this code can deadlock on heap locks acquired by the 142 // ResumeThread. Otherwise this code can deadlock on heap locks acquired by the
169 // target thread before it was suspended. This is why we pass instruction 143 // target thread before it was suspended. This is why we pass instruction
170 // pointers and module handles as preallocated arrays rather than vectors, since 144 // pointers and module handles as preallocated arrays rather than vectors, since
171 // vectors make it too easy to subtly allocate memory. 145 // vectors make it too easy to subtly allocate memory.
172 int SuspendThreadAndRecordStack(HANDLE thread_handle, 146 int SuspendThreadAndRecordStack(HANDLE thread_handle,
173 int max_stack_size, 147 int max_stack_size,
174 const void* instruction_pointers[], 148 const void* instruction_pointers[]) {
175 bool* last_frame_is_unknown_function) { 149 Win32StackFrameUnwinder frame_unwinder;
150
176 if (::SuspendThread(thread_handle) == -1) 151 if (::SuspendThread(thread_handle) == -1)
177 return 0; 152 return 0;
178 153
179 int stack_depth = 0; 154 int stack_depth = 0;
180 CONTEXT thread_context = {0}; 155 CONTEXT thread_context = {0};
181 thread_context.ContextFlags = CONTEXT_FULL; 156 thread_context.ContextFlags = CONTEXT_FULL;
182 if (::GetThreadContext(thread_handle, &thread_context)) { 157 if (::GetThreadContext(thread_handle, &thread_context)) {
183 stack_depth = 158 stack_depth = RecordStack(&thread_context, max_stack_size,
184 RecordStack(&thread_context, max_stack_size, instruction_pointers, 159 instruction_pointers, &frame_unwinder);
185 last_frame_is_unknown_function);
186 } 160 }
187 161
188 // Disable the priority boost that the thread would otherwise receive on 162 // Disable the priority boost that the thread would otherwise receive on
189 // resume. We do this to avoid artificially altering the dynamics of the 163 // resume. We do this to avoid artificially altering the dynamics of the
190 // executing application any more than we already are by suspending and 164 // executing application any more than we already are by suspending and
191 // resuming the thread. 165 // resuming the thread.
192 // 166 //
193 // Note that this can racily disable a priority boost that otherwise would 167 // Note that this can racily disable a priority boost that otherwise would
194 // have been given to the thread, if the thread is waiting on other wait 168 // have been given to the thread, if the thread is waiting on other wait
195 // conditions at the time of SuspendThread and those conditions are satisfied 169 // conditions at the time of SuspendThread and those conditions are satisfied
196 // before priority boost is reenabled. The measured length of this window is 170 // before priority boost is reenabled. The measured length of this window is
197 // ~100us, so this should occur fairly rarely. 171 // ~100us, so this should occur fairly rarely.
198 ScopedDisablePriorityBoost disable_priority_boost(thread_handle); 172 ScopedDisablePriorityBoost disable_priority_boost(thread_handle);
199 bool resume_thread_succeeded = ::ResumeThread(thread_handle) != -1; 173 bool resume_thread_succeeded = ::ResumeThread(thread_handle) != -1;
200 CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError(); 174 CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
201 175
202 return stack_depth; 176 return stack_depth;
203 } 177 }
204 178
179 // NativeStackSamplerWin ------------------------------------------------------
180
205 class NativeStackSamplerWin : public NativeStackSampler { 181 class NativeStackSamplerWin : public NativeStackSampler {
206 public: 182 public:
207 explicit NativeStackSamplerWin(win::ScopedHandle thread_handle); 183 explicit NativeStackSamplerWin(win::ScopedHandle thread_handle);
208 ~NativeStackSamplerWin() override; 184 ~NativeStackSamplerWin() override;
209 185
210 // StackSamplingProfiler::NativeStackSampler: 186 // StackSamplingProfiler::NativeStackSampler:
211 void ProfileRecordingStarting( 187 void ProfileRecordingStarting(
212 std::vector<StackSamplingProfiler::Module>* modules) override; 188 std::vector<StackSamplingProfiler::Module>* modules) override;
213 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; 189 void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
214 void ProfileRecordingStopped() override; 190 void ProfileRecordingStopped() override;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 } 233 }
258 234
259 void NativeStackSamplerWin::RecordStackSample( 235 void NativeStackSamplerWin::RecordStackSample(
260 StackSamplingProfiler::Sample* sample) { 236 StackSamplingProfiler::Sample* sample) {
261 DCHECK(current_modules_); 237 DCHECK(current_modules_);
262 238
263 const int max_stack_size = 64; 239 const int max_stack_size = 64;
264 const void* instruction_pointers[max_stack_size] = {0}; 240 const void* instruction_pointers[max_stack_size] = {0};
265 HMODULE module_handles[max_stack_size] = {0}; 241 HMODULE module_handles[max_stack_size] = {0};
266 242
267 bool last_frame_is_unknown_function = false;
268 int stack_depth = SuspendThreadAndRecordStack( 243 int stack_depth = SuspendThreadAndRecordStack(
269 thread_handle_.Get(), max_stack_size, instruction_pointers, 244 thread_handle_.Get(), max_stack_size, instruction_pointers);
270 &last_frame_is_unknown_function);
271 FindModuleHandlesForAddresses(instruction_pointers, module_handles, 245 FindModuleHandlesForAddresses(instruction_pointers, module_handles,
272 stack_depth, last_frame_is_unknown_function); 246 stack_depth);
273 CopyToSample(instruction_pointers, module_handles, stack_depth, sample, 247 CopyToSample(instruction_pointers, module_handles, stack_depth, sample,
274 current_modules_); 248 current_modules_);
275 FreeModuleHandles(stack_depth, module_handles); 249 FreeModuleHandles(stack_depth, module_handles);
276 } 250 }
277 251
278 void NativeStackSamplerWin::ProfileRecordingStopped() { 252 void NativeStackSamplerWin::ProfileRecordingStopped() {
279 current_modules_ = nullptr; 253 current_modules_ = nullptr;
280 } 254 }
281 255
282 // static 256 // static
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 321
348 if (thread_handle) { 322 if (thread_handle) {
349 return scoped_ptr<NativeStackSampler>( 323 return scoped_ptr<NativeStackSampler>(
350 new NativeStackSamplerWin(win::ScopedHandle(thread_handle))); 324 new NativeStackSamplerWin(win::ScopedHandle(thread_handle)));
351 } 325 }
352 #endif 326 #endif
353 return scoped_ptr<NativeStackSampler>(); 327 return scoped_ptr<NativeStackSampler>();
354 } 328 }
355 329
356 } // namespace base 330 } // namespace base
OLDNEW
« no previous file with comments | « process/process_util_unittest.cc ('k') | profiler/win32_stack_frame_unwinder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698