| #!/usr/bin/env python |
| # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import sys |
| import time |
| |
| import pyauto_functional # Must be imported before pyauto |
| import pyauto |
| import test_utils |
| |
| |
| class MemoryTest(pyauto.PyUITest): |
| """Tests for memory usage of Chrome-related processes. |
| |
| These tests are meant to be used manually, not as part of the continuous |
| test cycle. This is because each test starts up and periodically |
| measures/records the memory usage of a relevant Chrome process, doing so |
| repeatedly until the test is manually killed. Currently, this script only |
| works in Linux and ChromeOS, as it uses a Linux shell command to query the |
| system for process memory usage info (test_utils.GetMemoryUsageOfProcess()). |
| |
| The tests in this suite produce the following output files (relative to the |
| current working directory): |
| |
| testTabRendererProcessMemoryUsage: 'renderer_process_mem.txt' |
| testExtensionProcessMemoryUsage: 'extension_process_mem.txt' |
| """ |
| |
| # Constants for all tests in this suite. |
| NUM_SECONDS_BETWEEN_MEASUREMENTS = 10 |
| MEASUREMENT_LOG_MESSAGE_TEMPLATE = '[%s] %.2f MB (pid: %d)' |
| LOG_TO_OUTPUT_FILE = True |
| |
| # Constants for testTabRendererProcessMemoryUsage. |
| RENDERER_PROCESS_URL = 'http://chrome.angrybirds.com' |
| RENDERER_PROCESS_OUTPUT_FILE = 'renderer_process_mem.txt' |
| |
| # Constants for testExtensionProcessMemoryUsage. |
| EXTENSION_LOCATION = os.path.abspath(os.path.join( |
| pyauto.PyUITest.DataDir(), 'extensions', 'google_talk.crx')) |
| EXTENSION_PROCESS_NAME = 'Google Talk' |
| EXTENSION_PROCESS_OUTPUT_FILE = 'extension_process_mem.txt' |
| |
| def _GetPidOfExtensionProcessByName(self, name): |
| """Identifies the process ID of an extension process, given its name. |
| |
| Args: |
| name: The string name of an extension process, as returned by the function |
| GetBrowserInfo(). |
| |
| Returns: |
| The integer process identifier (PID) for the specified process, or |
| None if the PID cannot be identified. |
| """ |
| info = self.GetBrowserInfo()['extension_views'] |
| pid = [x['pid'] for x in info if x['name'] == '%s' % name] |
| if pid: |
| return pid[0] |
| return None |
| |
| def _LogMessage(self, log_file, msg): |
| """Logs a message to the screen, and to a log file if necessary. |
| |
| Args: |
| log_file: The string name of a log file to which to write. |
| msg: The message to log. |
| """ |
| print msg |
| sys.stdout.flush() |
| if self.LOG_TO_OUTPUT_FILE: |
| print >>open(log_file, 'a'), msg |
| |
| def testTabRendererProcessMemoryUsage(self): |
| """Test the memory usage of the renderer process for a tab. |
| |
| This test periodically queries the system for the current memory usage |
| of a tab's renderer process. The test will take measurements forever; you |
| must manually kill the test to terminate it. |
| """ |
| if (self.LOG_TO_OUTPUT_FILE and |
| os.path.exists(self.RENDERER_PROCESS_OUTPUT_FILE)): |
| os.remove(self.RENDERER_PROCESS_OUTPUT_FILE) |
| self.NavigateToURL(self.RENDERER_PROCESS_URL) |
| self._LogMessage( |
| self.RENDERER_PROCESS_OUTPUT_FILE, |
| 'Memory usage for renderer process of a tab navigated to: "%s"' % ( |
| self.RENDERER_PROCESS_URL)) |
| |
| # A user must manually kill this test to terminate the following loop. |
| while True: |
| pid = self.GetBrowserInfo()['windows'][0]['tabs'][0]['renderer_pid'] |
| usage = test_utils.GetMemoryUsageOfProcess(pid) |
| current_time = time.asctime(time.localtime(time.time())) |
| self._LogMessage( |
| self.RENDERER_PROCESS_OUTPUT_FILE, |
| self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid)) |
| time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS) |
| |
| def testExtensionProcessMemoryUsage(self): |
| """Test the memory usage of an extension process. |
| |
| This test periodically queries the system for the current memory usage |
| of an extension process. The test will take measurements forever; you |
| must manually kill the test to terminate it. |
| """ |
| if (self.LOG_TO_OUTPUT_FILE and |
| os.path.exists(self.EXTENSION_PROCESS_OUTPUT_FILE)): |
| os.remove(self.EXTENSION_PROCESS_OUTPUT_FILE) |
| self.InstallExtension(self.EXTENSION_LOCATION) |
| # The PID is 0 until the extension has a chance to start up. |
| self.WaitUntil( |
| lambda: self._GetPidOfExtensionProcessByName( |
| self.EXTENSION_PROCESS_NAME) not in [0, None]) |
| self._LogMessage( |
| self.EXTENSION_PROCESS_OUTPUT_FILE, |
| 'Memory usage for extension process with name: "%s"' % ( |
| self.EXTENSION_PROCESS_NAME)) |
| |
| # A user must manually kill this test to terminate the following loop. |
| while True: |
| pid = self._GetPidOfExtensionProcessByName(self.EXTENSION_PROCESS_NAME) |
| usage = test_utils.GetMemoryUsageOfProcess(pid) |
| current_time = time.asctime(time.localtime(time.time())) |
| self._LogMessage( |
| self.EXTENSION_PROCESS_OUTPUT_FILE, |
| self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid)) |
| time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS) |
| |
| |
| if __name__ == '__main__': |
| pyauto_functional.Main() |