diff options
Diffstat (limited to 'bin/parse-perfcheck.py')
-rwxr-xr-x | bin/parse-perfcheck.py | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/bin/parse-perfcheck.py b/bin/parse-perfcheck.py new file mode 100755 index 000000000..158ef62fe --- /dev/null +++ b/bin/parse-perfcheck.py @@ -0,0 +1,258 @@ +#!/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) |