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/browser/gpu/gpu_process_host.h" | 5 #include "content/browser/gpu/gpu_process_host.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/base_switches.h" | 8 #include "base/base_switches.h" |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 #endif | 61 #endif |
62 | 62 |
63 #if defined(USE_X11) && !defined(OS_CHROMEOS) | 63 #if defined(USE_X11) && !defined(OS_CHROMEOS) |
64 #include "ui/gfx/x/x11_switches.h" | 64 #include "ui/gfx/x/x11_switches.h" |
65 #endif | 65 #endif |
66 | 66 |
67 namespace content { | 67 namespace content { |
68 | 68 |
69 bool GpuProcessHost::gpu_enabled_ = true; | 69 bool GpuProcessHost::gpu_enabled_ = true; |
70 bool GpuProcessHost::hardware_gpu_enabled_ = true; | 70 bool GpuProcessHost::hardware_gpu_enabled_ = true; |
| 71 int GpuProcessHost::gpu_crash_count_ = 0; |
| 72 int GpuProcessHost::gpu_recent_crash_count_ = 0; |
| 73 bool GpuProcessHost::crashed_before_ = false; |
| 74 int GpuProcessHost::swiftshader_crash_count_ = 0; |
71 | 75 |
72 namespace { | 76 namespace { |
73 | 77 |
74 enum GPUProcessLifetimeEvent { | 78 enum GPUProcessLifetimeEvent { |
75 LAUNCHED, | 79 LAUNCHED, |
76 DIED_FIRST_TIME, | 80 DIED_FIRST_TIME, |
77 DIED_SECOND_TIME, | 81 DIED_SECOND_TIME, |
78 DIED_THIRD_TIME, | 82 DIED_THIRD_TIME, |
79 DIED_FOURTH_TIME, | 83 DIED_FOURTH_TIME, |
80 GPU_PROCESS_LIFETIME_EVENT_MAX = 100 | 84 GPU_PROCESS_LIFETIME_EVENT_MAX = 100 |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 } | 328 } |
325 | 329 |
326 GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind) | 330 GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind) |
327 : host_id_(host_id), | 331 : host_id_(host_id), |
328 valid_(true), | 332 valid_(true), |
329 in_process_(false), | 333 in_process_(false), |
330 swiftshader_rendering_(false), | 334 swiftshader_rendering_(false), |
331 kind_(kind), | 335 kind_(kind), |
332 process_launched_(false), | 336 process_launched_(false), |
333 initialized_(false), | 337 initialized_(false), |
| 338 gpu_crash_recorded_(false), |
334 uma_memory_stats_received_(false) { | 339 uma_memory_stats_received_(false) { |
335 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || | 340 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || |
336 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) { | 341 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) { |
337 in_process_ = true; | 342 in_process_ = true; |
338 } | 343 } |
339 | 344 |
340 // If the 'single GPU process' policy ever changes, we still want to maintain | 345 // If the 'single GPU process' policy ever changes, we still want to maintain |
341 // it for 'gpu thread' mode and only create one instance of host and thread. | 346 // it for 'gpu thread' mode and only create one instance of host and thread. |
342 DCHECK(!in_process_ || g_gpu_process_hosts[kind] == NULL); | 347 DCHECK(!in_process_ || g_gpu_process_hosts[kind] == NULL); |
343 | 348 |
(...skipping 10 matching lines...) Expand all Loading... |
354 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id)); | 359 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id)); |
355 | 360 |
356 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this)); | 361 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this)); |
357 } | 362 } |
358 | 363 |
359 GpuProcessHost::~GpuProcessHost() { | 364 GpuProcessHost::~GpuProcessHost() { |
360 DCHECK(CalledOnValidThread()); | 365 DCHECK(CalledOnValidThread()); |
361 | 366 |
362 SendOutstandingReplies(); | 367 SendOutstandingReplies(); |
363 | 368 |
364 // Maximum number of times the gpu process is allowed to crash in a session. | 369 RecordProcessCrash(); |
365 // Once this limit is reached, any request to launch the gpu process will | |
366 // fail. | |
367 const int kGpuMaxCrashCount = 3; | |
368 | |
369 // Number of times the gpu process has crashed in the current browser session. | |
370 static int gpu_crash_count = 0; | |
371 static int gpu_recent_crash_count = 0; | |
372 static base::Time last_gpu_crash_time; | |
373 static bool crashed_before = false; | |
374 static int swiftshader_crash_count = 0; | |
375 | |
376 bool disable_crash_limit = CommandLine::ForCurrentProcess()->HasSwitch( | |
377 switches::kDisableGpuProcessCrashLimit); | |
378 | |
379 // Ending only acts as a failure if the GPU process was actually started and | |
380 // was intended for actual rendering (and not just checking caps or other | |
381 // options). | |
382 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) { | |
383 if (swiftshader_rendering_) { | |
384 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents", | |
385 DIED_FIRST_TIME + swiftshader_crash_count, | |
386 GPU_PROCESS_LIFETIME_EVENT_MAX); | |
387 | |
388 if (++swiftshader_crash_count >= kGpuMaxCrashCount && | |
389 !disable_crash_limit) { | |
390 // SwiftShader is too unstable to use. Disable it for current session. | |
391 gpu_enabled_ = false; | |
392 } | |
393 } else { | |
394 ++gpu_crash_count; | |
395 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", | |
396 std::min(DIED_FIRST_TIME + gpu_crash_count, | |
397 GPU_PROCESS_LIFETIME_EVENT_MAX - 1), | |
398 GPU_PROCESS_LIFETIME_EVENT_MAX); | |
399 | |
400 // Allow about 1 GPU crash per hour to be removed from the crash count, | |
401 // so very occasional crashes won't eventually add up and prevent the | |
402 // GPU process from launching. | |
403 ++gpu_recent_crash_count; | |
404 base::Time current_time = base::Time::Now(); | |
405 if (crashed_before) { | |
406 int hours_different = (current_time - last_gpu_crash_time).InHours(); | |
407 gpu_recent_crash_count = | |
408 std::max(0, gpu_recent_crash_count - hours_different); | |
409 } | |
410 | |
411 crashed_before = true; | |
412 last_gpu_crash_time = current_time; | |
413 | |
414 if ((gpu_recent_crash_count >= kGpuMaxCrashCount && !disable_crash_limit) | |
415 || !initialized_) { | |
416 #if !defined(OS_CHROMEOS) | |
417 // The gpu process is too unstable to use. Disable it for current | |
418 // session. | |
419 hardware_gpu_enabled_ = false; | |
420 GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration(); | |
421 #endif | |
422 } | |
423 } | |
424 } | |
425 | 370 |
426 // In case we never started, clean up. | 371 // In case we never started, clean up. |
427 while (!queued_messages_.empty()) { | 372 while (!queued_messages_.empty()) { |
428 delete queued_messages_.front(); | 373 delete queued_messages_.front(); |
429 queued_messages_.pop(); | 374 queued_messages_.pop(); |
430 } | 375 } |
431 | 376 |
432 // This is only called on the IO thread so no race against the constructor | 377 // This is only called on the IO thread so no race against the constructor |
433 // for another GpuProcessHost. | 378 // for another GpuProcessHost. |
434 if (g_gpu_process_hosts[kind_] == this) | 379 if (g_gpu_process_hosts[kind_] == this) |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 } | 799 } |
855 #endif | 800 #endif |
856 | 801 |
857 void GpuProcessHost::OnProcessLaunched() { | 802 void GpuProcessHost::OnProcessLaunched() { |
858 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime", | 803 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime", |
859 base::TimeTicks::Now() - init_start_time_); | 804 base::TimeTicks::Now() - init_start_time_); |
860 } | 805 } |
861 | 806 |
862 void GpuProcessHost::OnProcessCrashed(int exit_code) { | 807 void GpuProcessHost::OnProcessCrashed(int exit_code) { |
863 SendOutstandingReplies(); | 808 SendOutstandingReplies(); |
| 809 RecordProcessCrash(); |
864 GpuDataManagerImpl::GetInstance()->ProcessCrashed( | 810 GpuDataManagerImpl::GetInstance()->ProcessCrashed( |
865 process_->GetTerminationStatus(true /* known_dead */, NULL)); | 811 process_->GetTerminationStatus(true /* known_dead */, NULL)); |
866 } | 812 } |
867 | 813 |
868 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() { | 814 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() { |
869 return kind_; | 815 return kind_; |
870 } | 816 } |
871 | 817 |
872 void GpuProcessHost::ForceShutdown() { | 818 void GpuProcessHost::ForceShutdown() { |
873 // This is only called on the IO thread so no race against the constructor | 819 // This is only called on the IO thread so no race against the constructor |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1016 | 962 |
1017 void GpuProcessHost::BlockLiveOffscreenContexts() { | 963 void GpuProcessHost::BlockLiveOffscreenContexts() { |
1018 for (std::multiset<GURL>::iterator iter = | 964 for (std::multiset<GURL>::iterator iter = |
1019 urls_with_live_offscreen_contexts_.begin(); | 965 urls_with_live_offscreen_contexts_.begin(); |
1020 iter != urls_with_live_offscreen_contexts_.end(); ++iter) { | 966 iter != urls_with_live_offscreen_contexts_.end(); ++iter) { |
1021 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( | 967 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( |
1022 *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN); | 968 *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN); |
1023 } | 969 } |
1024 } | 970 } |
1025 | 971 |
| 972 void GpuProcessHost::RecordProcessCrash() { |
| 973 // Skip if a GPU process crash was already counted. |
| 974 if (gpu_crash_recorded_) |
| 975 return; |
| 976 |
| 977 // Maximum number of times the gpu process is allowed to crash in a session. |
| 978 // Once this limit is reached, any request to launch the gpu process will |
| 979 // fail. |
| 980 const int kGpuMaxCrashCount = 3; |
| 981 |
| 982 // Last time the GPU process crashed. |
| 983 static base::Time last_gpu_crash_time; |
| 984 |
| 985 bool disable_crash_limit = CommandLine::ForCurrentProcess()->HasSwitch( |
| 986 switches::kDisableGpuProcessCrashLimit); |
| 987 |
| 988 // Ending only acts as a failure if the GPU process was actually started and |
| 989 // was intended for actual rendering (and not just checking caps or other |
| 990 // options). |
| 991 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) { |
| 992 gpu_crash_recorded_ = true; |
| 993 if (swiftshader_rendering_) { |
| 994 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents", |
| 995 DIED_FIRST_TIME + swiftshader_crash_count_, |
| 996 GPU_PROCESS_LIFETIME_EVENT_MAX); |
| 997 |
| 998 if (++swiftshader_crash_count_ >= kGpuMaxCrashCount && |
| 999 !disable_crash_limit) { |
| 1000 // SwiftShader is too unstable to use. Disable it for current session. |
| 1001 gpu_enabled_ = false; |
| 1002 } |
| 1003 } else { |
| 1004 ++gpu_crash_count_; |
| 1005 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", |
| 1006 std::min(DIED_FIRST_TIME + gpu_crash_count_, |
| 1007 GPU_PROCESS_LIFETIME_EVENT_MAX - 1), |
| 1008 GPU_PROCESS_LIFETIME_EVENT_MAX); |
| 1009 |
| 1010 // Allow about 1 GPU crash per hour to be removed from the crash count, |
| 1011 // so very occasional crashes won't eventually add up and prevent the |
| 1012 // GPU process from launching. |
| 1013 ++gpu_recent_crash_count_; |
| 1014 base::Time current_time = base::Time::Now(); |
| 1015 if (crashed_before_) { |
| 1016 int hours_different = (current_time - last_gpu_crash_time).InHours(); |
| 1017 gpu_recent_crash_count_ = |
| 1018 std::max(0, gpu_recent_crash_count_ - hours_different); |
| 1019 } |
| 1020 |
| 1021 crashed_before_ = true; |
| 1022 last_gpu_crash_time = current_time; |
| 1023 |
| 1024 if ((gpu_recent_crash_count_ >= kGpuMaxCrashCount && |
| 1025 !disable_crash_limit) || |
| 1026 !initialized_) { |
| 1027 #if !defined(OS_CHROMEOS) |
| 1028 // The gpu process is too unstable to use. Disable it for current |
| 1029 // session. |
| 1030 hardware_gpu_enabled_ = false; |
| 1031 GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration(); |
| 1032 #endif |
| 1033 } |
| 1034 } |
| 1035 } |
| 1036 } |
| 1037 |
1026 std::string GpuProcessHost::GetShaderPrefixKey() { | 1038 std::string GpuProcessHost::GetShaderPrefixKey() { |
1027 if (shader_prefix_key_.empty()) { | 1039 if (shader_prefix_key_.empty()) { |
1028 gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); | 1040 gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); |
1029 | 1041 |
1030 std::string in_str = GetContentClient()->GetProduct() + "-" + | 1042 std::string in_str = GetContentClient()->GetProduct() + "-" + |
1031 info.gl_vendor + "-" + info.gl_renderer + "-" + | 1043 info.gl_vendor + "-" + info.gl_renderer + "-" + |
1032 info.driver_version + "-" + info.driver_vendor; | 1044 info.driver_version + "-" + info.driver_vendor; |
1033 | 1045 |
1034 base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_); | 1046 base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_); |
1035 } | 1047 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); | 1080 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); |
1069 ClientIdToShaderCacheMap::iterator iter = | 1081 ClientIdToShaderCacheMap::iterator iter = |
1070 client_id_to_shader_cache_.find(client_id); | 1082 client_id_to_shader_cache_.find(client_id); |
1071 // If the cache doesn't exist then this is an off the record profile. | 1083 // If the cache doesn't exist then this is an off the record profile. |
1072 if (iter == client_id_to_shader_cache_.end()) | 1084 if (iter == client_id_to_shader_cache_.end()) |
1073 return; | 1085 return; |
1074 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); | 1086 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); |
1075 } | 1087 } |
1076 | 1088 |
1077 } // namespace content | 1089 } // namespace content |
OLD | NEW |