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

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: Addressed comments from patch set 4. Created 8 years, 7 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
1774 # Log in to get a fresh Chrome instance with a clean memory state (if
1775 # already logged in, log out first).
1776 if self.GetLoginInfo()['is_logged_in']:
1777 self.Logout()
1778 self.assertFalse(self.GetLoginInfo()['is_logged_in'],
1779 msg='Failed to log out.')
1780
1781 credentials = self.GetPrivateInfo()['test_google_account']
1782 self.Login(credentials['username'], credentials['password'])
1783 self.assertTrue(self.GetLoginInfo()['is_logged_in'],
1784 msg='Failed to log in.')
1785
1786 def _GetMemoryStats(self, duration):
1787 """Identifies and returns different kinds of current memory usage stats.
1788
1789 This function samples values each second for |duration| seconds, then
1790 outputs the min, max, and ending values for each measurement type.
1791
1792 Args:
1793 duration: The number of seconds to sample data before outputting the
1794 minimum, maximum, and ending values for each measurement type.
1795
1796 Returns:
1797 A dictionary containing memory usage information. Each measurement type
1798 is associated with the min, max, and ending values from among all
1799 sampled values. Values are specified in KB.
1800 {
1801 'gtt': { # GPU memory usage (graphics translation table)
1802 'min': ...,
1803 'max': ...,
1804 'end': ...,
1805 },
1806 'mem_available': { ... }, # CPU available memory
1807 'mem_shared': { ... }, # CPU shared memory
1808 }
1809 """
1810 logging.debug('Sampling memory information for %d seconds...' % duration)
1811 stats = {
1812 'gtt': [],
1813 'mem_available': [],
1814 'mem_shared': [],
1815 }
1816
1817 for _ in xrange(duration):
1818 p = subprocess.Popen('grep bytes /sys/kernel/debug/dri/0/i915_gem_gtt',
Sonny 2012/04/26 04:55:18 GTT isn't guaranteed to always be there. It'll on
ihf 2012/04/26 05:19:17 Good catch on the checking for file existence.
dennis_jeffrey 2012/04/26 18:47:39 I modified the code to exclude GTT values if the f
1819 stdout=subprocess.PIPE,
1820 shell=True)
1821 stdout = p.communicate()[0]
1822
1823 # GPU memory.
1824 gtt_used = re.search(
1825 'Total [\d]+ objects, ([\d]+) bytes', stdout).group(1)
1826 stats['gtt'].append(int(gtt_used) / 1024.0)
1827
1828 # CPU memory.
1829 stdout = ''
1830 with open('/proc/meminfo') as f:
1831 stdout = f.read()
1832 mem_free = re.search('MemFree:\s*([\d]+) kB', stdout).group(1)
1833 mem_dirty = re.search('Dirty:\s*([\d]+) kB', stdout).group(1)
Sonny 2012/04/26 04:55:18 Dirty Memory isn't really very interesting becaus
Sonny 2012/04/26 05:38:14 Now that I understand what mem_available is suppos
dennis_jeffrey 2012/04/26 18:47:39 See my comment at line 1846 below.
1834 mem_active_file = re.search(
1835 'Active\(file\):\s*([\d]+) kB', stdout).group(1)
1836 mem_inactive_file = re.search(
1837 'Inactive\(file\):\s*([\d]+) kB', stdout).group(1)
1838 stats['mem_available'].append(
1839 (int(mem_active_file) + int(mem_inactive_file)) - int(mem_dirty) +
1840 int(mem_free))
Sonny 2012/04/26 04:55:18 I'm not sure what mem_available is supposed to mea
ihf 2012/04/26 05:19:17 This was suggested by James as it is used for disc
James Cook 2012/04/26 05:25:59 It's apparently what Luigi uses in the kernel to p
Sonny 2012/04/26 05:38:14 Ah.. I see. That's not actually exactly true eith
dennis_jeffrey 2012/04/26 18:47:39 Let me know how the computation for available memo
Sonny 2012/04/26 22:25:40 so it should be MemFree + Inactive file + active f
dennis_jeffrey 2012/04/28 00:21:35 Done.
1841
1842 mem_shared = re.search('Shmem:\s*([\d]+) kB', stdout).group(1)
1843 stats['mem_shared'].append(int(mem_shared))
1844
1845 time.sleep(1)
1846
Sonny 2012/04/26 04:55:18 Also weren't we going to get the memory stats from
ihf 2012/04/26 05:19:17 First time I read about it.
Sonny 2012/04/26 05:38:14 we want the private and shared and possibly the ja
dennis_jeffrey 2012/04/26 18:47:39 Yes, there is lots more information that people wa
Sonny 2012/04/26 22:25:40 Ok... I just feel like we'll be adding more stuff
dennis_jeffrey 2012/04/28 00:21:35 We're now recording more different types of memory
1847 # Compute min, max, and ending values to return.
1848 result = {}
1849 for measurement_type in stats:
1850 values = stats[measurement_type]
1851 result[measurement_type] = {
1852 'min': min(values),
1853 'max': max(values),
1854 'end': values[-1],
1855 }
1856
1857 return result
1858
1859 def _RecordMemoryStats(self, description, when, duration):
1860 """Outputs memory statistics to be graphed.
1861
1862 Args:
1863 description: A string description for the test. Should not contain
1864 spaces. For example, 'MemCtrl'.
1865 when: A string description of when the memory stats are being recorded
1866 during test execution (since memory stats may be recorded multiple
1867 times during a test execution at certain "interesting" times). Should
1868 not contain spaces.
1869 duration: The number of seconds to sample data before outputting the
1870 memory statistics.
1871 """
1872 mem = self._GetMemoryStats(duration)
1873 measurement_types = [
1874 ('gtt', 'GTT'),
1875 ('mem_available', 'MemAvail'),
1876 ('mem_shared', 'MemShare'),
1877 ]
1878 for type_key, type_string in measurement_types:
1879 self._OutputPerfGraphValue(
1880 '%s-Min%s-%s' % (description, type_string, when),
1881 mem[type_key]['min'], 'KB', '%s-%s' % (description, type_string))
1882 self._OutputPerfGraphValue(
1883 '%s-Max%s-%s' % (description, type_string, when),
1884 mem[type_key]['max'], 'KB', '%s-%s' % (description, type_string))
1885 self._OutputPerfGraphValue(
1886 '%s-End%s-%s' % (description, type_string, when),
1887 mem[type_key]['end'], 'KB', '%s-%s' % (description, type_string))
1888
1889 def _RunTest(self, tabs, description, duration):
1890 """Runs a general memory test.
1891
1892 Args:
1893 tabs: A list of strings representing the URLs of the websites to open
1894 during this test.
1895 description: A string description for the test. Should not contain
1896 spaces. For example, 'MemCtrl'.
1897 duration: The number of seconds to sample data before outputting memory
1898 statistics.
1899 """
1900 self._RecordMemoryStats(description, '0Tabs0', duration)
1901
1902 for iteration_num in xrange(2):
1903 for site in tabs:
1904 self.AppendTab(pyauto.GURL(site))
1905
1906 self._RecordMemoryStats(description,
1907 '%dTabs%d' % (len(tabs), iteration_num + 1),
1908 duration)
Sonny 2012/04/26 04:55:18 I'm not sure we want to record after opening every
ihf 2012/04/26 05:19:17 This works exactly as you want it.
Sonny 2012/04/26 05:38:14 Ahh oops, didn't see the indent, thanks.
dennis_jeffrey 2012/04/26 18:47:39 Done - working as intended.
1909
1910 for _ in xrange(len(tabs)):
1911 self.GetBrowserWindow(0).GetTab(1).Close(True)
1912
1913 self._RecordMemoryStats(description, '0Tabs%d' % (iteration_num + 1),
1914 duration)
1915
1916 def testOpenCloseTabsControl(self):
1917 """Measures memory usage when opening/closing tabs to about:blank."""
1918 tabs = ['about:blank'] * 10
1919 self._RunTest(tabs, 'MemCtrl', 15)
1920
1921
1768 class PerfTestServerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 1922 class PerfTestServerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
1769 """Request handler for the local performance test server.""" 1923 """Request handler for the local performance test server."""
1770 1924
1771 def _IgnoreHandler(self, unused_args): 1925 def _IgnoreHandler(self, unused_args):
1772 """A GET request handler that simply replies with status code 200. 1926 """A GET request handler that simply replies with status code 200.
1773 1927
1774 Args: 1928 Args:
1775 unused_args: A dictionary of arguments for the current GET request. 1929 unused_args: A dictionary of arguments for the current GET request.
1776 The arguments are ignored. 1930 The arguments are ignored.
1777 """ 1931 """
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 """Identifies the port number to which the server is currently bound. 2144 """Identifies the port number to which the server is currently bound.
1991 2145
1992 Returns: 2146 Returns:
1993 The numeric port number to which the server is currently bound. 2147 The numeric port number to which the server is currently bound.
1994 """ 2148 """
1995 return self._server.server_address[1] 2149 return self._server.server_address[1]
1996 2150
1997 2151
1998 if __name__ == '__main__': 2152 if __name__ == '__main__':
1999 pyauto_functional.Main() 2153 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