#!/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 = 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)
4-1-4-2'>distro/mimo/mimo-4-1-4-2