• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Copyright (c) 2011 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import os
7import sys
8import time
9
10import pyauto_functional  # Must be imported before pyauto
11import pyauto
12import test_utils
13
14
15class MemoryTest(pyauto.PyUITest):
16  """Tests for memory usage of Chrome-related processes.
17
18  These tests are meant to be used manually, not as part of the continuous
19  test cycle.  This is because each test starts up and periodically
20  measures/records the memory usage of a relevant Chrome process, doing so
21  repeatedly until the test is manually killed.  Currently, this script only
22  works in Linux and ChromeOS, as it uses a Linux shell command to query the
23  system for process memory usage info (test_utils.GetMemoryUsageOfProcess()).
24
25  The tests in this suite produce the following output files (relative to the
26  current working directory):
27
28  testTabRendererProcessMemoryUsage: 'renderer_process_mem.txt'
29  testExtensionProcessMemoryUsage:   'extension_process_mem.txt'
30  """
31
32  # Constants for all tests in this suite.
33  NUM_SECONDS_BETWEEN_MEASUREMENTS = 10
34  MEASUREMENT_LOG_MESSAGE_TEMPLATE = '[%s] %.2f MB (pid: %d)'
35  LOG_TO_OUTPUT_FILE = True
36
37  # Constants for testTabRendererProcessMemoryUsage.
38  RENDERER_PROCESS_URL = 'http://chrome.angrybirds.com'
39  RENDERER_PROCESS_OUTPUT_FILE = 'renderer_process_mem.txt'
40
41  # Constants for testExtensionProcessMemoryUsage.
42  EXTENSION_LOCATION = os.path.abspath(os.path.join(
43      pyauto.PyUITest.DataDir(), 'extensions', 'google_talk.crx'))
44  EXTENSION_PROCESS_NAME = 'Google Talk'
45  EXTENSION_PROCESS_OUTPUT_FILE = 'extension_process_mem.txt'
46
47  def _GetPidOfExtensionProcessByName(self, name):
48    """Identifies the process ID of an extension process, given its name.
49
50    Args:
51      name: The string name of an extension process, as returned by the function
52            GetBrowserInfo().
53
54    Returns:
55      The integer process identifier (PID) for the specified process, or
56      None if the PID cannot be identified.
57    """
58    info = self.GetBrowserInfo()['extension_views']
59    pid = [x['pid'] for x in info if x['name'] == '%s' % name]
60    if pid:
61      return pid[0]
62    return None
63
64  def _LogMessage(self, log_file, msg):
65    """Logs a message to the screen, and to a log file if necessary.
66
67    Args:
68      log_file: The string name of a log file to which to write.
69      msg: The message to log.
70    """
71    print msg
72    sys.stdout.flush()
73    if self.LOG_TO_OUTPUT_FILE:
74      print >>open(log_file, 'a'), msg
75
76  def testTabRendererProcessMemoryUsage(self):
77    """Test the memory usage of the renderer process for a tab.
78
79    This test periodically queries the system for the current memory usage
80    of a tab's renderer process.  The test will take measurements forever; you
81    must manually kill the test to terminate it.
82    """
83    if (self.LOG_TO_OUTPUT_FILE and
84        os.path.exists(self.RENDERER_PROCESS_OUTPUT_FILE)):
85      os.remove(self.RENDERER_PROCESS_OUTPUT_FILE)
86    self.NavigateToURL(self.RENDERER_PROCESS_URL)
87    self._LogMessage(
88        self.RENDERER_PROCESS_OUTPUT_FILE,
89        'Memory usage for renderer process of a tab navigated to: "%s"' % (
90            self.RENDERER_PROCESS_URL))
91
92    # A user must manually kill this test to terminate the following loop.
93    while True:
94      pid = self.GetBrowserInfo()['windows'][0]['tabs'][0]['renderer_pid']
95      usage = test_utils.GetMemoryUsageOfProcess(pid)
96      current_time = time.asctime(time.localtime(time.time()))
97      self._LogMessage(
98          self.RENDERER_PROCESS_OUTPUT_FILE,
99          self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid))
100      time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS)
101
102  def testExtensionProcessMemoryUsage(self):
103    """Test the memory usage of an extension process.
104
105    This test periodically queries the system for the current memory usage
106    of an extension process.  The test will take measurements forever; you
107    must manually kill the test to terminate it.
108    """
109    if (self.LOG_TO_OUTPUT_FILE and
110        os.path.exists(self.EXTENSION_PROCESS_OUTPUT_FILE)):
111      os.remove(self.EXTENSION_PROCESS_OUTPUT_FILE)
112    self.InstallExtension(self.EXTENSION_LOCATION)
113    # The PID is 0 until the extension has a chance to start up.
114    self.WaitUntil(
115        lambda: self._GetPidOfExtensionProcessByName(
116                    self.EXTENSION_PROCESS_NAME) not in [0, None])
117    self._LogMessage(
118        self.EXTENSION_PROCESS_OUTPUT_FILE,
119        'Memory usage for extension process with name: "%s"' % (
120            self.EXTENSION_PROCESS_NAME))
121
122    # A user must manually kill this test to terminate the following loop.
123    while True:
124      pid = self._GetPidOfExtensionProcessByName(self.EXTENSION_PROCESS_NAME)
125      usage = test_utils.GetMemoryUsageOfProcess(pid)
126      current_time = time.asctime(time.localtime(time.time()))
127      self._LogMessage(
128          self.EXTENSION_PROCESS_OUTPUT_FILE,
129          self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid))
130      time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS)
131
132
133if __name__ == '__main__':
134  pyauto_functional.Main()
135