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