| 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 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 host_id = ++last_host_id; | 323 host_id = ++last_host_id; |
| 324 | 324 |
| 325 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", | 325 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", |
| 326 cause, | 326 cause, |
| 327 CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); | 327 CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); |
| 328 | 328 |
| 329 GpuProcessHost* host = new GpuProcessHost(host_id, kind); | 329 GpuProcessHost* host = new GpuProcessHost(host_id, kind); |
| 330 if (host->Init()) | 330 if (host->Init()) |
| 331 return host; | 331 return host; |
| 332 | 332 |
| 333 // TODO(sievers): Revisit this behavior. It's not really a crash, but we also |
| 334 // want the fallback-to-sw behavior if we cannot initialize the GPU. |
| 335 host->RecordProcessCrash(); |
| 336 |
| 333 delete host; | 337 delete host; |
| 334 return NULL; | 338 return NULL; |
| 335 } | 339 } |
| 336 | 340 |
| 337 // static | 341 // static |
| 338 void GpuProcessHost::GetProcessHandles( | 342 void GpuProcessHost::GetProcessHandles( |
| 339 const GpuDataManager::GetGpuProcessHandlesCallback& callback) { | 343 const GpuDataManager::GetGpuProcessHandlesCallback& callback) { |
| 340 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 344 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 341 BrowserThread::PostTask( | 345 BrowserThread::PostTask( |
| 342 BrowserThread::IO, | 346 BrowserThread::IO, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 } | 394 } |
| 391 | 395 |
| 392 GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind) | 396 GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind) |
| 393 : host_id_(host_id), | 397 : host_id_(host_id), |
| 394 valid_(true), | 398 valid_(true), |
| 395 in_process_(false), | 399 in_process_(false), |
| 396 swiftshader_rendering_(false), | 400 swiftshader_rendering_(false), |
| 397 kind_(kind), | 401 kind_(kind), |
| 398 process_launched_(false), | 402 process_launched_(false), |
| 399 initialized_(false), | 403 initialized_(false), |
| 400 gpu_crash_recorded_(false), | |
| 401 uma_memory_stats_received_(false) { | 404 uma_memory_stats_received_(false) { |
| 402 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 405 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 403 switches::kSingleProcess) || | 406 switches::kSingleProcess) || |
| 404 base::CommandLine::ForCurrentProcess()->HasSwitch( | 407 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 405 switches::kInProcessGPU)) { | 408 switches::kInProcessGPU)) { |
| 406 in_process_ = true; | 409 in_process_ = true; |
| 407 } | 410 } |
| 408 | 411 |
| 409 // If the 'single GPU process' policy ever changes, we still want to maintain | 412 // If the 'single GPU process' policy ever changes, we still want to maintain |
| 410 // it for 'gpu thread' mode and only create one instance of host and thread. | 413 // it for 'gpu thread' mode and only create one instance of host and thread. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 423 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id)); | 426 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id)); |
| 424 | 427 |
| 425 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this)); | 428 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this)); |
| 426 } | 429 } |
| 427 | 430 |
| 428 GpuProcessHost::~GpuProcessHost() { | 431 GpuProcessHost::~GpuProcessHost() { |
| 429 DCHECK(CalledOnValidThread()); | 432 DCHECK(CalledOnValidThread()); |
| 430 | 433 |
| 431 SendOutstandingReplies(); | 434 SendOutstandingReplies(); |
| 432 | 435 |
| 433 RecordProcessCrash(); | |
| 434 | |
| 435 // In case we never started, clean up. | 436 // In case we never started, clean up. |
| 436 while (!queued_messages_.empty()) { | 437 while (!queued_messages_.empty()) { |
| 437 delete queued_messages_.front(); | 438 delete queued_messages_.front(); |
| 438 queued_messages_.pop(); | 439 queued_messages_.pop(); |
| 439 } | 440 } |
| 440 | 441 |
| 441 #if defined(OS_MACOSX) && !defined(OS_IOS) | 442 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 442 if (!io_surface_manager_token_.IsZero()) { | 443 if (!io_surface_manager_token_.IsZero()) { |
| 443 BrowserIOSurfaceManager::GetInstance()->InvalidateGpuProcessToken(); | 444 BrowserIOSurfaceManager::GetInstance()->InvalidateGpuProcessToken(); |
| 444 io_surface_manager_token_.SetZero(); | 445 io_surface_manager_token_.SetZero(); |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 869 const IPC::Message& message) { | 870 const IPC::Message& message) { |
| 870 RenderWidgetResizeHelper::Get()->PostGpuProcessMsg(host_id_, message); | 871 RenderWidgetResizeHelper::Get()->PostGpuProcessMsg(host_id_, message); |
| 871 } | 872 } |
| 872 #endif | 873 #endif |
| 873 | 874 |
| 874 void GpuProcessHost::OnProcessLaunched() { | 875 void GpuProcessHost::OnProcessLaunched() { |
| 875 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime", | 876 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime", |
| 876 base::TimeTicks::Now() - init_start_time_); | 877 base::TimeTicks::Now() - init_start_time_); |
| 877 } | 878 } |
| 878 | 879 |
| 880 void GpuProcessHost::OnProcessLaunchFailed() { |
| 881 RecordProcessCrash(); |
| 882 } |
| 883 |
| 879 void GpuProcessHost::OnProcessCrashed(int exit_code) { | 884 void GpuProcessHost::OnProcessCrashed(int exit_code) { |
| 880 SendOutstandingReplies(); | 885 SendOutstandingReplies(); |
| 881 RecordProcessCrash(); | 886 RecordProcessCrash(); |
| 882 GpuDataManagerImpl::GetInstance()->ProcessCrashed( | 887 GpuDataManagerImpl::GetInstance()->ProcessCrashed( |
| 883 process_->GetTerminationStatus(true /* known_dead */, NULL)); | 888 process_->GetTerminationStatus(true /* known_dead */, NULL)); |
| 884 } | 889 } |
| 885 | 890 |
| 886 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() { | 891 GpuProcessHost::GpuProcessKind GpuProcessHost::kind() { |
| 887 return kind_; | 892 return kind_; |
| 888 } | 893 } |
| 889 | 894 |
| 890 void GpuProcessHost::ForceShutdown() { | 895 void GpuProcessHost::ForceShutdown() { |
| 891 // This is only called on the IO thread so no race against the constructor | 896 // This is only called on the IO thread so no race against the constructor |
| 892 // for another GpuProcessHost. | 897 // for another GpuProcessHost. |
| 893 if (g_gpu_process_hosts[kind_] == this) | 898 if (g_gpu_process_hosts[kind_] == this) |
| 894 g_gpu_process_hosts[kind_] = NULL; | 899 g_gpu_process_hosts[kind_] = NULL; |
| 895 | 900 |
| 896 #if defined(OS_MACOSX) && !defined(OS_IOS) | 901 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 897 if (!io_surface_manager_token_.IsZero()) { | 902 if (!io_surface_manager_token_.IsZero()) { |
| 898 BrowserIOSurfaceManager::GetInstance()->InvalidateGpuProcessToken(); | 903 BrowserIOSurfaceManager::GetInstance()->InvalidateGpuProcessToken(); |
| 899 io_surface_manager_token_.SetZero(); | 904 io_surface_manager_token_.SetZero(); |
| 900 } | 905 } |
| 901 #endif | 906 #endif |
| 902 | 907 |
| 903 process_->ForceShutdown(); | 908 process_->ForceShutdown(); |
| 904 } | 909 } |
| 905 | 910 |
| 911 void GpuProcessHost::StopGpuProcess() { |
| 912 Send(new GpuMsg_Finalize()); |
| 913 } |
| 914 |
| 906 void GpuProcessHost::BeginFrameSubscription( | 915 void GpuProcessHost::BeginFrameSubscription( |
| 907 int surface_id, | 916 int surface_id, |
| 908 base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber) { | 917 base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber) { |
| 909 frame_subscribers_[surface_id] = subscriber; | 918 frame_subscribers_[surface_id] = subscriber; |
| 910 } | 919 } |
| 911 | 920 |
| 912 void GpuProcessHost::EndFrameSubscription(int surface_id) { | 921 void GpuProcessHost::EndFrameSubscription(int surface_id) { |
| 913 frame_subscribers_.erase(surface_id); | 922 frame_subscribers_.erase(surface_id); |
| 914 } | 923 } |
| 915 | 924 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1019 void GpuProcessHost::BlockLiveOffscreenContexts() { | 1028 void GpuProcessHost::BlockLiveOffscreenContexts() { |
| 1020 for (std::multiset<GURL>::iterator iter = | 1029 for (std::multiset<GURL>::iterator iter = |
| 1021 urls_with_live_offscreen_contexts_.begin(); | 1030 urls_with_live_offscreen_contexts_.begin(); |
| 1022 iter != urls_with_live_offscreen_contexts_.end(); ++iter) { | 1031 iter != urls_with_live_offscreen_contexts_.end(); ++iter) { |
| 1023 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( | 1032 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( |
| 1024 *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN); | 1033 *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN); |
| 1025 } | 1034 } |
| 1026 } | 1035 } |
| 1027 | 1036 |
| 1028 void GpuProcessHost::RecordProcessCrash() { | 1037 void GpuProcessHost::RecordProcessCrash() { |
| 1029 // Skip if a GPU process crash was already counted. | |
| 1030 if (gpu_crash_recorded_) | |
| 1031 return; | |
| 1032 | |
| 1033 // Maximum number of times the GPU process is allowed to crash in a session. | 1038 // Maximum number of times the GPU process is allowed to crash in a session. |
| 1034 // Once this limit is reached, any request to launch the GPU process will | 1039 // Once this limit is reached, any request to launch the GPU process will |
| 1035 // fail. | 1040 // fail. |
| 1036 const int kGpuMaxCrashCount = 3; | 1041 const int kGpuMaxCrashCount = 3; |
| 1037 | 1042 |
| 1038 // Last time the GPU process crashed. | 1043 // Last time the GPU process crashed. |
| 1039 static base::Time last_gpu_crash_time; | 1044 static base::Time last_gpu_crash_time; |
| 1040 | 1045 |
| 1041 bool disable_crash_limit = base::CommandLine::ForCurrentProcess()->HasSwitch( | 1046 bool disable_crash_limit = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1042 switches::kDisableGpuProcessCrashLimit); | 1047 switches::kDisableGpuProcessCrashLimit); |
| 1043 | 1048 |
| 1044 // Ending only acts as a failure if the GPU process was actually started and | 1049 // Ending only acts as a failure if the GPU process was actually started and |
| 1045 // was intended for actual rendering (and not just checking caps or other | 1050 // was intended for actual rendering (and not just checking caps or other |
| 1046 // options). | 1051 // options). |
| 1047 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) { | 1052 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) { |
| 1048 gpu_crash_recorded_ = true; | |
| 1049 if (swiftshader_rendering_) { | 1053 if (swiftshader_rendering_) { |
| 1050 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents", | 1054 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents", |
| 1051 DIED_FIRST_TIME + swiftshader_crash_count_, | 1055 DIED_FIRST_TIME + swiftshader_crash_count_, |
| 1052 GPU_PROCESS_LIFETIME_EVENT_MAX); | 1056 GPU_PROCESS_LIFETIME_EVENT_MAX); |
| 1053 | 1057 |
| 1054 if (++swiftshader_crash_count_ >= kGpuMaxCrashCount && | 1058 if (++swiftshader_crash_count_ >= kGpuMaxCrashCount && |
| 1055 !disable_crash_limit) { | 1059 !disable_crash_limit) { |
| 1056 // SwiftShader is too unstable to use. Disable it for current session. | 1060 // SwiftShader is too unstable to use. Disable it for current session. |
| 1057 gpu_enabled_ = false; | 1061 gpu_enabled_ = false; |
| 1058 } | 1062 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); | 1143 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); |
| 1140 ClientIdToShaderCacheMap::iterator iter = | 1144 ClientIdToShaderCacheMap::iterator iter = |
| 1141 client_id_to_shader_cache_.find(client_id); | 1145 client_id_to_shader_cache_.find(client_id); |
| 1142 // If the cache doesn't exist then this is an off the record profile. | 1146 // If the cache doesn't exist then this is an off the record profile. |
| 1143 if (iter == client_id_to_shader_cache_.end()) | 1147 if (iter == client_id_to_shader_cache_.end()) |
| 1144 return; | 1148 return; |
| 1145 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); | 1149 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); |
| 1146 } | 1150 } |
| 1147 | 1151 |
| 1148 } // namespace content | 1152 } // namespace content |
| OLD | NEW |