dbd4d69632
Change-Id: I46db49472dcaa80b54a937f03bf03b06a2d8a87c Reviewed-on: https://gerrit.libreoffice.org/61240 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
258 lines
6.9 KiB
Python
Executable file
258 lines
6.9 KiB
Python
Executable file
#!/usr/bin/python
|
|
|
|
# This file is part of the LibreOffice project.
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import sys
|
|
import os
|
|
import getopt
|
|
import csv
|
|
|
|
|
|
colsResult = {}
|
|
allTests = []
|
|
|
|
def parseFile(dirname, filename, lastCommit):
|
|
|
|
curTestComment, total = None, None
|
|
|
|
path = os.path.join(dirname, filename)
|
|
|
|
trigger = "desc: Trigger: Client Request: "
|
|
trigger_len = len(trigger)
|
|
totals = "totals: "
|
|
totals_len = len(totals)
|
|
|
|
with open(path,'r') as callgrindFile:
|
|
lines = callgrindFile.readlines()
|
|
|
|
for line in lines:
|
|
if line.startswith(trigger):
|
|
curTestComment = line[trigger_len:].replace("\n","")
|
|
elif line.startswith(totals):
|
|
total = line[totals_len:].replace("\n","")
|
|
|
|
if curTestComment is None or total is None:
|
|
return None
|
|
|
|
testName = os.path.basename(dirname).replace(".test.core","")
|
|
|
|
lastCommitId, lastCommitDate = lastCommit
|
|
if lastCommitId not in colsResult:
|
|
colsResult[lastCommitId] = {}
|
|
colsResult[lastCommitId]['date'] = lastCommitDate
|
|
colsResult[lastCommitId]['values'] = {}
|
|
|
|
colsResult[lastCommitId]['values'][curTestComment] = total
|
|
|
|
return [lastCommitId, lastCommitDate, testName, curTestComment, total, filename]
|
|
|
|
def processDirectory(rootDir, needsCsvHeader, lastCommit):
|
|
|
|
results = []
|
|
|
|
if needsCsvHeader:
|
|
results.append(["lastCommit", "lastCommitDate", "test filename", "dump comment", "count", "filename"])
|
|
|
|
for dirName, subdirList, fileList in os.walk(rootDir):
|
|
files = [f for f in fileList if f.startswith("callgrind.out.")]
|
|
for fname in files:
|
|
found = parseFile(dirName, fname, lastCommit)
|
|
if found is not None:
|
|
results.append(found)
|
|
return results
|
|
|
|
def getLastCommitInfo():
|
|
|
|
stream = os.popen("git log --date=iso")
|
|
line = stream.readline()
|
|
commitId = line.replace("commit ","").replace("\n","")
|
|
line = stream.readline()
|
|
line = stream.readline()
|
|
commitDate = line.replace("Date: ","").replace("\n","").strip()
|
|
|
|
return commitId, commitDate
|
|
|
|
def displayUsage():
|
|
|
|
usage = """
|
|
|
|
Parses the callgrind results of make perfcheck
|
|
|
|
Arguments :
|
|
|
|
--csv-file\t\t the target CSV file - new or containing previous tests - default : perfcheckResult.csv
|
|
--source-directory\t directory containing make perfcheck output - default : ./workdir/CppunitTest
|
|
--alert-type\t\t mode for calculating alerts - valid values : previous first
|
|
--alert-value\t\t alert threshold in % - default = 10
|
|
|
|
--help\t\t this message
|
|
|
|
Columned output is dumped into csv-file + ".col"
|
|
|
|
Alerts, if any, are displayed in standard output
|
|
|
|
"""
|
|
print(usage)
|
|
|
|
class WrongArguments(Exception):
|
|
pass
|
|
|
|
def analyzeArgs(args):
|
|
|
|
try:
|
|
opts, args = getopt.getopt(args, 'x', [
|
|
'csv-file=', 'source-directory=', 'alert-type=', 'alert-value=', 'help'])
|
|
except getopt.GetoptError:
|
|
raise WrongArguments
|
|
|
|
targetFileName = "perfcheckResult.csv"
|
|
sourceDirectory = "./workdir/CppunitTest"
|
|
alertType = ""
|
|
alertValue = 10
|
|
|
|
for o, a in opts:
|
|
if o == '--help':
|
|
displayUsage()
|
|
sys.exit()
|
|
elif o == "--csv-file":
|
|
targetFileName = a
|
|
elif o == "--source-directory":
|
|
sourceDirectory = a
|
|
elif o == "--alert-type":
|
|
alertType = a
|
|
elif o == "--alert-value":
|
|
alertValue = float(a)
|
|
else:
|
|
raise WrongArguments
|
|
|
|
return targetFileName, sourceDirectory, alertType, alertValue
|
|
|
|
def readCsvFile(targetFilename):
|
|
|
|
with open(targetFilename, 'r') as csvfile:
|
|
reader = csv.reader(csvfile, delimiter="\t")
|
|
# skip header
|
|
next(reader)
|
|
for line in reader:
|
|
|
|
# do not process empty lines
|
|
if not line:
|
|
continue
|
|
|
|
curId, curDate, curTestName, curTestComment, curValue, currCallgrindFile = line
|
|
|
|
if curTestComment not in allTests:
|
|
allTests.append(curTestComment)
|
|
|
|
if curId not in colsResult:
|
|
colsResult[curId] = {}
|
|
colsResult[curId]['date'] = curDate
|
|
colsResult[curId]['values'] = {}
|
|
|
|
colsResult[curId]['values'][curTestComment] = curValue
|
|
|
|
if __name__ == '__main__':
|
|
|
|
#check args
|
|
try:
|
|
targetFileName, sourceDirectory, alertType, alertValue = analyzeArgs(sys.argv[1:])
|
|
except WrongArguments:
|
|
displayUsage()
|
|
sys.exit(1)
|
|
|
|
# check if sourceDirectory exists
|
|
if not os.path.isdir(sourceDirectory):
|
|
print("sourceDirectory %s not found - Aborting" % (sourceDirectory))
|
|
sys.exit(1)
|
|
|
|
# read the complete CSV file
|
|
if os.path.isfile(targetFileName):
|
|
readCsvFile(targetFileName)
|
|
needsCsvHeader = False
|
|
else:
|
|
needsCsvHeader = True
|
|
|
|
# last commit Id
|
|
lastCommitId, lastCommitDate = getLastCommitInfo()
|
|
|
|
# walker through directory
|
|
if lastCommitId not in colsResult:
|
|
|
|
lastCommit = (lastCommitId, lastCommitDate)
|
|
results = processDirectory(sourceDirectory, needsCsvHeader, lastCommit)
|
|
ppResults = "\n".join(["\t".join(row) for row in results])
|
|
|
|
print('\nNew results\n' + ppResults)
|
|
|
|
# append raw result
|
|
with open(targetFileName,'a') as csvfile:
|
|
writer = csv.writer(csvfile, delimiter='\t')
|
|
writer.writerows(results)
|
|
print("\nCSV file written at " + targetFileName + '\n')
|
|
|
|
else:
|
|
print("\nCSV file up to date " + targetFileName + '\n')
|
|
|
|
|
|
# build columned output
|
|
|
|
# header
|
|
mLine = '\t'.join(["commit", "date"] + allTests) + '\n'
|
|
|
|
alertTest = {}
|
|
|
|
with open(targetFileName + '.col','w') as fileResult:
|
|
for k in colsResult:
|
|
mLine += k + "\t" + colsResult[k]['date'] + "\t"
|
|
for t in allTests:
|
|
if t in colsResult[k]['values']:
|
|
mValue= colsResult[k]['values'][t]
|
|
if t not in alertTest:
|
|
alertTest[t] = {}
|
|
alertTest[t][colsResult[k]['date']] = mValue
|
|
else:
|
|
mValue = ""
|
|
mLine += mValue + "\t"
|
|
mLine += "\n"
|
|
|
|
# write columned result
|
|
fileResult.write(mLine)
|
|
|
|
print("Columned file written at " + targetFileName + '.col\n')
|
|
|
|
# check for Alerts
|
|
|
|
if alertType == "":
|
|
sys.exit(1)
|
|
|
|
alertResult = ""
|
|
|
|
for t in alertTest:
|
|
|
|
testDict = alertTest[t]
|
|
|
|
# sort
|
|
keylist = sorted(testDict.keys())
|
|
maxVal = float(testDict[keylist[-1]])
|
|
minVal = 0
|
|
|
|
if alertType == "previous":
|
|
if len(keylist) > 1:
|
|
minVal = float(testDict[keylist[-2]])
|
|
else:
|
|
minVal = float(testDict[keylist[0]])
|
|
|
|
if minVal != 0:
|
|
delta = 100 * ((maxVal-minVal)/minVal)
|
|
else:
|
|
delta = 0
|
|
|
|
if delta > float(alertValue):
|
|
alertResult += t + "\t" + "{:.2f}".format(delta) + " %\n"
|
|
|
|
if alertResult != "":
|
|
print("!!!!!!!! ALERT !!!!!!!\n")
|
|
print(alertResult)
|