Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(371)

Side by Side Diff: chrome/test/functional/perf.py

Issue 10161033: Adding pyauto-based memory usage tests for ChromeOS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: _GetMemoryStats now samples and outputs min/max/end values. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Basic pyauto performance tests. 6 """Basic pyauto performance tests.
7 7
8 For tests that need to be run for multiple iterations (e.g., so that average 8 For tests that need to be run for multiple iterations (e.g., so that average
9 and standard deviation values can be reported), the default number of iterations 9 and standard deviation values can be reported), the default number of iterations
10 run for each of these tests is specified by |_DEFAULT_NUM_ITERATIONS|. 10 run for each of these tests is specified by |_DEFAULT_NUM_ITERATIONS|.
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 self._seen_graph_lines = {} 83 self._seen_graph_lines = {}
84 84
85 pyauto.PyUITest.setUp(self) 85 pyauto.PyUITest.setUp(self)
86 86
87 # Flush all buffers to disk and wait until system calms down. Must be done 87 # Flush all buffers to disk and wait until system calms down. Must be done
88 # *after* calling pyauto.PyUITest.setUp, since that is where Chrome is 88 # *after* calling pyauto.PyUITest.setUp, since that is where Chrome is
89 # killed and re-initialized for a new test. 89 # killed and re-initialized for a new test.
90 # TODO(dennisjeffrey): Implement wait for idle CPU on Windows/Mac. 90 # TODO(dennisjeffrey): Implement wait for idle CPU on Windows/Mac.
91 if self.IsLinux(): # IsLinux() also implies IsChromeOS(). 91 if self.IsLinux(): # IsLinux() also implies IsChromeOS().
92 os.system('sync') 92 os.system('sync')
93 self._WaitForIdleCPU(60.0, 0.03) 93 self._WaitForIdleCPU(60.0, 0.05)
94 94
95 def _WaitForIdleCPU(self, timeout, utilization): 95 def _WaitForIdleCPU(self, timeout, utilization):
96 """Waits for the CPU to become idle (< utilization). 96 """Waits for the CPU to become idle (< utilization).
97 97
98 Args: 98 Args:
99 timeout: The longest time in seconds to wait before throwing an error. 99 timeout: The longest time in seconds to wait before throwing an error.
100 utilization: The CPU usage below which the system should be considered 100 utilization: The CPU usage below which the system should be considered
101 idle (between 0 and 1.0 independent of cores/hyperthreads). 101 idle (between 0 and 1.0 independent of cores/hyperthreads).
102 """ 102 """
103 time_passed = 0.0 103 time_passed = 0.0
(...skipping 1654 matching lines...) Expand 10 before | Expand all | Expand 10 after
1758 def testIntl2File(self): 1758 def testIntl2File(self):
1759 self._RunPageCyclerTest('intl2', self._num_iterations, 'Intl2File') 1759 self._RunPageCyclerTest('intl2', self._num_iterations, 'Intl2File')
1760 1760
1761 def testMozFile(self): 1761 def testMozFile(self):
1762 self._RunPageCyclerTest('moz', self._num_iterations, 'MozFile') 1762 self._RunPageCyclerTest('moz', self._num_iterations, 'MozFile')
1763 1763
1764 def testMoz2File(self): 1764 def testMoz2File(self):
1765 self._RunPageCyclerTest('moz2', self._num_iterations, 'Moz2File') 1765 self._RunPageCyclerTest('moz2', self._num_iterations, 'Moz2File')
1766 1766
1767 1767
1768 class MemoryTest(BasePerfTest):
1769 """Tests to measure memory consumption under different usage scenarios."""
1770
1771 def setUp(self):
1772 pyauto.PyUITest.setUp(self)
1773
ilja 2012/04/25 23:37:37 I assume you are logging out to use a fresh copy o
dennis_jeffrey 2012/04/26 01:46:25 Done.
1774 if self.GetLoginInfo()['is_logged_in']:
1775 self.Logout()
1776 self.assertFalse(self.GetLoginInfo()['is_logged_in'],
1777 msg='Failed to log out.')
1778
1779 # Log in.
1780 credentials = self.GetPrivateInfo()['test_google_account']
1781 self.Login(credentials['username'], credentials['password'])
1782 self.assertTrue(self.GetLoginInfo()['is_logged_in'],
1783 msg='Failed to log in.')
1784
1785 def _GetMemoryStats(self, duration=10):
ilja 2012/04/25 23:37:37 I spoke with James and he thinks duration should b
dennis_jeffrey 2012/04/26 01:46:25 I removed the default value to force the caller to
1786 """Identifies and returns different kinds of current memory usage stats.
1787
1788 This function samples values each second for |duration| seconds, then
1789 outputs the min, max, and ending values for each measurement type.
1790
1791 Args:
1792 duration: The number of seconds to sample data before outputting the
1793 minimum, maximum, and ending values for each measurement type.
1794
1795 Returns:
1796 A dictionary containing memory usage information. Each measurement type
1797 is associated with the min, max, and ending values from among all
1798 sampled values. Values are specified in KB.
1799 {
1800 'gtt': { # GPU memory usage (graphics translation table)
1801 'min': ...,
1802 'max': ...,
1803 'end': ...,
1804 },
1805 'mem_available': { ... }, # CPU available memory
1806 'mem_shared': { ... }, # CPU shared memory
1807 }
1808 """
1809 logging.debug('Sampling memory information for %d seconds...' % duration)
1810 stats = {
1811 'gtt': [],
1812 'mem_available': [],
1813 'mem_shared': [],
1814 }
1815
1816 for _ in xrange(duration):
1817 p = subprocess.Popen('grep bytes /sys/kernel/debug/dri/0/i915_gem_gtt',
1818 stdout=subprocess.PIPE,
1819 shell=True)
1820 stdout = p.communicate()[0]
1821
1822 # GPU memory.
1823 gtt_used = re.search(
1824 'Total [\d]+ objects, ([\d]+) bytes', stdout).group(1)
1825 stats['gtt'].append(int(gtt_used) / 1024.0)
1826
1827 # CPU memory.
1828 stdout = ''
1829 with open('/proc/meminfo') as f:
1830 stdout = f.read()
1831 mem_free = re.search('MemFree:\s*([\d]+) kB', stdout).group(1)
1832 mem_dirty = re.search('Dirty:\s*([\d]+) kB', stdout).group(1)
1833 mem_active_file = re.search(
1834 'Active\(file\):\s*([\d]+) kB', stdout).group(1)
1835 mem_inactive_file = re.search(
1836 'Inactive\(file\):\s*([\d]+) kB', stdout).group(1)
1837 stats['mem_available'].append(
1838 (int(mem_active_file) + int(mem_inactive_file)) - int(mem_dirty) +
1839 int(mem_free))
1840
1841 mem_shared = re.search('Shmem:\s*([\d]+) kB', stdout).group(1)
1842 stats['mem_shared'].append(int(mem_shared))
1843
1844 time.sleep(1)
1845
1846 # Compute min, max, and ending values to return.
1847 result = {}
1848 for measurement_type in stats:
1849 values = stats[measurement_type]
1850 result[measurement_type] = {
1851 'min': min(values),
1852 'max': max(values),
1853 'end': values[-1],
1854 }
1855
1856 return result
1857
1858 def _RecordMemoryStats(self, description, when):
1859 mem = self._GetMemoryStats()
ilja 2012/04/25 23:37:37 Lets not use the default duration here. If we are
dennis_jeffrey 2012/04/26 01:46:25 Now using 15 seconds as the duration for the empty
1860 measurement_types = [
1861 ('gtt', 'GTT'),
1862 ('mem_available', 'MemAvail'),
1863 ('mem_shared', 'MemShared'),
1864 ]
1865 for type_key, type_string in measurement_types:
1866 self._OutputPerfGraphValue(
1867 '%s-%sMin-%s' % (description, type_string, when),
ilja 2012/04/25 23:37:37 '%s-Min%s-%s' etc. is easier to read and does not
dennis_jeffrey 2012/04/26 01:46:25 Done.
1868 mem[type_key]['min'], 'KB', '%s-%s' % (description, type_string))
1869 self._OutputPerfGraphValue(
1870 '%s-%sMax-%s' % (description, type_string, when),
ilja 2012/04/25 23:37:37 dito
dennis_jeffrey 2012/04/26 01:46:25 Done.
1871 mem[type_key]['max'], 'KB', '%s-%s' % (description, type_string))
1872 self._OutputPerfGraphValue(
1873 '%s-%sEnd-%s' % (description, type_string, when),
ilja 2012/04/25 23:37:37 dito
dennis_jeffrey 2012/04/26 01:46:25 Done.
1874 mem[type_key]['end'], 'KB', '%s-%s' % (description, type_string))
1875
1876 def _RunTest(self, tabs, description):
ilja 2012/04/25 23:37:37 _RunTest needs duration as parameter when we run w
dennis_jeffrey 2012/04/26 01:46:25 Done.
1877 self._RecordMemoryStats(description, 'Start')
ilja 2012/04/25 23:37:37 Can we call this Close0 to be consistent with the
dennis_jeffrey 2012/04/26 01:46:25 I changed it to "0Tabs0" to follow the same format
1878
1879 for iteration_num in xrange(2):
1880 for site in tabs:
1881 self.AppendTab(pyauto.GURL(site))
1882
1883 self._RecordMemoryStats(description, 'Open%d' % (iteration_num + 1))
ilja 2012/04/25 23:37:37 '%dTabs%d' % (len(tabs), iteration_num + 1)
dennis_jeffrey 2012/04/26 01:46:25 Done.
1884
1885 for _ in xrange(len(tabs)):
1886 self.GetBrowserWindow(0).GetTab(1).Close(True)
1887
1888 self._RecordMemoryStats(description, 'Close%d' % (iteration_num + 1))
ilja 2012/04/25 23:37:37 '0Tabs%d'
dennis_jeffrey 2012/04/26 01:46:25 Done.
1889
1890 def testOpenCloseTabsControl(self):
1891 tabs = ['about:blank'] * 10
1892 self._RunTest(tabs, 'MemCtrl')
1893
1894
1768 class PerfTestServerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 1895 class PerfTestServerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
1769 """Request handler for the local performance test server.""" 1896 """Request handler for the local performance test server."""
1770 1897
1771 def _IgnoreHandler(self, unused_args): 1898 def _IgnoreHandler(self, unused_args):
1772 """A GET request handler that simply replies with status code 200. 1899 """A GET request handler that simply replies with status code 200.
1773 1900
1774 Args: 1901 Args:
1775 unused_args: A dictionary of arguments for the current GET request. 1902 unused_args: A dictionary of arguments for the current GET request.
1776 The arguments are ignored. 1903 The arguments are ignored.
1777 """ 1904 """
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 """Identifies the port number to which the server is currently bound. 2117 """Identifies the port number to which the server is currently bound.
1991 2118
1992 Returns: 2119 Returns:
1993 The numeric port number to which the server is currently bound. 2120 The numeric port number to which the server is currently bound.
1994 """ 2121 """
1995 return self._server.server_address[1] 2122 return self._server.server_address[1]
1996 2123
1997 2124
1998 if __name__ == '__main__': 2125 if __name__ == '__main__':
1999 pyauto_functional.Main() 2126 pyauto_functional.Main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698