| 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/renderer/render_thread_impl.h" | 5 #include "content/renderer/render_thread_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <map> | 9 #include <map> |
| 10 #include <utility> | 10 #include <utility> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/allocator/allocator_extension.h" | 13 #include "base/allocator/allocator_extension.h" |
| 14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 15 #include "base/debug/crash_logging.h" | 15 #include "base/debug/crash_logging.h" |
| 16 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/macros.h" | 18 #include "base/macros.h" |
| 19 #include "base/memory/discardable_memory_allocator.h" | 19 #include "base/memory/discardable_memory_allocator.h" |
| 20 #include "base/memory/memory_coordinator_client_registry.h" | 20 #include "base/memory/memory_coordinator_client_registry.h" |
| 21 #include "base/memory/ptr_util.h" | 21 #include "base/memory/ptr_util.h" |
| 22 #include "base/memory/shared_memory.h" | 22 #include "base/memory/shared_memory.h" |
| 23 #include "base/metrics/field_trial.h" | 23 #include "base/metrics/field_trial.h" |
| 24 #include "base/metrics/histogram_macros.h" | 24 #include "base/metrics/histogram_macros.h" |
| 25 #include "base/path_service.h" | 25 #include "base/path_service.h" |
| 26 #include "base/process/process_metrics.h" |
| 26 #include "base/run_loop.h" | 27 #include "base/run_loop.h" |
| 27 #include "base/strings/string16.h" | 28 #include "base/strings/string16.h" |
| 28 #include "base/strings/string_number_conversions.h" | 29 #include "base/strings/string_number_conversions.h" |
| 29 #include "base/strings/string_split.h" | 30 #include "base/strings/string_split.h" |
| 30 #include "base/strings/sys_string_conversions.h" | 31 #include "base/strings/sys_string_conversions.h" |
| 31 #include "base/strings/utf_string_conversions.h" | 32 #include "base/strings/utf_string_conversions.h" |
| 32 #include "base/threading/simple_thread.h" | 33 #include "base/threading/simple_thread.h" |
| 33 #include "base/threading/thread_local.h" | 34 #include "base/threading/thread_local.h" |
| 34 #include "base/threading/thread_restrictions.h" | 35 #include "base/threading/thread_restrictions.h" |
| 35 #include "base/threading/thread_task_runner_handle.h" | 36 #include "base/threading/thread_task_runner_handle.h" |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 #include "content/public/common/service_manager_connection.h" | 205 #include "content/public/common/service_manager_connection.h" |
| 205 #include "content/renderer/mus/render_widget_mus_connection.h" | 206 #include "content/renderer/mus/render_widget_mus_connection.h" |
| 206 #include "content/renderer/mus/render_widget_window_tree_client_factory.h" | 207 #include "content/renderer/mus/render_widget_window_tree_client_factory.h" |
| 207 #include "services/ui/public/cpp/gpu_service.h" | 208 #include "services/ui/public/cpp/gpu_service.h" |
| 208 #endif | 209 #endif |
| 209 | 210 |
| 210 #if defined(ENABLE_IPC_FUZZER) | 211 #if defined(ENABLE_IPC_FUZZER) |
| 211 #include "content/common/external_ipc_dumper.h" | 212 #include "content/common/external_ipc_dumper.h" |
| 212 #endif | 213 #endif |
| 213 | 214 |
| 215 #if defined(OS_MACOSX) |
| 216 #include <malloc/malloc.h> |
| 217 #else |
| 218 #include <malloc.h> |
| 219 #endif |
| 220 |
| 214 using base::ThreadRestrictions; | 221 using base::ThreadRestrictions; |
| 215 using blink::WebDocument; | 222 using blink::WebDocument; |
| 216 using blink::WebFrame; | 223 using blink::WebFrame; |
| 217 using blink::WebNetworkStateNotifier; | 224 using blink::WebNetworkStateNotifier; |
| 218 using blink::WebRuntimeFeatures; | 225 using blink::WebRuntimeFeatures; |
| 219 using blink::WebScriptController; | 226 using blink::WebScriptController; |
| 220 using blink::WebSecurityPolicy; | 227 using blink::WebSecurityPolicy; |
| 221 using blink::WebString; | 228 using blink::WebString; |
| 222 using blink::WebView; | 229 using blink::WebView; |
| 223 using blink::scheduler::WebThreadImplForWorkerScheduler; | 230 using blink::scheduler::WebThreadImplForWorkerScheduler; |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 891 time_zone_monitor->AddClient( | 898 time_zone_monitor->AddClient( |
| 892 time_zone_monitor_binding_.CreateInterfacePtrAndBind()); | 899 time_zone_monitor_binding_.CreateInterfacePtrAndBind()); |
| 893 | 900 |
| 894 #if defined(OS_LINUX) | 901 #if defined(OS_LINUX) |
| 895 ChildProcess::current()->SetIOThreadPriority(base::ThreadPriority::DISPLAY); | 902 ChildProcess::current()->SetIOThreadPriority(base::ThreadPriority::DISPLAY); |
| 896 ChildThreadImpl::current()->SetThreadPriority( | 903 ChildThreadImpl::current()->SetThreadPriority( |
| 897 categorized_worker_pool_->background_worker_thread_id(), | 904 categorized_worker_pool_->background_worker_thread_id(), |
| 898 base::ThreadPriority::BACKGROUND); | 905 base::ThreadPriority::BACKGROUND); |
| 899 #endif | 906 #endif |
| 900 | 907 |
| 908 record_purge_suspend_metric_closure_.Reset(base::Bind( |
| 909 &RenderThreadImpl::RecordPurgeAndSuspendMetrics, base::Unretained(this))); |
| 901 is_renderer_suspended_ = false; | 910 is_renderer_suspended_ = false; |
| 902 | 911 |
| 903 base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this); | 912 base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this); |
| 904 } | 913 } |
| 905 | 914 |
| 906 RenderThreadImpl::~RenderThreadImpl() { | 915 RenderThreadImpl::~RenderThreadImpl() { |
| 907 } | 916 } |
| 908 | 917 |
| 909 void RenderThreadImpl::Shutdown() { | 918 void RenderThreadImpl::Shutdown() { |
| 910 for (auto& observer : observers_) | 919 for (auto& observer : observers_) |
| (...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1758 return handled; | 1767 return handled; |
| 1759 } | 1768 } |
| 1760 | 1769 |
| 1761 void RenderThreadImpl::OnProcessBackgrounded(bool backgrounded) { | 1770 void RenderThreadImpl::OnProcessBackgrounded(bool backgrounded) { |
| 1762 ChildThreadImpl::OnProcessBackgrounded(backgrounded); | 1771 ChildThreadImpl::OnProcessBackgrounded(backgrounded); |
| 1763 | 1772 |
| 1764 if (backgrounded) { | 1773 if (backgrounded) { |
| 1765 renderer_scheduler_->OnRendererBackgrounded(); | 1774 renderer_scheduler_->OnRendererBackgrounded(); |
| 1766 } else { | 1775 } else { |
| 1767 renderer_scheduler_->OnRendererForegrounded(); | 1776 renderer_scheduler_->OnRendererForegrounded(); |
| 1777 record_purge_suspend_metric_closure_.Cancel(); |
| 1768 is_renderer_suspended_ = false; | 1778 is_renderer_suspended_ = false; |
| 1769 } | 1779 } |
| 1770 } | 1780 } |
| 1771 | 1781 |
| 1772 void RenderThreadImpl::OnProcessPurgeAndSuspend() { | 1782 void RenderThreadImpl::OnProcessPurgeAndSuspend() { |
| 1773 ChildThreadImpl::OnProcessPurgeAndSuspend(); | 1783 ChildThreadImpl::OnProcessPurgeAndSuspend(); |
| 1774 if (is_renderer_suspended_) | 1784 if (is_renderer_suspended_) |
| 1775 return; | 1785 return; |
| 1776 // TODO(hajimehoshi): Implement purging e.g. cache (crbug/607077) | 1786 // TODO(hajimehoshi): Implement purging e.g. cache (crbug/607077) |
| 1777 is_renderer_suspended_ = true; | 1787 is_renderer_suspended_ = true; |
| 1778 renderer_scheduler_->SuspendRenderer(); | 1788 renderer_scheduler_->SuspendRenderer(); |
| 1789 |
| 1790 // Since purging is not a synchronous task (e.g. v8 GC, oilpan GC, ...), |
| 1791 // we need to wait until the task is finished. So wait 15 seconds and |
| 1792 // update purge+suspend UMA histogram. |
| 1793 // TODO(tasak): use MemoryCoordinator's callback to report purge+suspend |
| 1794 // UMA when MemoryCoordinator is available. |
| 1795 GetRendererScheduler()->DefaultTaskRunner()->PostDelayedTask( |
| 1796 FROM_HERE, record_purge_suspend_metric_closure_.callback(), |
| 1797 base::TimeDelta::FromSeconds(15)); |
| 1798 } |
| 1799 |
| 1800 // TODO(tasak): Replace the following GetMallocUsage() with memory-infra |
| 1801 // when it is possible to run memory-infra without tracing. |
| 1802 #if defined(OS_WIN) |
| 1803 namespace { |
| 1804 |
| 1805 static size_t GetMallocUsage() { |
| 1806 DWORD number_of_heaps = ::GetProcessHeaps(0, NULL); |
| 1807 if (number_of_heaps <= 0) |
| 1808 return 0; |
| 1809 |
| 1810 size_t malloc_usage = 0; |
| 1811 std::unique_ptr<HANDLE[]> heaps(new HANDLE[number_of_heaps]); |
| 1812 ::GetProcessHeaps(number_of_heaps, heaps.get()); |
| 1813 for (size_t i = 0; i < number_of_heaps; i++) { |
| 1814 PROCESS_HEAP_ENTRY heap_entry; |
| 1815 ::HeapLock(heaps[i]); |
| 1816 heap_entry.lpData = NULL; |
| 1817 while (::HeapWalk(heaps[i], &heap_entry) != 0) { |
| 1818 if (heap_entry.lpData == heaps.get()) |
| 1819 continue; |
| 1820 if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) |
| 1821 malloc_usage += heap_entry.cbData; |
| 1822 } |
| 1823 ::HeapUnlock(heaps[i]); |
| 1824 } |
| 1825 return malloc_usage; |
| 1826 } |
| 1827 |
| 1828 } // namespace |
| 1829 #elif defined(OS_MACOSX) || defined(OS_IOS) |
| 1830 namespace { |
| 1831 |
| 1832 static size_t GetMallocUsage() { |
| 1833 malloc_statistics_t stats = {0}; |
| 1834 malloc_zone_statistics(nullptr, &stats); |
| 1835 return stats.size_in_use; |
| 1836 } |
| 1837 |
| 1838 } // namespace |
| 1839 #endif |
| 1840 |
| 1841 // TODO(tasak): Once it is possible to use memory-infra without tracing, |
| 1842 // we should collect the metrics using memory-infra. |
| 1843 // TODO(tasak): We should also report a difference between the memory usages |
| 1844 // before and after purging by using memory-infra. |
| 1845 void RenderThreadImpl::RecordPurgeAndSuspendMetrics() const { |
| 1846 // If this renderer is resumed, we should not update UMA. |
| 1847 if (!is_renderer_suspended_) |
| 1848 return; |
| 1849 |
| 1850 // TODO(tasak): Compare memory metrics between purge-enabled renderers and |
| 1851 // purge-disabled renderers (A/B testing). |
| 1852 blink::WebMemoryStatistics blink_stats = blink::WebMemoryStatistics::Get(); |
| 1853 UMA_HISTOGRAM_MEMORY_KB("PurgeAndSuspend.Memory.PartitionAllocKB", |
| 1854 blink_stats.partitionAllocTotalAllocatedBytes / 1024); |
| 1855 UMA_HISTOGRAM_MEMORY_KB("PurgeAndSuspend.Memory.BlinkGCKB", |
| 1856 blink_stats.blinkGCTotalAllocatedBytes / 1024); |
| 1857 #if defined(OS_LINUX) || defined(OS_ANDROID) |
| 1858 struct mallinfo minfo = mallinfo(); |
| 1859 #if defined(USE_TCMALLOC) |
| 1860 size_t malloc_usage = minfo.uordblks; |
| 1861 #else |
| 1862 size_t malloc_usage = minfo.hblkhd + minfo.arena; |
| 1863 #endif |
| 1864 #else |
| 1865 size_t malloc_usage = GetMallocUsage(); |
| 1866 #endif |
| 1867 UMA_HISTOGRAM_MEMORY_MB("PurgeAndSuspend.Memory.MallocMB", |
| 1868 malloc_usage / 1024 / 1024); |
| 1869 |
| 1870 ChildDiscardableSharedMemoryManager::Statistics discardable_stats = |
| 1871 ChildThreadImpl::discardable_shared_memory_manager()->GetStatistics(); |
| 1872 size_t discardable_usage = |
| 1873 discardable_stats.total_size - discardable_stats.freelist_size; |
| 1874 UMA_HISTOGRAM_MEMORY_KB("PurgeAndSuspend.Memory.DiscardableKB", |
| 1875 discardable_usage / 1024); |
| 1876 |
| 1877 size_t v8_usage = 0; |
| 1878 if (v8::Isolate* isolate = blink::mainThreadIsolate()) { |
| 1879 v8::HeapStatistics v8_heap_statistics; |
| 1880 isolate->GetHeapStatistics(&v8_heap_statistics); |
| 1881 v8_usage = v8_heap_statistics.total_heap_size(); |
| 1882 } |
| 1883 // TODO(tasak): Currently only memory usage of mainThreadIsolate() is |
| 1884 // reported. We should collect memory usages of all isolates using |
| 1885 // memory-infra. |
| 1886 UMA_HISTOGRAM_MEMORY_MB("PurgeAndSuspend.Memory.V8MainThreadIsolateMB", |
| 1887 v8_usage / 1024 / 1024); |
| 1888 UMA_HISTOGRAM_MEMORY_MB("PurgeAndSuspend.Memory.TotalAllocatedMB", |
| 1889 (blink_stats.partitionAllocTotalAllocatedBytes + |
| 1890 blink_stats.blinkGCTotalAllocatedBytes + |
| 1891 malloc_usage + v8_usage + discardable_usage) / |
| 1892 1024 / 1024); |
| 1779 } | 1893 } |
| 1780 | 1894 |
| 1781 scoped_refptr<gpu::GpuChannelHost> RenderThreadImpl::EstablishGpuChannelSync() { | 1895 scoped_refptr<gpu::GpuChannelHost> RenderThreadImpl::EstablishGpuChannelSync() { |
| 1782 TRACE_EVENT0("gpu", "RenderThreadImpl::EstablishGpuChannelSync"); | 1896 TRACE_EVENT0("gpu", "RenderThreadImpl::EstablishGpuChannelSync"); |
| 1783 | 1897 |
| 1784 if (gpu_channel_) { | 1898 if (gpu_channel_) { |
| 1785 // Do nothing if we already have a GPU channel or are already | 1899 // Do nothing if we already have a GPU channel or are already |
| 1786 // establishing one. | 1900 // establishing one. |
| 1787 if (!gpu_channel_->IsLost()) | 1901 if (!gpu_channel_->IsLost()) |
| 1788 return gpu_channel_; | 1902 return gpu_channel_; |
| (...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2362 } | 2476 } |
| 2363 } | 2477 } |
| 2364 | 2478 |
| 2365 void RenderThreadImpl::OnRendererInterfaceRequest( | 2479 void RenderThreadImpl::OnRendererInterfaceRequest( |
| 2366 mojom::RendererAssociatedRequest request) { | 2480 mojom::RendererAssociatedRequest request) { |
| 2367 DCHECK(!renderer_binding_.is_bound()); | 2481 DCHECK(!renderer_binding_.is_bound()); |
| 2368 renderer_binding_.Bind(std::move(request)); | 2482 renderer_binding_.Bind(std::move(request)); |
| 2369 } | 2483 } |
| 2370 | 2484 |
| 2371 } // namespace content | 2485 } // namespace content |
| OLD | NEW |