140 lines
4.4 KiB
Python
Executable file
140 lines
4.4 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import shlex
|
|
import time
|
|
import string
|
|
import os
|
|
import tempfile
|
|
import subprocess
|
|
import re
|
|
import argparse
|
|
import sys
|
|
import csv
|
|
from stat import *
|
|
|
|
class tstats:
|
|
close_threshold = 0.01
|
|
|
|
def __init__(self, stats_dict=None):
|
|
if stats_dict != None:
|
|
self.name = stats_dict["name"]
|
|
self.elapsed = float(stats_dict["elapsed"])
|
|
self.user = float(stats_dict["user"])
|
|
self.sys = float(stats_dict["sys"])
|
|
|
|
def times_str(self):
|
|
ctime = self.sys + self.user
|
|
return "time=%6.2f, cpu=%6.2f (%4.2f%%)" % (self.elapsed, ctime, (ctime * 100.0) / self.elapsed)
|
|
|
|
def dict(self):
|
|
return {"name":self.name, "elapsed":self.elapsed, "user":self.user, "sys":self.sys}
|
|
|
|
def is_close(self, other):
|
|
return abs(self.elapsed - other.elapsed) / self.elapsed < self.close_threshold
|
|
|
|
def __lt__(self, other):
|
|
return self.elapsed < other.elapsed
|
|
def __gt__(self, other):
|
|
return self.elapsed > other.elapsed
|
|
|
|
def time_file(name, prefix, args):
|
|
cmdargs = [args.ffmpeg]
|
|
for x in args.args :
|
|
if x == '{INPUT}':
|
|
cmdargs.append(prefix + name)
|
|
elif x == '{NULL}':
|
|
cmdargs.append(os.devnull)
|
|
else:
|
|
cmdargs.append(x)
|
|
|
|
stats = tstats()
|
|
stats.name = name
|
|
start_time = time.clock_gettime(time.CLOCK_MONOTONIC);
|
|
cproc = subprocess.Popen(cmdargs, bufsize=-1, stdout=flog, stderr=flog);
|
|
pinfo = os.wait4(cproc.pid, 0)
|
|
end_time = time.clock_gettime(time.CLOCK_MONOTONIC);
|
|
stats.elapsed = end_time - start_time
|
|
stats.user = pinfo[2].ru_utime
|
|
stats.sys = pinfo[2].ru_stime
|
|
return stats
|
|
|
|
|
|
def common_prefix(s1, s2):
|
|
for i in range(min(len(s1),len(s2))):
|
|
if s1[i] != s2[i]:
|
|
return s1[:i]
|
|
return s1[:i+1]
|
|
|
|
def main():
|
|
global flog
|
|
|
|
argp = argparse.ArgumentParser(description="FFmpeg performance tester", epilog="""
|
|
To blank the screen before starting use "xdg-screensaver activate"
|
|
(For some reason this doesn't seem to work from within python).
|
|
""")
|
|
|
|
argp.add_argument("streams", nargs='*')
|
|
argp.add_argument("--args", default='-t 30 -i {INPUT} -f null {NULL}', help="""
|
|
ffmpeg arguments, default='-t 30 -i {INPUT} -f null {NULL}';
|
|
{INPUT} is replaced by current inputfile path;
|
|
{NULL} is replaced by the system null device""")
|
|
argp.add_argument("--csv_out", default="ffperf_out.csv", help="CSV output filename")
|
|
argp.add_argument("--csv_in", help="CSV input filename")
|
|
argp.add_argument("--prefix", help="Filename prefix (include terminal '/' if a directory).")
|
|
argp.add_argument("--repeat", default=3, type=int, help="Run repeat count")
|
|
argp.add_argument("--ffmpeg", default="./ffmpeg", help="FFmpeg executable")
|
|
|
|
args = argp.parse_args()
|
|
args.args = shlex.split(args.args)
|
|
|
|
csv_out = csv.DictWriter(open(args.csv_out, 'w', newline=''), ["name", "elapsed", "user", "sys"])
|
|
csv_out.writeheader()
|
|
|
|
stats_in = {}
|
|
if args.csv_in != None:
|
|
with open(args.csv_in, 'r', newline='') as f_in:
|
|
stats_in = {x["name"]:tstats(x) for x in csv.DictReader(f_in)}
|
|
|
|
flog = open(os.path.join(tempfile.gettempdir(), "ffperf.log"), "wt")
|
|
|
|
streams = args.streams
|
|
if not streams:
|
|
if not stats_in:
|
|
print ("No source streams specified")
|
|
return 1
|
|
prefix = "" if args.prefix == None else args.prefix
|
|
streams = [k for k in stats_in]
|
|
elif args.prefix != None:
|
|
prefix = args.prefix
|
|
else:
|
|
prefix = streams[0]
|
|
for f in streams[1:]:
|
|
prefix = common_prefix(prefix, f)
|
|
pp = prefix.rpartition(os.sep)
|
|
prefix = pp[0] + pp[1]
|
|
streams = [s[len(prefix):] for s in streams]
|
|
|
|
for f in sorted(streams, key=lambda x : "~" * x.count(os.sep) + x.lower()):
|
|
print ("====", f)
|
|
|
|
t0 = tstats({"name":f, "elapsed":999, "user":999, "sys":999})
|
|
for i in range(args.repeat):
|
|
t = tstats.time_file(f, prefix, args)
|
|
print ("...", t.times_str())
|
|
if t0 > t:
|
|
t0 = t
|
|
|
|
if t0.name in stats_in:
|
|
pstat = stats_in[t0.name]
|
|
print("---" if pstat.is_close(t0) else "<<<" if t0 < pstat else ">>>", pstat.times_str())
|
|
|
|
csv_out.writerow(t0.dict())
|
|
|
|
print ()
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
exit(main())
|
|
|