aboutsummaryrefslogtreecommitdiff
path: root/utils/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'utils/analyzer')
-rwxr-xr-xutils/analyzer/CmpRuns.py35
-rw-r--r--utils/analyzer/SATestAdd.py17
-rw-r--r--utils/analyzer/SATestBuild.py78
-rwxr-xr-xutils/analyzer/SATestUpdateDiffs.py13
-rw-r--r--utils/analyzer/SumTimerInfo.py29
-rwxr-xr-xutils/analyzer/ubiviz76
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:])