#!/usr/bin/env python3
from getopt import getopt, GetoptError
import re
import sys, os, time
import subprocess
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import cpu_count
def usage():
USAGE = """\
Usage: %(progName)s
...
Options:
-h, --help Show this message
"""
print(USAGE % {'progName': sys.argv[0]})
sys.exit(1)
def process_directories(dirpath):
filenames = set()
if os.path.isdir(dirpath):
for filename in os.listdir(dirpath):
filenames.update(process_directories(os.path.join(dirpath, filename)))
else:
filenames.add(dirpath)
return filenames
def run_test(filename):
if ".out" in filename:
return ""
if ".shader_test" in filename:
command = ['./bin/shader_runner',
filename,
'-auto',
'-fbo']
else:
command = ['./bin/glslparsertest',
filename,
'pass']
timebefore = time.time()
try:
p = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
results = (stdout + stderr).decode("utf-8")
except KeyboardInterrupt:
exit(1)
except:
return filename + " FAIL\n"
timeafter = time.time()
with open(filename + '.out', 'w') as file:
file.write(results)
current_type = 'UNKNOWN'
counts = {}
lines = list(results.split('\n'))
re_builtin_shader = re.compile("shader 0")
re_fs_8 = re.compile("^Native code for .*fragment.*(8-wide|SIMD8)")
re_fs_16 = re.compile("^Native code for .*fragment.*(16-wide|SIMD16)")
re_gs = re.compile("^Native code for .*geometry")
re_vs = re.compile("^Native code for .*vertex")
re_align = re.compile("{ align")
re_2q = re.compile("\(8\).* 2Q };")
counts["ignore"] = 0
counts["vs "] = 0
counts["gs "] = 0
counts["fs8 "] = 0
counts["fs16"] = 0
last_was_paired8 = False
for line in lines:
if (re_builtin_shader.search(line)):
current_type = "ignore"
elif (re_vs.search(line)):
current_type = "vs "
elif (re_gs.search(line)):
current_type = "gs "
elif (re_fs_8.search(line)):
current_type = "fs8 "
elif (re_fs_16.search(line)):
current_type = "fs16"
elif (re_align.search(line)):
# Skip the 2Q (second half) SIMD8 instructions, since the
# 1Q+2Q pair should be the same cost as a single 1H
# (SIMD16) instruction, other than icache pressure.
if current_type != "fs16" or not re_2q.search(line):
counts[current_type] = counts[current_type] + 1
del counts["ignore"]
timestr = " {:.3f} secs".format(timeafter - timebefore)
out = ''
for t in counts:
if counts[t] != 0:
out += "{0:40} {1} : {2:6}{3}\n".format(filename, t, counts[t], timestr)
timestr = ""
return out
def main():
try:
option_list = [
"help",
]
options, args = getopt(sys.argv[1:], "h", option_list)
except GetoptError:
usage()
env_add = {}
env_add["shader_precompile"] = "true"
env_add["force_glsl_extensions_warn"] = "true"
env_add["INTEL_DEBUG"] = "vs,wm,gs"
os.environ.update(env_add)
for name, value in options:
if name in ('-h', '--help'):
usage()
if len(args) < 1:
args.append("shaders")
try:
os.stat("bin/glslparsertest")
except:
print("./bin must be a symlink to a built piglit bin directory")
sys.exit(1)
runtimebefore = time.time()
filenames = set()
for i in args:
filenames.update(process_directories(i))
executor = ThreadPoolExecutor(cpu_count())
for t in executor.map(run_test, filenames):
sys.stdout.write(t)
runtimeafter = time.time()
print("shader-db run completed in {:.1f} secs".format(runtimeafter - runtimebefore))
if __name__ == "__main__":
main()