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

Side by Side Diff: runtime/vm/thread_interrupter_fuchsia.cc

Issue 2916313003: [Fuchsia] Enable CPU profiling for the standalone VM (Closed)
Patch Set: Created 3 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 | « runtime/vm/os_thread_fuchsia.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(HOST_OS_FUCHSIA) 6 #if defined(HOST_OS_FUCHSIA)
7 7
8 #include "vm/thread_interrupter.h" 8 #include "vm/thread_interrupter.h"
9 9
10 #include <magenta/process.h> 10 #include <magenta/process.h>
11 #include <magenta/status.h> 11 #include <magenta/status.h>
12 #include <magenta/syscalls.h> 12 #include <magenta/syscalls.h>
13 #include <magenta/syscalls/debug.h> 13 #include <magenta/syscalls/debug.h>
14 #include <magenta/syscalls/object.h>
14 #include <magenta/types.h> 15 #include <magenta/types.h>
15 16
16 #include "vm/flags.h" 17 #include "vm/flags.h"
17 #include "vm/instructions.h" 18 #include "vm/instructions.h"
18 #include "vm/os.h" 19 #include "vm/os.h"
19 #include "vm/profiler.h" 20 #include "vm/profiler.h"
20 21
21 namespace dart { 22 namespace dart {
22 23
23 #ifndef PRODUCT 24 #ifndef PRODUCT
24 25
25 DECLARE_FLAG(bool, thread_interrupter); 26 DECLARE_FLAG(bool, thread_interrupter);
26 DECLARE_FLAG(bool, trace_thread_interrupter); 27 DECLARE_FLAG(bool, trace_thread_interrupter);
27 28
28 // TODO(MG-430): Currently, CPU profiling for Fuchsia is arranged very similarly 29 // TODO(MG-430): Currently, CPU profiling for Fuchsia is arranged very similarly
29 // to our Windows profiling. That is, the interrupter thread iterates over 30 // to our Windows profiling. That is, the interrupter thread iterates over
30 // all threads, suspends them, samples various things, and then resumes them. 31 // all threads, suspends them, samples various things, and then resumes them.
31 // When MG-430 is resolved, the code below should be rewritten to use whatever 32 // When MG-430 is resolved, the code below should be rewritten to use whatever
32 // feature is added for it. 33 // feature is added for it.
33 34
34 // TODO(MG-795): The profiler is currently off by default on Fuchsia because 35 // A scope within which a target thread is suspended. When the scope is exited,
35 // suspending a thread that is in a call to pthread_cond_wait() causes 36 // the thread is resumed and its handle is closed.
36 // pthread_cond_wait() to return ETIMEDOUT. 37 class ThreadSuspendScope {
38 public:
39 explicit ThreadSuspendScope(mx_handle_t thread_handle)
40 : thread_handle_(thread_handle), suspended_(true) {
41 mx_status_t status = mx_task_suspend(thread_handle);
42 // If a thread is somewhere where suspend is impossible, mx_task_suspend()
43 // can return ERR_NOT_SUPPORTED.
44 if ((status != NO_ERROR) && (status != ERR_NOT_SUPPORTED)) {
45 if (FLAG_trace_thread_interrupter) {
46 OS::PrintErr("ThreadInterrupter: mx_task_suspend failed: %s\n",
47 mx_status_get_string(status));
48 }
49 suspended_ = false;
50 }
51 }
52
53 ~ThreadSuspendScope() {
54 if (suspended_) {
55 mx_status_t status = mx_task_resume(thread_handle_, 0);
56 if (status != NO_ERROR) {
57 // If we fail to resume a thread, then it's likely the program will
58 // hang. Crash instead.
59 FATAL1("mx_task_resume failed: %s", mx_status_get_string(status));
60 }
61 }
62 mx_handle_close(thread_handle_);
63 }
64
65 bool suspended() const { return suspended_; }
66
67 private:
68 mx_handle_t thread_handle_;
69 bool suspended_;
70
71 DISALLOW_ALLOCATION();
72 DISALLOW_COPY_AND_ASSIGN(ThreadSuspendScope);
73 };
37 74
38 class ThreadInterrupterFuchsia : public AllStatic { 75 class ThreadInterrupterFuchsia : public AllStatic {
39 public: 76 public:
40 static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) { 77 static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) {
41 // TODO(zra): Enable this when mx_thread_read_state() works on suspended 78 char buf[MX_MAX_THREAD_STATE_SIZE];
dje 2017/06/02 17:09:06 This won't necessarily have sufficient alignment,
zra 2017/06/02 17:46:47 The docs don't mention alignment requirements for
dje 2017/06/02 18:40:07 The requirements are more related to how the conte
zra 2017/06/02 20:39:01 Done.
42 // threads. 79 uint32_t regset_size = MX_MAX_THREAD_STATE_SIZE;
43 while (false) { 80 mx_status_t status = mx_thread_read_state(
44 char buf[MX_MAX_THREAD_STATE_SIZE]; 81 thread, MX_THREAD_STATE_REGSET0, &buf[0], regset_size, &regset_size);
45 uint32_t regset_size = MX_MAX_THREAD_STATE_SIZE; 82 if (status != NO_ERROR) {
46 mx_status_t status = mx_thread_read_state( 83 if (FLAG_trace_thread_interrupter) {
47 thread, MX_THREAD_STATE_REGSET0, &buf[0], regset_size, &regset_size);
48 if (status != NO_ERROR) {
49 OS::PrintErr("ThreadInterrupter failed to get registers: %s\n", 84 OS::PrintErr("ThreadInterrupter failed to get registers: %s\n",
50 mx_status_get_string(status)); 85 mx_status_get_string(status));
51 return false;
52 } 86 }
87 return false;
88 }
53 #if defined(TARGET_ARCH_X64) 89 #if defined(TARGET_ARCH_X64)
54 mx_x86_64_general_regs_t* regs = 90 mx_x86_64_general_regs_t* regs =
55 reinterpret_cast<mx_x86_64_general_regs_t*>(&buf[0]); 91 reinterpret_cast<mx_x86_64_general_regs_t*>(&buf[0]);
56 state->pc = static_cast<uintptr_t>(regs->rip); 92 state->pc = static_cast<uintptr_t>(regs->rip);
57 state->fp = static_cast<uintptr_t>(regs->rbp); 93 state->fp = static_cast<uintptr_t>(regs->rbp);
58 state->csp = static_cast<uintptr_t>(regs->rsp); 94 state->csp = static_cast<uintptr_t>(regs->rsp);
59 state->dsp = static_cast<uintptr_t>(regs->rsp); 95 state->dsp = static_cast<uintptr_t>(regs->rsp);
60 #elif defined(TARGET_ARCH_ARM64) 96 #elif defined(TARGET_ARCH_ARM64)
61 mx_arm64_general_regs_t* regs = 97 mx_arm64_general_regs_t* regs =
62 reinterpret_cast<mx_arm64_general_regs_t*>(&buf[0]); 98 reinterpret_cast<mx_arm64_general_regs_t*>(&buf[0]);
63 state->pc = static_cast<uintptr_t>(regs->pc); 99 state->pc = static_cast<uintptr_t>(regs->pc);
64 state->fp = static_cast<uintptr_t>(regs->r[FPREG]); 100 state->fp = static_cast<uintptr_t>(regs->r[FPREG]);
65 state->csp = static_cast<uintptr_t>(regs->sp); 101 state->csp = static_cast<uintptr_t>(regs->sp);
66 state->dsp = static_cast<uintptr_t>(regs->r[SPREG]); 102 state->dsp = static_cast<uintptr_t>(regs->r[SPREG]);
67 state->lr = static_cast<uintptr_t>(regs->lr); 103 state->lr = static_cast<uintptr_t>(regs->lr);
68 #else 104 #else
69 #error "Unsupported architecture" 105 #error "Unsupported architecture"
70 #endif 106 #endif
71 }
72 return true; 107 return true;
73 } 108 }
74 109
75 110
76 static void Interrupt(OSThread* os_thread) { 111 static void Interrupt(OSThread* os_thread) {
112 ASSERT(os_thread->id() != MX_KOID_INVALID);
77 ASSERT(!OSThread::Compare(OSThread::GetCurrentThreadId(), os_thread->id())); 113 ASSERT(!OSThread::Compare(OSThread::GetCurrentThreadId(), os_thread->id()));
78 mx_status_t status; 114 mx_status_t status;
79 115
80 // Get a handle on the target thread. 116 // Get a handle on the target thread.
81 mx_koid_t target_thread_koid = os_thread->id(); 117 const mx_koid_t target_thread_koid = os_thread->id();
82 if (FLAG_trace_thread_interrupter) { 118 if (FLAG_trace_thread_interrupter) {
83 OS::Print("ThreadInterrupter: interrupting thread with koid=%d\n", 119 OS::PrintErr("ThreadInterrupter: interrupting thread with koid=%d\n",
84 target_thread_koid); 120 target_thread_koid);
85 } 121 }
86 mx_handle_t target_thread_handle; 122 mx_handle_t target_thread_handle;
87 status = mx_object_get_child(mx_process_self(), target_thread_koid, 123 status = mx_object_get_child(mx_process_self(), target_thread_koid,
88 MX_RIGHT_SAME_RIGHTS, &target_thread_handle); 124 MX_RIGHT_SAME_RIGHTS, &target_thread_handle);
89 if (status != NO_ERROR) { 125 if (status != NO_ERROR) {
90 if (FLAG_trace_thread_interrupter) { 126 if (FLAG_trace_thread_interrupter) {
91 OS::Print("ThreadInterrupter failed to get the thread handle: %s\n", 127 OS::PrintErr("ThreadInterrupter: mx_object_get_child failed: %s\n",
92 mx_status_get_string(status)); 128 mx_status_get_string(status));
93 } 129 }
94 FATAL1("mx_object_get_child failed: %s", mx_status_get_string(status)); 130 return;
95 } 131 }
96 if (target_thread_handle == MX_HANDLE_INVALID) { 132 if (target_thread_handle == MX_HANDLE_INVALID) {
97 FATAL("ThreadInterrupter got an invalid target thread handle!"); 133 if (FLAG_trace_thread_interrupter) {
134 OS::PrintErr("ThreadInterrupter: mx_object_get_child gave an invalid "
135 "thread handle!");
136 }
137 return;
98 } 138 }
99 139
100 // Pause the target thread. 140 // This scope suspends the thread. When we exit the scope, the thread is
101 status = mx_task_suspend(target_thread_handle); 141 // resumed, and the thread handle is closed.
142 ThreadSuspendScope tss(target_thread_handle);
143 if (!tss.suspended()) {
144 return;
145 }
146
147 // Check that the thread is suspended.
148 mx_info_thread_t thread_info;
149 status = mx_object_get_info(target_thread_handle,
150 MX_INFO_THREAD,
151 &thread_info,
152 sizeof(thread_info),
153 NULL,
154 NULL);
102 if (status != NO_ERROR) { 155 if (status != NO_ERROR) {
103 if (FLAG_trace_thread_interrupter) { 156 if (FLAG_trace_thread_interrupter) {
104 OS::Print("ThreadInterrupter failed to suspend thread %ld: %s\n", 157 OS::PrintErr("ThreadInterrupter: mx_object_get_info failed: %s\n",
105 static_cast<intptr_t>(os_thread->id()), 158 mx_status_get_string(status));
106 mx_status_get_string(status));
107 } 159 }
108 mx_handle_close(target_thread_handle); 160 return;
109 FATAL1("mx_task_suspend failed: %s", mx_status_get_string(status)); 161 }
162 if (thread_info.state != MX_THREAD_STATE_SUSPENDED) {
zra 2017/06/02 16:51:23 @dje: Frequently, after calling mx_task_suspend()
dje 2017/06/02 17:09:06 Yeah, you currently have to poll to wait for the t
zra 2017/06/02 17:46:47 Changed to poll.
163 if (FLAG_trace_thread_interrupter) {
164 OS::PrintErr("ThreadInterrupter: Thread is not suspended: state = %s\n",
165 ThreadStateGetString(thread_info.state));
166 }
167 return;
110 } 168 }
111 169
112 // TODO(zra): Enable this when mx_thread_read_state() works on suspended 170 // Grab the target thread's registers.
113 // threads. 171 InterruptedThreadState its;
114 while (false) { 172 if (!GrabRegisters(target_thread_handle, &its)) {
115 // Grab the target thread's registers. 173 return;
116 InterruptedThreadState its;
117 if (!GrabRegisters(target_thread_handle, &its)) {
118 // Failed to get thread registers.
119 status = mx_task_resume(target_thread_handle, 0);
120 if (status != NO_ERROR) {
121 FATAL1("mx_task_resume failed: %s", mx_status_get_string(status));
122 }
123 mx_handle_close(target_thread_handle);
124 return;
125 }
126 // Currently we sample only threads that are associated
127 // with an isolate. It is safe to call 'os_thread->thread()'
128 // here as the thread which is being queried is suspended.
129 Thread* thread = os_thread->thread();
130 if (thread != NULL) {
131 Profiler::SampleThread(thread, its);
132 }
133 } 174 }
175 // Currently we sample only threads that are associated
176 // with an isolate. It is safe to call 'os_thread->thread()'
177 // here as the thread which is being queried is suspended.
178 Thread* thread = os_thread->thread();
179 if (thread != NULL) {
180 Profiler::SampleThread(thread, its);
181 }
182 }
134 183
135 // Resume the target thread. 184 private:
136 status = mx_task_resume(target_thread_handle, 0); 185 static const char* ThreadStateGetString(uint32_t state) {
137 if (status != NO_ERROR) { 186 switch (state) {
138 FATAL1("mx_task_resume failed: %s", mx_status_get_string(status)); 187 case MX_THREAD_STATE_NEW:
188 return "MX_THREAD_STATE_NEW";
189 case MX_THREAD_STATE_RUNNING:
190 return "MX_THREAD_STATE_RUNNING";
191 case MX_THREAD_STATE_SUSPENDED:
192 return "MX_THREAD_STATE_SUSPENDED";
193 case MX_THREAD_STATE_BLOCKED:
194 return "MX_THREAD_STATE_BLOCKED";
195 case MX_THREAD_STATE_DYING:
196 return "MX_THREAD_STATE_DYING";
197 case MX_THREAD_STATE_DEAD:
198 return "MX_THREAD_STATE_DEAD";
199 default:
200 return "<Unknown>";
139 } 201 }
140 mx_handle_close(target_thread_handle);
141 } 202 }
142 }; 203 };
143 204
144 205
145 bool ThreadInterrupter::IsDebuggerAttached() { 206 bool ThreadInterrupter::IsDebuggerAttached() {
146 return false; 207 return false;
147 } 208 }
148 209
149 210
150 void ThreadInterrupter::InterruptThread(OSThread* thread) { 211 void ThreadInterrupter::InterruptThread(OSThread* thread) {
151 if (FLAG_trace_thread_interrupter) { 212 if (FLAG_trace_thread_interrupter) {
152 OS::Print("ThreadInterrupter suspending %p\n", 213 OS::PrintErr("ThreadInterrupter suspending %p\n",
153 reinterpret_cast<void*>(thread->id())); 214 reinterpret_cast<void*>(thread->id()));
154 } 215 }
155 ThreadInterrupterFuchsia::Interrupt(thread); 216 ThreadInterrupterFuchsia::Interrupt(thread);
156 if (FLAG_trace_thread_interrupter) { 217 if (FLAG_trace_thread_interrupter) {
157 OS::Print("ThreadInterrupter resuming %p\n", 218 OS::PrintErr("ThreadInterrupter resuming %p\n",
158 reinterpret_cast<void*>(thread->id())); 219 reinterpret_cast<void*>(thread->id()));
159 } 220 }
160 } 221 }
161 222
162 223
163 void ThreadInterrupter::InstallSignalHandler() { 224 void ThreadInterrupter::InstallSignalHandler() {
164 // Nothing to do on Fuchsia. 225 // Nothing to do on Fuchsia.
165 } 226 }
166 227
167 228
168 void ThreadInterrupter::RemoveSignalHandler() { 229 void ThreadInterrupter::RemoveSignalHandler() {
169 // Nothing to do on Fuchsia. 230 // Nothing to do on Fuchsia.
170 } 231 }
171 232
172 #endif // !PRODUCT 233 #endif // !PRODUCT
173 234
174 } // namespace dart 235 } // namespace dart
175 236
176 #endif // defined(HOST_OS_FUCHSIA) 237 #endif // defined(HOST_OS_FUCHSIA)
OLDNEW
« no previous file with comments | « runtime/vm/os_thread_fuchsia.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698