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 3# found in the LICENSE file. 4import memory_test_expectations 5import page_sets 6 7from telemetry import benchmark 8from telemetry.page import page_test 9from telemetry.core.platform import tracing_category_filter 10from telemetry.core.platform import tracing_options 11from telemetry.timeline import counter 12from telemetry.timeline import model 13 14MEMORY_LIMIT_MB = 192 15SINGLE_TAB_LIMIT_MB = 192 16WIGGLE_ROOM_MB = 12 17 18test_harness_script = r""" 19 var domAutomationController = {}; 20 domAutomationController._finished = false; 21 22 domAutomationController.send = function(msg) { 23 // This should wait until all effects of memory management complete. 24 // We will need to wait until all 25 // 1. pending commits from the main thread to the impl thread in the 26 // compositor complete (for visible compositors). 27 // 2. allocations that the renderer's impl thread will make due to the 28 // compositor and WebGL are completed. 29 // 3. pending GpuMemoryManager::Manage() calls to manage are made. 30 // 4. renderers' OnMemoryAllocationChanged callbacks in response to 31 // manager are made. 32 // Each step in this sequence can cause trigger the next (as a 1-2-3-4-1 33 // cycle), so we will need to pump this cycle until it stabilizes. 34 35 // Pump the cycle 8 times (in principle it could take an infinite number 36 // of iterations to settle). 37 38 var rafCount = 0; 39 40 // Impl-side painting has changed the behavior of this test. 41 // Currently the background of the page shows up checkerboarded 42 // initially, causing the test to fail because the memory 43 // allocation is too low (no root layer). Temporarily increase the 44 // rAF count to 32 in order to make the test work reliably again. 45 // crbug.com/373098 46 // TODO(kbr): revert this change and put it back to 8 iterations. 47 var totalRafCount = 32; 48 49 function pumpRAF() { 50 if (rafCount == totalRafCount) { 51 domAutomationController._finished = true; 52 return; 53 } 54 ++rafCount; 55 window.requestAnimationFrame(pumpRAF); 56 } 57 pumpRAF(); 58 } 59 60 window.domAutomationController = domAutomationController; 61 62 window.addEventListener("load", function() { 63 useGpuMemory(%d); 64 }, false); 65""" % MEMORY_LIMIT_MB 66 67class _MemoryValidator(page_test.PageTest): 68 def ValidateAndMeasurePage(self, page, tab, results): 69 timeline_data = tab.browser.platform.tracing_controller.Stop() 70 timeline_model = model.TimelineModel(timeline_data) 71 for process in timeline_model.GetAllProcesses(): 72 if 'gpu.GpuMemoryUsage' in process.counters: 73 counter = process.GetCounter('gpu', 'GpuMemoryUsage') 74 mb_used = counter.samples[-1] / 1048576 75 76 if mb_used + WIGGLE_ROOM_MB < SINGLE_TAB_LIMIT_MB: 77 raise page_test.Failure(self._FormatException('low', mb_used)) 78 79 if mb_used - WIGGLE_ROOM_MB > MEMORY_LIMIT_MB: 80 raise page_test.Failure(self._FormatException('high', mb_used)) 81 82 def CustomizeBrowserOptions(self, options): 83 options.AppendExtraBrowserArgs('--enable-logging') 84 options.AppendExtraBrowserArgs( 85 '--force-gpu-mem-available-mb=%s' % MEMORY_LIMIT_MB) 86 87 def WillNavigateToPage(self, page, tab): 88 # FIXME: Remove webkit.console when blink.console lands in chromium and the 89 # ref builds are updated. crbug.com/386847 90 custom_categories = ['webkit.console', 'blink.console', 'gpu'] 91 category_filter = tracing_category_filter.TracingCategoryFilter() 92 for c in custom_categories: 93 category_filter.AddIncludedCategory(c) 94 options = tracing_options.TracingOptions() 95 options.enable_chrome_trace = True 96 tab.browser.platform.tracing_controller.Start(options, category_filter, 60) 97 98 def _FormatException(self, low_or_high, mb_used): 99 return 'Memory allocation too %s (was %d MB, should be %d MB +/- %d MB)' % ( 100 low_or_high, mb_used, SINGLE_TAB_LIMIT_MB, WIGGLE_ROOM_MB) 101 102class MemoryTest(benchmark.Benchmark): 103 """Tests GPU memory limits""" 104 test = _MemoryValidator 105 106 def CreateExpectations(self, page_set): 107 return memory_test_expectations.MemoryTestExpectations() 108 109 def CreatePageSet(self, options): 110 page_set = page_sets.MemoryTestsPageSet() 111 for page in page_set.pages: 112 page.script_to_evaluate_on_commit = test_harness_script 113 return page_set 114