#!/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()