Bug 1463483: Add session store analysis to xperf; r=jmaher
authorAaron Klotz <aklotz@mozilla.com>
Fri, 10 Aug 2018 12:03:54 -0600
changeset 488176 f7d550d783449a155a5681f0db3939bd9ecad58b
parent 488175 675288974991830a083a7d8d4f761fa8ab4db493
child 488177 c70943a6b070698c59db4802c912a6c682b49ba4
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher
bugs1463483
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1463483: Add session store analysis to xperf; r=jmaher This patch uses the new xperf analyzer to determine the duration of time from the start of the first firefox process to the session store window restored event. I'd like to have this running for a little bit to collect some data points before we flip the switch to enable the launcher process by default.
testing/talos/talos/results.py
testing/talos/talos/test.py
testing/talos/talos/xtalos/etlparser.py
testing/talos/talos/xtalos/parse_xperf.py
--- a/testing/talos/talos/results.py
+++ b/testing/talos/talos/results.py
@@ -410,23 +410,27 @@ class BrowserLogResults(object):
         if global_counters is not None:
             if 'responsiveness' in global_counters:
                 global_counters['responsiveness'].extend(self.responsiveness())
             self.xperf(global_counters)
 
     def xperf(self, counter_results):
         """record xperf counters in counter_results dictionary"""
 
+        session_store_counter = 'time_to_session_store_window_restored_ms'
+
         counters = ['main_startup_fileio',
                     'main_startup_netio',
                     'main_normal_fileio',
                     'main_normal_netio',
                     'nonmain_startup_fileio',
                     'nonmain_normal_fileio',
-                    'nonmain_normal_netio']
+                    'nonmain_normal_netio',
+                    session_store_counter,
+                    ]
 
         mainthread_counter_keys = ['readcount', 'readbytes', 'writecount',
                                    'writebytes']
         mainthread_counters = ['_'.join(['mainthread', counter_key])
                                for counter_key in mainthread_counter_keys]
 
         self.mainthread_io(counter_results)
 
@@ -486,16 +490,25 @@ class BrowserLogResults(object):
                     continue
                 values = dict(zip(header, row))
                 for i, mainthread_counter in enumerate(mainthread_counters):
                     if int(values[mainthread_counter_keys[i]]) > 0:
                         counter_results.setdefault(mainthread_counter, [])\
                             .append([int(values[mainthread_counter_keys[i]]),
                                      values['filename']])
 
+        if session_store_counter in counter_results.keys():
+            filename = 'etl_output_session_restore_stats.csv'
+            # This file is a csv but it only contains one field, so we'll just
+            # obtain the value by converting the second line in the file.
+            with open(filename, 'r') as contents:
+                lines = contents.read().splitlines()
+                value = float(lines[1].strip())
+                counter_results.setdefault(session_store_counter, []).append(value)
+
     def mainthread_io(self, counter_results):
         """record mainthread IO counters in counter_results dictionary"""
 
         # we want to measure mtio on xperf runs.
         # this will be shoved into the xperf results as we ignore those
         SCRIPT_DIR = \
             os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
         filename = os.path.join(SCRIPT_DIR, 'mainthread_io.json')
--- a/testing/talos/talos/test.py
+++ b/testing/talos/talos/test.py
@@ -507,17 +507,19 @@ class tp5n(PageloaderTest):
     win_counters = []
     linux_counters = []
     mac_counters = []
     xperf_counters = ['main_startup_fileio', 'main_startup_netio',
                       'main_normal_fileio', 'main_normal_netio',
                       'nonmain_startup_fileio', 'nonmain_normal_fileio',
                       'nonmain_normal_netio', 'mainthread_readcount',
                       'mainthread_readbytes', 'mainthread_writecount',
-                      'mainthread_writebytes']
+                      'mainthread_writebytes',
+                      'time_to_session_store_window_restored_ms',
+                      ]
     xperf_providers = ['PROC_THREAD', 'LOADER', 'HARD_FAULTS', 'FILENAME',
                        'FILE_IO', 'FILE_IO_INIT']
     xperf_user_providers = ['Mozilla Generic Provider',
                             'Microsoft-Windows-TCPIP']
     xperf_stackwalk = ['FileCreate', 'FileRead', 'FileWrite', 'FileFlush',
                        'FileClose']
     filters = filter.ignore_first.prepare(1) + filter.median.prepare()
     timeout = 1800
--- a/testing/talos/talos/xtalos/etlparser.py
+++ b/testing/talos/talos/xtalos/etlparser.py
@@ -8,17 +8,16 @@ from __future__ import absolute_import, 
 import csv
 import json
 import os
 import re
 import shutil
 import subprocess
 import sys
 
-import mozfile
 import xtalos
 
 EVENTNAME_INDEX = 0
 PROCESS_INDEX = 2
 THREAD_ID_INDEX = 3
 DISKBYTES_COL = "Size"
 FNAME_COL = "FileName"
 IMAGEFUNC_COL = "Image!Function"
@@ -329,18 +328,16 @@ def etlparser(xperf_path, etl_filename, 
         elif event.endswith("Event/Classic") and \
                 row[THREAD_ID_INDEX] in gThreads:
             stage = updateStage(row, stage)
         elif event.startswith("Microsoft-Windows-TCPIP"):
             trackThreadNetIO(row, io, stage)
 
     if debug:
         uploadFile(csvname)
-    else:
-        mozfile.remove(csvname)
 
     output = "thread, stage, counter, value\n"
     for cntr in sorted(io.iterkeys()):
         output += "%s, %s\n" % (", ".join(cntr), str(io[cntr]))
     if outputFile:
         fname = "%s_thread_stats%s" % os.path.splitext(outputFile)
         with open(fname, "w") as f:
             f.write(output)
--- a/testing/talos/talos/xtalos/parse_xperf.py
+++ b/testing/talos/talos/xtalos/parse_xperf.py
@@ -5,17 +5,49 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from __future__ import absolute_import, print_function
 
 import os
 import subprocess
 import sys
 
 import etlparser
+import mozfile
 import xtalos
+from xperf_analyzer import (ProcessStart, SessionStoreWindowRestored,
+                            XPerfAttribute, XPerfFile, XPerfInterval)
+
+
+def run_session_restore_analysis(debug=False, **kwargs):
+    required = ('csv_filename', 'outputFile')
+    for r in required:
+        if r not in kwargs:
+            raise xtalos.XTalosError('%s required' % r)
+
+    final_output_file = "%s_session_restore_stats%s" % os.path.splitext(
+        kwargs['outputFile'])
+
+    output = 'time_to_session_store_window_restored_ms\n'
+
+    with XPerfFile(csvfile=kwargs['csv_filename'], debug=debug) as xperf:
+        fx_start = ProcessStart('firefox.exe')
+        ss_window_restored = SessionStoreWindowRestored()
+
+        interval = XPerfInterval(fx_start, ss_window_restored)
+        xperf.add_attr(interval)
+
+        xperf.analyze()
+
+        output += "%.3f\n" % (interval.get_results()[XPerfAttribute.RESULT])
+
+    with open(final_output_file, 'w') as out:
+        out.write(output)
+
+    if debug:
+        etlparser.uploadFile(final_output_file)
 
 
 def stop(xperf_path, debug=False):
     xperf_cmd = [xperf_path, '-stop', '-stop', 'talos_ses']
     if debug:
         print("executing '%s'" % subprocess.list2cmdline(xperf_cmd))
     subprocess.call(xperf_cmd)
 
@@ -52,24 +84,30 @@ def stop_from_config(config_file=None, d
     # call start
     stop(**stopargs)
 
     etlparser.etlparser_from_config(config_file,
                                     approot=kwargs['approot'],
                                     error_filename=kwargs['error_filename'],
                                     processID=kwargs['processID'])
 
+    csv_base = '%s.csv' % kwargs['etl_filename']
+    run_session_restore_analysis(csv_filename=csv_base, debug=debug, **kwargs)
+
+    if not debug:
+        mozfile.remove(csv_base)
+
 
 def main(args=sys.argv[1:]):
 
     # parse command line arguments
     parser = xtalos.XtalosOptions()
     args = parser.parse_args(args)
 
-    # start xperf
+    # stop xperf
     try:
         stop_from_config(config_file=args.configFile,
                          debug=args.debug_level >= xtalos.DEBUG_INFO,
                          **args.__dict__)
     except xtalos.XTalosError as e:
         parser.error(str(e))