diff options
Diffstat (limited to 'utils/analyzer')
-rwxr-xr-x | utils/analyzer/CmpRuns.py | 50 | ||||
-rw-r--r-- | utils/analyzer/SATestAdd.py | 54 | ||||
-rw-r--r-- | utils/analyzer/SATestBuild.py | 347 | ||||
-rw-r--r-- | utils/analyzer/SumTimerInfo.py | 5 | ||||
-rwxr-xr-x | utils/analyzer/ubiviz | 13 |
5 files changed, 296 insertions, 173 deletions
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py index ce5ddfb3add4..2d1f44f6880c 100755 --- a/utils/analyzer/CmpRuns.py +++ b/utils/analyzer/CmpRuns.py @@ -5,7 +5,7 @@ CmpRuns - A simple tool for comparing two static analyzer runs to determine which reports have been added, removed, or changed. This is designed to support automated testing using the static analyzer, from -two perspectives: +two perspectives: 1. To monitor changes in the static analyzer's reports on real code bases, for regression testing. @@ -19,11 +19,11 @@ Usage: # resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty) resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty) - - # Generate a relation from diagnostics in run A to diagnostics in run B - # to obtain a list of triples (a, b, confidence). + + # Generate a relation from diagnostics in run A to diagnostics in run B + # to obtain a list of triples (a, b, confidence). diff = compareResults(resultsA, resultsB) - + """ import os @@ -32,7 +32,7 @@ import CmpRuns # Information about analysis run: # path - the analysis output directory -# root - the name of the root directory, which will be disregarded when +# root - the name of the root directory, which will be disregarded when # determining the source file name class SingleRunInfo: def __init__(self, path, root="", verboseLog=None): @@ -56,7 +56,7 @@ class AnalysisDiagnostic: def getLine(self): return self._loc['line'] - + def getColumn(self): return self._loc['col'] @@ -70,8 +70,8 @@ class AnalysisDiagnostic: id = self.getFileName() + "+" if 'issue_context' in self._data : id += self._data['issue_context'] + "+" - if 'issue_hash' in self._data : - id += str(self._data['issue_hash']) + if 'issue_hash_content_of_line_in_context' in self._data : + id += str(self._data['issue_hash_content_of_line_in_context']) return id def getReport(self): @@ -80,12 +80,12 @@ class AnalysisDiagnostic: return os.path.join(self._report.run.path, self._htmlReport) def getReadableName(self): - return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(), - self.getColumn(), self.getCategory(), + return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(), + self.getColumn(), self.getCategory(), self.getDescription()) - - # Note, the data format is not an API and may change from one analyzer - # version to another. + + # Note, the data format is not an API and may change from one analyzer + # version to another. def getRawData(self): return self._data @@ -94,7 +94,7 @@ class multidict: self.data = {} for key,value in elts: self[key] = value - + def __getitem__(self, item): return self.data[item] def __setitem__(self, key, value): @@ -134,15 +134,15 @@ class AnalysisRun: # Cumulative list of all diagnostics from all the reports. self.diagnostics = [] self.clang_version = None - + def getClangVersion(self): return self.clang_version def readSingleFile(self, p, deleteEmpty): data = plistlib.readPlist(p) - # We want to retrieve the clang version even if there are no - # reports. Assume that all reports were created using the same + # We want to retrieve the clang version even if there are no + # reports. Assume that all reports were created using the same # clang version (this is always true and is more efficient). if 'clang_version' in data: if self.clang_version == None: @@ -166,9 +166,9 @@ class AnalysisRun: htmlFiles.append(d.pop('HTMLDiagnostics_files')[0]) else: htmlFiles = [None] * len(data['diagnostics']) - + report = AnalysisReport(self, data.pop('files')) - diagnostics = [AnalysisDiagnostic(d, report, h) + diagnostics = [AnalysisDiagnostic(d, report, h) for d,h in zip(data.pop('diagnostics'), htmlFiles)] @@ -179,7 +179,7 @@ class AnalysisRun: self.diagnostics.extend(diagnostics) -# Backward compatibility API. +# Backward compatibility API. def loadResults(path, opts, root = "", deleteEmpty=True): return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog), deleteEmpty) @@ -257,7 +257,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True): # Load the run results. resultsA = loadResults(dirA, opts, opts.rootA, deleteEmpty) resultsB = loadResults(dirB, opts, opts.rootB, deleteEmpty) - + # Open the verbose log, if given. if opts.verboseLog: auxLog = open(opts.verboseLog, "wb") @@ -285,7 +285,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True): b.getReadableName()) foundDiffs += 1 if auxLog: - print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" + print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" % (a.getReadableName(), b.getReadableName(), a.getReport(), @@ -299,7 +299,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True): if auxLog: print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs - + return foundDiffs, len(resultsA.diagnostics), len(resultsB.diagnostics) def main(): @@ -322,7 +322,7 @@ def main(): dirA,dirB = args - dumpScanBuildResultsDiff(dirA, dirB, opts) + dumpScanBuildResultsDiff(dirA, dirB, opts) if __name__ == '__main__': main() diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py index 64ff4ff65683..4b94a109ce64 100644 --- a/utils/analyzer/SATestAdd.py +++ b/utils/analyzer/SATestAdd.py @@ -1,20 +1,44 @@ #!/usr/bin/env python """ -Static Analyzer qualification infrastructure: adding a new project to +Static Analyzer qualification infrastructure: adding a new project to the Repository Directory. Add a new project for testing: build it and add to the Project Map file. Assumes it's being run from the Repository Directory. - The project directory should be added inside the Repository Directory and + The project directory should be added inside the Repository Directory and have the same name as the project ID - + The project should use the following files for set up: - - pre_run_static_analyzer.sh - prepare the build environment. + - cleanup_run_static_analyzer.sh - prepare the build environment. Ex: make clean can be a part of it. - run_static_analyzer.cmd - a list of commands to run through scan-build. Each command should be on a separate line. - Choose from: configure, make, xcodebuild + Choose from: configure, make, xcodebuild + - download_project.sh - download the project into the CachedSource/ + directory. For example, download a zip of + the project source from GitHub, unzip it, + and rename the unzipped directory to + 'CachedSource'. This script is not called + when 'CachedSource' is already present, + so an alternative is to check the + 'CachedSource' directory into the + repository directly. + - CachedSource/ - An optional directory containing the source of the + project being analyzed. If present, + download_project.sh will not be called. + - changes_for_analyzer.patch - An optional patch file for any local changes + (e.g., to adapt to newer version of clang) + that should be applied to CachedSource + before analysis. To construct this patch, + run the the download script to download + the project to CachedSource, copy the + CachedSource to another directory (for + example, PatchedSource) and make any needed + modifications to the the copied source. + Then run: + diff -ur CachedSource PatchedSource \ + > changes_for_analyzer.patch """ import SATestBuild @@ -27,7 +51,7 @@ def isExistingProject(PMapFile, projectID) : for I in PMapReader: if projectID == I[0]: return True - return False + return False # Add a new project for testing: build it and add to the Project Map file. # Params: @@ -39,7 +63,7 @@ def addNewProject(ID, BuildMode) : if not os.path.exists(Dir): print "Error: Project directory is missing: %s" % Dir sys.exit(-1) - + # Build the project. SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir) @@ -51,19 +75,19 @@ def addNewProject(ID, BuildMode) : print "Warning: Creating the Project Map file!!" PMapFile = open(ProjectMapPath, "w+b") try: - if (isExistingProject(PMapFile, ID)) : + if (isExistingProject(PMapFile, ID)) : print >> sys.stdout, 'Warning: Project with ID \'', ID, \ '\' already exists.' print >> sys.stdout, "Reference output has been regenerated." - else: + else: PMapWriter = csv.writer(PMapFile) PMapWriter.writerow( (ID, int(BuildMode)) ); print "The project map is updated: ", ProjectMapPath finally: PMapFile.close() - -# TODO: Add an option not to build. + +# TODO: Add an option not to build. # TODO: Set the path to the Repository directory. if __name__ == '__main__': if len(sys.argv) < 2: @@ -73,10 +97,10 @@ if __name__ == '__main__': '1 for scan_build; ' \ '2 for single file c++11 project' sys.exit(-1) - - BuildMode = 1 + + BuildMode = 1 if (len(sys.argv) >= 3): - BuildMode = int(sys.argv[2]) + BuildMode = int(sys.argv[2]) assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2)) - + addNewProject(sys.argv[1], BuildMode) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index 2d91ba41e24c..d0503c6389c9 100644 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -6,8 +6,8 @@ Static Analyzer qualification infrastructure. The goal is to test the analyzer against different projects, check for failures, compare results, and measure performance. -Repository Directory will contain sources of the projects as well as the -information on how to build them and the expected output. +Repository Directory will contain sources of the projects as well as the +information on how to build them and the expected output. Repository Directory structure: - ProjectMap file - Historical Performance Data @@ -19,16 +19,16 @@ Repository Directory structure: Note that the build tree must be inside the project dir. To test the build of the analyzer one would: - - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that + - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that the build directory does not pollute the repository to min network traffic). - Build all projects, until error. Produce logs to report errors. - - Compare results. + - Compare results. -The files which should be kept around for failure investigations: +The files which should be kept around for failure investigations: RepositoryCopy/Project DirI/ScanBuildResults - RepositoryCopy/Project DirI/run_static_analyzer.log - -Assumptions (TODO: shouldn't need to assume these.): + RepositoryCopy/Project DirI/run_static_analyzer.log + +Assumptions (TODO: shouldn't need to assume these.): The script is being run from the Repository Directory. The compiler for scan-build and scan-build are in the PATH. export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH @@ -36,6 +36,10 @@ Assumptions (TODO: shouldn't need to assume these.): For more logging, set the env variables: zaks:TI zaks$ export CCC_ANALYZER_LOG=1 zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1 + +The list of checkers tested are hardcoded in the Checkers variable. +For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment +variable. It should contain a comma separated list. """ import CmpRuns @@ -48,7 +52,7 @@ import shutil import time import plistlib import argparse -from subprocess import check_call, CalledProcessError +from subprocess import check_call, check_output, CalledProcessError #------------------------------------------------------------------------------ # Helper functions. @@ -116,16 +120,16 @@ class flushfile(object): sys.stdout = flushfile(sys.stdout) def getProjectMapPath(): - ProjectMapPath = os.path.join(os.path.abspath(os.curdir), + ProjectMapPath = os.path.join(os.path.abspath(os.curdir), ProjectMapFile) if not os.path.exists(ProjectMapPath): print "Error: Cannot find the Project Map file " + ProjectMapPath +\ "\nRunning script for the wrong directory?" - sys.exit(-1) - return ProjectMapPath + sys.exit(-1) + return ProjectMapPath def getProjectDir(ID): - return os.path.join(os.path.abspath(os.curdir), ID) + return os.path.join(os.path.abspath(os.curdir), ID) def getSBOutputDirName(IsReferenceBuild) : if IsReferenceBuild == True : @@ -150,15 +154,17 @@ Jobs = int(math.ceil(detectCPUs() * 0.75)) ProjectMapFile = "projectMap.csv" # Names of the project specific scripts. +# The script that downloads the project. +DownloadScript = "download_project.sh" # The script that needs to be executed before the build can start. CleanupScript = "cleanup_run_static_analyzer.sh" -# This is a file containing commands for scan-build. +# This is a file containing commands for scan-build. BuildScript = "run_static_analyzer.cmd" # The log file name. LogFolderName = "Logs" BuildLogName = "run_static_analyzer.log" -# Summary file - contains the summary of the failures. Ex: This info can be be +# Summary file - contains the summary of the failures. Ex: This info can be be # displayed when buildbot detects a build failure. NumOfFailuresInSummary = 10 FailuresSummaryFileName = "failures.txt" @@ -169,6 +175,21 @@ DiffsSummaryFileName = "diffs.txt" SBOutputDirName = "ScanBuildResults" SBOutputDirReferencePrefix = "Ref" +# The name of the directory storing the cached project source. If this directory +# does not exist, the download script will be executed. That script should +# create the "CachedSource" directory and download the project source into it. +CachedSourceDirName = "CachedSource" + +# The name of the directory containing the source code that will be analyzed. +# Each time a project is analyzed, a fresh copy of its CachedSource directory +# will be copied to the PatchedSource directory and then the local patches +# in PatchfileName will be applied (if PatchfileName exists). +PatchedSourceDirName = "PatchedSource" + +# The name of the patchfile specifying any changes that should be applied +# to the CachedSource before analyzing. +PatchfileName = "changes_for_analyzer.patch" + # The list of checkers used during analyzes. # Currently, consists of all the non-experimental checkers, plus a few alpha # checkers we don't want to regress on. @@ -182,35 +203,93 @@ Verbose = 1 # Run pre-processing script if any. def runCleanupScript(Dir, PBuildLogFile): + Cwd = os.path.join(Dir, PatchedSourceDirName) ScriptPath = os.path.join(Dir, CleanupScript) + runScript(ScriptPath, PBuildLogFile, Cwd) + +# Run the script to download the project, if it exists. +def runDownloadScript(Dir, PBuildLogFile): + ScriptPath = os.path.join(Dir, DownloadScript) + runScript(ScriptPath, PBuildLogFile, Dir) + +# Run the provided script if it exists. +def runScript(ScriptPath, PBuildLogFile, Cwd): if os.path.exists(ScriptPath): try: - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (ScriptPath,) - check_call("chmod +x %s" % ScriptPath, cwd = Dir, + check_call("chmod +x %s" % ScriptPath, cwd = Cwd, stderr=PBuildLogFile, - stdout=PBuildLogFile, - shell=True) - check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile, - stdout=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) + check_call(ScriptPath, cwd = Cwd, stderr=PBuildLogFile, + stdout=PBuildLogFile, shell=True) except: - print "Error: The pre-processing step failed. See ", \ - PBuildLogFile.name, " for details." + print "Error: Running %s failed. See %s for details." % (ScriptPath, + PBuildLogFile.name) sys.exit(-1) -# Build the project with scan-build by reading in the commands and +# Download the project and apply the local patchfile if it exists. +def downloadAndPatch(Dir, PBuildLogFile): + CachedSourceDirPath = os.path.join(Dir, CachedSourceDirName) + + # If the we don't already have the cached source, run the project's + # download script to download it. + if not os.path.exists(CachedSourceDirPath): + runDownloadScript(Dir, PBuildLogFile) + if not os.path.exists(CachedSourceDirPath): + print "Error: '%s' not found after download." % (CachedSourceDirPath) + exit(-1) + + PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) + + # Remove potentially stale patched source. + if os.path.exists(PatchedSourceDirPath): + shutil.rmtree(PatchedSourceDirPath) + + # Copy the cached source and apply any patches to the copy. + shutil.copytree(CachedSourceDirPath, PatchedSourceDirPath, symlinks=True) + applyPatch(Dir, PBuildLogFile) + +def applyPatch(Dir, PBuildLogFile): + PatchfilePath = os.path.join(Dir, PatchfileName) + PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) + if not os.path.exists(PatchfilePath): + print " No local patches." + return + + print " Applying patch." + try: + check_call("patch -p1 < %s" % (PatchfilePath), + cwd = PatchedSourceDirPath, + stderr=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) + except: + print "Error: Patch failed. See %s for details." % (PBuildLogFile.name) + sys.exit(-1) + +# Build the project with scan-build by reading in the commands and # prefixing them with the scan-build options. def runScanBuild(Dir, SBOutputDir, PBuildLogFile): BuildScriptPath = os.path.join(Dir, BuildScript) if not os.path.exists(BuildScriptPath): print "Error: build script is not defined: %s" % BuildScriptPath sys.exit(-1) + + AllCheckers = Checkers + if os.environ.has_key('SA_ADDITIONAL_CHECKERS'): + AllCheckers = AllCheckers + ',' + os.environ['SA_ADDITIONAL_CHECKERS'] + + # Run scan-build from within the patched source directory. + SBCwd = os.path.join(Dir, PatchedSourceDirName) + SBOptions = "--use-analyzer " + Clang + " " SBOptions += "-plist-html -o " + SBOutputDir + " " - SBOptions += "-enable-checker " + Checkers + " " + SBOptions += "-enable-checker " + AllCheckers + " " SBOptions += "--keep-empty " - # Always use ccc-analyze to ensure that we can locate the failures + # Always use ccc-analyze to ensure that we can locate the failures # directory. SBOptions += "--override-compiler " try: @@ -227,11 +306,11 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): "-j" not in Command: Command += " -j%d" % Jobs SBCommand = SBPrefix + Command - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (SBCommand,) - check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile, - stdout=PBuildLogFile, - shell=True) + check_call(SBCommand, cwd = SBCwd, stderr=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) except: print "Error: scan-build failed. See ",PBuildLogFile.name,\ " for details." @@ -245,97 +324,114 @@ def hasNoExtension(FileName): def isValidSingleInputFile(FileName): (Root, Ext) = os.path.splitext(FileName) - if ((Ext == ".i") | (Ext == ".ii") | - (Ext == ".c") | (Ext == ".cpp") | + if ((Ext == ".i") | (Ext == ".ii") | + (Ext == ".c") | (Ext == ".cpp") | (Ext == ".m") | (Ext == "")) : return True return False - + +# Get the path to the SDK for the given SDK name. Returns None if +# the path cannot be determined. +def getSDKPath(SDKName): + if which("xcrun") is None: + return None + + Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path" + return check_output(Cmd, shell=True).rstrip() + # Run analysis on a set of preprocessed files. def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): if os.path.exists(os.path.join(Dir, BuildScript)): print "Error: The preprocessed files project should not contain %s" % \ BuildScript - raise Exception() + raise Exception() + + CmdPrefix = Clang + " -cc1 " + + # For now, we assume the preprocessed files should be analyzed + # with the OS X SDK. + SDKPath = getSDKPath("macosx") + if SDKPath is not None: + CmdPrefix += "-isysroot " + SDKPath + " " + + CmdPrefix += "-analyze -analyzer-output=plist -w " + CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks " - CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w " - CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks " - if (Mode == 2) : - CmdPrefix += "-std=c++11 " - + CmdPrefix += "-std=c++11 " + PlistPath = os.path.join(Dir, SBOutputDir, "date") FailPath = os.path.join(PlistPath, "failures"); os.makedirs(FailPath); - + for FullFileName in glob.glob(Dir + "/*"): FileName = os.path.basename(FullFileName) Failed = False - + # Only run the analyzes on supported files. if (hasNoExtension(FileName)): continue if (isValidSingleInputFile(FileName) == False): print "Error: Invalid single input file %s." % (FullFileName,) raise Exception() - + # Build and call the analyzer command. OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist " Command = CmdPrefix + OutputOption + FileName LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b") try: - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (Command,) check_call(Command, cwd = Dir, stderr=LogFile, - stdout=LogFile, + stdout=LogFile, shell=True) except CalledProcessError, e: print "Error: Analyzes of %s failed. See %s for details." \ "Error code %d." % \ (FullFileName, LogFile.name, e.returncode) - Failed = True + Failed = True finally: - LogFile.close() - + LogFile.close() + # If command did not fail, erase the log file. if Failed == False: os.remove(LogFile.name); def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): - TBegin = time.time() + TBegin = time.time() BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName) - print "Log file: %s" % (BuildLogPath,) + print "Log file: %s" % (BuildLogPath,) print "Output directory: %s" %(SBOutputDir, ) - + # Clean up the log file. if (os.path.exists(BuildLogPath)) : RmCommand = "rm " + BuildLogPath if Verbose == 1: print " Executing: %s" % (RmCommand,) check_call(RmCommand, shell=True) - + # Clean up scan build results. if (os.path.exists(SBOutputDir)) : RmCommand = "rm -r " + SBOutputDir - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (RmCommand,) check_call(RmCommand, shell=True) assert(not os.path.exists(SBOutputDir)) os.makedirs(os.path.join(SBOutputDir, LogFolderName)) - + # Open the log file. PBuildLogFile = open(BuildLogPath, "wb+") - + # Build and analyze the project. try: - runCleanupScript(Dir, PBuildLogFile) - if (ProjectBuildMode == 1): + downloadAndPatch(Dir, PBuildLogFile) + runCleanupScript(Dir, PBuildLogFile) runScanBuild(Dir, SBOutputDir, PBuildLogFile) else: runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode) - + if IsReferenceBuild : runCleanupScript(Dir, PBuildLogFile) @@ -346,32 +442,36 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): continue Plist = os.path.join(DirPath, F) Data = plistlib.readPlist(Plist) - Paths = [SourceFile[len(Dir)+1:] if SourceFile.startswith(Dir)\ - else SourceFile for SourceFile in Data['files']] + PathPrefix = Dir + if (ProjectBuildMode == 1): + PathPrefix = os.path.join(Dir, PatchedSourceDirName) + Paths = [SourceFile[len(PathPrefix)+1:]\ + if SourceFile.startswith(PathPrefix)\ + else SourceFile for SourceFile in Data['files']] Data['files'] = Paths plistlib.writePlist(Data, Plist) - + finally: PBuildLogFile.close() - + print "Build complete (time: %.2f). See the log for more details: %s" % \ - ((time.time()-TBegin), BuildLogPath) - + ((time.time()-TBegin), BuildLogPath) + # A plist file is created for each call to the analyzer(each source file). -# We are only interested on the once that have bug reports, so delete the rest. +# We are only interested on the once that have bug reports, so delete the rest. def CleanUpEmptyPlists(SBOutputDir): for F in glob.glob(SBOutputDir + "/*/*.plist"): P = os.path.join(SBOutputDir, F) - + Data = plistlib.readPlist(P) # Delete empty reports. if not Data['files']: os.remove(P) continue -# Given the scan-build output directory, checks if the build failed -# (by searching for the failures directories). If there are failures, it -# creates a summary file in the output directory. +# Given the scan-build output directory, checks if the build failed +# (by searching for the failures directories). If there are failures, it +# creates a summary file in the output directory. def checkBuild(SBOutputDir): # Check if there are failures. Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt") @@ -382,37 +482,37 @@ def checkBuild(SBOutputDir): print "Number of bug reports (non-empty plist files) produced: %d" %\ len(Plists) return; - + # Create summary file to display when the build fails. SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName) if (Verbose > 0): print " Creating the failures summary file %s" % (SummaryPath,) - + SummaryLog = open(SummaryPath, "w+") try: SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,)) if TotalFailed > NumOfFailuresInSummary: - SummaryLog.write("See the first %d below.\n" + SummaryLog.write("See the first %d below.\n" % (NumOfFailuresInSummary,)) # TODO: Add a line "See the results folder for more." - + FailuresCopied = NumOfFailuresInSummary Idx = 0 for FailLogPathI in Failures: if Idx >= NumOfFailuresInSummary: break; - Idx += 1 + Idx += 1 SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,)); FailLogI = open(FailLogPathI, "r"); - try: + try: shutil.copyfileobj(FailLogI, SummaryLog); finally: FailLogI.close() finally: SummaryLog.close() - + print "Error: analysis failed. See ", SummaryPath - sys.exit(-1) + sys.exit(-1) # Auxiliary object to discard stdout. class Discarder(object): @@ -424,46 +524,47 @@ class Discarder(object): # 0 - success if there are no crashes or analyzer failure. # 1 - success if there are no difference in the number of reported bugs. # 2 - success if all the bug reports are identical. -def runCmpResults(Dir, Strictness = 0): - TBegin = time.time() +def runCmpResults(Dir, Strictness = 0): + TBegin = time.time() RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName) NewDir = os.path.join(Dir, SBOutputDirName) - + # We have to go one level down the directory tree. - RefList = glob.glob(RefDir + "/*") + RefList = glob.glob(RefDir + "/*") NewList = glob.glob(NewDir + "/*") - + # Log folders are also located in the results dir, so ignore them. RefLogDir = os.path.join(RefDir, LogFolderName) if RefLogDir in RefList: RefList.remove(RefLogDir) NewList.remove(os.path.join(NewDir, LogFolderName)) - + if len(RefList) == 0 or len(NewList) == 0: return False assert(len(RefList) == len(NewList)) - # There might be more then one folder underneath - one per each scan-build + # There might be more then one folder underneath - one per each scan-build # command (Ex: one for configure and one for make). if (len(RefList) > 1): # Assume that the corresponding folders have the same names. RefList.sort() NewList.sort() - + # Iterate and find the differences. NumDiffs = 0 - PairList = zip(RefList, NewList) - for P in PairList: - RefDir = P[0] + PairList = zip(RefList, NewList) + for P in PairList: + RefDir = P[0] NewDir = P[1] - - assert(RefDir != NewDir) - if Verbose == 1: + + assert(RefDir != NewDir) + if Verbose == 1: print " Comparing Results: %s %s" % (RefDir, NewDir) - + DiffsPath = os.path.join(NewDir, DiffsSummaryFileName) - Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir) + PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) + Opts = CmpRuns.CmpOptions(DiffsPath, "", PatchedSourceDirPath) # Discard everything coming out of stdout (CmpRun produces a lot of them). OLD_STDOUT = sys.stdout sys.stdout = Discarder() @@ -476,70 +577,70 @@ def runCmpResults(Dir, Strictness = 0): (NumDiffs, DiffsPath,) if Strictness >= 2 and NumDiffs > 0: print "Error: Diffs found in strict mode (2)." - sys.exit(-1) + sys.exit(-1) elif Strictness >= 1 and ReportsInRef != ReportsInNew: print "Error: The number of results are different in strict mode (1)." - sys.exit(-1) - - print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) + sys.exit(-1) + + print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) return (NumDiffs > 0) - + def updateSVN(Mode, ProjectsMap): try: - ProjectsMap.seek(0) + ProjectsMap.seek(0) for I in csv.reader(ProjectsMap): - ProjName = I[0] + ProjName = I[0] Path = os.path.join(ProjName, getSBOutputDirName(True)) - + if Mode == "delete": Command = "svn delete %s" % (Path,) else: Command = "svn add %s" % (Path,) - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (Command,) - check_call(Command, shell=True) - + check_call(Command, shell=True) + if Mode == "delete": CommitCommand = "svn commit -m \"[analyzer tests] Remove " \ - "reference results.\"" + "reference results.\"" else: CommitCommand = "svn commit -m \"[analyzer tests] Add new " \ "reference results.\"" - if Verbose == 1: + if Verbose == 1: print " Executing: %s" % (CommitCommand,) - check_call(CommitCommand, shell=True) + check_call(CommitCommand, shell=True) except: print "Error: SVN update failed." sys.exit(-1) - + def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0): print " \n\n--- Building project %s" % (ID,) - TBegin = time.time() + TBegin = time.time() if Dir is None : - Dir = getProjectDir(ID) - if Verbose == 1: + Dir = getProjectDir(ID) + if Verbose == 1: print " Build directory: %s." % (Dir,) - + # Set the build results directory. RelOutputDir = getSBOutputDirName(IsReferenceBuild) SBOutputDir = os.path.join(Dir, RelOutputDir) - + buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild) checkBuild(SBOutputDir) - + if IsReferenceBuild == False: runCmpResults(Dir, Strictness) - + print "Completed tests for project %s (time: %.2f)." % \ (ID, (time.time()-TBegin)) - + def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): PMapFile = open(getProjectMapPath(), "rb") - try: + try: # Validate the input. for I in csv.reader(PMapFile): if (len(I) != 2) : @@ -548,16 +649,16 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))): print "Error: Second entry in the ProjectMapFile should be 0" \ " (single file), 1 (project), or 2(single file c++11)." - raise Exception() + raise Exception() - # When we are regenerating the reference results, we might need to + # When we are regenerating the reference results, we might need to # update svn. Remove reference results from SVN. if UpdateSVN == True: assert(IsReferenceBuild == True); updateSVN("delete", PMapFile); - + # Test the projects. - PMapFile.seek(0) + PMapFile.seek(0) for I in csv.reader(PMapFile): testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness) @@ -567,10 +668,10 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): except: print "Error occurred. Premature termination." - raise + raise finally: - PMapFile.close() - + PMapFile.close() + if __name__ == '__main__': # Parse command line arguments. Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.') diff --git a/utils/analyzer/SumTimerInfo.py b/utils/analyzer/SumTimerInfo.py index 4ef1ceb4cec5..0c3585bbc279 100644 --- a/utils/analyzer/SumTimerInfo.py +++ b/utils/analyzer/SumTimerInfo.py @@ -3,7 +3,7 @@ """ Script to Summarize statistics in the scan-build output. -Statistics are enabled by passing '-internal-stats' option to scan-build +Statistics are enabled by passing '-internal-stats' option to scan-build (or '-analyzer-stats' to the analyzer). """ @@ -69,7 +69,7 @@ if __name__ == '__main__': if ((") Total" in line) and (Mode == 1)) : s = line.split() TotalTime = TotalTime + float(s[6]) - + print "TU Count %d" % (Count) print "Time %f" % (Time) print "Warnings %d" % (Warnings) @@ -81,4 +81,3 @@ if __name__ == '__main__': print "MaxTime %f" % (MaxTime) print "TotalTime %f" % (TotalTime) print "Max CFG Size %d" % (MaxCFGSize) -
\ No newline at end of file diff --git a/utils/analyzer/ubiviz b/utils/analyzer/ubiviz index 1582797c63f9..9d821c3c10a0 100755 --- a/utils/analyzer/ubiviz +++ b/utils/analyzer/ubiviz @@ -18,7 +18,7 @@ import sys def Error(message): print >> sys.stderr, 'ubiviz: ' + message sys.exit(1) - + def StreamData(filename): file = open(filename) for ln in file: @@ -55,20 +55,19 @@ def Display(G, data): def main(args): if len(args) == 0: - Error('no input files') + Error('no input files') server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2') G = server.ubigraph - + for arg in args: G.clear() for x in StreamData(arg): Display(G,x) - + sys.exit(0) - + if __name__ == '__main__': main(sys.argv[1:]) - -
\ No newline at end of file + |