Bug 1196430 - part 7 - teach process_leak_log how to symbolicate leaked object stacks; r=mccr8
authorNathan Froyd <froydnj@mozilla.com>
Wed, 26 Aug 2015 19:41:43 -0400
changeset 294406 3f6c4bdd629574281b4648545f963b05cd0774a6
parent 294405 95b4e5d5b14c27268f60832be0bc1062c7199b05
child 294407 5b0c8bcaaa9a7deea45ed6a54dd91ac9d204126a
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1196430
milestone43.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 1196430 - part 7 - teach process_leak_log how to symbolicate leaked object stacks; r=mccr8
layout/tools/reftest/runreftest.py
testing/mochitest/runtests.py
testing/mochitest/runtestsb2g.py
testing/mozbase/mozleak/mozleak/leaklog.py
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -625,17 +625,20 @@ class RefTest(object):
                                  # its own timeouts
                                  env=browserEnv,
                                  timeout=options.timeout + 30.0,
                                  symbolsPath=options.symbolsPath,
                                  options=options,
                                  debuggerInfo=debuggerInfo)
             mozleak.process_leak_log(self.leakLogFile,
                                      leak_thresholds=options.leakThresholds,
-                                     log=log)
+                                     log=log,
+                                     stack_fixer=get_stack_fixer_function(options.utilityPath,
+                                                                          options.symbolsPath),
+            )
             log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
         finally:
             self.cleanup(profileDir)
         return status
 
     def copyExtraFilesToProfile(self, options, profile):
         "Copy extra files or dirs specified on the command line to the testing profile."
         profileDir = profile.profile
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -2243,16 +2243,18 @@ class Mochitest(MochitestUtilsMixin):
         finally:
             self.stopServers()
 
         mozleak.process_leak_log(
             self.leak_report_file,
             leak_thresholds=options.leakThresholds,
             ignore_missing_leaks=options.ignoreMissingLeaks,
             log=self.log,
+            stack_fixer=get_stack_fixer_function(options.utilityPath,
+                                                 options.symbolsPath),
         )
 
         if self.nsprLogs:
             with zipfile.ZipFile("%s/nsprlog.zip" % self.browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
                 for logfile in glob.glob(
                         "%s/nspr*.log*" %
                         tempfile.gettempdir()):
                     logzip.write(logfile)
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -14,16 +14,17 @@ import traceback
 here = os.path.abspath(os.path.dirname(__file__))
 sys.path.insert(0, here)
 
 from runtests import Mochitest
 from runtests import MochitestUtilsMixin
 from mochitest_options import MochitestArgumentParser
 from marionette import Marionette
 from mozprofile import Profile, Preferences
+from mozrunner.utils import get_stack_fixer_function
 import mozinfo
 import mozleak
 
 
 class B2GMochitest(MochitestUtilsMixin):
     marionette = None
 
     def __init__(self, marionette_args,
@@ -273,16 +274,18 @@ class B2GMochitest(MochitestUtilsMixin):
                 local_leak_file.name)
             self.app_ctx.dm.removeFile(self.leak_report_file)
 
             mozleak.process_leak_log(
                 local_leak_file.name,
                 leak_thresholds=options.leakThresholds,
                 ignore_missing_leaks=options.ignoreMissingLeaks,
                 log=self.log,
+                stack_fixer=get_stack_fixer_function(options.utilityPath,
+                                                     options.symbolsPath),
             )
         except KeyboardInterrupt:
             self.log.info("runtests.py | Received keyboard interrupt.\n")
             status = -1
         except:
             traceback.print_exc()
             self.log.error(
                 "Automation Error: Received unexpected exception while running application\n")
--- a/testing/mozbase/mozleak/mozleak/leaklog.py
+++ b/testing/mozbase/mozleak/mozleak/leaklog.py
@@ -1,24 +1,28 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
 import os
 import re
+import sys
 
+import mozinfo
+import mozrunner.utils
 
 def _raw_log():
     import logging
     return logging.getLogger(__name__)
 
 
 def process_single_leak_file(leakLogFileName, processType, leakThreshold,
-                             ignoreMissingLeaks, log=None):
+                             ignoreMissingLeaks, log=None,
+                             stackFixer=None):
     """Process a single leak log.
     """
 
     #     |              |Per-Inst  Leaked|     Total  Rem|
     #   0 |TOTAL         |      17     192| 419115886    2|
     # 833 |nsTimerImpl   |      60     120|     24726    2|
     # 930 |Foo<Bar, Bar> |      32       8|       100    1|
     lineRe = re.compile(r"^\s*\d+ \|"
@@ -39,17 +43,18 @@ def process_single_leak_file(leakLogFile
     recordLeakedObjects = False
     with open(leakLogFileName, "r") as leaks:
         for line in leaks:
             if line.find("purposefully crash") > -1:
                 crashedOnPurpose = True
             matches = lineRe.match(line)
             if not matches:
                 # eg: the leak table header row
-                log.info(line.rstrip())
+                strippedLine = line.rstrip()
+                log.info(stackFixer(strippedLine) if stackFixer else strippedLine)
                 continue
             name = matches.group("name").rstrip()
             size = int(matches.group("size"))
             bytesLeaked = int(matches.group("bytesLeaked"))
             numLeaked = int(matches.group("numLeaked"))
             # Output the raw line from the leak log table if it is the TOTAL row,
             # or is for an object row that has been leaked.
             if numLeaked != 0 or name == "TOTAL":
@@ -131,17 +136,18 @@ def process_single_leak_file(leakLogFile
         log.warning("%s | leakcheck | %s %d bytes leaked (%s)"
                     % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
     else:
         log.info("%s | leakcheck | %s %d bytes leaked (%s)"
                  % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
 
 
 def process_leak_log(leak_log_file, leak_thresholds=None,
-                     ignore_missing_leaks=None, log=None):
+                     ignore_missing_leaks=None, log=None,
+                     stack_fixer=None):
     """Process the leak log, including separate leak logs created
     by child processes.
 
     Use this function if you want an additional PASS/FAIL summary.
     It must be used with the |XPCOM_MEM_BLOAT_LOG| environment variable.
 
     The base of leak_log_file for a non-default process needs to end with
       _proctype_pid12345.log
@@ -201,9 +207,9 @@ def process_leak_log(leak_log_file, leak
             else:
                 processType = "default"
             if not processType in knownProcessTypes:
                 log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
                          % processType)
             leakThreshold = leakThresholds.get(processType, 0)
             process_single_leak_file(thisFile, processType, leakThreshold,
                                      processType in ignoreMissingLeaks,
-                                     log=log)
+                                     log=log, stackFixer=stack_fixer)