]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
test-zstd-speed.py: send e-mail in case of error
authorinikep <inikep@gmail.com>
Wed, 22 Jun 2016 10:12:35 +0000 (12:12 +0200)
committerinikep <inikep@gmail.com>
Wed, 22 Jun 2016 10:12:35 +0000 (12:12 +0200)
tests/test-zstd-speed.py

index 2c13fd386b663d7ea37db5b9cd2a861ba828445c..c693b2188e44be1481a3373be0f7cfaa620c5d7a 100755 (executable)
@@ -1,16 +1,19 @@
 #! /usr/bin/env python
-# execute(), fetch(), notify() are based on https://github.com/getlantern/build-automation/blob/master/build.py
 
 import argparse
 import os
 import string
 import time
 import traceback
-from subprocess import Popen, PIPE
+import subprocess
 
 default_repo_url = 'https://github.com/Cyan4973/zstd.git'
-test_dir_name = 'speedTest'
+working_dir_name = 'speedTest'
+working_path = os.getcwd() + '/' + working_dir_name     # /path/to/zstd/tests/speedTest 
+clone_path = working_path + '/' + 'zstd'                # /path/to/zstd/tests/speedTest/zstd 
 email_header = '[ZSTD_speedTest]'
+pid = str(os.getpid())
+
 
 def log(text):
     print(time.strftime("%Y/%m/%d %H:%M:%S") + ' - ' + text)
@@ -18,36 +21,34 @@ def log(text):
 
 def execute(command, print_output=False, print_error=True, param_shell=True):
     log("> " + command)
-    popen = Popen(command, stdout=PIPE, stderr=PIPE, shell=param_shell, cwd=execute.cwd)
-    itout = iter(popen.stdout.readline, b"")
-    iterr = iter(popen.stderr.readline, b"")
-    stdout_lines = list(itout)
-    stderr_lines = list(iterr)
-    popen.communicate()
+    popen = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=param_shell, cwd=execute.cwd)
+    stdout = popen.communicate()[0]
+    stdout_lines = stdout.splitlines()
     if print_output:
-        print(''.join(stdout_lines))
-        print(''.join(stderr_lines))
+        print('\n'.join(stdout_lines))
     if popen.returncode is not None and popen.returncode != 0:
         if not print_output and print_error:
-            print(''.join(stderr_lines))
-    return popen.returncode, stdout_lines, stderr_lines
+            print('\n'.join(stdout_lines))
+        raise RuntimeError('\n'.join(stdout_lines))
+    return stdout_lines
 execute.cwd = None
 
 
 def does_command_exist(command):
-    result, stdoutdata, stderrdata = execute(command, False, False);
-    return result == 0
+    try:
+        execute(command, False, False);
+    except Exception as e:
+        return False
+    return True
 
 
-def fetch():
+def get_branches():
     execute('git fetch -p')
-    returncode, output, stderrdata = execute('git branch -rl')
+    output = execute('git branch -rl')
     for line in output:
         if "HEAD" in line: 
             output.remove(line)  # remove "origin/HEAD -> origin/dev"
-    branches = map(lambda l: l.strip(), output)
-    print("branches=%s" % branches)
-    return map(lambda b: (b, execute('git show -s --format=%h ' + b)[1][0].strip()), branches)
+    return map(lambda l: l.strip(), output)
 
 
 def notify(branch, commit, last_commit):
@@ -55,10 +56,10 @@ def notify(branch, commit, last_commit):
     branch = branch.split('/')[1]
     fmt = '--format="%h: (%an) %s, %ar"'
     if last_commit is None:
-        returncode, commits, stderrdata = execute('git log -n 10 %s %s' % (fmt, commit))
+        commits = execute('git log -n 10 %s %s' % (fmt, commit))
     else:
-        returncode, commits, stderrdata = execute('git --no-pager log %s %s..%s' % (fmt, last_commit, commit))
-    text = text_tmpl.substitute({'last_commit': last_commit, 'commits': ''.join(commits)})
+        commits = execute('git --no-pager log %s %s..%s' % (fmt, last_commit, commit))
+    text = text_tmpl.substitute({'last_commit': last_commit, 'commits': '\n'.join(commits)})
     print(str("commits for %s: %s" % (commit, text)))
 
  
@@ -98,21 +99,22 @@ def benchmark_and_compare(branch, commit, resultsFileName, lastCLevel, testFileP
         log("WARNING: bench loadavg=%.2f is higher than %s, sleeping for %s seconds" % (os.getloadavg()[0], maxLoadAvg, sleepTime))
         time.sleep(sleepTime)
     start_load = str(os.getloadavg())
-    returncode, result, stderrdata = execute('programs/zstd -qi5b1e' + str(lastCLevel) + ' ' + testFilePath)
+    result = execute('programs/zstd -qi5b1e' + str(lastCLevel) + ' ' + testFilePath, print_output=True)
     end_load = str(os.getloadavg())
     linesExpected = lastCLevel + 2;
     if len(result) != linesExpected:
-        log("ERROR: number of result lines=%d is different that expected %d" % (len(result), linesExpected))
-        return ""
+        raise RuntimeError("ERROR: number of result lines=%d is different that expected %d" % (len(result), linesExpected))
     with open(resultsFileName, "a") as myfile:
         myfile.write(branch + " " + commit + "\n")
-        myfile.writelines(result)
+        myfile.write('\n'.join(result) + '\n')
         myfile.close()
         if (last_cspeed == None):
+            log("WARNING: No data for comparison for branch=%s file=%s " % (branch, fileName))
             return ""
         commit, cspeed, dspeed = get_last_commit(resultsFileName)
         text = ""
         for i in range(0, min(len(cspeed), len(last_cspeed))):
+            print("%s: -%d cspeed=%6.2f clast=%6.2f cdiff=%1.4f dspeed=%6.2f dlast=%6.2f ddiff=%1.4f %s" % (branch, i+1, cspeed[i], last_cspeed[i], cspeed[i]/last_cspeed[i], dspeed[i], last_dspeed[i], dspeed[i]/last_dspeed[i], fileName))
             if (cspeed[i]/last_cspeed[i] < lower_limit):
                 text += "WARNING: File=%s level=%d cspeed=%s last=%s diff=%s\n" % (fileName, i+1, cspeed[i], last_cspeed[i], cspeed[i]/last_cspeed[i])
             if (dspeed[i]/last_dspeed[i] < lower_limit):
@@ -122,31 +124,37 @@ def benchmark_and_compare(branch, commit, resultsFileName, lastCLevel, testFileP
         return text
 
 
-def send_simple_email(emails, email_topic, have_mutt, have_mail):
-    if have_mutt:
-        execute('mutt -s "' + email_header + ' ' + email_topic + '" ' + emails + ' </dev/null')
-    elif have_mail:
-        execute('mail -s "' + email_header + ' ' + email_topic + '" ' + emails + ' </dev/null')
-    else:
-        log("e-mail cannot be sent (mail and mutt not found)")
+def send_email(emails, topic, text, have_mutt, have_mail):
+    logFileName = working_path + '/' + 'tmpEmailContent'
+    with open(logFileName, "w") as myfile:
+        myfile.writelines(text)
+        myfile.close()
+        if have_mutt:
+            execute('mutt -s "' + topic + '" ' + emails + ' < ' + logFileName)
+        elif have_mail:
+            execute('mail -s "' + topic + '" ' + emails + ' < ' + logFileName)
+        else:
+            log("e-mail cannot be sent (mail or mutt not found)")
 
 
-def send_email(branch, commit, last_commit, emails, text, results_files, logFileName, lower_limit, have_mutt, have_mail):
+def send_email_with_attachments(branch, commit, last_commit, emails, text, results_files, logFileName, lower_limit, have_mutt, have_mail):
     with open(logFileName, "w") as myfile:
         myfile.writelines(text)
         myfile.close()
+        email_topic = '%s:%s Warning for branch=%s commit=%s last_commit=%s speed<%s' % (email_header, pid, branch, commit, last_commit, lower_limit)
         if have_mutt:
-            execute('mutt -s "' + email_header + ' Warning for branch=' + branch + ' commit=' + commit + ' last_commit=' + last_commit + ' speed<' + str(lower_limit) + '" ' + emails + ' -a ' + results_files + ' < ' + logFileName)
+            execute('mutt -s "' + email_topic + '" ' + emails + ' -a ' + results_files + ' < ' + logFileName)
         elif have_mail:
-            execute('mail -s "' + email_header + ' Warning for branch=' + branch + ' commit=' + commit + ' last_commit=' + last_commit + ' speed<' + str(lower_limit) + '" ' + emails + ' < ' + logFileName)
+            execute('mail -s "' + email_topic + '" ' + emails + ' < ' + logFileName)
         else:
-            log("e-mail cannot be sent (mail and mutt not found)")
+            log("e-mail cannot be sent (mail or mutt not found)")
 
 
-def check_branches(args, test_path, testFilePaths, have_mutt, have_mail):
-    for branch, commit in fetch():
+def check_branch(branch, args, testFilePaths, have_mutt, have_mail):
+    commits = execute('git show -s --format=%h ' + branch)[0]
+    for commit in [commits]:
         try:
-            commitFileName = test_path + "/commit_" + branch.replace("/", "_")
+            commitFileName = working_path + "/commit_" + branch.replace("/", "_")
             if os.path.isfile(commitFileName):
                 last_commit = file(commitFileName, 'r').read()
             else:
@@ -159,27 +167,29 @@ def check_branches(args, test_path, testFilePaths, have_mutt, have_mail):
                 log("build branch %s: head %s is different from prev %s" % (branch, commit, last_commit))
                 compile(branch, commit, args.dry_run)
 
-                logFileName = test_path + "/log_" + branch.replace("/", "_")
+                logFileName = working_path + "/log_" + branch.replace("/", "_")
                 text_to_send = []
                 results_files = ""
                 for filePath in testFilePaths:
                     fileName = filePath.rpartition('/')[2]
-                    resultsFileName = test_path + "/results_" + branch.replace("/", "_") + "_" + fileName
+                    resultsFileName = working_path + "/results_" + branch.replace("/", "_") + "_" + fileName
                     last_commit, cspeed, dspeed = get_last_commit(resultsFileName)
 
                     if not args.dry_run:
                         text = benchmark_and_compare(branch, commit, resultsFileName, args.lastCLevel, filePath, fileName, cspeed, dspeed, args.lowerLimit, args.maxLoadAvg, args.message)
                         if text:
+                            log("WARNING: redoing tests for branch %s: commit %s" % (branch, commit))
                             text = benchmark_and_compare(branch, commit, resultsFileName, args.lastCLevel, filePath, fileName, cspeed, dspeed, args.lowerLimit, args.maxLoadAvg, args.message)
                             if text:
                                 text_to_send.append(text)
                                 results_files += resultsFileName + " "
                 if text_to_send:
-                    send_email(branch, commit, last_commit, args.emails, text_to_send, results_files, logFileName, args.lowerLimit, have_mutt, have_mail)
+                    send_email_with_attachments(branch, commit, last_commit, args.emails, text_to_send, results_files, logFileName, args.lowerLimit, have_mutt, have_mail)
                 notify(branch, commit, last_commit)
         except Exception as e:
             stack = traceback.format_exc()
-            log("ERROR: build %s, error %s" % (branch, str(e)) )
+            email_topic = '%s:%s ERROR in branch=%s commit=%s' % (email_header, pid, branch, commit)
+            send_email(args.emails, email_topic, stack,  have_mutt, have_mail)
             print(stack)
 
 
@@ -206,9 +216,6 @@ if __name__ == '__main__':
             log("ERROR: File not found: " + fileName)
             exit(1)
 
-    test_path = os.getcwd() + '/' + test_dir_name     # /path/to/zstd/tests/speedTest 
-    clone_path = test_path + '/' + 'zstd'             # /path/to/zstd/tests/speedTest/zstd 
-
     # check availability of e-mail senders
     have_mutt = does_command_exist("mutt -h");
     have_mail = does_command_exist("mail -V");
@@ -217,7 +224,7 @@ if __name__ == '__main__':
         exit(1)
 
     print("PARAMETERS:\nrepoURL=%s" % args.repoURL)
-    print("test_path=%s" % test_path)
+    print("working_path=%s" % working_path)
     print("clone_path=%s" % clone_path)
     print("testFilePath(%s)=%s" % (len(testFilePaths), testFilePaths))
     print("message=%s" % args.message)
@@ -230,10 +237,10 @@ if __name__ == '__main__':
     print("have_mutt=%s have_mail=%s" % (have_mutt, have_mail))
 
     # clone ZSTD repo if needed
-    if not os.path.isdir(test_path):
-        os.mkdir(test_path)
+    if not os.path.isdir(working_path):
+        os.mkdir(working_path)
     if not os.path.isdir(clone_path):
-        execute.cwd = test_path
+        execute.cwd = working_path
         execute('git clone ' + args.repoURL)
     if not os.path.isdir(clone_path):
         log("ERROR: ZSTD clone not found: " + clone_path)
@@ -241,22 +248,25 @@ if __name__ == '__main__':
     execute.cwd = clone_path
 
     # check if speedTest.pid already exists
-    pid = str(os.getpid())
     pidfile = "./speedTest.pid"
     if os.path.isfile(pidfile):
         log("ERROR: %s already exists, exiting" % pidfile)
         exit(1)
 
-    send_simple_email(args.emails, "test-zstd-speed.py(%s) has been started" % pid, have_mutt, have_mail)
+    send_email(args.emails, email_header + ':%s test-zstd-speed.py has been started' % pid, '',  have_mutt, have_mail)
+
+    file(pidfile, 'w').write(pid)
     while True:
-        file(pidfile, 'w').write(pid)
         try:
             loadavg = os.getloadavg()[0]
             if (loadavg <= args.maxLoadAvg):
-                check_branches(args, test_path, testFilePaths, have_mutt, have_mail)
+                branches = get_branches()
+                for branch in branches:
+                    check_branch(branch, args, testFilePaths, have_mutt, have_mail)
             else:
                 log("WARNING: main loadavg=%.2f is higher than %s" % (loadavg, args.maxLoadAvg))
+            log("sleep for %s seconds" % args.sleepTime)
+            time.sleep(args.sleepTime)
         finally:
             os.unlink(pidfile)
-        log("sleep for %s seconds" % args.sleepTime)
-        time.sleep(args.sleepTime)
+            send_email(args.emails, email_header + ':%s test-zstd-speed.py has been stopped' % pid, '',  have_mutt, have_mail)