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

Side by Side Diff: content/gpu/gpu_watchdog_thread.cc

Issue 1980263002: GPU Watchdog to check I/O before terminating GPU process (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed feedback Created 4 years, 7 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 | « content/gpu/gpu_watchdog_thread.h ('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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/gpu/gpu_watchdog_thread.h" 5 #include "content/gpu/gpu_watchdog_thread.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
14 #include "base/debug/alias.h" 14 #include "base/debug/alias.h"
15 #include "base/files/file_path.h"
15 #include "base/files/file_util.h" 16 #include "base/files/file_util.h"
16 #include "base/location.h" 17 #include "base/location.h"
17 #include "base/macros.h" 18 #include "base/macros.h"
18 #include "base/power_monitor/power_monitor.h" 19 #include "base/power_monitor/power_monitor.h"
19 #include "base/process/process.h" 20 #include "base/process/process.h"
20 #include "base/single_thread_task_runner.h" 21 #include "base/single_thread_task_runner.h"
21 #include "base/threading/platform_thread.h" 22 #include "base/threading/platform_thread.h"
23 #include "base/timer/elapsed_timer.h"
22 #include "build/build_config.h" 24 #include "build/build_config.h"
23 #include "content/public/common/content_switches.h" 25 #include "content/public/common/content_switches.h"
24 #include "content/public/common/result_codes.h" 26 #include "content/public/common/result_codes.h"
25 27
26 #if defined(OS_WIN) 28 #if defined(OS_WIN)
27 #include <windows.h> 29 #include <windows.h>
28 #endif 30 #endif
29 31
30 namespace content { 32 namespace content {
31 namespace { 33 namespace {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 DCHECK(result); 75 DCHECK(result);
74 #endif 76 #endif
75 77
76 #if defined(OS_CHROMEOS) 78 #if defined(OS_CHROMEOS)
77 tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r"); 79 tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r");
78 #endif 80 #endif
79 #if defined(USE_X11) 81 #if defined(USE_X11)
80 SetupXServer(); 82 SetupXServer();
81 #endif 83 #endif
82 watched_message_loop_->AddTaskObserver(&task_observer_); 84 watched_message_loop_->AddTaskObserver(&task_observer_);
85
86 // Create a temp file for checking whether I/O is a bottleneck.
87 // This code runs on the main GPU thread before the sandbox is lowered.
88 base::FilePath temp_dir_path;
89 if (GetTempDir(&temp_dir_path)) {
90 base::FilePath temp_file_path =
91 temp_dir_path.Append(FILE_PATH_LITERAL("gpu-watchdog.tmp"));
Will Harris 2016/05/19 10:25:01 use a constant for "gpu-watchdog.tmp" as it's used
stanisc 2016/06/09 00:33:46 Done.
92 // Please note that multiple instances of GPU process may reuse the same
93 // temporary file. That's OK because the file is written to only when
94 // the watchdog gets triggered and about to crash the process. The file
95 // should be deleted when the last handle is closed.
96 temp_file_for_io_checking_.Initialize(
97 temp_file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE |
98 base::File::FLAG_DELETE_ON_CLOSE |
99 base::File::FLAG_SHARE_DELETE);
Will Harris 2016/05/19 10:25:01 two chrome's running on the same machine as same u
stanisc 2016/05/19 18:47:26 It does work with two clients. I've tested that. T
100 if (!temp_file_for_io_checking_.IsValid()) {
101 LOG(ERROR) << "Couldn't create " << temp_file_path.value().c_str()
102 << ", error: " << temp_file_for_io_checking_.error_details();
103 }
104 }
83 } 105 }
84 106
85 void GpuWatchdogThread::PostAcknowledge() { 107 void GpuWatchdogThread::PostAcknowledge() {
86 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use 108 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use
87 // the method factory. Rely on reference counting instead. 109 // the method factory. Rely on reference counting instead.
88 task_runner()->PostTask(FROM_HERE, 110 task_runner()->PostTask(FROM_HERE,
89 base::Bind(&GpuWatchdogThread::OnAcknowledge, this)); 111 base::Bind(&GpuWatchdogThread::OnAcknowledge, this));
90 } 112 }
91 113
92 void GpuWatchdogThread::CheckArmed() { 114 void GpuWatchdogThread::CheckArmed() {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 245
224 // Post a task to the monitored thread that does nothing but wake up the 246 // Post a task to the monitored thread that does nothing but wake up the
225 // TaskObserver. Any other tasks that are pending on the watched thread will 247 // TaskObserver. Any other tasks that are pending on the watched thread will
226 // also wake up the observer. This simply ensures there is at least one. 248 // also wake up the observer. This simply ensures there is at least one.
227 watched_message_loop_->task_runner()->PostTask(FROM_HERE, 249 watched_message_loop_->task_runner()->PostTask(FROM_HERE,
228 base::Bind(&base::DoNothing)); 250 base::Bind(&base::DoNothing));
229 251
230 // Post a task to the watchdog thread to exit if the monitored thread does 252 // Post a task to the watchdog thread to exit if the monitored thread does
231 // not respond in time. 253 // not respond in time.
232 task_runner()->PostDelayedTask( 254 task_runner()->PostDelayedTask(
233 FROM_HERE, 255 FROM_HERE, base::Bind(&GpuWatchdogThread::BeginTerminating,
234 base::Bind(&GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang, 256 weak_factory_.GetWeakPtr()),
235 weak_factory_.GetWeakPtr()),
236 timeout); 257 timeout);
237 } 258 }
238 259
239 // Use the --disable-gpu-watchdog command line switch to disable this. 260 void GpuWatchdogThread::BeginTerminating() {
240 void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
241 // Should not get here while the system is suspended. 261 // Should not get here while the system is suspended.
242 DCHECK(!suspended_); 262 DCHECK(!suspended_);
243 263
244 #if defined(OS_WIN) 264 #if defined(OS_WIN)
245 // Defer termination until a certain amount of CPU time has elapsed on the 265 // Defer termination until a certain amount of CPU time has elapsed on the
246 // watched thread. 266 // watched thread.
247 base::ThreadTicks current_cpu_time = GetWatchedThreadTime(); 267 base::ThreadTicks current_cpu_time = GetWatchedThreadTime();
248 base::TimeDelta time_since_arm = current_cpu_time - arm_cpu_time_; 268 base::TimeDelta time_since_arm = current_cpu_time - arm_cpu_time_;
249 if (use_thread_cpu_time_ && (time_since_arm < timeout_)) { 269 if (use_thread_cpu_time_ && (time_since_arm < timeout_)) {
250 message_loop()->PostDelayedTask( 270 message_loop()->PostDelayedTask(
251 FROM_HERE, 271 FROM_HERE, base::Bind(&GpuWatchdogThread::BeginTerminating,
252 base::Bind( 272 weak_factory_.GetWeakPtr()),
253 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
254 weak_factory_.GetWeakPtr()),
255 timeout_ - time_since_arm); 273 timeout_ - time_since_arm);
256 return; 274 return;
257 } 275 }
258 #endif 276 #endif
259 277
278 // If the machine is busy with heavy I/O activity this should defer
279 // termination until the I/O queue clears (on the drive that contains
280 // the temp directory).
281 if (temp_file_for_io_checking_.IsValid()) {
282 // Write a few bytes and wait for the write to flush.
283 const char temp_data[32] = {0};
284 base::ElapsedTimer timer;
285 temp_file_for_io_checking_.Write(0, temp_data, sizeof(temp_data));
286 temp_file_for_io_checking_.Flush();
287 io_check_duration_ = timer.Elapsed();
288 }
289
290 // Post a new task to actually terminate unless an acknowledge from the
291 // watched thread arrives in between.
292 message_loop()->PostTask(
293 FROM_HERE,
294 base::Bind(&GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
295 weak_factory_.GetWeakPtr()));
296 }
297
298 // Use the --disable-gpu-watchdog command line switch to disable this.
299 void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
300 // Should not get here while the system is suspended.
301 DCHECK(!suspended_);
302
260 // If the watchdog woke up significantly behind schedule, disarm and reset 303 // If the watchdog woke up significantly behind schedule, disarm and reset
261 // the watchdog check. This is to prevent the watchdog thread from terminating 304 // the watchdog check. This is to prevent the watchdog thread from terminating
262 // when a machine wakes up from sleep or hibernation, which would otherwise 305 // when a machine wakes up from sleep or hibernation, which would otherwise
263 // appear to be a hang. 306 // appear to be a hang.
264 if (base::Time::Now() > suspension_timeout_) { 307 if (base::Time::Now() > suspension_timeout_) {
265 armed_ = false; 308 armed_ = false;
266 OnCheck(true); 309 OnCheck(true);
267 return; 310 return;
268 } 311 }
269 312
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 384
342 // Store variables so they're available in crash dumps to help determine the 385 // Store variables so they're available in crash dumps to help determine the
343 // cause of any hang. 386 // cause of any hang.
344 #if defined(OS_WIN) 387 #if defined(OS_WIN)
345 ULONGLONG fire_interrupt_time; 388 ULONGLONG fire_interrupt_time;
346 QueryUnbiasedInterruptTime(&fire_interrupt_time); 389 QueryUnbiasedInterruptTime(&fire_interrupt_time);
347 390
348 // This is the time since the watchdog was armed, in 100ns intervals, 391 // This is the time since the watchdog was armed, in 100ns intervals,
349 // ignoring time where the computer is suspended. 392 // ignoring time where the computer is suspended.
350 ULONGLONG interrupt_delay = fire_interrupt_time - arm_interrupt_time_; 393 ULONGLONG interrupt_delay = fire_interrupt_time - arm_interrupt_time_;
394 base::debug::Alias(&interrupt_delay);
351 395
352 base::debug::Alias(&interrupt_delay); 396 base::ThreadTicks current_cpu_time = GetWatchedThreadTime();
353 base::debug::Alias(&current_cpu_time); 397 base::debug::Alias(&current_cpu_time);
398
399 base::TimeDelta time_since_arm = current_cpu_time - arm_cpu_time_;
354 base::debug::Alias(&time_since_arm); 400 base::debug::Alias(&time_since_arm);
355 401
356 bool using_thread_ticks = base::ThreadTicks::IsSupported(); 402 bool using_thread_ticks = base::ThreadTicks::IsSupported();
357 base::debug::Alias(&using_thread_ticks); 403 base::debug::Alias(&using_thread_ticks);
358 404
359 bool using_high_res_timer = base::Time::IsHighResolutionTimerInUse(); 405 bool using_high_res_timer = base::Time::IsHighResolutionTimerInUse();
360 base::debug::Alias(&using_high_res_timer); 406 base::debug::Alias(&using_high_res_timer);
361 #endif 407 #endif
362 408
363 base::Time current_time = base::Time::Now(); 409 base::Time current_time = base::Time::Now();
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 // calls into kernel level repeatedly, giving up its quanta before it is 503 // calls into kernel level repeatedly, giving up its quanta before it is
458 // tracked, for example a loop that repeatedly Sleeps. 504 // tracked, for example a loop that repeatedly Sleeps.
459 return base::ThreadTicks() + 505 return base::ThreadTicks() +
460 base::TimeDelta::FromMilliseconds(static_cast<int64_t>( 506 base::TimeDelta::FromMilliseconds(static_cast<int64_t>(
461 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); 507 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000));
462 } 508 }
463 } 509 }
464 #endif 510 #endif
465 511
466 } // namespace content 512 } // namespace content
OLDNEW
« no previous file with comments | « content/gpu/gpu_watchdog_thread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698