| Index: tools/valgrind/valgrind_test.py
|
| diff --git a/tools/valgrind/valgrind_test.py b/tools/valgrind/valgrind_test.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..1a6f3636c92f9570886b976ce4a9fd5d6b7aaedf
|
| --- /dev/null
|
| +++ b/tools/valgrind/valgrind_test.py
|
| @@ -0,0 +1,154 @@
|
| +#!/usr/bin/python
|
| +# Copyright (c) 2006-2008 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.
|
| +
|
| +# purify_test.py
|
| +
|
| +'''Runs an exe through Valgrind and puts the intermediate files in a
|
| +directory.
|
| +'''
|
| +
|
| +import datetime
|
| +import glob
|
| +import logging
|
| +import optparse
|
| +import os
|
| +import re
|
| +import shutil
|
| +import sys
|
| +import time
|
| +
|
| +import google.path_utils
|
| +
|
| +import common
|
| +
|
| +import valgrind_analyze
|
| +
|
| +rmtree = shutil.rmtree
|
| +
|
| +class Valgrind():
|
| + TMP_DIR = "valgrind.tmp"
|
| +
|
| + def __init__(self):
|
| + self._data_dir = None
|
| +
|
| + def CreateOptionParser(self):
|
| + self._parser = optparse.OptionParser("usage: %prog [options] <program to "
|
| + "test>")
|
| + self._parser.add_option("-e", "--echo_to_stdout",
|
| + dest="echo_to_stdout", action="store_true", default=False,
|
| + help="echo purify output to standard output")
|
| + self._parser.add_option("-t", "--timeout",
|
| + dest="timeout", metavar="TIMEOUT", default=10000,
|
| + help="timeout in seconds for the run (default 10000)")
|
| + self._parser.add_option("", "--source_dir",
|
| + help="path to top of source tree for this build"
|
| + "(used to normalize source paths in baseline)")
|
| + self._parser.add_option("", "--data_dir", default=".",
|
| + help="path to where purify data files live")
|
| + self._parser.add_option("", "--generate_suppressions", action="store_true",
|
| + default=False,
|
| + help="Skip analysis and generate suppressions")
|
| + self._parser.description = __doc__
|
| +
|
| + def ParseArgv(self):
|
| + self.CreateOptionParser()
|
| + self._options, self._args = self._parser.parse_args()
|
| + self._timeout = int(self._options.timeout)
|
| + self._data_dir = self._options.data_dir
|
| + self._generate_suppressions = self._options.generate_suppressions
|
| + self._source_dir = self._options.source_dir
|
| + return True
|
| +
|
| + def Setup(self):
|
| + return self.ParseArgv()
|
| +
|
| + def Execute(self):
|
| + ''' Execute the app to be tested after successful instrumentation.
|
| + Full execution command-line provided by subclassers via proc.'''
|
| + logging.info("starting execution...")
|
| + # note that self._args begins with the exe to be run
|
| + proc = ["valgrind", "--smc-check=all", "--leak-check=full",
|
| + "--track-origins=yes", "--num-callers=30"]
|
| +
|
| + # Either generate suppressions or load them.
|
| + if self._generate_suppressions:
|
| + proc += ["--gen-suppressions=all"]
|
| + else:
|
| + proc += ["--xml=yes"]
|
| +
|
| + suppressions = os.path.join(self._data_dir, "suppressions.txt")
|
| + if os.path.exists(suppressions):
|
| + proc += ["--suppressions=%s" % suppressions]
|
| + else:
|
| + logging.warning("WARNING: NOT USING SUPPRESSIONS!")
|
| +
|
| + proc += ["--log-file=" + self.TMP_DIR + "/valgrind.%p"] + self._args
|
| +
|
| + # If we have a valgrind.tmp directory, we failed to cleanup last time.
|
| + if os.path.exists(self.TMP_DIR):
|
| + shutil.rmtree(self.TMP_DIR)
|
| + os.mkdir(self.TMP_DIR)
|
| + common.RunSubprocess(proc, self._timeout)
|
| +
|
| + # Always return true, even if running the subprocess failed. We depend on
|
| + # Analyze to determine if the run was valid. (This behaviour copied from
|
| + # the purify_test.py script.)
|
| + return True
|
| +
|
| + def Analyze(self):
|
| + # Glob all the files in the "valgrind.tmp" directory
|
| + filenames = glob.glob(self.TMP_DIR + "/valgrind.*")
|
| + analyzer = valgrind_analyze.ValgrindAnalyze(self._source_dir, filenames)
|
| + analyzer.Report()
|
| + return 1
|
| +
|
| + def Cleanup(self):
|
| + # Right now, we can cleanup by deleting our temporary directory. Other
|
| + # cleanup is still a TODO?
|
| + shutil.rmtree(self.TMP_DIR)
|
| + return True
|
| +
|
| + def RunTestsAndAnalyze(self):
|
| + self.Execute()
|
| + if self._generate_suppressions:
|
| + logging.info("Skipping analysis to let you look at the raw output...")
|
| + return 0
|
| +
|
| + retcode = self.Analyze()
|
| + if retcode:
|
| + logging.error("Analyze failed.")
|
| + return retcode
|
| + logging.info("Execution and analysis completed successfully.")
|
| + return 0
|
| +
|
| + def Main(self):
|
| + '''Call this to run through the whole process: Setup, Execute, Analyze'''
|
| + start = datetime.datetime.now()
|
| + retcode = -1
|
| + if self.Setup():
|
| + retcode = self.RunTestsAndAnalyze()
|
| +
|
| + # Skip cleanup on generate.
|
| + if not self._generate_suppressions:
|
| + self.Cleanup()
|
| + else:
|
| + logging.error("Setup failed")
|
| + end = datetime.datetime.now()
|
| + seconds = (end - start).seconds
|
| + hours = seconds / 3600
|
| + seconds = seconds % 3600
|
| + minutes = seconds / 60
|
| + seconds = seconds % 60
|
| + logging.info("elapsed time: %02d:%02d:%02d" % (hours, minutes, seconds))
|
| + return retcode
|
| +
|
| +
|
| +
|
| +if __name__ == "__main__":
|
| + valgrind = Valgrind()
|
| + retcode = valgrind.Main()
|
| + sys.exit(retcode)
|
| +
|
| +
|
|
|