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 |