15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto_functional  # Must be imported before pyauto
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import test_utils
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryTest(pyauto.PyUITest):
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Tests for memory usage of Chrome-related processes.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  These tests are meant to be used manually, not as part of the continuous
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  test cycle.  This is because each test starts up and periodically
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  measures/records the memory usage of a relevant Chrome process, doing so
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  repeatedly until the test is manually killed.  Currently, this script only
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  works in Linux and ChromeOS, as it uses a Linux shell command to query the
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  system for process memory usage info (test_utils.GetMemoryUsageOfProcess()).
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The tests in this suite produce the following output files (relative to the
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current working directory):
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testTabRendererProcessMemoryUsage: 'renderer_process_mem.txt'
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testExtensionProcessMemoryUsage:   'extension_process_mem.txt'
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Constants for all tests in this suite.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NUM_SECONDS_BETWEEN_MEASUREMENTS = 10
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MEASUREMENT_LOG_MESSAGE_TEMPLATE = '[%s] %.2f MB (pid: %d)'
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_TO_OUTPUT_FILE = True
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Constants for testTabRendererProcessMemoryUsage.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RENDERER_PROCESS_URL = 'http://chrome.angrybirds.com'
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RENDERER_PROCESS_OUTPUT_FILE = 'renderer_process_mem.txt'
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Constants for testExtensionProcessMemoryUsage.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_LOCATION = os.path.abspath(os.path.join(
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto.PyUITest.DataDir(), 'extensions', 'google_talk.crx'))
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_PROCESS_NAME = 'Google Talk'
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_PROCESS_OUTPUT_FILE = 'extension_process_mem.txt'
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetPidOfExtensionProcessByName(self, name):
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Identifies the process ID of an extension process, given its name.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name: The string name of an extension process, as returned by the function
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            GetBrowserInfo().
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The integer process identifier (PID) for the specified process, or
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None if the PID cannot be identified.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info = self.GetBrowserInfo()['extension_views']
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pid = [x['pid'] for x in info if x['name'] == '%s' % name]
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if pid:
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return pid[0]
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _LogMessage(self, log_file, msg):
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Logs a message to the screen, and to a log file if necessary.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_file: The string name of a log file to which to write.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      msg: The message to log.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print msg
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stdout.flush()
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.LOG_TO_OUTPUT_FILE:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print >>open(log_file, 'a'), msg
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testTabRendererProcessMemoryUsage(self):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Test the memory usage of the renderer process for a tab.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This test periodically queries the system for the current memory usage
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of a tab's renderer process.  The test will take measurements forever; you
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    must manually kill the test to terminate it.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self.LOG_TO_OUTPUT_FILE and
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.path.exists(self.RENDERER_PROCESS_OUTPUT_FILE)):
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.remove(self.RENDERER_PROCESS_OUTPUT_FILE)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(self.RENDERER_PROCESS_URL)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._LogMessage(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.RENDERER_PROCESS_OUTPUT_FILE,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Memory usage for renderer process of a tab navigated to: "%s"' % (
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.RENDERER_PROCESS_URL))
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # A user must manually kill this test to terminate the following loop.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while True:
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pid = self.GetBrowserInfo()['windows'][0]['tabs'][0]['renderer_pid']
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usage = test_utils.GetMemoryUsageOfProcess(pid)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_time = time.asctime(time.localtime(time.time()))
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._LogMessage(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self.RENDERER_PROCESS_OUTPUT_FILE,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid))
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testExtensionProcessMemoryUsage(self):
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Test the memory usage of an extension process.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This test periodically queries the system for the current memory usage
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of an extension process.  The test will take measurements forever; you
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    must manually kill the test to terminate it.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self.LOG_TO_OUTPUT_FILE and
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.path.exists(self.EXTENSION_PROCESS_OUTPUT_FILE)):
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.remove(self.EXTENSION_PROCESS_OUTPUT_FILE)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.InstallExtension(self.EXTENSION_LOCATION)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The PID is 0 until the extension has a chance to start up.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitUntil(
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: self._GetPidOfExtensionProcessByName(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    self.EXTENSION_PROCESS_NAME) not in [0, None])
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._LogMessage(
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.EXTENSION_PROCESS_OUTPUT_FILE,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Memory usage for extension process with name: "%s"' % (
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self.EXTENSION_PROCESS_NAME))
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # A user must manually kill this test to terminate the following loop.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while True:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pid = self._GetPidOfExtensionProcessByName(self.EXTENSION_PROCESS_NAME)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usage = test_utils.GetMemoryUsageOfProcess(pid)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_time = time.asctime(time.localtime(time.time()))
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._LogMessage(
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self.EXTENSION_PROCESS_OUTPUT_FILE,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid))
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pyauto_functional.Main()
135