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

Side by Side Diff: base/profiler/cpu_profiler_win.cc

Issue 888923004: Temporary commit to evaluate perf impact of prototype CPU profiler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: address comments Created 5 years, 10 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/profiler/cpu_profiler.h"
6
7 #include <Tlhelp32.h>
8 #include <dbghelp.h>
9 #include <stddef.h>
10 #include <windows.h>
11
12 #include "base/debug/stack_trace.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread_id_name_manager.h"
15 #include "base/time/time.h"
16
17 namespace base {
18
19 namespace {
20
21 const DWORD kSuspendFailed = static_cast<DWORD>(-1);
22
23 int StackTrace64(CONTEXT* context, int stack_depth,
24 StackTraceEntry* stack_trace) {
25 #ifdef _WIN64
26 IMAGEHLP_SYMBOL64 sym;
27 sym.SizeOfStruct = sizeof(sym);
28 sym.MaxNameLength = 0;
29
30 for (int i = 0; i < stack_depth; ++i, ++stack_trace) {
31 // Try to look up unwind metadata for the current function.
32 ULONG64 image_base;
33 PRUNTIME_FUNCTION runtime_function =
34 RtlLookupFunctionEntry(context->Rip, &image_base, nullptr);
35
36 stack_trace->rsp = context->Rsp;
37 stack_trace->rip = context->Rip;
38 stack_trace->module = nullptr;
39
40 if (runtime_function) {
41 HMODULE module = NULL;
42 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
cpu_(ooo_6.6-7.5) 2015/02/05 01:03:26 I think or-ing both should work GET_MODULE_HANDLE_
Mike Wittman 2015/02/05 02:08:48 It seems that specifying GET_MODULE_HANDLE_EX_UNCH
43 reinterpret_cast<LPCTSTR>(context->Rip), &module)) {
44 stack_trace->module = module;
45 FreeLibrary(module);
46 }
47
48 KNONVOLATILE_CONTEXT_POINTERS nvcontext = {0};
49 PVOID handler_data;
cpu_(ooo_6.6-7.5) 2015/02/05 01:03:27 pvoid --> void*
Mike Wittman 2015/02/05 02:08:48 Done.
50 ULONG64 establisher_frame;
51 RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
52 &handler_data, &establisher_frame, &nvcontext);
53 } else {
54 // If we don't have a RUNTIME_FUNCTION, then we've encountered
55 // a leaf function. Adjust the stack appropriately.
56 context->Rip = *reinterpret_cast<PDWORD64>(context->Rsp);
57 context->Rsp += 8;
58 }
59
60 if (!context->Rip)
61 return i;
62 }
63 return stack_depth;
64 #else
65 return 0;
66 #endif
67 }
68
69 int SampleThread(HANDLE thread_handle, int max_stack_size,
70 StackTraceEntry* stack) {
71 if (!thread_handle)
cpu_(ooo_6.6-7.5) 2015/02/05 01:03:26 can we not fire the timer when you don't have a th
Mike Wittman 2015/02/05 02:08:47 We should always have a thread handle on x64 since
72 return 0;
73
74 if (::SuspendThread(thread_handle) == kSuspendFailed) {
75 LOG(ERROR) << "SuspendThread failed: " << GetLastError();
76 return 0;
77 }
78
79 CONTEXT thread_context = {0};
80 thread_context.ContextFlags = CONTEXT_ALL;
81 if (!::GetThreadContext(thread_handle, &thread_context)) {
82 LOG(ERROR) << "GetThreadContext failed: " << GetLastError();
83 }
84
85 int stack_depth = StackTrace64(&thread_context, max_stack_size, stack);
86
87 if (::ResumeThread(thread_handle) == kSuspendFailed) {
88 LOG(ERROR) << "ResumeThread failed: " << GetLastError();
89 }
90 return stack_depth;
91 }
92
93 void GetNames(StackTraceEntry* stack_trace, int stack_depth) {
94 HANDLE process = GetCurrentProcess();
95 DWORD64 displacement = 0;
96 DWORD line_displacement = 0;
97 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(wchar_t)];
98 PSYMBOL_INFO symbol_info = reinterpret_cast<PSYMBOL_INFO>(buffer);
cpu_(ooo_6.6-7.5) 2015/02/05 01:03:27 psymbol_info -->symbol_info*
Mike Wittman 2015/02/05 02:08:48 Done.
99 symbol_info->SizeOfStruct = sizeof(SYMBOL_INFO);
100 symbol_info->MaxNameLen = MAX_SYM_NAME;
101 std::string file_name;
102
103 IMAGEHLP_LINE64 line;
104 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
105
106 for (int i = 0; i < stack_depth; ++i, ++stack_trace) {
107 DWORD64 address = stack_trace->rip;
108 if (!SymFromAddr(process, address, &displacement, symbol_info)) {
109 wcscpy(reinterpret_cast<wchar_t*>(symbol_info->Name), L"failed");
cpu_(ooo_6.6-7.5) 2015/02/05 01:03:26 use the safe versions wcscpy_s
Mike Wittman 2015/02/05 02:08:48 Done.
110 }
111 if (!SymGetLineFromAddr64(process, address, &line_displacement, &line)) {
112 line.LineNumber = 0;
113 file_name.clear();
114 } else {
115 file_name.assign(line.FileName);
116 }
117 }
118 }
119
120 }
121
122 CpuProfiler::CpuProfiler()
123 : main_thread_(0),
124 main_thread_stack_depth_(0) {
125 #ifdef _WIN64
126 // Record the main thread's handle.
127 BOOL result = ::DuplicateHandle(::GetCurrentProcess(), ::GetCurrentThread(),
128 ::GetCurrentProcess(), &main_thread_, 0,
129 FALSE, DUPLICATE_SAME_ACCESS);
130 DCHECK(result) << "DuplicateHandle failed";
131
132 // Initialization
133 if (RtlVirtualUnwind == NULL && RtlLookupFunctionEntry == NULL) {
134 const HMODULE nt_dll_handle = ::GetModuleHandle(L"ntdll.dll");
135 reinterpret_cast<void*&>(RtlVirtualUnwind) =
136 ::GetProcAddress(nt_dll_handle, "RtlVirtualUnwind");
137 reinterpret_cast<void*&>(RtlLookupFunctionEntry) =
138 ::GetProcAddress(nt_dll_handle, "RtlLookupFunctionEntry");
139 }
140 #endif
141 }
142
143 CpuProfiler::~CpuProfiler() {
144 CloseHandle(main_thread_);
145 }
146
147 // static
148 bool CpuProfiler::IsPlatformSupported() {
149 #ifdef _WIN64
150 return true;
151 #else
152 return false;
153 #endif
154 }
155
156 void CpuProfiler::OnTimer() {
157 main_thread_stack_depth_ = SampleThread(
158 main_thread_, arraysize(main_thread_stack_), main_thread_stack_);
159 ProcessStack(main_thread_stack_, main_thread_stack_depth_);
160
161 modules_.clear();
162 main_thread_stack_depth_ = 0;
163 }
164
165 void CpuProfiler::ProcessStack(StackTraceEntry* stack, int stack_depth) {
166 for (int i = 0; i < stack_depth; ++i, ++stack) {
167 HMODULE module = stack->module;
168 if (!module || (modules_.find(module) != modules_.end()))
169 continue;
170
171 wchar_t module_name[MAX_PATH];
172 if (GetModuleFileName(module, module_name, arraysize(module_name))) {
173 modules_.insert(std::pair<HMODULE, base::string16>(module, module_name));
174 }
175 }
176 }
177
178 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698