OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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() |
OLD | NEW |