зеркало из https://github.com/mozilla/gecko-dev.git
Bug 384341 - Talos Mac support. Also add environment variable settings,
quit.js to quit the browser afters tests, and ffprofile_unix with mac and linux code. r=alice
This commit is contained in:
Родитель
695f5ec87a
Коммит
7ec5a2bdde
|
@ -9,19 +9,28 @@ these performance tests:
|
|||
|
||||
Make sure to correctly set the path to python in the paths.py file.
|
||||
|
||||
After you download and install Python 2.4, you'll need to install
|
||||
After you download and install Python 2.4, Windows users will need to install
|
||||
some extensions:
|
||||
|
||||
* Python Win32 Extensions
|
||||
These extensions provide some support for process management and
|
||||
performance monitoring.
|
||||
http://prdownloads.sourceforge.net/pywin32/pywin32-208.win32-py2.4.exe?download
|
||||
|
||||
Mac users may use Python 2.3.5, included with Mac OS X, but they will need
|
||||
to download the 'subprocess.py' file included with more recent Python distributions
|
||||
and install it in the library path (/Library/Python/2.3/site-packages/).
|
||||
|
||||
* Apache HTTP Server
|
||||
Found at http://httpd.apache.org/
|
||||
The page cycler works on a local Apache server. After installing Apache simply place
|
||||
the page_load_test/ directory into htdocs/ directory of Apache (found on most systems
|
||||
at c:\Program Files\Apache Software Foundation\Apache2.2\htdocs)
|
||||
|
||||
* Syck YAML Parser
|
||||
You'll need to download and install Syck from http://whytheluckystiff.net/syck/
|
||||
Install the binary (a standard install) and the Python extension:
|
||||
cd ext/python/ && python setup.py build && sudo python setup.py install
|
||||
|
||||
1. Make sure the prerequisites, above, are installed.
|
||||
2. Copy this entire directory and all subdirectories onto your local disk
|
||||
|
@ -32,41 +41,8 @@ these performance tests:
|
|||
network.proxy.http_port:80 - these settings ensure that the browser will only
|
||||
contact local web pages and will not attempt to pull information from the live web,
|
||||
this is important for collecting consistant testing results.
|
||||
It should look something like this:
|
||||
|
||||
# Filename will be appended to the timestamp in the report filename.
|
||||
# Use letters and underscores only
|
||||
filename: testfilename
|
||||
|
||||
# The title of the report
|
||||
title: testtitle
|
||||
|
||||
# Name of profile to test
|
||||
Test profile 1:
|
||||
# Path to Firefox to test
|
||||
firefox: C:\cygwin\tmp\test\firefox\firefox\firefox.exe
|
||||
|
||||
branch: testbranch
|
||||
|
||||
branchid: testbranchid
|
||||
|
||||
profile_path: C:\win32\base_profile
|
||||
|
||||
# Preferences to set in the test (use "preferences : {}" for no prefs)
|
||||
preferences :
|
||||
browser.shell.checkDefaultBrowser : false
|
||||
dom.allow_scripts_to_close_windows : true
|
||||
dom.disable_open_during_load: false
|
||||
browser.dom.window.dump.enabled: true
|
||||
network.proxy.type : 1
|
||||
network.proxy.http : localhost
|
||||
network.proxy.http_port : 80
|
||||
|
||||
# Extensions to install in test (use "extensions: {}" for none)
|
||||
extensions :
|
||||
# Need quotes around guid because of curly braces
|
||||
"{12345678-1234-1234-1234-abcd12345678}" : c:\path\to\unzipped\xpi
|
||||
foo@sample.com : c:\path\to\other\unzipped\xpi
|
||||
Your config file should look something like the sample.config file in the
|
||||
Talos distribution.
|
||||
|
||||
5. Provide a pages/ directory
|
||||
The page_load_test/ relies upon having a pages directory that includes the web pages
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// This file is needed to work around a Firefox bug where capability.principal
|
||||
// prefs in user.js don't get recognized until the second browser launch
|
||||
// which is too late for our purposes of using quit.js. Loading the principals
|
||||
// from prefs.js avoids this issue.
|
||||
user_pref("capability.principal.codebase.p0.granted", "UniversalPreferencesWrite UniversalXPConnect UniversalPreferencesRead");
|
||||
user_pref("capability.principal.codebase.p0.id", "file://");
|
||||
user_pref("capability.principal.codebase.p0.subjectName", "");
|
||||
user_pref("signed.applets.codebase_principal_support", true);
|
|
@ -41,7 +41,6 @@
|
|||
|
||||
__author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
|
||||
|
||||
|
||||
BROWSER_HEIGHT = 768
|
||||
BROWSER_WIDTH = 1024
|
||||
|
||||
|
@ -85,12 +84,14 @@ TP_RESOLUTION = 1
|
|||
"""Run page load test.
|
||||
For possible values of counters argument on Windows, see
|
||||
http://technet2.microsoft.com/WindowsServer/en/Library/86b5d116-6fb3-427b-af8c-9077162125fe1033.mspx?mfr=true
|
||||
Possible values on Linux:
|
||||
Possible values on Linux and Mac:
|
||||
'Private Bytes', '% Processor Time', 'RSS'
|
||||
"""
|
||||
|
||||
COUNTERS = ['Private Bytes', 'Working Set', '% Processor Time']
|
||||
|
||||
"""URL for the results server"""
|
||||
RESULTS_SERVER = 'graphserver.url.here'
|
||||
RESULTS_LINK = '/bulk.cgi'
|
||||
|
||||
"""Enable/disable debugging output"""
|
||||
DEBUG = 0
|
||||
|
|
|
@ -45,6 +45,7 @@ import platform
|
|||
import os
|
||||
import re
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
import config
|
||||
|
||||
|
@ -52,6 +53,8 @@ if platform.system() == "Linux":
|
|||
from ffprocess_linux import *
|
||||
elif platform.system() == "Windows":
|
||||
from ffprocess_win32 import *
|
||||
elif platform.system() == "Darwin":
|
||||
from ffprocess_mac import *
|
||||
|
||||
|
||||
|
||||
|
@ -61,7 +64,7 @@ def SyncAndSleep():
|
|||
"""
|
||||
|
||||
os.spawnl(os.P_WAIT, config.SYNC)
|
||||
time.sleep(3)
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
def RunProcessAndWaitForOutput(command, process_name, output_regex, timeout):
|
||||
|
@ -83,7 +86,8 @@ def RunProcessAndWaitForOutput(command, process_name, output_regex, timeout):
|
|||
"""
|
||||
|
||||
# Start the process
|
||||
handle = os.popen(command)
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True, shell=True, env=os.environ)
|
||||
handle = process.stdout
|
||||
|
||||
# Wait for it to print output, terminate, or time out.
|
||||
time_elapsed = 0
|
||||
|
@ -96,7 +100,7 @@ def RunProcessAndWaitForOutput(command, process_name, output_regex, timeout):
|
|||
|
||||
(bytes, current_output) = NonBlockingReadProcessOutput(handle)
|
||||
output += current_output
|
||||
|
||||
|
||||
result = output_regex.search(output)
|
||||
if result:
|
||||
try:
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is standalone Firefox Mac performance test.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Google Inc.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2006
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Annie Sullivan <annie.sullivan@gmail.com> (original author)
|
||||
# Ben Hearsum <bhearsum@wittydomain.com> (OS independence)
|
||||
# Zach Lipton <zach@zachlipton.com> (Mac port)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import subprocess
|
||||
import signal
|
||||
import os
|
||||
import time
|
||||
import config
|
||||
from select import select
|
||||
|
||||
|
||||
def GenerateFirefoxCommandLine(firefox_path, profile_dir, url):
|
||||
"""Generates the command line for a process to run Firefox
|
||||
|
||||
Args:
|
||||
firefox_path: String containing the path to the firefox binary to use
|
||||
profile_dir: String containing the directory of the profile to run Firefox in
|
||||
url: String containing url to start with.
|
||||
"""
|
||||
|
||||
profile_arg = ''
|
||||
if profile_dir:
|
||||
profile_arg = '-profile %s' % profile_dir
|
||||
|
||||
url_arg = ''
|
||||
if url:
|
||||
url_arg = '-url %s' % url
|
||||
|
||||
cmd = '%s %s %s -width %d -height %d' % (firefox_path,
|
||||
profile_arg,
|
||||
url_arg,
|
||||
config.BROWSER_WIDTH,
|
||||
config.BROWSER_HEIGHT)
|
||||
return cmd
|
||||
|
||||
|
||||
def GetPidsByName(process_name):
|
||||
"""Searches for processes containing a given string.
|
||||
|
||||
Args:
|
||||
process_name: The string to be searched for
|
||||
|
||||
Returns:
|
||||
A list of PIDs containing the string. An empty list is returned if none are
|
||||
found.
|
||||
"""
|
||||
|
||||
matchingPids = []
|
||||
|
||||
command = ['ps -Axc']
|
||||
handle = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True, shell=True)
|
||||
|
||||
# wait for the process to terminate
|
||||
handle.wait()
|
||||
data = handle.stdout.readlines()
|
||||
|
||||
# find all matching processes and add them to the list
|
||||
for line in data:
|
||||
if line.find(process_name) >= 0:
|
||||
# splits by whitespace, the first one should be the pid
|
||||
pid = int(line.split()[0])
|
||||
matchingPids.append(pid)
|
||||
|
||||
return matchingPids
|
||||
|
||||
|
||||
def ProcessesWithNameExist(process_name):
|
||||
"""Returns true if there are any processes running with the
|
||||
given name. Useful to check whether a Firefox process is still running
|
||||
|
||||
Args:
|
||||
process_name: String containing the process name, i.e. "firefox"
|
||||
|
||||
Returns:
|
||||
True if any processes with that name are running, False otherwise.
|
||||
"""
|
||||
|
||||
pids = GetPidsByName(process_name)
|
||||
return len(pids) > 0
|
||||
|
||||
|
||||
def TerminateProcess(pid):
|
||||
"""Helper function to terminate a process, given the pid
|
||||
|
||||
Args:
|
||||
pid: integer process id of the process to terminate.
|
||||
"""
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
|
||||
def TerminateAllProcesses(process_name):
|
||||
"""Helper function to terminate all processes with the given process name
|
||||
|
||||
Args:
|
||||
process_name: String containing the process name, i.e. "firefox"
|
||||
"""
|
||||
pids = GetPidsByName(process_name)
|
||||
for pid in pids:
|
||||
TerminateProcess(pid)
|
||||
|
||||
def NonBlockingReadProcessOutput(handle):
|
||||
"""Does a non-blocking read from the output of the process
|
||||
with the given handle.
|
||||
|
||||
Args:
|
||||
handle: The process handle returned from os.popen()
|
||||
|
||||
Returns:
|
||||
A tuple (bytes, output) containing the number of output
|
||||
bytes read, and the actual output.
|
||||
"""
|
||||
|
||||
output = ""
|
||||
num_avail = 0
|
||||
|
||||
# check for data
|
||||
# select() does not seem to work well with pipes.
|
||||
# after data is available once it *always* thinks there is data available
|
||||
# readline() will continue to return an empty string however
|
||||
# so we can use this behavior to work around the problem
|
||||
while select([handle], [], [], 0)[0]:
|
||||
line = handle.readline()
|
||||
if line:
|
||||
output += line
|
||||
else:
|
||||
break
|
||||
# this statement is true for encodings that have 1byte/char
|
||||
num_avail = len(output)
|
||||
|
||||
return (num_avail, output)
|
|
@ -53,14 +53,16 @@ import shutil
|
|||
import tempfile
|
||||
import time
|
||||
|
||||
import utils
|
||||
import ffprocess
|
||||
import config
|
||||
|
||||
if platform.system() == "Linux":
|
||||
from ffprofile_linux import *
|
||||
from ffprofile_unix import *
|
||||
elif platform.system() == "Windows":
|
||||
from ffprofile_win32 import *
|
||||
|
||||
elif platform.system() == "Darwin":
|
||||
from ffprofile_unix import *
|
||||
|
||||
def PrefString(name, value, newline):
|
||||
"""Helper function to create a pref string for Firefox profile prefs.js
|
||||
|
@ -150,5 +152,6 @@ def InitializeNewProfile(firefox_path, profile_dir):
|
|||
time.sleep(5)
|
||||
if not ffprocess.ProcessesWithNameExist("firefox"):
|
||||
return
|
||||
|
||||
utils.debug("terminating firefox process")
|
||||
ffprocess.TerminateAllProcesses("firefox")
|
||||
ffprocess.SyncAndSleep()
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
# Contributor(s):
|
||||
# Annie Sullivan <annie.sullivan@gmail.com> (original author)
|
||||
# Ben Hearsum <bhearsum@wittydomain.com> (OS independence)
|
||||
# Zach Lipton <zach@zachlipton.com> (Mac port)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
@ -39,13 +39,15 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<script language="Javascript" type="text/javascript" src="page_load_test/quit.js"></script>
|
||||
<title>shutdown script</title>
|
||||
</head>
|
||||
|
||||
<body onload="
|
||||
if (window.dump) {
|
||||
dump('\n\n__metricsScreen width:' + screen.width + ' Screen height:' + screen.height + ' colorDepth:' + screen.colorDepth);
|
||||
dump('__metricsScreen width:' + screen.width + ' Screen height:' + screen.height + ' colorDepth:' + screen.colorDepth + '\n\n');
|
||||
}
|
||||
goQuitApplication();
|
||||
window.close();
|
||||
">
|
||||
</body>
|
||||
|
|
|
@ -38,10 +38,11 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<script language="Javascript" type="text/javascript" src="page_load_test/quit.js"></script>
|
||||
<title>shutdown script</title>
|
||||
</head>
|
||||
|
||||
<body onload="window.close();">
|
||||
<body onload="goQuitApplication(); window.close();">
|
||||
This page should close Firefox. If it does not, please make sure that
|
||||
the dom.allow_scripts_to_close_windows preference is set to true in
|
||||
<a href="about:config">about:config</a>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<html>
|
||||
<script language="Javascript" type="text/javascript" src="parray.js"></script>
|
||||
<script language="Javascript" type="text/javascript" src="quit.js"></script>
|
||||
<script>
|
||||
|
||||
var NUM_PAGES;
|
||||
var NUM_CYCLES;
|
||||
var DEFAULT_TIMEOUT = 25000; //how long any given page can take to load
|
||||
var QUIT; // whether to quit the app (with quit.js) after the tests
|
||||
var t;
|
||||
|
||||
function parseParams() {
|
||||
|
@ -24,6 +26,9 @@
|
|||
pages = pages.concat(pages_i18n);
|
||||
}
|
||||
break;
|
||||
case 'quit':
|
||||
QUIT = (fields[1] - 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!NUM_PAGES)
|
||||
|
@ -155,7 +160,7 @@
|
|||
}
|
||||
dump("\n")
|
||||
}
|
||||
dump("__end_tp_report\n");
|
||||
dump("__end_tp_report\n\n");
|
||||
//rstring += "__end_page_load_report";
|
||||
//alert(rstring);
|
||||
//dump(rstring);
|
||||
|
@ -203,6 +208,13 @@
|
|||
if (cycle == NUM_CYCLES) {
|
||||
showReport();
|
||||
dumpReport();
|
||||
|
||||
// use quit.js to quit the app if the quit param is true and
|
||||
// we have universalxpconnect privs:
|
||||
if (QUIT && canQuitApplication()) {
|
||||
goQuitApplication();
|
||||
}
|
||||
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla Automated Testing Code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Bob Clary <bob@bclary.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
From mozilla/toolkit/content
|
||||
These files did not have a license
|
||||
*/
|
||||
|
||||
function canQuitApplication()
|
||||
{
|
||||
var os = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
if (!os)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Components.interfaces.nsISupportsPRBool);
|
||||
os.notifyObservers(cancelQuit, "quit-application-requested", null);
|
||||
|
||||
// Something aborted the quit process.
|
||||
if (cancelQuit.data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
}
|
||||
os.notifyObservers(null, "quit-application-granted", null);
|
||||
return true;
|
||||
}
|
||||
|
||||
function goQuitApplication()
|
||||
{
|
||||
const privs = 'UniversalPreferencesRead UniversalPreferencesWrite ' +
|
||||
'UniversalXPConnect';
|
||||
|
||||
try
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege(privs);
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
throw('goQuitApplication: privilege failure ' + ex);
|
||||
}
|
||||
|
||||
if (!canQuitApplication())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const kAppStartup = '@mozilla.org/toolkit/app-startup;1';
|
||||
const kAppShell = '@mozilla.org/appshell/appShellService;1';
|
||||
var appService;
|
||||
var forceQuit;
|
||||
|
||||
if (kAppStartup in Components.classes)
|
||||
{
|
||||
appService = Components.classes[kAppStartup].
|
||||
getService(Components.interfaces.nsIAppStartup);
|
||||
forceQuit = Components.interfaces.nsIAppStartup.eForceQuit;
|
||||
|
||||
}
|
||||
else if (kAppShell in Components.classes)
|
||||
{
|
||||
appService = Components.classes[kAppShell].
|
||||
getService(Components.interfaces.nsIAppShellService);
|
||||
forceQuit = Components.interfaces.nsIAppShellService.eForceQuit;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw 'goQuitApplication: no AppStartup/appShell';
|
||||
}
|
||||
|
||||
var windowManager = Components.
|
||||
classes['@mozilla.org/appshell/window-mediator;1'].getService();
|
||||
|
||||
var windowManagerInterface = windowManager.
|
||||
QueryInterface(Components.interfaces.nsIWindowMediator);
|
||||
|
||||
var enumerator = windowManagerInterface.getEnumerator(null);
|
||||
|
||||
while (enumerator.hasMoreElements())
|
||||
{
|
||||
var domWindow = enumerator.getNext();
|
||||
if (("tryToClose" in domWindow) && !domWindow.tryToClose())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
domWindow.close();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
appService.quit(forceQuit);
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
throw('goQuitApplication: ' + ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +58,7 @@ import string
|
|||
import socket
|
||||
socket.setdefaulttimeout(480)
|
||||
|
||||
import utils
|
||||
import config
|
||||
import post_file
|
||||
import tp
|
||||
|
@ -80,7 +81,7 @@ def process_Request(post):
|
|||
lines = post.split('\n')
|
||||
for line in lines:
|
||||
if line.find("RETURN:") > -1:
|
||||
str += line.rsplit(":")[3] + ":" + shortNames(line.rsplit(":")[1]) + ":" + line.rsplit(":")[2] + '\n'
|
||||
str += line.split(":")[3] + ":" + shortNames(line.split(":")[1]) + ":" + line.split(":")[2] + '\n'
|
||||
return str
|
||||
|
||||
def test_file(filename):
|
||||
|
@ -117,7 +118,8 @@ def test_file(filename):
|
|||
yaml[item]['firefox'],
|
||||
yaml[item]['branch'],
|
||||
yaml[item]['branchid'],
|
||||
yaml[item]['profile_path']]
|
||||
yaml[item]['profile_path'],
|
||||
yaml[item]['env']]
|
||||
test_configs.append(new_config)
|
||||
test_names.append(item)
|
||||
config_file.close()
|
||||
|
@ -230,11 +232,11 @@ def test_file(filename):
|
|||
url = url_format % (config.RESULTS_SERVER, values[0],)
|
||||
link = link_format % (url, linkName,)
|
||||
print "RETURN: " + link
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
|
||||
# Read in each config file and run the tests on it.
|
||||
for i in range(1, len(sys.argv)):
|
||||
utils.debug("running test file " + sys.argv[i])
|
||||
test_file(sys.argv[i])
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# Sample Talos configuration file
|
||||
|
||||
# Filename will be appended to the timestamp in the report filename.
|
||||
# Use letters and underscores only
|
||||
filename: testfilename
|
||||
|
@ -28,8 +30,19 @@ Test profile 1:
|
|||
dom.disable_window_flip : true
|
||||
dom.disable_window_move_resize : true
|
||||
security.enable_java : false
|
||||
extensions.checkCompatibility : false
|
||||
extensions.update.notifyUser: false
|
||||
capability.principal.codebase.p0.granted : UniversalPreferencesWrite UniversalXPConnect UniversalPreferencesRead
|
||||
capability.principal.codebase.p0.id : file://
|
||||
capability.principal.codebase.p1.granted : UniversalXPConnect
|
||||
|
||||
# Extensions to install in test (use "extensions: {}" for none)
|
||||
#extensions:
|
||||
# Need quotes around guid because of curly braces
|
||||
# extensions :
|
||||
# "{12345678-1234-1234-1234-abcd12345678}" : c:\path\to\unzipped\xpi
|
||||
# foo@sample.com : c:\path\to\other\unzipped\xpi
|
||||
extensions : {}
|
||||
|
||||
|
||||
# Environment variables to set during test (use env: {} for none)
|
||||
env :
|
||||
NO_EM_RESTART : 1
|
||||
|
|
|
@ -33,17 +33,23 @@
|
|||
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||
- the provisions above, a recipient may use your version of this file under
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
<!-- Pick off begin time as a cgi argument and print it out -->
<html>
<!-- call this with an arg, e.g. file://foo/startup-test.html?begin=12345678 -->
<!-- In-line this to avoid compilation. -->
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
<!-- Pick off begin time as a cgi argument and print it out -->
|
||||
<html>
|
||||
<!-- call this with an arg, e.g. file://foo/startup-test.html?begin=12345678 -->
|
||||
<!-- In-line this to avoid compilation. -->
|
||||
|
||||
<body onload="
|
||||
var now = (new Date()).getTime();
|
||||
var begin = document.location.search.split('=')[1]; // ?begin=nnnnn
|
||||
var startupTime = now - begin;
|
||||
document.write('\n\nStartup time = ' + startupTime + ' ms<br>');
|
||||
if (window.dump) {
|
||||
dump('\n\n__startuptime,' + startupTime + '\n\n');
|
||||
dump('__startuptime,' + startupTime + '\n\n');
|
||||
}
|
||||
window.close();
|
||||
">
|
||||
">
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ import re
|
|||
import shutil
|
||||
import time
|
||||
import sys
|
||||
import subprocess
|
||||
import utils
|
||||
|
||||
import ffprocess
|
||||
import ffprofile
|
||||
|
@ -65,6 +67,8 @@ if platform.system() == "Linux":
|
|||
from tp_linux import *
|
||||
elif platform.system() == "Windows":
|
||||
from tp_win32 import *
|
||||
elif platform.system() == "Darwin":
|
||||
from tp_mac import *
|
||||
|
||||
|
||||
# Regular expression to get stats for page load test (Tp)
|
||||
|
@ -105,10 +109,11 @@ def RunPltTests(profile_configs,
|
|||
plt_results = []
|
||||
results_string = []
|
||||
for pconfig in profile_configs:
|
||||
print "in tp"
|
||||
utils.debug("running pageload tests")
|
||||
print pconfig
|
||||
sys.stdout.flush()
|
||||
rstring = ""
|
||||
utils.setEnvironmentVars(pconfig[6])
|
||||
# Create the new profile
|
||||
profile_dir = ffprofile.CreateTempProfileDir(pconfig[5],
|
||||
pconfig[0],
|
||||
|
@ -127,9 +132,10 @@ def RunPltTests(profile_configs,
|
|||
timeout = 10000
|
||||
total_time = 0
|
||||
output = ''
|
||||
url = config.TP_URL + '?cycles=' + str(num_cycles)
|
||||
url = config.TP_URL + '?quit=1&cycles=' + str(num_cycles)
|
||||
command_line = ffprocess.GenerateFirefoxCommandLine(pconfig[2], profile_dir, url)
|
||||
handle = os.popen(command_line)
|
||||
process = subprocess.Popen(command_line, stdout=subprocess.PIPE, universal_newlines=True, shell=True, bufsize=0, env=os.environ)
|
||||
handle = process.stdout
|
||||
# give firefox a chance to open
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -185,6 +191,8 @@ def RunPltTests(profile_configs,
|
|||
ffprofile.MakeDirectoryContentsWritable(profile_dir)
|
||||
shutil.rmtree(profile_dir)
|
||||
|
||||
utils.restoreEnvironmentVars()
|
||||
|
||||
counter_data.append(counts)
|
||||
results_string.append(rstring)
|
||||
|
||||
|
|
|
@ -95,49 +95,8 @@ def GetResidentSize(pid):
|
|||
|
||||
|
||||
def GetCpuTime(pid, sampleTime=1):
|
||||
"""Calculates the percent of time a process spent executing
|
||||
This function samples /proc/PID/status at a rate of 20samples/sec to
|
||||
check whether a process is active or idle.
|
||||
|
||||
Args:
|
||||
pid: The PID of process to calculate time for
|
||||
sampleTime: The length of time to monitor the process for. If this
|
||||
argument is unspecified or 0 it will be monitored until
|
||||
it terminates
|
||||
Returns:
|
||||
A percent of time a PID was idle (between 0.00 and 100.00)
|
||||
"""
|
||||
file = '/proc/%s/status' % pid
|
||||
|
||||
sampleInterval = .05
|
||||
totalSamples = (1 / sampleInterval) * sampleTime
|
||||
|
||||
states = []
|
||||
|
||||
while os.path.exists(file):
|
||||
status = open(file)
|
||||
|
||||
for line in status:
|
||||
if line.find("State") >= 0:
|
||||
states.append(line.split()[1])
|
||||
|
||||
# check to see if we've reached the maximum number of samples
|
||||
if totalSamples != 0 and len(states) >= totalSamples:
|
||||
break;
|
||||
|
||||
time.sleep(sampleInterval);
|
||||
|
||||
# non-idle cpu time = active cpu time / total cpu time
|
||||
# ex: 10 total cycles, 8 idle cycles, 2 active cycles
|
||||
# non-idle cpu time = 2 / 10
|
||||
# non-idle cpu time = .2 (20%)
|
||||
try:
|
||||
activeCpuTime = float(states.count("R")) / float(len(states))
|
||||
except ZeroDivisionError:
|
||||
activeCpuTime = -1
|
||||
|
||||
return float("%.2lf" % (activeCpuTime * 100))
|
||||
|
||||
# return all zeros on this platform as per the 7/18/07 perf meeting
|
||||
return 0
|
||||
|
||||
counterDict = {}
|
||||
counterDict["Private Bytes"] = GetPrivateBytes
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is standalone Firefox Windows performance test.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Google Inc.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2006
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Annie Sullivan <annie.sullivan@gmail.com> (original author)
|
||||
# Ben Hearsum <bhearsum@wittydomain.com> (ported to linux)
|
||||
# Zach Lipton <zach@zachlipton.com> (Mac port)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
"""A set of functions to run the Tp test.
|
||||
|
||||
The Tp test measures page load times in Firefox. It does this with a
|
||||
JavaScript script that opens a new window and cycles through page loads
|
||||
from the local disk, timing each one. The script dumps the sum of the
|
||||
mean times to open each page, and the standard deviation, to standard out.
|
||||
We can also measure performance attributes during the test. See below for
|
||||
what can be monitored
|
||||
"""
|
||||
|
||||
__author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
|
||||
|
||||
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
import subprocess
|
||||
|
||||
import ffprocess
|
||||
|
||||
def GetProcessData(pid):
|
||||
"""Runs a ps on the process identified by pid and returns the output line
|
||||
as a list (uid, pid, ppid, cpu, pri, ni, vsz, rss, wchan, stat, tt, time, command)
|
||||
"""
|
||||
command = ['ps -Acup'+str(pid)]
|
||||
handle = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True, shell=True)
|
||||
handle.wait()
|
||||
data = handle.stdout.readlines()
|
||||
|
||||
# find all matching processes and add them to the list
|
||||
for line in data:
|
||||
if line.find(str(pid)) >= 0:
|
||||
# splits by whitespace
|
||||
line = line.split()
|
||||
if (line[1] == str(pid)):
|
||||
return line
|
||||
|
||||
def GetPrivateBytes(pid):
|
||||
"""Calculate the amount of private, writeable memory allocated to a process.
|
||||
"""
|
||||
psData = GetProcessData(pid)
|
||||
return psData[5]
|
||||
|
||||
|
||||
def GetResidentSize(pid):
|
||||
"""Retrieve the current resident memory for a given process"""
|
||||
psData = GetProcessData(pid)
|
||||
return psData[4]
|
||||
|
||||
def GetCpuTime(pid):
|
||||
# return all zeros for now on this platform as per 7/18/07 perf meeting
|
||||
return 0
|
||||
|
||||
counterDict = {}
|
||||
counterDict["Private Bytes"] = GetPrivateBytes
|
||||
counterDict["RSS"] = GetResidentSize
|
||||
counterDict["% Processor Time"] = GetCpuTime
|
||||
|
||||
class CounterManager(threading.Thread):
|
||||
"""This class manages the monitoring of a process with any number of
|
||||
counters.
|
||||
|
||||
A counter can be any function that takes an argument of one pid and
|
||||
returns a piece of data about that process.
|
||||
Some examples are: CalcCPUTime, GetResidentSize, and GetPrivateBytes
|
||||
"""
|
||||
|
||||
pollInterval = .25
|
||||
|
||||
def __init__(self, process, counters=None):
|
||||
"""Args:
|
||||
counters: A list of counters to monitor. Any counters whose name does
|
||||
not match a key in 'counterDict' will be ignored.
|
||||
"""
|
||||
self.allCounters = {}
|
||||
self.registeredCounters = {}
|
||||
self.process = process
|
||||
self.runThread = False
|
||||
self.pid = -1
|
||||
|
||||
self._loadCounters()
|
||||
self.registerCounters(counters)
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def _loadCounters(self):
|
||||
"""Loads all of the counters defined in the counterDict"""
|
||||
for counter in counterDict.keys():
|
||||
self.allCounters[counter] = counterDict[counter]
|
||||
|
||||
def registerCounters(self, counters):
|
||||
"""Registers a list of counters that will be monitoring.
|
||||
Only counters whose names are found in allCounters will be added
|
||||
"""
|
||||
for counter in counters:
|
||||
if counter in self.allCounters:
|
||||
self.registeredCounters[counter] = \
|
||||
[self.allCounters[counter], []]
|
||||
|
||||
def unregisterCounters(self, counters):
|
||||
"""Unregister a list of counters.
|
||||
Only counters whose names are found in registeredCounters will be
|
||||
paid attention to
|
||||
"""
|
||||
for counter in counters:
|
||||
if counter in self.registeredCounters:
|
||||
del self.registeredCounters[counter]
|
||||
|
||||
def getRegisteredCounters(self):
|
||||
"""Returns a list of the registered counters."""
|
||||
return keys(self.registeredCounters)
|
||||
|
||||
def getCounterValue(self, counterName):
|
||||
"""Returns the last value of the counter 'counterName'"""
|
||||
try:
|
||||
if counterName is "% Processor Time":
|
||||
return self._getCounterAverage(counterName)
|
||||
else:
|
||||
return self.registeredCounters[counterName][1][-1]
|
||||
except:
|
||||
return None
|
||||
|
||||
def _getCounterAverage(self, counterName):
|
||||
"""Returns the average value of the counter 'counterName'"""
|
||||
try:
|
||||
total = 0
|
||||
for v in self.registeredCounters[counterName][1]:
|
||||
total += v
|
||||
return total / len(self.registeredCounters[counterName][1])
|
||||
except:
|
||||
return None
|
||||
|
||||
def getProcess(self):
|
||||
"""Returns the process currently associated with this CounterManager"""
|
||||
return self.process
|
||||
|
||||
def startMonitor(self):
|
||||
"""Starts the monitoring process.
|
||||
Throws an exception if any error occurs
|
||||
"""
|
||||
# TODO: make this function less ugly
|
||||
try:
|
||||
# the last process is the useful one
|
||||
self.pid = ffprocess.GetPidsByName(self.process)[-1]
|
||||
self.runThread = True
|
||||
self.start()
|
||||
except:
|
||||
raise
|
||||
|
||||
def stopMonitor(self):
|
||||
"""Stops the monitor"""
|
||||
# TODO: should probably wait until we know run() is completely stopped
|
||||
# before setting self.pid to None. Use a lock?
|
||||
self.runThread = False
|
||||
|
||||
def run(self):
|
||||
"""Performs the actual monitoring of the process. Will keep running
|
||||
until stopMonitor() is called
|
||||
"""
|
||||
while self.runThread:
|
||||
for counter in self.registeredCounters.keys():
|
||||
# counter[0] is a function that gets the current value for
|
||||
# a counter
|
||||
# counter[1] is a list of recorded values
|
||||
try:
|
||||
self.registeredCounters[counter][1].append(
|
||||
self.registeredCounters[counter][0](self.pid))
|
||||
except:
|
||||
# if a counter throws an exception, remove it
|
||||
self.unregisterCounters([counter])
|
||||
|
||||
time.sleep(self.pollInterval)
|
|
@ -52,6 +52,7 @@ import re
|
|||
import shutil
|
||||
import time
|
||||
|
||||
import utils
|
||||
import ffprocess
|
||||
import ffprofile
|
||||
import ffinfo
|
||||
|
@ -91,6 +92,7 @@ def RunStartupTest(firefox_path, profile_dir, num_runs, timeout):
|
|||
startup_times = []
|
||||
for i in range(-1, num_runs):
|
||||
# Make sure we don't get "Firefox is already running..." errors
|
||||
utils.debug("syncing and sleeping")
|
||||
ffprocess.SyncAndSleep()
|
||||
|
||||
# Create a command line that passes in the url of the startup test
|
||||
|
@ -98,15 +100,19 @@ def RunStartupTest(firefox_path, profile_dir, num_runs, timeout):
|
|||
time_arg = int(time.time() * 1000)
|
||||
url = config.TS_URL + str(time_arg)
|
||||
command_line = ffprocess.GenerateFirefoxCommandLine(firefox_path, profile_dir, url)
|
||||
utils.debug("about to run ts test iteration")
|
||||
(match, timed_out) = ffprocess.RunProcessAndWaitForOutput(command_line,
|
||||
'firefox',
|
||||
TS_REGEX,
|
||||
timeout)
|
||||
if match > 0:
|
||||
utils.debug("ts output match is " + match)
|
||||
else:
|
||||
utils.debug("ts failed to match")
|
||||
if timed_out or not IsInteger(match):
|
||||
match = None
|
||||
if i > -1 and match and match > 0:
|
||||
startup_times.append(match)
|
||||
|
||||
return startup_times
|
||||
|
||||
|
||||
|
@ -123,18 +129,22 @@ def RunStartupTests(profile_configs, num_runs):
|
|||
Returns:
|
||||
Array of arrays of startup times, one for each profile.
|
||||
"""
|
||||
|
||||
utils.debug("Running startup time tests")
|
||||
all_times = []
|
||||
for config in profile_configs:
|
||||
utils.setEnvironmentVars(config[6])
|
||||
# Create the new profile
|
||||
profile_dir = ffprofile.CreateTempProfileDir(config[5],
|
||||
config[0],
|
||||
config[1])
|
||||
|
||||
utils.debug("temp profile dir created")
|
||||
# Run Firefox once with new profile so initializing it doesn't
|
||||
# cause a performance hit, and the second Firefox that gets
|
||||
# created is properly terminated.
|
||||
utils.debug("initializing new profile")
|
||||
ffprofile.InitializeNewProfile(config[2], profile_dir)
|
||||
|
||||
utils.debug("getting configuration metrics from browser")
|
||||
ffinfo.GetMetricsFromBrowser(config[2], profile_dir)
|
||||
|
||||
# Run the startup tests for this profile and log the results.
|
||||
|
@ -147,5 +157,7 @@ def RunStartupTests(profile_configs, num_runs):
|
|||
ffprocess.SyncAndSleep()
|
||||
ffprofile.MakeDirectoryContentsWritable(profile_dir)
|
||||
shutil.rmtree(profile_dir)
|
||||
|
||||
utils.restoreEnvironmentVars()
|
||||
|
||||
return all_times
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is standalone Firefox performance tests.
|
||||
#
|
||||
# The Initial Developer of the Original Code is The Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Zach Lipton <zach@zachlipton.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
"""Utility functions"""
|
||||
|
||||
import config
|
||||
import os
|
||||
|
||||
saved_environment = {}
|
||||
|
||||
def debug(message):
|
||||
"""Prints a debug message to the console if the DEBUG switch is turned on
|
||||
in config.py
|
||||
Args:
|
||||
message: string containing a debugging statement
|
||||
"""
|
||||
if config.DEBUG == 1:
|
||||
print message
|
||||
|
||||
def setEnvironmentVars(newVars):
|
||||
"""Sets environment variables as specified by env, an array of variables
|
||||
from config.py"""
|
||||
env = os.environ
|
||||
for var in newVars:
|
||||
# save the old values so they can be restored later:
|
||||
try:
|
||||
saved_environment[var] = str(env[var])
|
||||
except :
|
||||
saved_environment[var] = ""
|
||||
env[var] = str(newVars[var])
|
||||
|
||||
def restoreEnvironmentVars():
|
||||
"""Restores environment variables to the state they were in before
|
||||
setEnvironmentVars() was last called"""
|
||||
for var in saved_environment:
|
||||
os.environ[var] = saved_environment[var]
|
Загрузка…
Ссылка в новой задаче