diff options
Diffstat (limited to 'utils/analyzer')
| -rwxr-xr-x | utils/analyzer/CmpRuns.py | 35 | ||||
| -rw-r--r-- | utils/analyzer/SATestAdd.py | 17 | ||||
| -rw-r--r-- | utils/analyzer/SATestBuild.py | 78 | ||||
| -rwxr-xr-x | utils/analyzer/SATestUpdateDiffs.py | 13 | ||||
| -rw-r--r-- | utils/analyzer/SumTimerInfo.py | 29 | ||||
| -rwxr-xr-x | utils/analyzer/ubiviz | 76 |
6 files changed, 100 insertions, 148 deletions
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py index 7c9744727e90..be503499622d 100755 --- a/utils/analyzer/CmpRuns.py +++ b/utils/analyzer/CmpRuns.py @@ -25,6 +25,7 @@ Usage: diff = compareResults(resultsA, resultsB) """ +from __future__ import division, print_function from collections import defaultdict @@ -38,7 +39,7 @@ import sys STATS_REGEXP = re.compile(r"Statistics: (\{.+\})", re.MULTILINE | re.DOTALL) -class Colors: +class Colors(object): """ Color for terminal highlight. """ @@ -50,14 +51,14 @@ class Colors: # path - the analysis output directory # root - the name of the root directory, which will be disregarded when # determining the source file name -class SingleRunInfo: +class SingleRunInfo(object): def __init__(self, path, root="", verboseLog=None): self.path = path self.root = root.rstrip("/\\") self.verboseLog = verboseLog -class AnalysisDiagnostic: +class AnalysisDiagnostic(object): def __init__(self, data, report, htmlReport): self._data = data self._loc = self._data['location'] @@ -117,14 +118,14 @@ class AnalysisDiagnostic: return self._data -class AnalysisReport: +class AnalysisReport(object): def __init__(self, run, files): self.run = run self.files = files self.diagnostics = [] -class AnalysisRun: +class AnalysisRun(object): def __init__(self, info): self.path = info.path self.root = info.root @@ -281,19 +282,33 @@ def compareResults(A, B, opts): return res +def computePercentile(l, percentile): + """ + Return computed percentile. + """ + return sorted(l)[int(round(percentile * len(l) + 0.5)) - 1] + def deriveStats(results): # Assume all keys are the same in each statistics bucket. combined_data = defaultdict(list) + + # Collect data on paths length. + for report in results.reports: + for diagnostic in report.diagnostics: + combined_data['PathsLength'].append(diagnostic.getPathLength()) + for stat in results.stats: - for key, value in stat.iteritems(): + for key, value in stat.items(): combined_data[key].append(value) combined_stats = {} - for key, values in combined_data.iteritems(): + for key, values in combined_data.items(): combined_stats[str(key)] = { "max": max(values), "min": min(values), "mean": sum(values) / len(values), - "median": sorted(values)[len(values) / 2], + "90th %tile": computePercentile(values, 0.9), + "95th %tile": computePercentile(values, 0.95), + "median": sorted(values)[len(values) // 2], "total": sum(values) } return combined_stats @@ -304,7 +319,7 @@ def compareStats(resultsA, resultsB): statsB = deriveStats(resultsB) keys = sorted(statsA.keys()) for key in keys: - print key + print(key) for kkey in statsA[key]: valA = float(statsA[key][kkey]) valB = float(statsB[key][kkey]) @@ -317,7 +332,7 @@ def compareStats(resultsA, resultsB): report = Colors.GREEN + report + Colors.CLEAR elif ratio > 0.2: report = Colors.RED + report + Colors.CLEAR - print "\t %s %s" % (kkey, report) + print("\t %s %s" % (kkey, report)) def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True, Stdout=sys.stdout): diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py index 041b24409fe3..52089f4e0660 100644 --- a/utils/analyzer/SATestAdd.py +++ b/utils/analyzer/SATestAdd.py @@ -42,6 +42,7 @@ the Repository Directory. diff -ur CachedSource PatchedSource \ > changes_for_analyzer.patch """ +from __future__ import absolute_import, division, print_function import SATestBuild import os @@ -66,7 +67,7 @@ def addNewProject(ID, BuildMode): CurDir = os.path.abspath(os.curdir) Dir = SATestBuild.getProjectDir(ID) if not os.path.exists(Dir): - print "Error: Project directory is missing: %s" % Dir + print("Error: Project directory is missing: %s" % Dir) sys.exit(-1) # Build the project. @@ -78,30 +79,30 @@ def addNewProject(ID, BuildMode): if os.path.exists(ProjectMapPath): FileMode = "r+b" else: - print "Warning: Creating the Project Map file!!" + print("Warning: Creating the Project Map file!!") FileMode = "w+b" with open(ProjectMapPath, FileMode) as PMapFile: if (isExistingProject(PMapFile, ID)): - print >> sys.stdout, 'Warning: Project with ID \'', ID, \ - '\' already exists.' - print >> sys.stdout, "Reference output has been regenerated." + print('Warning: Project with ID \'', ID, \ + '\' already exists.', file=sys.stdout) + print("Reference output has been regenerated.", file=sys.stdout) else: PMapWriter = csv.writer(PMapFile) PMapWriter.writerow((ID, int(BuildMode))) - print "The project map is updated: ", ProjectMapPath + print("The project map is updated: ", ProjectMapPath) # TODO: Add an option not to build. # TODO: Set the path to the Repository directory. if __name__ == '__main__': if len(sys.argv) < 2 or sys.argv[1] in ('-h', '--help'): - print >> sys.stderr, 'Add a new project for testing to the analyzer'\ + print('Add a new project for testing to the analyzer'\ '\nUsage: ', sys.argv[0],\ 'project_ID <mode>\n' \ 'mode: 0 for single file project, ' \ '1 for scan_build, ' \ - '2 for single file c++11 project' + '2 for single file c++11 project', file=sys.stderr) sys.exit(-1) BuildMode = 1 diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index ea95ee289e99..1c96cd883818 100644 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -58,7 +58,10 @@ import shutil import sys import threading import time -import Queue +try: + import queue +except ImportError: + import Queue as queue ############################################################################### # Helper functions. @@ -119,7 +122,7 @@ if 'CC' in os.environ: else: Clang = SATestUtils.which("clang", os.environ['PATH']) if not Clang: - print "Error: cannot find 'clang' in PATH" + print("Error: cannot find 'clang' in PATH") sys.exit(1) # Number of jobs. @@ -255,7 +258,14 @@ def applyPatch(Dir, PBuildLogFile): sys.exit(1) -def runScanBuild(Dir, SBOutputDir, PBuildLogFile): +def generateAnalyzerConfig(Args): + Out = "serialize-stats=true,stable-report-filename=true" + if Args.extra_analyzer_config: + Out += "," + Args.extra_analyzer_config + return Out + + +def runScanBuild(Args, Dir, SBOutputDir, PBuildLogFile): """ Build the project with scan-build by reading in the commands and prefixing them with the scan-build options. @@ -277,13 +287,7 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): SBOptions += "-plist-html -o '%s' " % SBOutputDir SBOptions += "-enable-checker " + AllCheckers + " " SBOptions += "--keep-empty " - AnalyzerConfig = [ - ("stable-report-filename", "true"), - ("serialize-stats", "true"), - ] - - SBOptions += "-analyzer-config '%s' " % ( - ",".join("%s=%s" % (key, value) for (key, value) in AnalyzerConfig)) + SBOptions += "-analyzer-config '%s' " % generateAnalyzerConfig(Args) # Always use ccc-analyze to ensure that we can locate the failures # directory. @@ -304,6 +308,7 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): SBPrefix = "" ExtraEnv['OUTPUT'] = SBOutputDir ExtraEnv['CC'] = Clang + ExtraEnv['ANALYZER_CONFIG'] = generateAnalyzerConfig(Args) continue # If using 'make', auto imply a -jX argument @@ -328,7 +333,7 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): sys.exit(1) -def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): +def runAnalyzePreprocessed(Args, Dir, SBOutputDir, Mode): """ Run analysis on a set of preprocessed files. """ @@ -349,6 +354,7 @@ def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): CmdPrefix += "-analyze -analyzer-output=plist -w " CmdPrefix += "-analyzer-checker=" + Checkers CmdPrefix += " -fcxx-exceptions -fblocks " + CmdPrefix += " -analyzer-config %s " % generateAnalyzerConfig(Args) if (Mode == 2): CmdPrefix += "-std=c++11 " @@ -379,7 +385,7 @@ def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): check_call(Command, cwd=Dir, stderr=LogFile, stdout=LogFile, shell=True) - except CalledProcessError, e: + except CalledProcessError as e: Local.stderr.write("Error: Analyzes of %s failed. " "See %s for details." "Error code %d.\n" % ( @@ -407,7 +413,7 @@ def removeLogFile(SBOutputDir): check_call(RmCommand, shell=True) -def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): +def buildProject(Args, Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): TBegin = time.time() BuildLogPath = getBuildLogPath(SBOutputDir) @@ -431,9 +437,9 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): if (ProjectBuildMode == 1): downloadAndPatch(Dir, PBuildLogFile) runCleanupScript(Dir, PBuildLogFile) - runScanBuild(Dir, SBOutputDir, PBuildLogFile) + runScanBuild(Args, Dir, SBOutputDir, PBuildLogFile) else: - runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode) + runAnalyzePreprocessed(Args, Dir, SBOutputDir, ProjectBuildMode) if IsReferenceBuild: runCleanupScript(Dir, PBuildLogFile) @@ -564,8 +570,8 @@ def runCmpResults(Dir, Strictness=0): NewList.remove(os.path.join(NewDir, LogFolderName)) if len(RefList) != len(NewList): - print "Mismatch in number of results folders: %s vs %s" % ( - RefList, NewList) + print("Mismatch in number of results folders: %s vs %s" % ( + RefList, NewList)) sys.exit(1) # There might be more then one folder underneath - one per each scan-build @@ -577,8 +583,7 @@ def runCmpResults(Dir, Strictness=0): # Iterate and find the differences. NumDiffs = 0 - PairList = zip(RefList, NewList) - for P in PairList: + for P in zip(RefList, NewList): RefDir = P[0] NewDir = P[1] @@ -628,12 +633,13 @@ def cleanupReferenceResults(SBOutputDir): class TestProjectThread(threading.Thread): - def __init__(self, TasksQueue, ResultsDiffer, FailureFlag): + def __init__(self, Args, TasksQueue, ResultsDiffer, FailureFlag): """ :param ResultsDiffer: Used to signify that results differ from the canonical ones. :param FailureFlag: Used to signify a failure during the run. """ + self.Args = Args self.TasksQueue = TasksQueue self.ResultsDiffer = ResultsDiffer self.FailureFlag = FailureFlag @@ -649,7 +655,7 @@ class TestProjectThread(threading.Thread): Logger = logging.getLogger(ProjArgs[0]) Local.stdout = StreamToLogger(Logger, logging.INFO) Local.stderr = StreamToLogger(Logger, logging.ERROR) - if not testProject(*ProjArgs): + if not testProject(Args, *ProjArgs): self.ResultsDiffer.set() self.TasksQueue.task_done() except: @@ -657,7 +663,7 @@ class TestProjectThread(threading.Thread): raise -def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Strictness=0): +def testProject(Args, ID, ProjectBuildMode, IsReferenceBuild=False, Strictness=0): """ Test a given project. :return TestsPassed: Whether tests have passed according @@ -675,7 +681,7 @@ def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Strictness=0): RelOutputDir = getSBOutputDirName(IsReferenceBuild) SBOutputDir = os.path.join(Dir, RelOutputDir) - buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild) + buildProject(Args, Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild) checkBuild(SBOutputDir) @@ -712,24 +718,24 @@ def validateProjectFile(PMapFile): """ for I in iterateOverProjects(PMapFile): if len(I) != 2: - print "Error: Rows in the ProjectMapFile should have 2 entries." + print("Error: Rows in the ProjectMapFile should have 2 entries.") raise Exception() if I[1] not in ('0', '1', '2'): - print "Error: Second entry in the ProjectMapFile should be 0" \ - " (single file), 1 (project), or 2(single file c++11)." + print("Error: Second entry in the ProjectMapFile should be 0" \ + " (single file), 1 (project), or 2(single file c++11).") raise Exception() -def singleThreadedTestAll(ProjectsToTest): +def singleThreadedTestAll(Args, ProjectsToTest): """ Run all projects. :return: whether tests have passed. """ Success = True for ProjArgs in ProjectsToTest: - Success &= testProject(*ProjArgs) + Success &= testProject(Args, *ProjArgs) return Success -def multiThreadedTestAll(ProjectsToTest, Jobs): +def multiThreadedTestAll(Args, ProjectsToTest, Jobs): """ Run each project in a separate thread. @@ -738,7 +744,7 @@ def multiThreadedTestAll(ProjectsToTest, Jobs): :return: whether tests have passed. """ - TasksQueue = Queue.Queue() + TasksQueue = queue.Queue() for ProjArgs in ProjectsToTest: TasksQueue.put(ProjArgs) @@ -747,7 +753,7 @@ def multiThreadedTestAll(ProjectsToTest, Jobs): FailureFlag = threading.Event() for i in range(Jobs): - T = TestProjectThread(TasksQueue, ResultsDiffer, FailureFlag) + T = TestProjectThread(Args, TasksQueue, ResultsDiffer, FailureFlag) T.start() # Required to handle Ctrl-C gracefully. @@ -772,9 +778,9 @@ def testAll(Args): Args.regenerate, Args.strictness)) if Args.jobs <= 1: - return singleThreadedTestAll(ProjectsToTest) + return singleThreadedTestAll(Args, ProjectsToTest) else: - return multiThreadedTestAll(ProjectsToTest, Args.jobs) + return multiThreadedTestAll(Args, ProjectsToTest, Args.jobs) if __name__ == '__main__': @@ -791,9 +797,13 @@ if __name__ == '__main__': Parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=0, help='Number of projects to test concurrently') + Parser.add_argument('--extra-analyzer-config', dest='extra_analyzer_config', + type=str, + default="", + help="Arguments passed to to -analyzer-config") Args = Parser.parse_args() TestsPassed = testAll(Args) if not TestsPassed: - print "ERROR: Tests failed." + print("ERROR: Tests failed.") sys.exit(42) diff --git a/utils/analyzer/SATestUpdateDiffs.py b/utils/analyzer/SATestUpdateDiffs.py index 92bbd83172ef..ea3c08cc210c 100755 --- a/utils/analyzer/SATestUpdateDiffs.py +++ b/utils/analyzer/SATestUpdateDiffs.py @@ -3,6 +3,7 @@ """ Update reference results for static analyzer. """ +from __future__ import absolute_import, division, print_function import SATestBuild @@ -10,12 +11,12 @@ from subprocess import check_call import os import sys -Verbose = 1 +Verbose = 0 def runCmd(Command, **kwargs): if Verbose: - print "Executing %s" % Command + print("Executing %s" % Command) check_call(Command, shell=True, **kwargs) @@ -30,8 +31,8 @@ def updateReferenceResults(ProjName, ProjBuildMode): SATestBuild.getSBOutputDirName(IsReferenceBuild=False)) if not os.path.exists(CreatedResultsPath): - print >> sys.stderr, "New results not found, was SATestBuild.py "\ - "previously run?" + print("New results not found, was SATestBuild.py "\ + "previously run?", file=sys.stderr) sys.exit(1) BuildLogPath = SATestBuild.getBuildLogPath(RefResultsPath) @@ -62,9 +63,9 @@ def updateReferenceResults(ProjName, ProjBuildMode): def main(argv): if len(argv) == 2 and argv[1] in ('-h', '--help'): - print >> sys.stderr, "Update static analyzer reference results based "\ + print("Update static analyzer reference results based "\ "\non the previous run of SATestBuild.py.\n"\ - "\nN.B.: Assumes that SATestBuild.py was just run" + "\nN.B.: Assumes that SATestBuild.py was just run", file=sys.stderr) sys.exit(1) with SATestBuild.projectFileHandler() as f: diff --git a/utils/analyzer/SumTimerInfo.py b/utils/analyzer/SumTimerInfo.py index 50e1cb854f4e..36e519adbf71 100644 --- a/utils/analyzer/SumTimerInfo.py +++ b/utils/analyzer/SumTimerInfo.py @@ -6,13 +6,14 @@ Script to Summarize statistics in the scan-build output. Statistics are enabled by passing '-internal-stats' option to scan-build (or '-analyzer-stats' to the analyzer). """ +from __future__ import absolute_import, division, print_function import sys if __name__ == '__main__': if len(sys.argv) < 2: - print >> sys.stderr, 'Usage: ', sys.argv[0],\ - 'scan_build_output_file' + print('Usage: ', sys.argv[0],\ + 'scan_build_output_file', file=sys.stderr) sys.exit(-1) f = open(sys.argv[1], 'r') @@ -65,15 +66,15 @@ if __name__ == '__main__': s = line.split() TotalTime = TotalTime + float(s[6]) - print "TU Count %d" % (Count) - print "Time %f" % (Time) - print "Warnings %d" % (Warnings) - print "Functions Analyzed %d" % (FunctionsAnalyzed) - print "Reachable Blocks %d" % (ReachableBlocks) - print "Reached Max Steps %d" % (ReachedMaxSteps) - print "Number of Steps %d" % (NumSteps) - print "Number of Inlined calls %d (bifurcated %d)" % ( - NumInlinedCallSites, NumBifurcatedCallSites) - print "MaxTime %f" % (MaxTime) - print "TotalTime %f" % (TotalTime) - print "Max CFG Size %d" % (MaxCFGSize) + print("TU Count %d" % (Count)) + print("Time %f" % (Time)) + print("Warnings %d" % (Warnings)) + print("Functions Analyzed %d" % (FunctionsAnalyzed)) + print("Reachable Blocks %d" % (ReachableBlocks)) + print("Reached Max Steps %d" % (ReachedMaxSteps)) + print("Number of Steps %d" % (NumSteps)) + print("Number of Inlined calls %d (bifurcated %d)" % ( + NumInlinedCallSites, NumBifurcatedCallSites)) + print("MaxTime %f" % (MaxTime)) + print("TotalTime %f" % (TotalTime)) + print("Max CFG Size %d" % (MaxCFGSize)) diff --git a/utils/analyzer/ubiviz b/utils/analyzer/ubiviz deleted file mode 100755 index 137e130fe74c..000000000000 --- a/utils/analyzer/ubiviz +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===--------------------------------------------------------------------===## -# -# This script reads visualization data emitted by the static analyzer for -# display in Ubigraph. -# -##===--------------------------------------------------------------------===## - -import xmlrpclib -import sys - - -def Error(message): - print >> sys.stderr, 'ubiviz: ' + message - sys.exit(1) - - -def StreamData(filename): - file = open(filename) - for ln in file: - yield eval(ln) - file.close() - - -def Display(G, data): - action = data[0] - if action == 'vertex': - vertex = data[1] - G.new_vertex_w_id(vertex) - for attribute in data[2:]: - G.set_vertex_attribute(vertex, attribute[0], attribute[1]) - elif action == 'edge': - src = data[1] - dst = data[2] - edge = G.new_edge(src, dst) - for attribute in data[3:]: - G.set_edge_attribute(edge, attribute[0], attribute[1]) - elif action == "vertex_style": - style_id = data[1] - parent_id = data[2] - G.new_vertex_style_w_id(style_id, parent_id) - for attribute in data[3:]: - G.set_vertex_style_attribute(style_id, attribute[0], attribute[1]) - elif action == "vertex_style_attribute": - style_id = data[1] - for attribute in data[2:]: - G.set_vertex_style_attribute(style_id, attribute[0], attribute[1]) - elif action == "change_vertex_style": - vertex_id = data[1] - style_id = data[2] - G.change_vertex_style(vertex_id, style_id) - - -def main(args): - if len(args) == 0: - 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:]) |
