Chromium Code Reviews| OLD | NEW | 
|---|---|
| 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_util.h" | 15 #include "base/files/file_util.h" | 
| 16 #include "base/location.h" | 16 #include "base/location.h" | 
| 17 #include "base/macros.h" | 17 #include "base/macros.h" | 
| 18 #include "base/power_monitor/power_monitor.h" | 18 #include "base/power_monitor/power_monitor.h" | 
| 19 #include "base/process/process.h" | 19 #include "base/process/process.h" | 
| 20 #include "base/single_thread_task_runner.h" | 20 #include "base/single_thread_task_runner.h" | 
| 21 #include "base/threading/platform_thread.h" | |
| 21 #include "build/build_config.h" | 22 #include "build/build_config.h" | 
| 22 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" | 
| 23 #include "content/public/common/result_codes.h" | 24 #include "content/public/common/result_codes.h" | 
| 24 | 25 | 
| 25 #if defined(OS_WIN) | 26 #if defined(OS_WIN) | 
| 26 #include <windows.h> | 27 #include <windows.h> | 
| 27 #endif | 28 #endif | 
| 28 | 29 | 
| 29 namespace content { | 30 namespace content { | 
| 30 namespace { | 31 namespace { | 
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 } | 237 } | 
| 237 | 238 | 
| 238 // Use the --disable-gpu-watchdog command line switch to disable this. | 239 // Use the --disable-gpu-watchdog command line switch to disable this. | 
| 239 void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() { | 240 void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() { | 
| 240 // Should not get here while the system is suspended. | 241 // Should not get here while the system is suspended. | 
| 241 DCHECK(!suspended_); | 242 DCHECK(!suspended_); | 
| 242 | 243 | 
| 243 #if defined(OS_WIN) | 244 #if defined(OS_WIN) | 
| 244 // Defer termination until a certain amount of CPU time has elapsed on the | 245 // Defer termination until a certain amount of CPU time has elapsed on the | 
| 245 // watched thread. | 246 // watched thread. | 
| 246 base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_; | 247 base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_; | 
| 
 
fdoray
2016/04/21 21:08:38
ThreadTicks::Now() returns a null ThreadTicks befo
 
stanisc
2016/04/22 01:11:45
I think it should be fine for GetWatchedThreadTime
 
 | |
| 247 if (use_thread_cpu_time_ && (time_since_arm < timeout_)) { | 248 if (use_thread_cpu_time_ && (time_since_arm < timeout_)) { | 
| 248 message_loop()->PostDelayedTask( | 249 message_loop()->PostDelayedTask( | 
| 249 FROM_HERE, | 250 FROM_HERE, | 
| 250 base::Bind( | 251 base::Bind( | 
| 251 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang, | 252 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang, | 
| 252 weak_factory_.GetWeakPtr()), | 253 weak_factory_.GetWeakPtr()), | 
| 253 timeout_ - time_since_arm); | 254 timeout_ - time_since_arm); | 
| 254 return; | 255 return; | 
| 255 } | 256 } | 
| 256 #endif | 257 #endif | 
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 suspended_ = false; | 415 suspended_ = false; | 
| 415 resume_time_ = base::Time::Now(); | 416 resume_time_ = base::Time::Now(); | 
| 416 | 417 | 
| 417 // After resuming jump-start the watchdog again. | 418 // After resuming jump-start the watchdog again. | 
| 418 armed_ = false; | 419 armed_ = false; | 
| 419 OnCheck(true); | 420 OnCheck(true); | 
| 420 } | 421 } | 
| 421 | 422 | 
| 422 #if defined(OS_WIN) | 423 #if defined(OS_WIN) | 
| 423 base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() { | 424 base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() { | 
| 424 FILETIME creation_time; | 425 if (base::ThreadTicks::IsSupported()) { | 
| 425 FILETIME exit_time; | 426 // Convert ThreadTicks::Now() to TimeDelta. | 
| 426 FILETIME user_time; | 427 return base::ThreadTicks::Now( | 
| 427 FILETIME kernel_time; | 428 base::PlatformThreadHandle(watched_thread_handle_)) - | 
| 428 BOOL result = GetThreadTimes(watched_thread_handle_, | 429 base::ThreadTicks(); | 
| 
 
fdoray
2016/04/21 21:08:37
Ideally, you would store a ThreadTicks and compute
 
stanisc
2016/04/22 01:11:45
Yes, it seems like a good idea for this method to
 
 | |
| 429 &creation_time, | |
| 430 &exit_time, | |
| 431 &kernel_time, | |
| 432 &user_time); | |
| 433 DCHECK(result); | |
| 434 | 430 | 
| 435 ULARGE_INTEGER user_time64; | 431 } else { | 
| 436 user_time64.HighPart = user_time.dwHighDateTime; | 432 // Use GetThreadTimes as a backup mechanism. | 
| 437 user_time64.LowPart = user_time.dwLowDateTime; | 433 FILETIME creation_time; | 
| 434 FILETIME exit_time; | |
| 435 FILETIME user_time; | |
| 436 FILETIME kernel_time; | |
| 437 BOOL result = GetThreadTimes(watched_thread_handle_, &creation_time, | |
| 438 &exit_time, &kernel_time, &user_time); | |
| 439 DCHECK(result); | |
| 438 | 440 | 
| 439 ULARGE_INTEGER kernel_time64; | 441 ULARGE_INTEGER user_time64; | 
| 440 kernel_time64.HighPart = kernel_time.dwHighDateTime; | 442 user_time64.HighPart = user_time.dwHighDateTime; | 
| 441 kernel_time64.LowPart = kernel_time.dwLowDateTime; | 443 user_time64.LowPart = user_time.dwLowDateTime; | 
| 442 | 444 | 
| 443 // Time is reported in units of 100 nanoseconds. Kernel and user time are | 445 ULARGE_INTEGER kernel_time64; | 
| 444 // summed to deal with to kinds of hangs. One is where the GPU process is | 446 kernel_time64.HighPart = kernel_time.dwHighDateTime; | 
| 445 // stuck in user level, never calling into the kernel and kernel time is | 447 kernel_time64.LowPart = kernel_time.dwLowDateTime; | 
| 446 // not increasing. The other is where either the kernel hangs and never | 448 | 
| 447 // returns to user level or where user level code | 449 // Time is reported in units of 100 nanoseconds. Kernel and user time are | 
| 448 // calls into kernel level repeatedly, giving up its quanta before it is | 450 // summed to deal with to kinds of hangs. One is where the GPU process is | 
| 449 // tracked, for example a loop that repeatedly Sleeps. | 451 // stuck in user level, never calling into the kernel and kernel time is | 
| 450 return base::TimeDelta::FromMilliseconds(static_cast<int64_t>( | 452 // not increasing. The other is where either the kernel hangs and never | 
| 451 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); | 453 // returns to user level or where user level code | 
| 454 // calls into kernel level repeatedly, giving up its quanta before it is | |
| 455 // tracked, for example a loop that repeatedly Sleeps. | |
| 456 return base::TimeDelta::FromMilliseconds(static_cast<int64_t>( | |
| 457 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); | |
| 458 } | |
| 452 } | 459 } | 
| 453 #endif | 460 #endif | 
| 454 | 461 | 
| 455 } // namespace content | 462 } // namespace content | 
| OLD | NEW |