Merge from trunk WEB_CONTENT_HANDLING_20070621_BRANCH WEB_CONTENT_HANDLING_20070621_POSTMERGE_20070719 WEB_CONTENT_HANDLING_20070621_POSTMERGE_20070719_FIXED WEB_CONTENT_HANDLING_20070621_POST_HANDLER_SERVICE_20070720
authorDan Mosedale <dmose@mozilla.org>
Thu, 19 Jul 2007 21:57:21 +0000
branchWEB_CONTENT_HANDLING_20070621_BRANCH
changeset 195 1f6ba03e33ad80c50372ca5079e8ff16fb530a7b
parent 2 08b5c641ae5da4fbd7af292ff0847779ff47f93f
push id1
push useranodelman@mozilla.com
push dateMon, 13 Sep 2010 22:12:15 +0000
Merge from trunk
README.txt
base_profile/localstore.rdf
config.py
ffinfo.py
ffprocess.py
ffprocess_linux.py
ffprocess_win32.py
ffprofile.py
ffprofile_win32.py
getInfo.html
page_load_test/framecycler.html
page_load_test/parray.js
page_load_test/report.html
post_file.py
run_tests.py
sample.config
startup_test/startup_test.html
tp.py
tp_linux.py
tp_win32.py
ts.py
--- a/README.txt
+++ b/README.txt
@@ -1,9 +1,100 @@
-PREREQUISITES:
You'll need to download some software onto your Windows machine before running
these performance tests:
-  * Python 2.4
    The scripts all run from Python 2.4.  You will need the windows version
-    (not the cygwin version).  You can download it here:
    http://www.python.org/ftp/python/2.4/python-2.4.msi
-    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
    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
-      * Numerical Python:
        This is required by Matplotlib.
        http://prdownloads.sourceforge.net/numpy/Numeric-24.2.win32-py2.4.exe?download
-      * Matplotlib
        This library is used to plot the graphs of performance characteristics
        of Firefox during the page load test.
        http://prdownloads.sourceforge.net/matplotlib/matplotlib-0.87.3.win32-py2.4.exe?download

      * PySyc
        This is used for reading/writing config files in YAML.
        http://pyyaml.org/download/pysyck/PySyck-0.61.2.win32-py2.4.exe

  * Cygwin
    For some reason, we can't get output from Firefox unless it's wrapped in a
    Cygwin sh shell.  So we use cygwin for that, and to sync between Firefox
    runs.  Download it here:
    http://www.cygwin.com/setup.exe

    Make sure to correctly set the path to Cygwin in the paths.py file.

  * msvcp71.dll
    You need a copy of this file to run Python with all the libraries.  If you have
    Visual Studio 2003 installed, you've already got it.

SETUP:
-  1. Make sure the prerequisites, above, are installed.
  2. Copy this entire directory and all subdirectories onto your local disk
  3. Edit the paths.py file to set the paths to Cygwin, Firefox, etc. on your 
     machine.
  4. Create a YAML config file with info about the profiles you want to test.
     It should look something like this:

     # Filename will be appended to the timestamp in the report filename.
     # Use letters and underscores only
     filename: slowmachine
     # The title of the report
     title: 1 GHz Celeron

     # Name of profile to test
     Test profile 1:
       # Path to Firefox to test
       firefox: C:\Program Files\Mozilla Firefox 2 Beta 1\firefox.exe

       # Preferences to set in the test (use "preferences : {}" for no prefs)
       preferences:
         javascript.options.showInConsole : true
         xpinstall.enabled : true

       # 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

  5. Run run_tests.py with the name of your config file as an argument. You can use
     a space-separated list of config files, to generate a report of startup and page load times. The
     report will be placed in the REPORTS_DIR directory you specified in
     paths.py.

DIRECTORY STRUCTURE:
   page_load_test/
     This directory contains the JavaScript files and html data files for the
     page load test. The page load test opens a new window and cycles through
     loading each html file, timing each load.
   startup_test/
     This directory contains the JavaScript to run the startup test.  It
     measures how long it takes Firefox to start up.
   base_profile/
     This directory contains the base profile used for testing.  A copy of
     this profile is made for each testing profile, and extensions or prefs
     are added according to the test_configs array in run_tests.py.  For the
     page load test to run correctly, the hostperm.1 file must be set to allow
     scheme:file uris to open in new windows, and the pref to force a window
     to open in a tab must not be set.  The dom.allow_scripts_to_close_windows
     pref should also be set to true.  The browser.shell.checkDefaultBrowser
     pref should be set to false.
   run_tests.py, paths.py
     These files should be configured to run the test on different machines,
     with different extensions or preferences.  See setup above.
     
\ No newline at end of file
+PREREQUISITES:
+You'll need to download some software onto your Windows machine before running
+these performance tests:
+
+  * Python 2.4
+    The scripts all run from Python 2.4.  You will need the windows version
+    (not the cygwin version).  You can download it here:
+    http://www.python.org/ftp/python/2.4/python-2.4.msi
+
+    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
+    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
+
+  * 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)
+
+  1. Make sure the prerequisites, above, are installed.
+  2. Copy this entire directory and all subdirectories onto your local disk
+  3. Edit the config.py file to set the paths to Cygwin, Firefox, etc. on your 
+     machine.
+  4. Create a YAML config file with info about the profiles you want to test.
+     NOTE: You should set the preferences network.proxy.type:1, network.proxy.http:localhost and 
+     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
+
+  5. Provide a pages/ directory
+     The page_load_test/ relies upon having a pages directory that includes the web pages
+     to be cycled through.  Each directory in pages/ should be a given web page.  
+     The parray.js file needs to be edited to reflect the list of index pages of the web pages 
+     that are to be tested - it is currently full of a sample list.
+
+  6. Run "python run_tests.py" with the name of your config file as an argument. You can use
+     a space-separated list of config files, to generate a report of startup and page load times. 
+
+DIRECTORY STRUCTURE:
+   page_load_test/
+     This directory contains the JavaScript files and html data files for the
+     page load test. The page load test opens a new window and cycles through
+     loading each html file, timing each load.
+   startup_test/
+     This directory contains the JavaScript to run the startup test.  It
+     measures how long it takes Firefox to start up.
+   base_profile/
+     This directory contains the base profile used for testing.  A copy of
+     this profile is made for each testing profile, and extensions or prefs
+     are added according to the test_configs array in run_tests.py.  For the
+     page load test to run correctly, the hostperm.1 file must be set to allow
+     scheme:file uris to open in new windows, and the pref to force a window
+     to open in a tab must not be set.  The dom.allow_scripts_to_close_windows
+     pref should also be set to true.  The browser.shell.checkDefaultBrowser
+     pref should be set to false.
+   config.py
+     This file should be configured to run the test on different machines,
+     with different extensions or preferences.  See setup above.
+     
--- a/base_profile/localstore.rdf
+++ b/base_profile/localstore.rdf
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <RDF:RDF xmlns:NC="http://home.netscape.com/NC-rdf#"
          xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
   <RDF:Description RDF:about="chrome://browser/content/browser.xul#toolbar-menubar"
                    currentset="menubar-items,spring,gwa-status-button,gwa-speedo-button,throbber-box" />
   <RDF:Description RDF:about="chrome://browser/content/browser.xul#main-window"
-                   width="994"
-                   height="1010"
+                   width="1024"
+                   height="768"
                    sizemode="normal"
-                   screenX="432"
-                   screenY="69" />
+                   screenX="0"
+                   screenY="0" />
   <RDF:Description RDF:about="chrome://browser/content/browser.xul">
     <NC:persist RDF:resource="chrome://browser/content/browser.xul#main-window"/>
     <NC:persist RDF:resource="chrome://browser/content/browser.xul#toolbar-menubar"/>
     <NC:persist RDF:resource="chrome://browser/content/browser.xul#sidebar-box"/>
     <NC:persist RDF:resource="chrome://browser/content/browser.xul#sidebar-title"/>
   </RDF:Description>
   <RDF:Description RDF:about="chrome://browser/content/browser.xul#sidebar-box"
                    sidebarcommand=""
--- a/config.py
+++ b/config.py
@@ -37,44 +37,45 @@
 
 """A list of constants containing the paths to programs and files
    needed by the performance testing scripts.
 """
 
 __author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
 
 
-OS = r'win32'
+BROWSER_HEIGHT = 768
+BROWSER_WIDTH = 1024
 
 """For some reason, can only get output from dump() in Firefox if
    it's run through cygwin bash.  So here's the path to cygwin.
 """
 CYGWIN = r'c:\cygwin\bin\bash.exe -c'
 
 """The tinderbox scripts run sync between Ts runs, so we do, too."""
 SYNC = r'c:\cygwin\bin\sync'
 
 """The path to the base profile directory to use for testing.  For the page
    load test to work, this profile should have its hostperm.1 file set to allow
    urls with scheme:file to open in new windows, and the preference to open
    new windows in a tab should be off.
 """
-BASE_PROFILE_DIR = r'C:\win32\base_profile'
-
-"""The directory the generated reports go into."""
-REPORTS_DIR = r'c:\extension_perf_reports'
+BASE_PROFILE_DIR = r'C:\talos\base_profile'
 
 """The path to the file url to load when initializing a new profile"""
-INIT_URL = 'file:///c:/win32/initialize.html'
+INIT_URL = 'file:///c:/talos/initialize.html'
+
+"""The path to the file url to load when collecting information from the browser"""
+INFO_URL = 'file:///c:/talos/getInfo.html'
 
 """The path to the file url to load for startup test (Ts)"""
-TS_URL = 'file:///c:/win32/startup_test/startup_test.html?begin='
+TS_URL = 'file:///c:/talos/startup_test/startup_test.html?begin='
 
 """Number of times to run startup test (Ts)"""
-TS_NUM_RUNS = 5
+TS_NUM_RUNS = 20
 
 """The path to the file url to load for page load test (Tp)"""
 TP_URL = 'http://localhost/page_load_test/framecycler.html'
 
 """Number of times the page load test (Tp) loads each page in the test."""
 TP_NUM_CYCLES = 5
 
 """Resolution of counter sample data for page load test (Tp), in seconds
@@ -87,8 +88,9 @@ TP_RESOLUTION = 1
    Possible values on Linux:
      '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'
new file mode 100644
--- /dev/null
+++ b/ffinfo.py
@@ -0,0 +1,57 @@
+# ***** 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):
+#   Alice Nodelman <anodelman@mozilla.com> (original author)
+#
+# 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 *****
+
+__author__ = 'anodelman@mozilla.com'
+
+import re
+import ffprocess
+import config
+
+PROFILE_REGEX = re.compile('__metrics(.*)')
+
+def GetMetricsFromBrowser(firefox_path, profile_dir):
+  """Opens the browser at the specified URL, prints out the information collected from
+     the browser"""
+  cmd = ffprocess.GenerateFirefoxCommandLine(firefox_path, profile_dir, config.INFO_URL)
+  (match, timed_out) = ffprocess.RunProcessAndWaitForOutput(cmd,
+                                                              'firefox',
+                                                              PROFILE_REGEX,
+                                                              30)
+  if (not timed_out):
+    print match
+  else:
+    print "ERROR:no metrics"
+
--- a/ffprocess.py
+++ b/ffprocess.py
@@ -1,10 +1,8 @@
-#!c:/Python24/python.exe
-#
 # ***** 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/
 #
@@ -37,158 +35,40 @@
 # ***** END LICENSE BLOCK *****
 
 """A set of functions for process management on Windows.
 """
 
 __author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
 
 
-import msvcrt
+
+import platform
 import os
 import re
 import time
-import win32api
-import win32file
-import win32pdhutil
-import win32pipe
 
-import paths
-
-
-def GetCygwinPath(dos_path):
-  """Helper function to get the Cygwin path from a dos path.
-     Used to generate a Firefox command line piped through the
-     Cygwin bash shell
-
-  Args:
-    dos_path: String containing the dos path
-
-  Returns:
-    String containing the cygwin path
-  """
+import config
 
-  # Convert the path to a cygwin path. Assumes the path starts with
-  # /cygdrive/driveletter
-  cygwin_path = '/' + dos_path[3:]                       # Remove 'C:\'
-  cygwin_path = cygwin_path.replace('\\', '/')           # Backslashes->slashes
-  cygwin_path = cygwin_path.replace(' ', '\\ ')          # Escape spaces
-  cygwin_path = '/cygdrive/' + dos_path[0] + cygwin_path # Add drive letter
-  return cygwin_path
-
-
-def GenerateFirefoxCommandLine(firefox_path, profile_dir, url):
-  """Generates the command line for a process to run Firefox, wrapped
-     by cygwin so that we can read the output from dump() statements.
+if platform.system() == "Linux":
+    from ffprocess_linux import *
+elif platform.system() == "Windows":
+    from ffprocess_win32 import *
 
-  Args:
-    firefox_path: String containing the path to the firefox exe 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_dir = profile_dir.replace('\\', '\\\\\\')
-    profile_arg = '-profile %s' % profile_dir
-
-  url_arg = ''
-  if url:
-    url_arg = '-url %s' % url
-
-  cmd = '%s "%s %s %s"' % (paths.CYGWIN,
-                           GetCygwinPath(firefox_path),
-                           profile_arg,
-                           url_arg)
-  return cmd
 
 
 def SyncAndSleep():
   """Runs sync and sleeps for a few seconds between Firefox runs.
      Otherwise "Firefox is already running.." errors occur
   """
 
-  os.spawnl(os.P_WAIT, paths.SYNC)
+  os.spawnl(os.P_WAIT, config.SYNC)
   time.sleep(3)
 
 
-def TerminateProcess(pid):
-  """Helper function to terminate a process, given the pid
-
-  Args:
-    pid: integer process id of the process to terminate.
-  """
-
-  PROCESS_TERMINATE = 1
-  handle = win32api.OpenProcess(PROCESS_TERMINATE, False, pid)
-  win32api.TerminateProcess(handle, -1)
-  win32api.CloseHandle(handle)
-
-
-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.
-  """
-
-  try:
-    pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process")
-    return len(pids) > 0
-  except:
-    # Might get an exception if there are no instances of the process running.
-    return False
-
-
-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"
-  """
-
-  # Get all the process ids of running instances of this process, and terminate them.
-  try:
-    pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process")
-    for pid in pids:
-      TerminateProcess(pid)
-  except:
-    # Might get an exception if there are no instances of the process running.
-    pass
-
-
-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 = ""
-
-  try:
-    osfhandle = msvcrt.get_osfhandle(handle.fileno())
-    (read, num_avail, num_message) = win32pipe.PeekNamedPipe(osfhandle, 0)
-    if num_avail > 0:
-      (error_code, output) = win32file.ReadFile(osfhandle, num_avail, None)
-
-    return (num_avail, output)
-  except:
-    return (0, output)
-
-
 def RunProcessAndWaitForOutput(command, process_name, output_regex, timeout):
   """Runs the given process and waits for the output that matches the given
      regular expression.  Stops if the process exits early or times out.
 
   Args:
     command: String containing command to run
     process_name: Name of the process to run, in case it has to be killed
     output_regex: Regular expression to check against each output line.
new file mode 100644
--- /dev/null
+++ b/ffprocess_linux.py
@@ -0,0 +1,171 @@
+# ***** 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> (OS independence)
+#
+# 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
+from select import select
+
+import config
+
+
+def GenerateFirefoxCommandLine(firefox_path, profile_dir, url):
+  """Generates the command line for a process to run Firefox, wrapped
+     by cygwin so that we can read the output from dump() statements.
+
+  Args:
+    firefox_path: String containing the path to the firefox exe 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.
+     This function is UNIX specific.
+
+  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', 'ax']
+  handle = subprocess.Popen(command, stdout=subprocess.PIPE)
+
+  # wait for the process to terminate
+  handle.wait()
+  data = handle.stdout.read()
+  
+  # find all matching processes and add them to the list
+  for line in data.splitlines():
+    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"
+  """
+
+  # Get all the process ids of running instances of this process,
+  # and terminate them
+  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)
new file mode 100644
--- /dev/null
+++ b/ffprocess_win32.py
@@ -0,0 +1,167 @@
+# ***** 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> (OS independence)
+#
+# 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 win32api
+import win32file
+import win32pdhutil
+import win32pipe
+import msvcrt
+
+import config
+
+
+def GetCygwinPath(dos_path):
+  """Helper function to get the Cygwin path from a dos path.
+     Used to generate a Firefox command line piped through the
+     Cygwin bash shell
+
+  Args:
+    dos_path: String containing the dos path
+
+  Returns:
+    String containing the cygwin path
+  """
+
+  # Convert the path to a cygwin path. Assumes the path starts with
+  # /cygdrive/driveletter
+  cygwin_path = '/' + dos_path[3:]                       # Remove 'C:\'
+  cygwin_path = cygwin_path.replace('\\', '/')           # Backslashes->slashes
+  cygwin_path = cygwin_path.replace(' ', '\\ ')          # Escape spaces
+  cygwin_path = '/cygdrive/' + dos_path[0] + cygwin_path # Add drive letter
+  return cygwin_path
+
+
+def GenerateFirefoxCommandLine(firefox_path, profile_dir, url):
+  """Generates the command line for a process to run Firefox, wrapped
+     by cygwin so that we can read the output from dump() statements.
+
+  Args:
+    firefox_path: String containing the path to the firefox exe 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_dir = profile_dir.replace('\\', '\\\\\\')
+    profile_arg = '-profile %s' % profile_dir
+
+  url_arg = ''
+  if url:
+    url_arg = '-url %s' % url
+
+  cmd = '%s "%s %s %s -width %d -height %d"' % (config.CYGWIN,
+                           GetCygwinPath(firefox_path),
+                           profile_arg,
+                           url_arg,
+                           config.BROWSER_WIDTH,
+                           config.BROWSER_HEIGHT)
+  return cmd
+
+
+def TerminateProcess(pid):
+  """Helper function to terminate a process, given the pid
+
+  Args:
+    pid: integer process id of the process to terminate.
+  """
+
+  PROCESS_TERMINATE = 1
+  handle = win32api.OpenProcess(PROCESS_TERMINATE, False, pid)
+  win32api.TerminateProcess(handle, -1)
+  win32api.CloseHandle(handle)
+
+
+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.
+  """
+
+  try:
+    pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process")
+    return len(pids) > 0
+  except:
+    # Might get an exception if there are no instances of the process running.
+    return False
+
+
+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"
+  """
+
+  # Get all the process ids of running instances of this process, and terminate them.
+  try:
+    pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process")
+    for pid in pids:
+      TerminateProcess(pid)
+  except:
+    # Might get an exception if there are no instances of the process running.
+    pass
+
+
+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 = ""
+
+  try:
+    osfhandle = msvcrt.get_osfhandle(handle.fileno())
+    (read, num_avail, num_message) = win32pipe.PeekNamedPipe(osfhandle, 0)
+    if num_avail > 0:
+      (error_code, output) = win32file.ReadFile(osfhandle, num_avail, None)
+
+    return (num_avail, output)
+  except:
+    return (0, output)
--- a/ffprofile.py
+++ b/ffprofile.py
@@ -41,28 +41,29 @@
    prefs.js file to set the prefs, and creating a file to link to each
    extension.  The profile is run with Firefox to make sure it is fully
    initialized and won't cause extra startup time on the first run.
 """
 
 __author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
 
 
+import platform
 import os
 import re
 import shutil
 import tempfile
 import time
 
 import ffprocess
 import config
 
-if config.OS is "linux":
+if platform.system() == "Linux":
     from ffprofile_linux import *
-elif config.OS is "win32":
+elif platform.system() == "Windows":
     from ffprofile_win32 import *
 
 
 def PrefString(name, value, newline):
   """Helper function to create a pref string for Firefox profile prefs.js
      in the form 'user_pref("name", value);<newline>'
 
   Args:
new file mode 100644
--- /dev/null
+++ b/ffprofile_win32.py
@@ -0,0 +1,51 @@
+# ***** 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> (OS independence)
+#
+# 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 os
+
+def MakeDirectoryContentsWritable(dirname):
+  """Recursively makes all the contents of a directory writable.
+     Uses os.chmod(filename, 0777), which works on Windows.
+
+  Args:
+    dirname: Name of the directory to make contents writable.
+  """
+
+  for (root, dirs, files) in os.walk(dirname):
+    os.chmod(root, 0777)
+    for filename in files:
+      os.chmod(os.path.join(root, filename), 0777)
new file mode 100644
--- /dev/null
+++ b/getInfo.html
@@ -0,0 +1,52 @@
+<!-- ***** 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 Windows performance test.
+   -
+   - The Initial Developer of the Original Code is
+   - Google Inc.
+   - Portions created by the Initial Developer are Copyright (C) 1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   - Annie Sullivan <annie.sullivan@gmail.com>
+   - Alice Nodelman <anodelman@mozilla.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 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 ***** -->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>shutdown script</title>
+  </head>
+
+  <body onload="
+	if (window.dump) {
+		dump('\n\n__metricsScreen width:' + screen.width + ' Screen height:' + screen.height + ' colorDepth:' + screen.colorDepth);
+	}
+	window.close();
+">
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/page_load_test/framecycler.html
@@ -0,0 +1,246 @@
+<html>
+<script language="Javascript" type="text/javascript" src="parray.js"></script>
+<script>
+
+  var NUM_PAGES;
+  var NUM_CYCLES;
+  var DEFAULT_TIMEOUT = 25000; //how long any given page can take to load
+  var t; 
+
+  function parseParams() {
+    var s = document.location.search.substring(1);
+    var params = s.split('&');
+    for (var i = 0; i < params.length; ++i) {
+      var fields = params[i].split('=');
+      switch (fields[0]) {
+      case 'cycles':
+        NUM_CYCLES = (fields[1] - 0);
+        break;
+      case 'pages':
+        NUM_PAGES = (fields[1] - 0);
+        break;
+      case 'i18n':
+        if (fields[1] == '1') {
+          pages = pages.concat(pages_i18n);
+        }
+        break;
+      }
+    }
+    if (!NUM_PAGES)
+      NUM_PAGES = pages.length;
+    if (!NUM_CYCLES)
+      NUM_CYCLES = 5;
+  }
+  parseParams();
+
+  var timeVals = new Array(NUM_PAGES);  // matrix of times
+  for (var i = 0; i < timeVals.length; ++i) {
+    timeVals[i] = new Array;
+  }
+  var tstart;
+  var index = 0;
+  var cycle = 0;
+
+  function compareNumbers(a, b) {
+    return a - b;
+  }
+
+  // returns an object with the following properties:
+  //   min  : min value of array elements
+  //   max  : max value of array elements
+  //   mean : mean value of array elements
+  //   vari : variance computation
+  //   stdd : standard deviation, sqrt(vari)
+  //   indexOfMax : index of max element (the element that is
+  //                removed from the mean computation)
+  function getArrayStats(ary) {
+    var r = {};
+    r.min = ary[0];
+    r.max = ary[0];
+    r.indexOfMax = 0;
+    var sum = 0;
+    for (var i = 0; i < ary.length; ++i) {
+      if (ary[i] < r.min) {
+        r.min = ary[i];
+      } else if (ary[i] > r.max) {
+        r.max = ary[i];
+        r.indexOfMax = i;
+      }
+      sum = sum + ary[i];
+    }
+
+    // median
+    sorted_ary = ary.concat();
+    sorted_ary.sort(compareNumbers);
+    // remove longest run
+    sorted_ary.pop();
+    if (sorted_ary.length%2) {
+      r.median = sorted_ary[(sorted_ary.length-1)/2]; 
+    }else{
+      var n = Math.floor(sorted_ary.length / 2);
+      r.median = (sorted_ary[n - 1] + sorted_ary[n]) / 2;
+    }
+
+    // ignore max value when computing mean and stddev
+    r.mean = (sum - r.max) / (ary.length - 1);
+
+    r.vari = 0;
+    for (var i = 0; i < ary.length; ++i) {
+      if (i == r.indexOfMax)
+        continue;
+      var d = r.mean - ary[i];
+      r.vari = r.vari + d * d;
+    }
+
+    r.vari = r.vari / (ary.length - 1);
+    r.stdd = Math.sqrt(r.vari);
+    return r;
+  }
+
+  function appendTableCol(tr, text) {
+    var doc = tr.ownerDocument;
+    var td = doc.createElement("TD");
+    td.appendChild(doc.createTextNode(text));
+    tr.appendChild(td);
+    return td;
+  }
+
+  function dumpReport() {
+    var all = new Array();
+    var counter = 0;
+    
+    for (var i = 0; i < timeVals.length; ++i) {
+      for (var j = 0; j < timeVals[i].length; ++j) {
+        all[counter] = timeVals[i][j];
+        ++counter;
+      }
+    }
+
+    // avg and avg median are cumulative for all the pages
+    var avgs = new Array();
+    var medians = new Array();
+    for (var i = 0; i < timeVals.length; ++i) {
+       avgs[i] = getArrayStats(timeVals[i]).mean;
+       medians[i] = getArrayStats(timeVals[i]).median;
+    }
+    var avg = getArrayStats(avgs).mean;
+    var avgmed = getArrayStats(medians).mean;
+    var rstring = "__start_page_load_report";
+
+    var r = getArrayStats(all);
+    dump(
+      "__start_tp_report\n" + 
+      "_x_x_mozilla_page_load,"+avgmed+","+r.max+","+r.min+"\n"+
+      "_x_x_mozilla_page_load_details,avgmedian|"+avgmed+"|average|"+avg.toFixed(2)+"|minimum|"+r.min+"|maximum|"+r.max+"|stddev|"+r.stdd.toFixed(2)+"\n"
+    );
+
+    for (var i = 0; i < timeVals.length; ++i) {
+      r = getArrayStats(timeVals[i]);
+      fields = pages[i].split('/');
+      //rstring += "page:" + fields[5] + ":" + r.median.toFixed(2) + "\n";
+      dump(
+        '|'+
+        i+';'+
+        //pages[i]+';'+
+        fields[5]+';'+
+        r.median+';'+
+        r.mean+';'+
+        r.min+';'+
+        r.max
+      );
+      for (var j = 0; j < timeVals[i].length; ++j) {
+        dump(
+          ';'+timeVals[i][j]
+        );
+      }
+      dump("\n")
+    } 
+    dump("__end_tp_report\n");
+    //rstring += "__end_page_load_report";
+    //alert(rstring);
+    //dump(rstring);
+  }
+
+  function showReport() {
+    var doc = frames["content"].document;
+    var tbody = doc.getElementById("tbody");
+    for (var i = 0; i < timeVals.length; ++i) {
+      var tr = doc.createElement("TR");
+
+      appendTableCol(tr, pages[i]);
+
+      var r = getArrayStats(timeVals[i]);
+      appendTableCol(tr, r.min.toFixed(2));
+      appendTableCol(tr, r.max.toFixed(2));
+      appendTableCol(tr, r.mean.toFixed(2));
+      appendTableCol(tr, r.stdd.toFixed(2));
+      appendTableCol(tr, r.median.toFixed(2));
+
+      for (var j = 0; j < timeVals[i].length; ++j) {
+        var tv = timeVals[i][j];
+        var td = appendTableCol(tr, tv);
+        if (j == r.indexOfMax)
+          td.setAttribute("class", "discarded");
+      }
+
+      tbody.appendChild(tr);
+    }
+  }
+
+  function loadFail() {
+    dump("__FAILtimeout:" + frames["content"].document.location.href + "__FAIL");
+    window.close();
+  }
+
+  function loadPage(i) {
+    tstart = new Date();
+    t = setTimeout('loadFail()', DEFAULT_TIMEOUT);
+    frames["content"].document.location = pages[i];
+  }
+
+  function frameLoad() {
+    clearTimeout(t);
+    if (cycle == NUM_CYCLES) {
+      showReport();
+      dumpReport();
+      window.close();
+      return;
+    }
+    var tend = new Date();
+    var href = frames["content"].document.location.href;
+    if (href == "about:blank")
+      return;
+    var tdelta = tend - tstart;
+    timeVals[index].push(tdelta);
+    var fields = href.split('/');
+
+    var text = (cycle + 1) + ', ' + (index + 1) + ', ' + fields[fields.length - 2] + ", " + tdelta;
+
+    var doc = frames["header"].document;
+    var body = doc.body;
+    while (body.firstChild)
+      body.removeChild(body.firstChild);
+    body.appendChild(doc.createTextNode(text));
+
+    if (++index == NUM_PAGES) {
+      index = 0;
+      if (++cycle == NUM_CYCLES) {
+        // display summary
+        frames["content"].document.location = "report.html";
+        return;
+      }
+    }
+
+    window.setTimeout("loadPage(" + index + ")", 500);
+  }
+
+  function init() {
+    window.resizeTo(800, 800);
+    window.setTimeout("loadPage(" + index + ")", 500);
+  }
+</script>
+<frameset rows="40,*" onload="init()">
+  <frame name="header" src="header.html">
+  <frame name="content" src="" onload="frameLoad()">
+</frameset>
+</html>
new file mode 100644
--- /dev/null
+++ b/page_load_test/parray.js
@@ -0,0 +1,398 @@
+ pages = [
+"http://localhost/page_load_test/pages/www.yahoo.com/www.yahoo.com/index.html",
+"http://localhost/page_load_test/pages/www.msn.com/www.msn.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com/www.google.com/index.html",
+"http://localhost/page_load_test/pages/www.baidu.com/www.baidu.com/index.html",
+"http://localhost/page_load_test/pages/www.myspace.com/www.myspace.com/index.html",
+"http://localhost/page_load_test/pages/www.qq.com/www.qq.com/index.html",
+"http://localhost/page_load_test/pages/www.live.com/www.live.com/index.html",
+"http://localhost/page_load_test/pages/www.ebay.com/www.ebay.com/index.html",
+"http://localhost/page_load_test/pages/www.wikipedia.org/www.wikipedia.org/index.html",
+"http://localhost/page_load_test/pages/www.163.com/www.163.com/index.html",
+"http://localhost/page_load_test/pages/www.microsoft.com/www.microsoft.com/index.html",
+"http://localhost/page_load_test/pages/www.blogger.com/www.blogger.com/start.html",
+"http://localhost/page_load_test/pages/www.yahoo.com.cn/cn.yahoo.com/index.html",
+"http://localhost/page_load_test/pages/www.amazon.com/www.amazon.com/index.html",
+"http://localhost/page_load_test/pages/www.google.co.uk/www.google.co.uk/index.html",
+"http://localhost/page_load_test/pages/www.taobao.com/www.taobao.com/index.html",
+"http://localhost/page_load_test/pages/www.google.de/www.google.de/index.html",
+"http://localhost/page_load_test/pages/www.google.co.jp/www.google.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.wretch.cc/www.wretch.cc/index.html",
+"http://localhost/page_load_test/pages/www.google.com.br/www.google.com.br/index.html",
+"http://localhost/page_load_test/pages/www.bbc.co.uk/www.bbc.co.uk/index.html",
+"http://localhost/page_load_test/pages/www.uol.com.br/www.uol.com.br/index.html",
+"http://localhost/page_load_test/pages/www.fotolog.net/www.fotolog.com/index.html",
+"http://localhost/page_load_test/pages/www.passport.net/accountservices.passport.net/ppnetworkhome.srf@vv=450&lc=1033.html",
+"http://localhost/page_load_test/pages/www.craigslist.org/sfbay.craigslist.org/index.html",
+"http://localhost/page_load_test/pages/www.cnn.com/www.cnn.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com.mx/www.google.com.mx/index.html",
+"http://localhost/page_load_test/pages/www.imdb.com/www.imdb.com/index.html",
+"http://localhost/page_load_test/pages/www.flickr.com/www.flickr.com/index.html",
+"http://localhost/page_load_test/pages/www.mail.ru/www.mail.ru/index.html",
+"http://localhost/page_load_test/pages/www.xanga.com/www.xanga.com/index.html",
+"http://localhost/page_load_test/pages/www.aol.com/www.aol.com/index.html",
+"http://localhost/page_load_test/pages/www.google.es/www.google.es/index.html",
+"http://localhost/page_load_test/pages/www.yandex.ru/www.yandex.ru/index.html",
+"http://localhost/page_load_test/pages/www.google.co.in/www.google.co.in/index.html",
+//"http://localhost/page_load_test/pages/www.discuss.com.hk/www.discuss.com.hk/index.html",
+"http://localhost/page_load_test/pages/www.ebay.co.uk/www.ebay.co.uk/index.html",
+"http://localhost/page_load_test/pages/www.mixi.jp/mixi.jp/index.html",
+"http://localhost/page_load_test/pages/www.naver.com/www.naver.com/index.html",
+"http://localhost/page_load_test/pages/www.friendster.com/www.friendster.com/index.html",
+"http://localhost/page_load_test/pages/www.google.fr/www.google.fr/index.html",
+"http://localhost/page_load_test/pages/www.facebook.com/www.facebook.com/index.html",
+"http://localhost/page_load_test/pages/www.google.pl/www.google.pl/index.html",
+"http://localhost/page_load_test/pages/www.google.ca/www.google.ca/index.html",
+"http://localhost/page_load_test/pages/www.google.com.tr/www.google.com.tr/index.html",
+"http://localhost/page_load_test/pages/www.onet.pl/www.onet.pl/index.html",
+"http://localhost/page_load_test/pages/www.google.cl/www.google.cl/index.html",
+"http://localhost/page_load_test/pages/www.pchome.com.tw/www.pchome.com.tw/index.html",
+"http://localhost/page_load_test/pages/www.terra.com.br/www.terra.com.br/capa/index.html",
+"http://localhost/page_load_test/pages/www.imageshack.us/www.imageshack.us/index.html",
+"http://localhost/page_load_test/pages/www.google.com.sa/www.google.com.sa/index.html",
+"http://localhost/page_load_test/pages/www.rakuten.co.jp/www.rakuten.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.geocities.com/geocities.yahoo.com/index.html",
+"http://localhost/page_load_test/pages/www.vnet.cn/www.vnet.cn/default.aspx.html",
+"http://localhost/page_load_test/pages/www.ebay.de/www.ebay.de/index.html",
+"http://localhost/page_load_test/pages/www.uwants.com/www.uwants.com/index.html",
+"http://localhost/page_load_test/pages/www.rediff.com/www.rediff.com/index.html",
+"http://localhost/page_load_test/pages/www.photobucket.com/photobucket.com/index.html",
+"http://localhost/page_load_test/pages/www.soso.com/www.soso.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com.ar/www.google.com.ar/index.html",
+"http://localhost/page_load_test/pages/www.adultfriendfinder.com/www.adultfriendfinder.com/index.html",
+"http://localhost/page_load_test/pages/www.apple.com/www.apple.com/index.html",
+"http://localhost/page_load_test/pages/www.livedoor.com/www.livedoor.com/index.html",
+"http://localhost/page_load_test/pages/www.sogou.com/www.sogou.com/index.html",
+"http://localhost/page_load_test/pages/www.google.cn/www.google.cn/index.html",
+"http://localhost/page_load_test/pages/www.newsgroup.la/www.newsgroup.la/index.html",
+"http://localhost/page_load_test/pages/www.chinaren.com/www.chinaren.com/index.html",
+"http://localhost/page_load_test/pages/www.sourceforge.net/sourceforge.net/index.php.html",
+"http://localhost/page_load_test/pages/www.digg.com/www.digg.com/index.html",
+"http://localhost/page_load_test/pages/www.126.com/www.126.com/index.html",
+"http://localhost/page_load_test/pages/www.daum.net/www.daum.net/index.html",
+"http://localhost/page_load_test/pages/www.xinhuanet.com/www.xinhuanet.com/index.html",
+"http://localhost/page_load_test/pages/www.about.com/www.about.com/index.html",
+"http://localhost/page_load_test/pages/www.nate.com/www.nate.com/index.html",
+"http://localhost/page_load_test/pages/www.rambler.ru/www.rambler.ru/index.html",
+"http://localhost/page_load_test/pages/www.google.it/www.google.it/index.html",
+"http://localhost/page_load_test/pages/www.comcast.net/www.comcast.net/index.html",
+"http://localhost/page_load_test/pages/www.badongo.com/www.badongo.com/index.html",
+"http://localhost/page_load_test/pages/www.free.fr/www.free.fr/index.html",
+"http://localhost/page_load_test/pages/www.3721.com/www.3721.com/wlsm/index.htm.html",
+"http://localhost/page_load_test/pages/www.ebay.com.cn/www.ebay.com.cn/index.html",
+"http://localhost/page_load_test/pages/www.hinet.net/www.hinet.net/index.html",
+"http://localhost/page_load_test/pages/www.statcounter.com/www.statcounter.com/index.html",
+"http://localhost/page_load_test/pages/www.adobe.com/www.adobe.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com.au/www.google.com.au/index.html",
+"http://localhost/page_load_test/pages/www.mop.com/www.mop.com/index.html",
+"http://localhost/page_load_test/pages/www.ig.com.br/www.ig.com.br/index.html",
+"http://localhost/page_load_test/pages/www.starware.com/www.starware.com/2.0.0.0/index.html",
+"http://localhost/page_load_test/pages/www.google.co.il/www.google.co.il/index.html",
+//"http://localhost/page_load_test/pages/www.hkjc.com/www.hkjc.com/index.html",
+"http://localhost/page_load_test/pages/www.china.com/www.china.com/index.html",
+"http://localhost/page_load_test/pages/www.dell.com/www.dell.com/index.html",
+"http://localhost/page_load_test/pages/www.51.com/www.51.com/index.html",
+"http://localhost/page_load_test/pages/www.digitalpoint.com/www.digitalpoint.com/index.html",
+"http://localhost/page_load_test/pages/www.flurl.com/www.flurl.com/index.html",
+"http://localhost/page_load_test/pages/www.goo.ne.jp/www.goo.ne.jp/index.html",
+"http://localhost/page_load_test/pages/www.atnext.com/www.atnext.com/index.html",
+"http://localhost/page_load_test/pages/www.download.com/www.download.com/index.html",
+"http://localhost/page_load_test/pages/www.cnnic.cn/www.cnnic.cn/index.html",
+"http://localhost/page_load_test/pages/www.cmfu.com/www.cmfu.com/index.html",
+"http://localhost/page_load_test/pages/www.mediaplex.com/www.mediaplex.com/index.html",
+"http://localhost/page_load_test/pages/www.googlesyndication.com/www.googlesyndication.com/index.html",
+"http://localhost/page_load_test/pages/www.mapquest.com/www.mapquest.com/index.html",
+"http://localhost/page_load_test/pages/www.globo.com/www.globo.com/index.html",
+"http://localhost/page_load_test/pages/www.weather.com/www.weather.com/index.html",
+"http://localhost/page_load_test/pages/www.imagevenue.com/www.imagevenue.com/index.html",
+"http://localhost/page_load_test/pages/www.overture.com/www.content.overture.com/d/index.html",
+"http://localhost/page_load_test/pages/www.theplanet.com/www.theplanet.com/index.html",
+"http://localhost/page_load_test/pages/www.icio.us/",
+"http://localhost/page_load_test/pages/www.pconline.com.cn/www.pconline.com.cn/index.html",
+"http://localhost/page_load_test/pages/www.mywebsearch.com/search.mywebsearch.com/mywebsearch/default.jhtml.html",
+"http://localhost/page_load_test/pages/www.sendspace.com/www.sendspace.com/index.html",
+"http://localhost/page_load_test/pages/www.typepad.com/www.typepad.com/index.html",
+"http://localhost/page_load_test/pages/www.amazon.co.jp/www.amazon.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.infoseek.co.jp/www.infoseek.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.21cn.com/www.21cn.com/index.html",
+"http://localhost/page_load_test/pages/www.gamer.com.tw/www.gamer.com.tw/index.html",
+"http://localhost/page_load_test/pages/www.tianya.cn/www.tianya.cn/index.html",
+"http://localhost/page_load_test/pages/www.google.com.eg/www.google.com.eg/index.html",
+"http://localhost/page_load_test/pages/www.deviantart.com/www.deviantart.com/index.html",
+"http://localhost/page_load_test/pages/www.metacafe.com/www.metacafe.com/index.html",
+"http://localhost/page_load_test/pages/www.265.com/www.265.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com.tw/www.google.com.tw/index.html",
+"http://localhost/page_load_test/pages/www.match.com/www.match.com/index.html",
+"http://localhost/page_load_test/pages/www.php.net/www.php.net/index.html",
+"http://localhost/page_load_test/pages/www.spiegel.de/www.spiegel.de/index.html",
+"http://localhost/page_load_test/pages/www.neopets.com/www.neopets.com/index.html",
+"http://localhost/page_load_test/pages/www.phoenixtv.com/www.phoenixtv.com/index.html",
+"http://localhost/page_load_test/pages/www.hp.com/www.hp.com/index.html",
+"http://localhost/page_load_test/pages/www.google.nl/www.google.nl/index.html",
+"http://localhost/page_load_test/pages/www.nifty.com/www.nifty.com/index.html",
+"http://localhost/page_load_test/pages/www.sina.com.hk/www.sina.com.hk/index.html",
+"http://localhost/page_load_test/pages/www.sexyono.com/www.sexyono.com/index.html",
+"http://localhost/page_load_test/pages/www.paipai.com/www.paipai.com/index.html",
+"http://localhost/page_load_test/pages/www.amazon.co.uk/www.amazon.co.uk/index.html",
+"http://localhost/page_load_test/pages/www.chinahr.com/www.chinahr.com/index.html",
+"http://localhost/page_load_test/pages/www.tripod.com/www.tripod.lycos.com/index.html",
+"http://localhost/page_load_test/pages/www.google.co.ve/www.google.co.ve/index.html",
+"http://localhost/page_load_test/pages/www.yam.com/www.yam.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com.pe/www.google.com.pe/index.html",
+"http://localhost/page_load_test/pages/www.reference.com/www.reference.com/index.html",
+"http://localhost/page_load_test/pages/www.maktoob.com/www.maktoob.com/index.html",
+"http://localhost/page_load_test/pages/www.wordpress.com/wordpress.com/index.html",
+"http://localhost/page_load_test/pages/www.gmx.net/www.gmx.net/index.html",
+"http://localhost/page_load_test/pages/www.google.com.co/www.google.com.co/index.html",
+"http://localhost/page_load_test/pages/www.sexuploader.com/www.megarotic.com/index.html",
+"http://localhost/page_load_test/pages/www.webs-tv.net/www.webs-tv.net/index.html",
+"http://localhost/page_load_test/pages/www.narod.ru/narod.yandex.ru/index.html",
+"http://localhost/page_load_test/pages/www.aebn.net/www.aebn.net/index.html",
+"http://localhost/page_load_test/pages/www.mozilla.com/www.mozilla.com/en-US/index.html",
+"http://localhost/page_load_test/pages/www.invisionfree.com/www.invisionfree.com/index.html",
+"http://localhost/page_load_test/pages/www.gamespot.com/www.gamespot.com/index.html",
+"http://localhost/page_load_test/pages/www.nastydollars.com/www.nastydollars.com/index.html",
+"http://localhost/page_load_test/pages/www.wefong.com/www.wefong.com/index.html",
+"http://localhost/page_load_test/pages/www.homeway.com.cn/www.hexun.com/index.html",
+"http://localhost/page_load_test/pages/www.rapidshare.com/www.rapidshare.com/index.html",
+"http://localhost/page_load_test/pages/www.vnexpress.net/www.vnexpress.net/Vietnam/Home/index.html",
+"http://localhost/page_load_test/pages/www.ask.com/www.ask.com/index.html",
+"http://localhost/page_load_test/pages/www.uusee.com/www.uusee.com/index.html",
+"http://localhost/page_load_test/pages/www.linkedin.com/www.linkedin.com/index.html",
+"http://localhost/page_load_test/pages/www.yesky.com/www.yesky.com/index.html",
+"http://localhost/page_load_test/pages/www.information.com/www.information.com/index.html",
+"http://localhost/page_load_test/pages/www.msn.com.br/br.msn.com/index.html",
+"http://localhost/page_load_test/pages/www.51job.com/www.51job.com/index.html",
+"http://localhost/page_load_test/pages/www.people.com.cn/www.people.com.cn/index.html",
+"http://localhost/page_load_test/pages/www.verycd.com/www.verycd.com/index.html",
+"http://localhost/page_load_test/pages/www.sportsline.com/www.sportsline.com/index.html",
+"http://localhost/page_load_test/pages/www.youthwant.com.tw/www.youthwant.com.tw/index.html",
+"http://localhost/page_load_test/pages/www.skyblog.com/www.skyblog.com/index.html",
+"http://localhost/page_load_test/pages/www.technorati.com/www.technorati.com/index.html",
+"http://localhost/page_load_test/pages/www.google.co.th/www.google.co.th/index.html",
+"http://localhost/page_load_test/pages/www.google.com.vn/www.google.com.vn/index.html",
+"http://localhost/page_load_test/pages/www.hatena.ne.jp/www.hatena.ne.jp/index.html",
+"http://localhost/page_load_test/pages/www.yourfilehost.com/www.yourfilehost.com/index.html",
+"http://localhost/page_load_test/pages/www.amazon.de/www.amazon.de/index.html",
+"http://localhost/page_load_test/pages/www.chinamobile.com/www.chinamobile.com/index.html",
+"http://localhost/page_load_test/pages/www.centrum.cz/www.centrum.cz/index.html",
+"http://localhost/page_load_test/pages/www.flogao.com.br/www.flogao.com/index.html",
+"http://localhost/page_load_test/pages/www.myway.com/www.myway.com/index.html",
+"http://localhost/page_load_test/pages/www.xuite.net/www.xuite.net/index.html",
+"http://localhost/page_load_test/pages/www.msn.com.cn/cn.msn.com/index.html",
+"http://localhost/page_load_test/pages/www.kooora.com/www.kooora.com/index.html",
+"http://localhost/page_load_test/pages/www.godaddy.com/www.godaddy.com/gdshop/default.asp.html",
+"http://localhost/page_load_test/pages/www.google.com.sg/www.google.com.sg/index.html",
+"http://localhost/page_load_test/pages/www.4399.com/www.4399.com/index.html",
+"http://localhost/page_load_test/pages/www.earthlink.net/www.earthlink.net/index.html",
+"http://localhost/page_load_test/pages/www.torrentspy.com/www.torrentspy.com/index.html",
+"http://localhost/page_load_test/pages/www.pornotube.com/www.pornotube.com/index.html",
+"http://localhost/page_load_test/pages/www.aweber.com/www.aweber.com/index.html",
+"http://localhost/page_load_test/pages/www.slashdot.org/slashdot.org/index.html",
+"http://localhost/page_load_test/pages/www.2ch.net/www.2ch.net/index.html",
+"http://localhost/page_load_test/pages/www.ev1servers.net/www.ev1servers.net/index.html",
+"http://localhost/page_load_test/pages/www.webshots.com/www.webshots.com/index.html",
+"http://localhost/page_load_test/pages/www.webmasterworld.com/www.webmasterworld.com/index.html",
+"http://localhost/page_load_test/pages/www.google.se/www.google.se/index.html",
+"http://localhost/page_load_test/pages/www.biglobe.ne.jp/www.biglobe.ne.jp/index.html",
+"http://localhost/page_load_test/pages/www.domaintools.com/www.domaintools.com/index.html",
+"http://localhost/page_load_test/pages/www.mininova.org/www.mininova.org/index.html",
+"http://localhost/page_load_test/pages/www.elmundo.es/www.elmundo.es/index.html",
+"http://localhost/page_load_test/pages/www.google.ro/www.google.ro/index.html",
+"http://localhost/page_load_test/pages/www.google.ae/www.google.ae/index.html",
+"http://localhost/page_load_test/pages/www.clubbox.co.kr/www.clubbox.co.kr/index.html",
+"http://localhost/page_load_test/pages/www.w3.org/www.w3.org/index.html",
+"http://localhost/page_load_test/pages/www.qihoo.com/www.qihoo.com/index.html",
+"http://localhost/page_load_test/pages/www.google.ru/www.google.ru/index.html",
+"http://localhost/page_load_test/pages/www.miniclip.com/www.miniclip.com/games/en/index.html",
+"http://localhost/page_load_test/pages/www.milliyet.com.tr/www.milliyet.com.tr/2006/12/05/index.html",
+"http://localhost/page_load_test/pages/www.google.com.my/www.google.com.my/index.html",
+"http://localhost/page_load_test/pages/www.bebo.com/www.bebo.com/index.html",
+"http://localhost/page_load_test/pages/www.dmm.co.jp/www.dmm.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.orange.fr/www.orange.fr/index.html",
+"http://localhost/page_load_test/pages/www.bta.net.cn/www.bta.net.cn/index.html",
+"http://localhost/page_load_test/pages/www.istockphoto.com/www.istockphoto.com/index.php.html",
+"http://localhost/page_load_test/pages/www.qianlong.com/www.qianlong.com/index.html",
+"http://localhost/page_load_test/pages/www.ebay.com.au/www.ebay.com.au/index.html",
+"http://localhost/page_load_test/pages/www.chinaz.com/www.chinaz.com/index.html",
+"http://localhost/page_load_test/pages/www.adbrite.com/www.adbrite.com/index.html",
+"http://localhost/page_load_test/pages/www.sitepoint.com/www.sitepoint.com/index.html",
+"http://localhost/page_load_test/pages/www.zhongsou.com/www.zhongsou.com/index.html",
+"http://localhost/page_load_test/pages/www.ups.com/www.ups.com/index.html",
+"http://localhost/page_load_test/pages/www.wwe.com/www.wwe.com/index.html",
+"http://localhost/page_load_test/pages/www.netflix.com/www.netflix.com/Register.html",
+"http://localhost/page_load_test/pages/www.target.com/www.target.com/gp/homepage.html",
+"http://localhost/page_load_test/pages/www.it.com.cn/www.it.com.cn/index.html",
+"http://localhost/page_load_test/pages/www.washingtonpost.com/www.washingtonpost.com/index.html",
+"http://localhost/page_load_test/pages/www.usps.com/www.usps.com/index.html",
+"http://localhost/page_load_test/pages/www.iask.com/www.iask.com/index.html",
+"http://localhost/page_load_test/pages/www.google.com.hk/www.google.com.hk/index.html",
+"http://localhost/page_load_test/pages/www.ibm.com/www.ibm.com/us/index.html",
+"http://localhost/page_load_test/pages/www.google.gr/www.google.gr/index.html",
+"http://localhost/page_load_test/pages/www.6park.com/www.6park.com/index.html",
+"http://localhost/page_load_test/pages/www.sex141.com/www.sex141.com/index.html",
+"http://localhost/page_load_test/pages/www.excite.co.jp/www.excite.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.sakura.ne.jp/www.sakura.ne.jp/index.html",
+"http://localhost/page_load_test/pages/www.icq.com/www.icq.com/index.html",
+"http://localhost/page_load_test/pages/www.bangbros1.com/www.bangbros1.com/index.html",
+"http://localhost/page_load_test/pages/www.answers.com/www.answers.com/index.html",
+"http://localhost/page_load_test/pages/www.foxsports.com/msn.foxsports.com/index.html",
+"http://localhost/page_load_test/pages/www.clickbank.com/www.clickbank.com/index.html",
+"http://localhost/page_load_test/pages/www.skype.com/www.skype.com/index.html",
+"http://localhost/page_load_test/pages/www.mofile.com/tv.mofile.com/cn/index/main.do.html",
+"http://localhost/page_load_test/pages/www.mlb.com/mlb.mlb.com/NASApp/mlb/index.jsp.html",
+"http://localhost/page_load_test/pages/www.89.com/www.89.com/index.html",
+"http://localhost/page_load_test/pages/www.nba.com/www.nba.com/index.html",
+"http://localhost/page_load_test/pages/www.pornaccess.com/www.pornaccess.com/index.html",
+"http://localhost/page_load_test/pages/www.imagefap.com/www.imagefap.com/index.html",
+"http://localhost/page_load_test/pages/www.pcpop.com/www.pcpop.com/index.html",
+"http://localhost/page_load_test/pages/www.hurriyet.com.tr/www.hurriyet.com.tr/anasayfa/index.html",
+"http://localhost/page_load_test/pages/www.t-online.de/www.t-online.de/index.html",
+"http://localhost/page_load_test/pages/www.google.pt/www.google.pt/index.html",
+"http://localhost/page_load_test/pages/www.no-ip.com/www.no-ip.com/index.html",
+"http://localhost/page_load_test/pages/www.ocn.ne.jp/www.ocn.ne.jp/index.html",
+"http://localhost/page_load_test/pages/www.it168.com/www.it168.com/index.html",
+"http://localhost/page_load_test/pages/www.seesaa.net/tag.seesaa.jp/index.html",
+"http://localhost/page_load_test/pages/www.nih.gov/www.nih.gov/index.html",
+"http://localhost/page_load_test/pages/www.raaga.com/www.raaga.com/index.html",
+"http://localhost/page_load_test/pages/www.lide.cz/www.lide.cz/index.html",
+"http://localhost/page_load_test/pages/www.indiatimes.com/in.indiatimes.com/usdefault.cms.html",
+"http://localhost/page_load_test/pages/www.doubleclick.com/www.doubleclick.com/us/index.html",
+"http://localhost/page_load_test/pages/www.reuters.com/today.reuters.com/news/home.aspx.html",
+"http://localhost/page_load_test/pages/www.dantri.com.vn/www19.dantri.com.vn/news/index.html",
+"http://localhost/page_load_test/pages/www.fotka.pl/www.fotka.pl/index.html",
+"http://localhost/page_load_test/pages/www.miarroba.com/miarroba.com/index.html",
+"http://localhost/page_load_test/pages/www.readnovel.com/www.readnovel.com/index.html",
+"http://localhost/page_load_test/pages/www.hawaaworld.com/www.hawaaworld.com/index.html",
+"http://localhost/page_load_test/pages/www.expedia.com/www.expedia.com/Default.asp@CCheck=1&.html",
+"http://localhost/page_load_test/pages/www.msn.co.uk/uk.msn.com/index.html",
+"http://localhost/page_load_test/pages/www.104.com.tw/www.104.com.tw/index.html",
+"http://localhost/page_load_test/pages/www.eastmoney.com/www.eastmoney.com/index.html",
+"http://localhost/page_load_test/pages/www.fares.net/www.fares.net/index.html",
+"http://localhost/page_load_test/pages/www.zhaopin.com/www.zhaopin.com/index.html",
+"http://localhost/page_load_test/pages/www.clarin.com/www.clarin.com/index.html",
+"http://localhost/page_load_test/pages/www.dreamwiz.com/www.dreamwiz.com/index.html",
+"http://localhost/page_load_test/pages/www.ameblo.jp/www.ameba.jp/index.html",
+"http://localhost/page_load_test/pages/www.dailymotion.com/www.dailymotion.com/index.html",
+"http://localhost/page_load_test/pages/www.ikea.com/www.ikea.com/index.html",
+"http://localhost/page_load_test/pages/www.constantcontact.com/www.constantcontact.com/index.jsp.html",
+"http://localhost/page_load_test/pages/www.mainichi-msn.co.jp/www.mainichi-msn.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.xnxx.com/www.xnxx.com/index.html",
+"http://localhost/page_load_test/pages/www.dnsstuff.com/www.dnsstuff.com/index.html",
+"http://localhost/page_load_test/pages/www.tigerdirect.com/www.tigerdirect.com/index.html",
+"http://localhost/page_load_test/pages/www.nikkei.co.jp/www.nikkei.co.jp/index.html",
+"http://localhost/page_load_test/pages/www.liveinternet.ru/www.liveinternet.ru/index.html",
+"http://localhost/page_load_test/pages/www.forbes.com/www.forbes.com/index.html",
+"http://localhost/page_load_test/pages/www.linksynergy.com/",
+"http://localhost/page_load_test/pages/www.yousendit.com/www.yousendit.com/index.html",
+"http://localhost/page_load_test/pages/www.6rb.com/www.6rb.com/index.html",
+"http://localhost/page_load_test/pages/www.nfl.com/www.nfl.com/index.html",
+"http://localhost/page_load_test/pages/www.bestbuy.com/www.bestbuy.com/index.html",
+"http://localhost/page_load_test/pages/www.iwiw.hu/www.iwiw.hu/pages/user/login.jsp.html",
+"http://localhost/page_load_test/pages/www.aim.com/www.aim.com/index.html",
+"http://localhost/page_load_test/pages/www.zaobao.com/www.zaobao.com/index.html",
+"http://localhost/page_load_test/pages/www.gamefaqs.com/www.gamefaqs.com/index.html",
+"http://localhost/page_load_test/pages/www.whenu.com/www.whenu.com/index.html",
+"http://localhost/page_load_test/pages/www.pogo.com/www.pogo.com/home/home.do@sls=2&site=pogo.html",
+"http://localhost/page_load_test/pages/www.online.sh.cn/www.online.sh.cn/index.html",
+"http://localhost/page_load_test/pages/www.sanook.com/www.sanook.com/index.html",
+"http://localhost/page_load_test/pages/www.blog.cz/blog.cz/index.html",
+"http://localhost/page_load_test/pages/www.feedburner.com/www.feedburner.com/fb/a/home.html",
+"http://localhost/page_load_test/pages/www.msn.ca/sympatico.msn.ca/index.html",
+"http://localhost/page_load_test/pages/www.libero.it/www.libero.it/index.html",
+"http://localhost/page_load_test/pages/72.14.235.104/72.14.235.104/index.html",
+"http://localhost/page_load_test/pages/www.excite.com/www.excite.com/index.html",
+"http://localhost/page_load_test/pages/www.leo.org/www.leo.org/index.html",
+"http://localhost/page_load_test/pages/www.ebay.fr/www.ebay.fr/index.html",
+"http://localhost/page_load_test/pages/www.ctrip.com/www.ctrip.com/index.html",
+"http://localhost/page_load_test/pages/www.last.fm/www.last.fm/index.html",
+"http://localhost/page_load_test/pages/www.gamebase.com.tw/www.gamebase.com.tw/index.html",
+"http://localhost/page_load_test/pages/www.ebay.ca/www.ebay.ca/index.html",
+"http://localhost/page_load_test/pages/www.yimg.com/",
+"http://localhost/page_load_test/pages/www.vietnamnet.vn/www.vietnamnet.vn/index.html",
+"http://localhost/page_load_test/pages/www.uploading.com/www.uploading.com/index.html",
+"http://localhost/page_load_test/pages/www.sapo.pt/www.sapo.pt/index.html",
+"http://localhost/page_load_test/pages/www.usatoday.com/www.usatoday.com/index.html",
+"http://localhost/page_load_test/pages/www.pplive.com/www.pplive.com/zh-cn/index.html",
+"http://localhost/page_load_test/pages/www.multiply.com/multiply.com/index.html",
+"http://localhost/page_load_test/pages/www.jobsdb.com/www.jobsdb.com/default.htm@58518.html",
+"http://localhost/page_load_test/pages/www.4399.net/www.4399.net/index.html",
+"http://localhost/page_load_test/pages/www.ynet.com/www.ynet.com/index.html",
+"http://localhost/page_load_test/pages/www.google.ch/www.google.ch/index.html",
+"http://localhost/page_load_test/pages/www.mac.com/www.apple.com/dotmac/index.html",
+"http://localhost/page_load_test/pages/www.joomla.org/www.joomla.org/index.html",
+"http://localhost/page_load_test/pages/www.dyndns.org/www.dyndns.com/index.html",
+"http://localhost/page_load_test/pages/www.voyeurweb.com/www.voyeurweb.com/index.html",
+"http://localhost/page_load_test/pages/www.wuhan.net.cn/www.wuhan.net.cn/index.html",
+"http://localhost/page_load_test/pages/www.piczo.com/www.piczo.com/index.html@cr=4&rfm=y.html",
+"http://localhost/page_load_test/pages/www.google.be/www.google.be/index.html",
+"http://localhost/page_load_test/pages/www.panet.co.il/www.panet.co.il/index.html",
+"http://localhost/page_load_test/pages/www.google.co.ma/www.google.co.ma/index.html",
+"http://localhost/page_load_test/pages/72.14.221.104/72.14.221.104/index.html",
+"http://localhost/page_load_test/pages/www.msn.com.tw/tw.msn.com/index.html",
+"http://localhost/page_load_test/pages/www.wangyou.com/www.wangyou.com/index.html",
+"http://localhost/page_load_test/pages/www.6arab.com/www.6arab.com/index.html",
+"http://localhost/page_load_test/pages/www.wordpress.org/wordpress.org/index.html",
+"http://localhost/page_load_test/pages/www.onlinedown.net/www.onlinedown.net/index.html",
+"http://localhost/page_load_test/pages/www.drudgereport.com/www.drudgereport.com/index.html",
+"http://localhost/page_load_test/pages/www.joyo.com/www.joyo.com/index.html",
+"http://localhost/page_load_test/pages/www.skycn.com/www.skycn.com/index.html",
+"http://localhost/page_load_test/pages/www.zedo.com/www.zedo.com/index.html",
+"http://localhost/page_load_test/pages/www.i-part.com.cn/www.i-part.com.cn/index.html",
+"http://localhost/page_load_test/pages/www.w3schools.com/www.w3schools.com/index.html",
+"http://localhost/page_load_test/pages/www.payserve.com/www.payserve.com/index.html",
+"http://localhost/page_load_test/pages/www.macromedia.com/www.adobe.com/index.html",
+"http://localhost/page_load_test/pages/www.usercash.com/www.usercash.com/index.html",
+"http://localhost/page_load_test/pages/www.51.la/www.51.la/index.html",
+"http://localhost/page_load_test/pages/www.chinacars.com/www.chinacars.com/index.html",
+"http://localhost/page_load_test/pages/www.cj.com/www.cj.com/index.html",
+"http://localhost/page_load_test/pages/www.isohunt.com/www.isohunt.com/index.html",
+"http://localhost/page_load_test/pages/www.engadget.com/www.engadget.com/index.html",
+"http://localhost/page_load_test/pages/www.nikkansports.com/www.nikkansports.com/index.html",
+"http://localhost/page_load_test/pages/www.fedex.com/www.fedex.com/index.html",
+"http://localhost/page_load_test/pages/www.mobile.de/www.mobile.de/index.html",
+"http://localhost/page_load_test/pages/www.cams.com/www.cams.com/index.html",
+"http://localhost/page_load_test/pages/www.kinghost.com/www.kinghost.com/index.html",
+"http://localhost/page_load_test/pages/www.made-in-china.com/www.made-in-china.com/index.html",
+"http://localhost/page_load_test/pages/www.24h.com.vn/www14.24h.com.vn/index.php.html",
+"http://localhost/page_load_test/pages/www.sxc.hu/www.sxc.hu/index.html",
+"http://localhost/page_load_test/pages/www.tv.com/www.tv.com/index.html",
+"http://localhost/page_load_test/pages/www.nextag.com/www.nextag.com/index.html",
+"http://localhost/page_load_test/pages/www.jrj.com.cn/www.jrj.com.cn/index.html",
+"http://localhost/page_load_test/pages/www.msn.es/es.msn.com/index.html",
+"http://localhost/page_load_test/pages/www.terra.com.ar/www.terra.com.ar/index.html",
+"http://localhost/page_load_test/pages/www.wikimedia.org/www.wikimedia.org/index.html",
+"http://localhost/page_load_test/pages/www.google.lt/www.google.lt/index.html",
+"http://localhost/page_load_test/pages/www.aftonbladet.se/www.aftonbladet.se/index.html",
+"http://localhost/page_load_test/pages/72.14.209.104/72.14.209.104/index.html",
+"http://localhost/page_load_test/pages/www.xrea.com/www.xrea.com/index.html",
+"http://localhost/page_load_test/pages/www.mysql.com/www.mysql.com/index.html",
+"http://localhost/page_load_test/pages/www.overstock.com/www.overstock.com/index.html",
+"http://localhost/page_load_test/pages/www.sitemeter.com/www.sitemeter.com/index.html",
+"http://localhost/page_load_test/pages/www.yok.com/www.yok.com/index.html",
+"http://localhost/page_load_test/pages/www.met-art.com/www.met-art.com/index.html",
+"http://localhost/page_load_test/pages/www.sun.com/www.sun.com/index.html",
+"http://localhost/page_load_test/pages/www.tripadvisor.com/www.tripadvisor.com/index.html",
+"http://localhost/page_load_test/pages/www.gc.ca/www.gc.ca/index.html",
+"http://localhost/page_load_test/pages/www.realtor.com/www.realtor.com/Default.asp@poe=realtor.html",
+"http://localhost/page_load_test/pages/www.spoluzaci.cz/www.spoluzaci.cz/index.html",
+"http://localhost/page_load_test/pages/www.netscape.com/www.netscape.com/index.html",
+"http://localhost/page_load_test/pages/www.asahi.com/www.asahi.com/index.html",
+"http://localhost/page_load_test/pages/www.fanfiction.net/www.fanfiction.net/index.html",
+"http://localhost/page_load_test/pages/www.msn.com.hk/www.msn.com.hk/Default.asp.html",
+"http://localhost/page_load_test/pages/www.travelocity.com/www.travelocity.com/index.html",
+"http://localhost/page_load_test/pages/www.ninemsn.com.au/ninemsn.com.au/index.html",
+"http://localhost/page_load_test/pages/www.stumbleupon.com/www.stumbleupon.com/index.html",
+"http://localhost/page_load_test/pages/www.cafepress.com/www.cafepress.com/index.html",
+"http://localhost/page_load_test/pages/www.livejasmin.com/www.2.livejasmin.com/index.php.html",
+"http://localhost/page_load_test/pages/www.ezinearticles.com/www.ezinearticles.com/index.html",
+"http://localhost/page_load_test/pages/www.pricegrabber.com/www.pricegrabber.com/index.html",
+"http://localhost/page_load_test/pages/www.sina.com/www.sina.com/index.html",
+"http://localhost/page_load_test/pages/www.lycos.com/www.lycos.com/index.html",
+"http://localhost/page_load_test/pages/www.apache.org/www.apache.org/index.html",
+"http://localhost/page_load_test/pages/www.ringo.com/www.ringo.com/index.html",
+"http://localhost/page_load_test/pages/www.videosz.com/www.videosz.com/index.html",
+"http://localhost/page_load_test/pages/www.fotop.net/www.fotop.net/index.html",
+"http://localhost/page_load_test/pages/www.fatwallet.com/www.fatwallet.com/index.html", 
+  ];
+pages_i18n =  pages;
--- a/page_load_test/report.html
+++ b/page_load_test/report.html
@@ -14,17 +14,17 @@
    - The Original Code is JavaScript local page load test.
    -
    - The Initial Developer of the Original Code is
    - Google Inc.
    - Portions created by the Initial Developer are Copyright (C) 1999
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
-   -   Darin Fisher <darin@meer.net>
+   - Darin Fisher <darin@meer.net>
    -
    - 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
@@ -64,14 +64,14 @@
     td.discarded {
       color: gray;
     }
   </style>
 </head>
 <body>
 <table>
   <thead>
-    <tr><th>Page</th><th>Min</th><th>Max</th><th>Mean</th><th>Std</th><th>Times...</th></tr>
+    <tr><th>Page</th><th>Min</th><th>Max</th><th>Mean</th><th>Std</th><th>Median</th><th>Times...</th></tr>
   </thead>
   <tbody id="tbody"></tbody>
 </table>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/post_file.py
@@ -0,0 +1,54 @@
+#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
+#   Submitter: Wade Leftwich
+# Licensing:
+#   according to http://aspn.activestate.com/ASPN/Cookbook/Python
+#   "Except where otherwise noted, recipes in the Python Cookbook are published under the Python license ."
+#   This recipe is covered under the Python license: http://www.python.org/license
+
+import httplib, mimetypes
+
+def post_multipart(host, selector, fields, files):
+    """
+    Post fields and files to an http host as multipart/form-data.
+    fields is a sequence of (name, value) elements for regular form fields.
+    files is a sequence of (name, filename, value) elements for data to be uploaded as files
+    Return the server's response page.
+    """
+    content_type, body = encode_multipart_formdata(fields, files)
+    h = httplib.HTTP(host)
+    h.putrequest('POST', selector)
+    h.putheader('content-type', content_type)
+    h.putheader('content-length', str(len(body)))
+    h.endheaders()
+    h.send(body)
+    errcode, errmsg, headers = h.getreply()
+    return h.file.read()
+
+def encode_multipart_formdata(fields, files):
+    """
+    fields is a sequence of (name, value) elements for regular form fields.
+    files is a sequence of (name, filename, value) elements for data to be uploaded as files
+    Return (content_type, body) ready for httplib.HTTP instance
+    """
+    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
+    CRLF = '\r\n'
+    L = []
+    for (key, value) in fields:
+        L.append('--' + BOUNDARY)
+        L.append('Content-Disposition: form-data; name="%s"' % key)
+        L.append('')
+        L.append(value)
+    for (key, filename, value) in files:
+        L.append('--' + BOUNDARY)
+        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
+        L.append('Content-Type: %s' % get_content_type(filename))
+        L.append('')
+        L.append(value)
+    L.append('--' + BOUNDARY + '--')
+    L.append('')
+    body = CRLF.join(L)
+    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+    return content_type, body
+
+def get_content_type(filename):
+    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
--- a/run_tests.py
+++ b/run_tests.py
@@ -1,10 +1,8 @@
-#!c:/Python24/python.exe
-#
 # ***** 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/
 #
@@ -16,16 +14,17 @@
 # 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)
+#   Alice Nodelman <anodelman@mozilla.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
@@ -47,84 +46,195 @@
 """
 
 __author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
 
 
 import time
 import syck
 import sys
+import urllib 
+import tempfile
+import os
+import string
+import socket
+socket.setdefaulttimeout(480)
 
-import report
-import paths
+import config
+import post_file
 import tp
 import ts
 
-
-# Number of times to run startup test (Ts)
-TS_NUM_RUNS = 5
+def shortNames(name):
+  if name == "tp_loadtime":
+    return "tp_l"
+  elif name == "tp_Percent Processor Time":
+    return "tp_%cpu"
+  elif name == "tp_Working Set":
+    return "tp_memset"
+  elif name == "tp_Private Bytes":
+    return "tp_pbytes"
+  else:
+    return name
 
-# Number of times the page load test (Tp) loads each page in the test.
-TP_NUM_CYCLES = 7
-
-# Resolution of counter sample data for page load test (Tp), in seconds
-# (For example, if TP_RESOLUTION=1, sample counters every 1 second
-TP_RESOLUTION = 1
-
+def process_Request(post):
+  str = ""
+  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'
+  return str
 
 def test_file(filename):
   """Runs the Ts and Tp tests on the given config file and generates a report.
   
   Args:
     filename: the name of the file to run the tests on
   """
   
   test_configs = []
   test_names = []
   title = ''
   filename_prefix = ''
+  testdate = ''
   
   # Read in the profile info from the YAML config file
   config_file = open(filename, 'r')
-  yaml = syck.load(config_file)
+  # some versions of syck take a file, while others take a string
+  try:
+    yaml = syck.load(config_file)
+  except:
+    yaml = syck.load("".join(config_file.readlines()))
   config_file.close()
   for item in yaml:
     if item == 'title':
       title = yaml[item]
     elif item == 'filename':
       filename_prefix = yaml[item]
+    elif item == 'testdate':
+      testdate = yaml[item]
     else:
       new_config = [yaml[item]['preferences'],
                     yaml[item]['extensions'],
-                    yaml[item]['firefox']]
+                    yaml[item]['firefox'],
+                    yaml[item]['branch'],
+                    yaml[item]['branchid'],
+                    yaml[item]['profile_path']]
       test_configs.append(new_config)
       test_names.append(item)
   config_file.close()
-  
+
+  print test_configs
+  sys.stdout.flush()
+  if (testdate != ''):
+    date = int(time.mktime(time.strptime(testdate, '%a, %d %b %Y %H:%M:%S GMT')))
+  else:
+    date = int(time.time()) #TODO get this into own file
+  print "using testdate: %d" % date
+  print "actual date: %d" % int(time.time())
+ 
+
   # Run startup time test
-  ts_times = ts.RunStartupTests(paths.BASE_PROFILE_DIR,
-                                test_configs,
-                                TS_NUM_RUNS)
-  
-  # Run page load test.  For possible values of counters argument, see
-  # http://technet2.microsoft.com/WindowsServer/en/Library/86b5d116-6fb3-427b-af8c-9077162125fe1033.mspx?mfr=true
-  (tp_times, tp_counters) = tp.RunPltTests(paths.BASE_PROFILE_DIR,
-                                           test_configs,
-                                           TP_NUM_CYCLES,
-                                           ['Private Bytes', 'Working Set', '% Processor Time'],
-                                           TP_RESOLUTION)
-  
-  # Generate a report of the results.
-  report.GenerateReport(title,
-                        filename_prefix,
-                        test_names,
-                        ts_times,
-                        tp_times,
-                        tp_counters,
-                        TP_RESOLUTION)
+  ts_times = ts.RunStartupTests(test_configs,
+                                config.TS_NUM_RUNS)
+
+  print "finished ts"
+  sys.stdout.flush()
+  for ts_set in ts_times:
+    if len(ts_set) == 0:
+	print "FAIL:no ts results, build failed to run:BAD BUILD"
+	sys.exit(0)
+
+  (res, r_strings, tp_times, tp_counters) = tp.RunPltTests(test_configs,
+                                           config.TP_NUM_CYCLES,
+                                           config.COUNTERS,
+                                           config.TP_RESOLUTION)
+
+  print "finished tp"
+  sys.stdout.flush()
+
+  if not res:
+    print "FAIL:tp did not run to completion"
+    print "FAIL:" + r_strings[0]
+    sys.exit(0)
+
+  #TODO: place this in its own file
+  #send results to the graph server
+  # each line of the string is of the format i;page_name;median;mean;min;max;time vals\n
+  tbox = title
+  url_format = "http://%s/%s"
+  link_format= "<a href = \"%s\">%s</a>"
+  #value, testname, tbox, timeval, date, branch, branchid, type, data
+  result_format = "%.2f,%s,%s,%d,%d,%s,%s,%s,%s,\n"
+  result_format2 = "%.2f,%s,%s,%d,%d,%s,%s,%s,\n"
+  filename = tempfile.mktemp()
+  tmpf = open(filename, "w")
+
+  testname = "ts"
+  print "formating results for: ts"
+  print "# of values: %d" % len(ts_times)
+  for index in range(len(ts_times)):
+    i = 0
+    for tstime in ts_times[index]:
+      tmpf.write(result_format % (float(tstime), testname, tbox, i, date, test_configs[index][3], test_configs[index][4], "discrete", "ms"))
+      i = i+1
+
+  testname = "tp"
+  for index in range(len(r_strings)):
+    r_strings[index].strip('\n')
+    page_results = r_strings[index].splitlines()
+    i = 0
+    print "formating results for: loadtime"
+    print "# of values: %d" % len(page_results)
+    for mypage in page_results[3:]:
+      r = mypage.split(';')
+      tmpf.write(result_format % (float(r[2]), testname + "_loadtime", tbox, i, date, test_configs[index][3], test_configs[index][4], "discrete", r[1]))
+      i = i+1
+
+  for index in range(len(tp_counters)):
+    for count_type in config.COUNTERS:
+      i = 0
+      print "formating results for: " + count_type
+      print "# of values: %d" % len(tp_counters[index][count_type])
+      for value in tp_counters[index][count_type]:
+        tmpf.write(result_format2 % (float(value), testname + "_" + count_type.replace("%", "Percent"), tbox, i, date, test_configs[index][3], test_configs[index][4], "discrete"))
+        i = i+1
 
 
+  print "finished formating results"
+  tmpf.flush()
+  tmpf.close()
+  tmpf = open(filename, "r")
+  file_data = tmpf.read()
+  while True:
+    try:
+      ret = post_file.post_multipart(config.RESULTS_SERVER, config.RESULTS_LINK, [("key", "value")], [("filename", filename, file_data)
+   ])
+    except IOError:
+      print "IOError"
+    else:
+      break
+  print "completed sending results"
+  links = process_Request(ret)
+  tmpf.close()
+  os.remove(filename)
+
+  lines = links.split('\n')
+  for line in lines:
+    if line == "":
+      continue
+    values = line.split(":")
+    linkName = values[1]
+    if float(values[2]) > 0:
+      linkName += "_T: " + values[2]
+    else:
+      linkName += "_1"
+    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)):
     test_file(sys.argv[i])
 
--- a/sample.config
+++ b/sample.config
@@ -1,36 +1,35 @@
-# This is a sample configuration file to show how to run the Windows
-# performance tests.
-
-# The title of the html report
-title: Windows 2000, 1Ghz Celeron, 256MB Ram
-
-# Text to append to the filename (should only contain letters, numbers,
-# and underscores)
-filename: win2k_lowmem
-
-# Profiles to test. Each of these can have different extensions installed,
-# different prefs set, and different paths to firefox.
-
-Firefox 1.5:
-  # Path to Firefox executable to test:
-  firefox: "C:\\Program Files\\Mozilla Firefox\\firefox.exe"
-  
-  # No preferences beyond the defaults
-  preferences: {}
-  
-  # No extensions installed
-  extensions: {}
-
-Firefox 2.0 beta 1:
-  # Path to Firefox executable to test:
-  firefox: "C:\\Program Files\Mozilla Firefox 2 Beta 1\\firefox.exe"
-  
-  # Turn on prefs to enable safe browsing with no remote lookups
-  # As an example of a string pref, make the selected search eBay
-  preferences:
-    browser.safebrowsing.enabled: true
-    browser.safebrowsing.remoteLookups: false
-    browser.search.selectedEngine: "eBay"
-   
-  # No extensions
-  extensions: {}
+# 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.exe
+
+  branch: testbranch
+
+  branchid: testbranchid
+
+  profile_path: C:\talos\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
+    dom.disable_window_flip : true
+    dom.disable_window_move_resize : true
+    security.enable_java : false
+
+  # Extensions to install in test (use "extensions: {}" for none)
+  #extensions:
+  extensions : {}
+
--- a/startup_test/startup_test.html
+++ b/startup_test/startup_test.html
@@ -14,17 +14,18 @@
    - The Original Code is JavaScript startup test.
    -
    - The Initial Developer of the Original Code is
    - Google Inc.
    - Portions created by the Initial Developer are Copyright (C) 1999
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
-   -   Annie Sullivan <annie.sullivan@gmail.com>
+   - Annie Sullivan <annie.sullivan@gmail.com>
+   - Alice Nodelman <anodelman@mozilla.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
@@ -38,12 +39,11 @@
     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');
     }
     window.close();
-}
 ">
 </body>
 </html>
--- a/tp.py
+++ b/tp.py
@@ -1,10 +1,8 @@
-#!c:/Python24/python.exe
-#
 # ***** 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/
 #
@@ -16,16 +14,17 @@
 # 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> (OS independence)
 #
 # 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
@@ -45,101 +44,48 @@
    We can also measure performance attributes during the test.  See
    http://technet2.microsoft.com/WindowsServer/en/Library/86b5d116-6fb3-427b-af8c-9077162125fe1033.mspx?mfr=true
    for a description of what can be measured.
 """
 
 __author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
 
 
+import platform
 import os
 import re
 import shutil
 import time
-import win32pdh
-import win32pdhutil
+import sys
 
 import ffprocess
 import ffprofile
-import paths
+import ffinfo
+import config
+
+if platform.system() == "Linux":
+    from tp_linux import *
+elif platform.system() == "Windows":
+    from tp_win32 import *
 
 
 # Regular expression to get stats for page load test (Tp)
-TP_REGEX = re.compile('__start_page_load_report(.*)__end_page_load_report',
+TP_REGEX = re.compile('__start_tp_report(.*)__end_tp_report',
                       re.DOTALL | re.MULTILINE)
-
-
-def AddCounter(counter_name):
-  """Adds a pdh query and counter of the given name to Firefox.
-  
-  Args: counter_name: The name of the counter to add, i.e. "% Processor Time"
-  
-  Returns:
-    (query handle, counter handle)
-  """
-  
-  path = win32pdh.MakeCounterPath( (None,
-                                    'process',
-                                    'firefox',
-                                    None,
-                                    -1,
-                                    counter_name) )
-  hq = win32pdh.OpenQuery()
-  try:
-    hc = win32pdh.AddCounter(hq, path)
-  except:
-    win32pdh.CloseQuery(hq)
-  return hq, hc
+TP_REGEX_FAIL = re.compile('__FAIL(.*)__FAIL', re.DOTALL|re.MULTILINE)
 
 
-def CleanupCounter(hq, hc):
-  """Cleans up a counter after it is no longer needed.
-  
-  Args:
-    hq: handle to the query for the counter
-    hc: handle to the counter
-  """
-  
-  try:
-    win32pdh.RemoveCounter(hc)
-    win32pdh.CloseQuery(hq)
-  except:
-    # Sometimes we get unexpected win32 errors.  Not much can be done.
-    pass
-
-
-def GetCounterValue(hq, hc):
-  """Returns the current value of the given counter
-  
-  Args:
-    hq: Handle of the query for the counter
-    hc: Handle of the counter
-  
-  Returns:
-    The current value of the counter
-  """
-  
-  try:
-    win32pdh.CollectQueryData(hq)
-    type, val = win32pdh.GetFormattedCounterValue(hc, win32pdh.PDH_FMT_LONG)
-    return val
-  except:
-    return None
-
-
-def RunPltTests(source_profile_dir,
-                profile_configs,
+def RunPltTests(profile_configs,
                 num_cycles,
                 counters,
                 resolution):
   """Runs the Page Load tests with profiles created from the given
      base diectory and list of configuations.
   
   Args:
-    source_profile_dir:  Full path to base directory to copy profile from.
     profile_configs:  Array of configuration options for each profile.
       These are of the format:
       [{prefname:prevalue,prefname2:prefvalue2},
        {extensionguid:path_to_extension}],[{prefname...
     num_cycles: Number of times to cycle through all the urls on each test.
     counters: Array of counters ("% Processor Time", "Working Set", etc)
               See http://technet2.microsoft.com/WindowsServer/en/Library/86b5d116-6fb3-427b-af8c-9077162125fe1033.mspx?mfr=true
               for a list of available counters and their descriptions.
@@ -148,83 +94,98 @@ def RunPltTests(source_profile_dir,
   Returns:
     A tuple containing:
       An array of plt results for each run.  For example:
         ["mean: 150.30\nstdd:34.2", "mean 170.33\nstdd:22.4"]
       An array of counter data from each run.  For example:
         [{"counter1": [1, 2, 3], "counter2":[4,5,6]},
          {"counter1":[1,3,5], "counter2":[2,4,6]}]
   """
-  
+ 
+  res = 0
   counter_data = []
   plt_results = []
-  for config in profile_configs:
+  results_string = []
+  for pconfig in profile_configs:
+    print "in tp"
+    print pconfig
+    sys.stdout.flush()
+    rstring = ""
     # Create the new profile
-    profile_dir = ffprofile.CreateTempProfileDir(source_profile_dir,
-                                                 config[0],
-                                                 config[1])
-  
+    profile_dir = ffprofile.CreateTempProfileDir(pconfig[5],
+                                                 pconfig[0],
+                                                 pconfig[1])
+    print "created profile" 
     # 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.
-    ffprofile.InitializeNewProfile(config[2], profile_dir)
+    ffprofile.InitializeNewProfile(pconfig[2], profile_dir)
+    ffinfo.GetMetricsFromBrowser(pconfig[2], profile_dir)
+    print "initialized firefox"
+    sys.stdout.flush()
     ffprocess.SyncAndSleep()
 
     # Run the plt test for this profile
-    timeout = 300
+    timeout = 10000
     total_time = 0
     output = ''
-    url = paths.TP_URL + '?cycles=' + str(num_cycles)
-    command_line = ffprocess.GenerateFirefoxCommandLine(config[2], profile_dir, url)
+    url = config.TP_URL + '?cycles=' + str(num_cycles)
+    command_line = ffprocess.GenerateFirefoxCommandLine(pconfig[2], profile_dir, url)
     handle = os.popen(command_line)
-    # PDH might need to be "refreshed" if it has been queried while
-    # Firefox is closed.
-    win32pdh.EnumObjects(None, None, 0, 1)
-    
-    # Initialize counts
+    # give firefox a chance to open
+    time.sleep(1)
+
+    cm = CounterManager("firefox", counters)
+
+    cm.startMonitor()
+
     counts = {}
-    counter_handles = {}
     for counter in counters:
       counts[counter] = []
-      counter_handles[counter] = AddCounter(counter)
     
     while total_time < timeout:
     
       # Sleep for [resolution] seconds
       time.sleep(resolution)
       total_time += resolution
       
       # Get the output from all the possible counters
       for count_type in counters:
-        val = GetCounterValue(counter_handles[count_type][0],
-                              counter_handles[count_type][1])
+        val = cm.getCounterValue(count_type)
+
         if (val):
-          # Sometimes the first sample can be None, or PLT test will have
-          # closed Firefox by this point.  Only count real values. 
           counts[count_type].append(val)
 
       # Check to see if page load times were outputted
       (bytes, current_output) = ffprocess.NonBlockingReadProcessOutput(handle)
       output += current_output
       match = TP_REGEX.search(output)
       if match:
+        rstring += match.group(1)
         plt_results.append(match.group(1))
-        break;
-    
-    # Cleanup counters
-    for counter in counters:
-      CleanupCounter(counter_handles[counter][0], counter_handles[counter][1])
+	res = 1
+        break
+      match = TP_REGEX_FAIL.search(output)
+      if match:
+        rstring += match.group(1)
+        plt_results.append(match.group(1))
+        break
+
+    cm.stopMonitor()
+   
+    print "got tp results from browser" 
 
     # Firefox should have exited cleanly, but close it if it doesn't
     # after 2 seconds.
     time.sleep(2)
     ffprocess.TerminateAllProcesses("firefox")
     ffprocess.SyncAndSleep()
     
     # Delete the temp profile directory  Make it writeable first,
     # because every once in a while Firefox seems to drop a read-only
     # file into it.
     ffprofile.MakeDirectoryContentsWritable(profile_dir)
     shutil.rmtree(profile_dir)
     
     counter_data.append(counts)
-  
-  return (plt_results, counter_data)
+    results_string.append(rstring)
+
+  return (res, results_string, plt_results, counter_data)
new file mode 100644
--- /dev/null
+++ b/tp_linux.py
@@ -0,0 +1,261 @@
+#!/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)
+#
+# 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 ffprocess
+
+def GetPrivateBytes(pid):
+  """Calculate the amount of private, writeable memory allocated to a process.
+     This code was adapted from 'pmap.c', part of the procps project.
+  """
+  mapfile = '/proc/%s/maps' % pid
+  maps = open(mapfile)
+
+  private = 0
+
+  for line in maps:
+    # split up
+    (range,line) = line.split(" ", 1)
+
+    (start,end) = range.split("-")
+    flags = line.split(" ", 1)[0]
+
+    size = int(end, 16) - int(start, 16)
+
+    if flags.find("p") >= 0:
+      if flags.find("w") >= 0:
+        private += size
+
+  return private
+
+
+def GetResidentSize(pid):
+  """Retrieve the current resident memory for a given process"""
+  # for some reason /proc/PID/stat doesn't give accurate information
+  # so we use status instead
+  file = '/proc/%s/status' % pid
+
+  status = open(file)
+
+  for line in status:
+    if line.find("VmRSS") >= 0:
+      return int(line.split()[1]) * 1024
+
+
+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))
+
+
+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]
+      os.stat('/proc/%s' % self.pid)
+      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)
new file mode 100644
--- /dev/null
+++ b/tp_win32.py
@@ -0,0 +1,98 @@
+# ***** 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> (OS independence)
+#
+# 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 win32pdh
+import win32pdhutil
+
+
+class CounterManager:
+
+  def __init__(self, process, counters=None):
+    self.process = process
+    self.registeredCounters = {}
+    self.registerCounters(counters)
+    # PDH might need to be "refreshed" if it has been queried while Firefox
+    # is closed
+    win32pdh.EnumObjects(None, None, 0, 1)
+
+  def registerCounters(self, counters):
+    for counter in counters:
+      self.registeredCounters[counter] = []
+            
+  def unregisterCounters(self, counters):
+    for counter in counters:
+      if counter in self.registeredCounters:
+        del self.registeredCounters[counter]
+
+  def getRegisteredCounters(self):
+    return keys(self.registeredCounters)
+
+  def getCounterValue(self, counter):
+    hq = self.registeredCounters[counter][0]
+    hc = self.registeredCounters[counter][1]
+    try:
+      win32pdh.CollectQueryData(hq)
+      type, val = win32pdh.GetFormattedCounterValue(hc, win32pdh.PDH_FMT_LONG)
+      return val
+    except:
+      return None
+
+  def getProcess(self):
+    return self.process
+
+  def startMonitor(self):
+    # PDH might need to be "refreshed" if it has been queried while Firefox
+    # is closed
+    win32pdh.EnumObjects(None, None, 0, 1)
+
+    for counter in self.registeredCounters:
+      path = win32pdh.MakeCounterPath((None, 'process', self.process,
+                                       None, -1, counter))
+      hq = win32pdh.OpenQuery()
+      try:
+        hc = win32pdh.AddCounter(hq, path)
+      except:
+        win32pdh.CloseQuery(hq)
+
+      self.registeredCounters[counter] = [hq, hc]
+
+  def stopMonitor(self):
+    for counter in self.registeredCounters:
+      win32pdh.RemoveCounter(self.registeredCounters[counter][1])
+      win32pdh.CloseQuery(self.registeredCounters[counter][0])
+    self.registeredCounters.clear()
--- a/ts.py
+++ b/ts.py
@@ -1,10 +1,8 @@
-#!c:/Python24/python.exe
-#
 # ***** 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/
 #
@@ -16,16 +14,17 @@
 # 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)
+#   Alice Nodelman <anodelman@mozilla.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
@@ -50,17 +49,18 @@
 
 
 import re
 import shutil
 import time
 
 import ffprocess
 import ffprofile
-import paths
+import ffinfo
+import config
 
 
 # Regular expression to get the time for startup test (Ts)
 TS_REGEX = re.compile('__startuptime,(\d*)')
 
 
 def IsInteger(number):
   """Helper function to determine if a variable is an integer"""
@@ -91,59 +91,59 @@ def RunStartupTest(firefox_path, profile
   startup_times = []
   for i in range(-1, num_runs):
     # Make sure we don't get "Firefox is already running..." errors
     ffprocess.SyncAndSleep()
 
     # Create a command line that passes in the url of the startup test
     # with the current time as the begin_time argument
     time_arg = int(time.time() * 1000)
-    url = paths.TS_URL + str(time_arg)
+    url = config.TS_URL + str(time_arg)
     command_line = ffprocess.GenerateFirefoxCommandLine(firefox_path, profile_dir, url)
     (match, timed_out) = ffprocess.RunProcessAndWaitForOutput(command_line,
                                                               'firefox',
                                                               TS_REGEX,
                                                               timeout)
     if timed_out or not IsInteger(match):
       match = None
     if i > -1 and match and match > 0:
       startup_times.append(match)
 
   return startup_times
 
 
-def RunStartupTests(source_profile_dir, profile_configs, num_runs):
+def RunStartupTests(profile_configs, num_runs):
   """Runs the startup tests with profiles created from the
      given base profile directory and list of configurations.
 
   Args:
-    source_profile_dir:  Full path to base directory to copy profile from.
     profile_configs:  Array of configuration options for each profile.
       These are of the format:
       [{prefname:prevalue,prefname2:prefvalue2},{extensionguid:path_to_extension}],[{prefname...
     num_runs: Number of times to run startup tests for each profile
 
   Returns:
     Array of arrays of startup times, one for each profile.
   """
 
   all_times = []
   for config in profile_configs:
     # Create the new profile
-    profile_dir = ffprofile.CreateTempProfileDir(source_profile_dir,
+    profile_dir = ffprofile.CreateTempProfileDir(config[5],
                                                  config[0],
                                                  config[1])
 
     # 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.
     ffprofile.InitializeNewProfile(config[2], profile_dir)
+    ffinfo.GetMetricsFromBrowser(config[2], profile_dir)
 
     # Run the startup tests for this profile and log the results.
-    times = RunStartupTest(config[2], profile_dir, 5, 30)
+    times = RunStartupTest(config[2], profile_dir, num_runs, 10)
     all_times.append(times)
 
     # Delete the temp profile directory.  Make it writeable first,
     # because every once in a while Firefox seems to drop a read-only
     # file into it.
     ffprocess.SyncAndSleep()
     ffprofile.MakeDirectoryContentsWritable(profile_dir)
     shutil.rmtree(profile_dir)