Commit ee2bcc4e authored by timurrrr@chromium.org's avatar timurrrr@chromium.org

Set up python BROWSER_WRAPPER for ui_tests under Dr. Memory

Also, clean-up and slightly re-design drmemory_analyze.py to be more like
memcheck_analyze.py
Looks like more refactoring can be done later to really share the code with
Valgrind and TSan, esp. the BROWSER_WRAPPER itself.
No idea why it was a bash script initially.

TBR=bruening,glider
TEST=ran tools\valgrind\chrome_tests.bat --tool drmemory_light --keep_logs -t base --gtest_filter="*Sanity*"
     and ... -t ui --gtest_filter="RedirectTest.Server:RedirectTest.Client"
     with tools/valgrind/drmemory/suppressions.txt removed
Review URL: http://codereview.chromium.org/8688006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111528 0039d316-1c4b-4281-b951-d872f2087c98
parent 16892aca
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import re
import sys
import subprocess
# TODO(timurrrr): we may use it on POSIX too to avoid code duplication once we
# support layout_tests, remove Dr. Memory specific code and verify it works
# on a "clean" Mac.
wrapper_pid = os.getpid()
testcase_name = None
for arg in sys.argv:
m = re.match("\-\-test\-name=(.*)", arg)
if m:
assert testcase_name is None
testcase_name = m.groups()[0]
# arg #0 is the path to this python script
cmd_to_run = sys.argv[1:]
# TODO(timurrrr): this is Dr. Memory-specific
# Usually, we pass "-logdir" "foo\bar\spam path" args to Dr. Memory.
# To group reports per UI test, we want to put the reports for each test into a
# separate directory. This code can be simplified when we have
# http://code.google.com/p/drmemory/issues/detail?id=684 fixed.
logdir_idx = cmd_to_run.index("-logdir")
old_logdir = cmd_to_run[logdir_idx + 1]
cmd_to_run[logdir_idx + 1] += "\\testcase.%d.logs" % wrapper_pid
os.makedirs(cmd_to_run[logdir_idx + 1])
if testcase_name:
f = open(old_logdir + "\\testcase.%d.name" % wrapper_pid, "w")
print >>f, testcase_name
f.close()
exit(subprocess.call(cmd_to_run))
......@@ -162,7 +162,7 @@ def BoringCallers(mangled, use_re_wildcards):
# Don't show our testing framework:
("testing::Test::Run", "_ZN7testing4Test3RunEv"),
("testing::TestInfo::Run", "_ZN7testing8TestInfo3RunEv"),
("testing::internal::Handle*ExceptionsInMethodIfSupported",
("testing::internal::Handle*ExceptionsInMethodIfSupported*",
"_ZN7testing8internal3?Handle*ExceptionsInMethodIfSupported*"),
# Depend on scheduling:
......@@ -212,3 +212,26 @@ def NormalizeWindowsPath(path):
return out.strip()
else:
return path
############################
# Common output format code
def PrintUsedSuppressionsList(suppcounts):
""" Prints out the list of used suppressions in a format common to all the
memory tools. If the list is empty, prints nothing and returns False,
otherwise True.
suppcounts: a dictionary of used suppression counts,
Key -> name, Value -> count.
"""
if not suppcounts:
return False
print "-----------------------------------------------------"
print "Suppressions used:"
print " count name"
for (name, count) in sorted(suppcounts.items(), key=lambda (k,v): (v,k)):
print "%7d %s" % (count, name)
print "-----------------------------------------------------"
sys.stdout.flush()
return True
......@@ -7,6 +7,8 @@
''' Given a Dr. Memory output file, parses errors and uniques them.'''
from collections import defaultdict
import common
import logging
import optparse
import os
......@@ -15,30 +17,13 @@ import subprocess
import sys
import time
class _StackTraceLine(object):
def __init__(self, line, address, binary):
self.raw_line_ = line
self.address = address
self.binary = binary
def __str__(self):
return self.raw_line_
class DrMemoryAnalyze:
class DrMemoryAnalyzer:
''' Given a set of Dr.Memory output files, parse all the errors out of
them, unique them and output the results.'''
def __init__(self, source_dir, files):
'''Reads in a set of files.
Args:
source_dir: Path to top of source tree for this build
files: A list of filenames.
'''
self.reports = []
self.used_suppressions = []
for file in files:
self.ParseReportFile(file)
def __init__(self):
self.known_errors = set()
def ReadLine(self):
self.line_ = self.cur_fd_.readline()
......@@ -52,8 +37,9 @@ class DrMemoryAnalyze:
return result
def ParseReportFile(self, filename):
self.cur_fd_ = open(filename, 'r')
ret = []
self.cur_fd_ = open(filename, 'r')
while True:
self.ReadLine()
if (self.line_ == ''): break
......@@ -62,7 +48,7 @@ class DrMemoryAnalyze:
if match:
self.line_ = match.groups()[0].strip() + "\n"
tmp = self.ReadSection()
self.reports.append(tmp)
ret.append("".join(tmp).strip())
if re.search("SUPPRESSIONS USED:", self.line_):
self.ReadLine()
......@@ -70,53 +56,59 @@ class DrMemoryAnalyze:
line = self.line_.strip()
(count, name) = re.match(" *([0-9]+)x(?: \(leaked .*\))?: (.*)",
line).groups()
self.used_suppressions.append("%7s %s" % (count, name))
count = int(count)
self.used_suppressions[name] += count
self.ReadLine()
if self.line_.startswith("ASSERT FAILURE"):
self.reports.append(self.line_.strip())
ret.append(self.line_.strip())
self.cur_fd_.close()
return ret
def Report(self, check_sanity):
def Report(self, filenames, testcase, check_sanity):
sys.stdout.flush()
#TODO(timurrrr): support positive tests / check_sanity==True
if self.used_suppressions:
print "-----------------------------------------------------"
# TODO(timurrrr): sum up the counts from different wrappers (e.g. ui_tests)
# or does it work now already? Or add the memcheck-like per-test printing.
print "Suppressions used:\n count name\n%s" % (
"\n".join(self.used_suppressions))
print "-----------------------------------------------------"
sys.stdout.flush()
if len(self.reports) > 0:
logging.error("Found %i error reports" % len(self.reports))
for report_list in self.reports:
report = ''
for line in report_list:
report += str(line)
logging.error('\n' + report)
logging.error("Total: %i error reports" % len(self.reports))
return -1
logging.info("PASS: No error reports found")
return 0
# TODO(timurrrr): support positive tests / check_sanity==True
to_report = []
self.used_suppressions = defaultdict(int)
for f in filenames:
cur_reports = self.ParseReportFile(f)
# Filter out the reports that were there in previous tests.
for r in cur_reports:
if r in self.known_errors:
pass # TODO: print out a hash once we add hashes to the reports.
else:
self.known_errors.add(r)
to_report.append(r)
common.PrintUsedSuppressionsList(self.used_suppressions)
if not to_report:
logging.info("PASS: No error reports found")
return 0
logging.error("Found %i error reports" % len(to_report))
for report in to_report:
if testcase:
logging.error("\n%s\nNote: observed on `%s`\n" %
(report, testcase))
else:
logging.error("\n%s\n" % report)
logging.error("Total: %i error reports" % len(to_report))
return -1
if __name__ == '__main__':
'''For testing only. The DrMemoryAnalyze class should be imported instead.'''
'''For testing only. The DrMemoryAnalyzer class should be imported instead.'''
retcode = 0
parser = optparse.OptionParser("usage: %prog [options] <files to analyze>")
parser.add_option("", "--source_dir",
help="path to top of source tree for this build"
"(used to normalize source paths in baseline)")
parser = optparse.OptionParser("usage: %prog <files to analyze>")
(options, args) = parser.parse_args()
if len(args) == 0:
parser.error("no filename specified")
filenames = args
analyzer = DrMemoryAnalyze(options.source_dir, filenames)
retcode = analyzer.Report(False)
analyzer = DrMemoryAnalyzer()
retcode = analyzer.Report(filenames, None, False)
sys.exit(retcode)
......@@ -436,7 +436,7 @@ class ValgrindTool(BaseTool):
"in the tool-specific subclass"
def GetAnalyzeResults(self, check_sanity=False):
# Glob all the files in the "testing.tmp" directory
# Glob all the files in the log directory
filenames = glob.glob(self.log_dir + "/" + self.ToolName() + ".*")
# If we have browser wrapper, the logfiles are named as
......@@ -879,7 +879,9 @@ class DrMemory(BaseTool):
proc += ["--"]
if self._options.indirect:
self.CreateBrowserWrapper(" ".join(proc))
# TODO(timurrrr): reuse for TSan on Windows
self.CreateBrowserWrapper(" ".join(
["python", "tools/valgrind/browser_wrapper_win.py"] + proc))
proc = []
# Note that self._args begins with the name of the exe to be run.
......@@ -891,11 +893,49 @@ class DrMemory(BaseTool):
os.putenv("BROWSER_WRAPPER", command)
def Analyze(self, check_sanity=False):
# Glob all the results files in the "testing.tmp" directory
filenames = glob.glob(self.log_dir + "/*/results.txt")
# Use one analyzer for all the log files to avoid printing duplicate reports
#
# TODO(timurrrr): unify this with Valgrind and other tools when we have
# http://code.google.com/p/drmemory/issues/detail?id=684
analyzer = drmemory_analyze.DrMemoryAnalyzer()
analyzer = drmemory_analyze.DrMemoryAnalyze(self._source_dir, filenames)
ret = analyzer.Report(check_sanity)
ret = 0
if not self._options.indirect:
filenames = glob.glob(self.log_dir + "/*/results.txt")
ret = analyzer.Report(filenames, None, check_sanity)
else:
testcases = glob.glob(self.log_dir + "/testcase.*.logs")
# If we have browser wrapper, the per-test logdirs are named as
# "testcase.wrapper_PID".
# Let's extract the list of wrapper_PIDs and name it ppids
ppids = set([int(f.split(".")[-2]) for f in testcases])
for ppid in ppids:
testcase_name = None
try:
f = open(self.log_dir + ("/testcase.%d.name" % ppid))
testcase_name = f.read().strip()
f.close()
except IOError:
pass
print "====================================================="
print " Below is the report for drmemory wrapper PID=%d." % ppid
if testcase_name:
print " It was used while running the `%s` test." % testcase_name
else:
# TODO(timurrrr): hm, the PID line is suppressed on Windows...
print " You can find the corresponding test"
print " by searching the above log for 'PID=%d'" % ppid
sys.stdout.flush()
ppid_filenames = glob.glob("%s/testcase.%d.logs/*/results.txt" %
(self.log_dir, ppid))
ret |= analyzer.Report(ppid_filenames, testcase_name, False)
print "====================================================="
sys.stdout.flush()
logging.info("Please see http://dev.chromium.org/developers/how-tos/"
"using-drmemory for the info on Dr. Memory")
return ret
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment