CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
547 lines
21 KiB
Python
Executable File
547 lines
21 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# ########################################################################
|
|
# Copyright (C) 2022-2023 Advanced Micro Devices, Inc.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
#
|
|
# ########################################################################
|
|
|
|
#Expand hipBLASLt YAML test data file into binary Arguments records"""
|
|
|
|
import re
|
|
import sys
|
|
import os
|
|
import argparse
|
|
import ctypes
|
|
from fnmatch import fnmatchcase
|
|
from typing import List, Tuple
|
|
try: # Import either the C or pure-Python YAML parser
|
|
from yaml import CLoader as Loader
|
|
except ImportError:
|
|
from yaml import Loader
|
|
import yaml
|
|
|
|
# Regex for type names in the YAML file. Optional *nnn indicates array.
|
|
TYPE_RE = re.compile(r'[a-z_A-Z]\w*(:?\s*\*\s*\d+)?$')
|
|
|
|
# Regex for integer ranges A..B[..C]
|
|
INT_RANGE_RE = re.compile(
|
|
r'\s*(-?\d+)\s*\.\.\s*(-?\d+)\s*(?:\.\.\s*(-?\d+)\s*)?$')
|
|
|
|
# Regex for include: YAML extension
|
|
INCLUDE_RE = re.compile(r'include\s*:\s*([-.\w/]+)')
|
|
|
|
args = {}
|
|
testcases = set()
|
|
datatypes = {}
|
|
param = {}
|
|
|
|
|
|
def main():
|
|
args.update(parse_args().__dict__)
|
|
for doc in get_yaml_docs():
|
|
process_doc(doc)
|
|
|
|
|
|
def process_doc(doc):
|
|
"""Process one document in the YAML file"""
|
|
|
|
# Ignore empty documents
|
|
if not doc or not doc.get('Tests'):
|
|
return
|
|
|
|
# Clear datatypes and params from previous documents
|
|
datatypes.clear()
|
|
param.clear()
|
|
|
|
# Return dictionary of all known datatypes
|
|
datatypes.update(get_datatypes(doc))
|
|
|
|
# Arguments structure corresponding to C/C++ structure
|
|
param['Arguments'] = type('Arguments', (ctypes.Structure,),
|
|
{'_fields_': get_arguments(doc)})
|
|
|
|
# Special names which get expanded as lists of arguments
|
|
param['dict_lists_to_expand'] = doc.get('Dictionary lists to expand') or ()
|
|
|
|
# Lists which are not expanded
|
|
param['lists_to_not_expand'] = doc.get('Lists to not expand') or ()
|
|
|
|
# Defaults
|
|
defaults = doc.get('Defaults') or {}
|
|
|
|
# Known Bugs
|
|
param['known_bugs'] = doc.get('Known bugs') or []
|
|
|
|
# Functions
|
|
param['Functions'] = doc.get('Functions') or {}
|
|
|
|
# Instantiate all of the tests, starting with defaults
|
|
for test in doc['Tests']:
|
|
case = defaults.copy()
|
|
case.update(test)
|
|
generate(case, instantiate)
|
|
|
|
|
|
def parse_args():
|
|
"""Parse command-line arguments, returning input and output files"""
|
|
parser = argparse.ArgumentParser(description="""
|
|
Expand hipBLASLt YAML test data file into binary Arguments records
|
|
""")
|
|
parser.add_argument('infile',
|
|
nargs='?',
|
|
type=argparse.FileType('r'),
|
|
default=sys.stdin)
|
|
parser.add_argument('-o', '--out',
|
|
dest='outfile',
|
|
type=argparse.FileType('wb'),
|
|
default=sys.stdout)
|
|
parser.add_argument('-I',
|
|
help="Add include path",
|
|
action='append',
|
|
dest='includes',
|
|
default=[])
|
|
parser.add_argument('-t', '--template',
|
|
type=argparse.FileType('r'))
|
|
return parser.parse_args()
|
|
|
|
|
|
def read_yaml_file(file):
|
|
"""Read the YAML file, processing include: lines as an extension"""
|
|
file_dir = os.path.dirname(file.name) or os.getcwd()
|
|
source = []
|
|
for line_no, line in enumerate(file, start=1):
|
|
# Keep track of file names and line numbers for each line of YAML
|
|
match = line.startswith('include') and INCLUDE_RE.match(line)
|
|
if not match:
|
|
source.append([line, file.name, line_no])
|
|
else:
|
|
include_file = match.group(1)
|
|
include_dirs = [file_dir] + args['includes']
|
|
for path in include_dirs:
|
|
path = os.path.join(path, include_file)
|
|
if os.path.exists(path):
|
|
source.extend(read_yaml_file(open(path, 'r')))
|
|
break
|
|
else:
|
|
sys.exit("In file " + file.name + ", line " +
|
|
str(line_no) + ", column " + str(match.start(1)+1) +
|
|
":\n" + line.rstrip() + "\n" + " " * match.start(1) +
|
|
"^\nCannot open " + include_file +
|
|
"\n\nInclude paths:\n" + "\n".join(include_dirs))
|
|
file.close()
|
|
return source
|
|
|
|
|
|
def get_yaml_docs():
|
|
"""Parse the YAML file"""
|
|
source = read_yaml_file(args['infile'])
|
|
|
|
if args.get('template'):
|
|
source = read_yaml_file(args['template']) + source
|
|
|
|
source_str = ''.join([line[0] for line in source])
|
|
|
|
def mark_str(mark):
|
|
line = source[mark.line]
|
|
return("In file " + line[1] + ", line " + str(line[2]) + ", column " +
|
|
str(mark.column + 1) + ":\n" + line[0].rstrip() + "\n" +
|
|
' ' * mark.column + "^\n")
|
|
|
|
# We iterate through all of the documents to properly diagnose errors,
|
|
# because the load_all generator does not handle exceptions correctly.
|
|
docs = []
|
|
load = Loader(source_str)
|
|
while load.check_data():
|
|
try:
|
|
doc = load.get_data()
|
|
except yaml.YAMLError as err:
|
|
sys.exit((mark_str(err.problem_mark) if err.problem_mark else "") +
|
|
(err.problem + "\n" if err.problem else "") +
|
|
(err.note + "\n" if err.note else ""))
|
|
else:
|
|
docs.append(doc)
|
|
return docs
|
|
|
|
|
|
def get_datatypes(doc):
|
|
""" Get datatypes from YAML doc"""
|
|
dt = ctypes.__dict__.copy()
|
|
for declaration in doc.get('Datatypes') or ():
|
|
for name, decl in declaration.items():
|
|
if isinstance(decl, dict):
|
|
# Create derived class type based on bases and attr entries
|
|
dt[name] = type(name,
|
|
tuple([eval(t, dt)
|
|
for t in decl.get('bases') or ()
|
|
if TYPE_RE.match(t)]
|
|
), decl.get('attr') or {})
|
|
# Import class' attributes into the datatype namespace
|
|
for subtype in decl.get('attr') or {}:
|
|
if TYPE_RE.match(subtype):
|
|
dt[subtype] = eval(name+'.'+subtype, dt)
|
|
elif isinstance(decl, str) and TYPE_RE.match(decl):
|
|
dt[name] = dt[decl]
|
|
else:
|
|
sys.exit("Unrecognized data type "+name+": "+repr(decl))
|
|
return dt
|
|
|
|
|
|
def get_arguments(doc):
|
|
"""The kernel argument list, with argument names and types"""
|
|
return [(var, eval(decl[var], datatypes))
|
|
for decl in doc.get('Arguments') or ()
|
|
if len(decl) == 1
|
|
for var in decl
|
|
if TYPE_RE.match(decl[var])]
|
|
|
|
|
|
def setkey_product(test, key, vals):
|
|
"""Helper for setdefaults. Tests that all values in vals is present
|
|
in test, if so then sets test[key] to product of all test[vals]."""
|
|
if all(x in test for x in vals):
|
|
result = 1
|
|
for x in vals:
|
|
if x in ('incx', 'incy'):
|
|
result *= abs(test[x])
|
|
else:
|
|
result *= test[x]
|
|
test[key] = int(result)
|
|
|
|
|
|
def setdefaults(test):
|
|
"""Set default values for parameters"""
|
|
# Do not put constant defaults here -- use hipblaslt_common.yaml for that.
|
|
# These are only for dynamic defaults
|
|
|
|
if test['transA'] == '*' or test['transB'] == '*':
|
|
test.setdefault('lda', 0)
|
|
test.setdefault('ldb', 0)
|
|
test.setdefault('ldc', 0)
|
|
test.setdefault('ldd', 0)
|
|
test.setdefault('lde', 0)
|
|
elif not test['grouped_gemm']: #catered to gemm default behavior
|
|
M = test['M'][0] if isinstance(test['M'], list) else test['M']
|
|
N = test['N'][0] if isinstance(test['N'], list) else test['N']
|
|
K = test['K'][0] if isinstance(test['K'], list) else test['K']
|
|
test.setdefault('lda', (M if M != 0 else 1) if test['transA'].upper() == 'N'
|
|
else K if K != 0 else 1)
|
|
test.setdefault('ldb', (K if K != 0 else 1) if test['transB'].upper() == 'N'
|
|
else N if N != 0 else 1)
|
|
test.setdefault('ldc', M if M != 0 else 1)
|
|
test.setdefault('ldd', M if M != 0 else 1)
|
|
test.setdefault('lde', M if M != 0 else 1)
|
|
if test['batch_count'] > 0:
|
|
test.setdefault('stride_a', test['lda'] *
|
|
(K if test['transA'].upper() == 'N' else
|
|
M))
|
|
test.setdefault('stride_b', test['ldb'] *
|
|
(N if test['transB'].upper() == 'N' else
|
|
K))
|
|
test.setdefault('stride_c', test['ldc'] * N)
|
|
test.setdefault('stride_d', test['ldd'] * N)
|
|
test.setdefault('stride_e', test['lde'] * N)
|
|
return
|
|
else:
|
|
Ms = test['M']
|
|
Ns = test['N']
|
|
Ks = test['K']
|
|
test.setdefault('lda', [(M if M != 0 else 1) if test['transA'].upper() == 'N'
|
|
else K if K != 0 else 1 for M, K in zip(Ms, Ks)])
|
|
test.setdefault('ldb', [(K if K != 0 else 1) if test['transB'].upper() == 'N'
|
|
else N if N != 0 else 1 for K, N in zip(Ks, Ns)])
|
|
test.setdefault('ldc', [M if M != 0 else 1 for M in Ms])
|
|
test.setdefault('ldd', [M if M != 0 else 1 for M in Ms])
|
|
test.setdefault('lde', [M if M != 0 else 1 for M in Ms])
|
|
|
|
if test['batch_count'] > 0:
|
|
test.setdefault('stride_a', [lda * K if test['transA'].upper() == 'N' else lda * M for K, M, lda in zip(Ks, Ms, test['lda'])])
|
|
test.setdefault('stride_b',
|
|
[N * ldb if test['transB'].upper() == 'N' else
|
|
K * ldb for N, K, ldb in zip(Ns, Ks, test['ldb'])])
|
|
test.setdefault('stride_c', [ldc * N for ldc, N in zip(test['ldc'], Ns)])
|
|
test.setdefault('stride_d', [ldd * N for ldd, N in zip(test['ldd'], Ns)])
|
|
test.setdefault('stride_e', [lde * N for lde, N in zip(test['lde'], Ns)])
|
|
return
|
|
|
|
|
|
test.setdefault('stride_a', 0)
|
|
test.setdefault('stride_b', 0)
|
|
test.setdefault('stride_c', 0)
|
|
test.setdefault('stride_d', 0)
|
|
test.setdefault('stride_e', 0)
|
|
|
|
|
|
def write_signature(out):
|
|
"""Write the signature used to verify binary file compatibility"""
|
|
if 'signature_written' not in args:
|
|
sig = 0
|
|
byt = bytearray("hipBLASLt", 'utf_8')
|
|
byt.append(0)
|
|
last_ofs = 0
|
|
for (name, ctype) in param['Arguments']._fields_:
|
|
member = getattr(param['Arguments'], name)
|
|
for i in range(0, member.offset - last_ofs):
|
|
byt.append(0)
|
|
for i in range(0, member.size):
|
|
byt.append(sig ^ i)
|
|
sig = (sig + 89) % 256
|
|
last_ofs = member.offset + member.size
|
|
for i in range(0, ctypes.sizeof(param['Arguments']) - last_ofs):
|
|
byt.append(0)
|
|
byt.extend(bytes("HIPblaslT", 'utf_8'))
|
|
byt.append(0)
|
|
out.write(byt)
|
|
args['signature_written'] = True
|
|
|
|
def gen_shape_combinations(M: List, N: List, K: List) -> Tuple[List, List, List]:
|
|
"""Generate all shape combinations. This suitable for grouped gemm case."""
|
|
from itertools import product
|
|
|
|
if not isinstance(M, List):
|
|
M = [M,]
|
|
|
|
if not isinstance(N, List):
|
|
N = [N,]
|
|
|
|
if not isinstance(K, List):
|
|
K = [K,]
|
|
|
|
problem_sizes = list(product(M, N, K))
|
|
return tuple(tuple(s[i] for s in problem_sizes) for i in range(len(problem_sizes[0])))
|
|
|
|
def write_test(test):
|
|
"""Write the test case out to the binary file if not seen already"""
|
|
|
|
# For each argument declared in arguments, we generate a positional
|
|
# argument in the Arguments constructor. For strings, we pass the
|
|
# value of the string directly. For arrays, we unpack their contents
|
|
# into the ctype array constructor and pass the ctype array. For
|
|
# scalars, we coerce the string/numeric value into ctype.
|
|
arg = []
|
|
for name, ctype in param['Arguments']._fields_:
|
|
try:
|
|
if issubclass(ctype, ctypes.Array):
|
|
if issubclass(ctype._type_, ctypes.c_char):
|
|
arg.append(bytes(test[name], 'utf_8'))
|
|
else:
|
|
try:
|
|
arg.append(ctype(*test[name]))
|
|
except TypeError:
|
|
arg.append(ctype(test[name]))
|
|
elif issubclass(ctype, ctypes.c_char):
|
|
arg.append(bytes(test[name], 'utf_8'))
|
|
else:
|
|
arg.append(ctype(test[name]))
|
|
except TypeError as err:
|
|
sys.exit("TypeError: " + str(err) + " for " + name +
|
|
", which has type " + str(type(test[name])) + "\n")
|
|
byt = bytes(param['Arguments'](*arg))
|
|
if byt not in testcases:
|
|
testcases.add(byt)
|
|
write_signature(args['outfile'])
|
|
args['outfile'].write(byt)
|
|
|
|
|
|
def instantiate(test):
|
|
"""Instantiate a given test case"""
|
|
test = test.copy()
|
|
|
|
if test['grouped_gemm']:
|
|
if 'matrix_size' in test:
|
|
sizes = test.pop('matrix_size')
|
|
for s in ('M', 'N', 'K'):
|
|
test[s] = tuple(l[s] for l in sizes)
|
|
else:
|
|
M, N, K = gen_shape_combinations(test['M'], test['N'], test['K'])
|
|
test['M'] = M
|
|
test['N'] = N
|
|
test['K'] = K
|
|
|
|
gsu_vector = [-1 for _ in range(32)]
|
|
if 'gsu_vector' in test:
|
|
gsu_vector[0] = test['gsu_vector']
|
|
else:
|
|
gsu_vector[0] = 0
|
|
test['gsu_vector'] = gsu_vector
|
|
|
|
wgm_vector = [-1 for _ in range(32)]
|
|
if 'wgm_vector' in test:
|
|
wgm_vector[0] = test['wgm_vector']
|
|
else:
|
|
wgm_vector[0] = 0
|
|
test['wgm_vector'] = wgm_vector
|
|
|
|
|
|
# Any Arguments fields declared as enums (a_type, b_type, etc.)
|
|
enum_args = [decl[0] for decl in param['Arguments']._fields_
|
|
if decl[1].__module__ == '__main__']
|
|
array_value_args = ["gsu_vector", "wgm_vector"]
|
|
|
|
try:
|
|
setdefaults(test)
|
|
|
|
# For enum arguments, replace name with value
|
|
for typename in enum_args:
|
|
if test[typename] in datatypes:
|
|
test[typename] = datatypes[test[typename]]
|
|
|
|
known_bug_platforms = set()
|
|
|
|
# Match known bugs
|
|
if test['category'] not in ('known_bug'):
|
|
for bug in param['known_bugs']:
|
|
for key, value in bug.items():
|
|
if key == 'known_bug_platforms' or key == 'category':
|
|
continue
|
|
if key not in test:
|
|
break
|
|
if key == 'function':
|
|
if not fnmatchcase(test[key], value):
|
|
break
|
|
# For keys declared as enums, compare resulting values
|
|
if key in enum_args:
|
|
if test[key] != datatypes.get(value, value):
|
|
break
|
|
# For array value type, treat as known bug if empty array was given
|
|
elif key in array_value_args:
|
|
stripped_val = [i for i in test[key] if i >= 0]
|
|
|
|
# default case in test
|
|
if stripped_val == [0,]:
|
|
break
|
|
|
|
if len(value) == 0:
|
|
continue
|
|
else:
|
|
if stripped_val != value:
|
|
break
|
|
elif test[key] != value:
|
|
break
|
|
else:
|
|
# All values specified in known bug match the test case
|
|
platforms = bug.get('known_bug_platforms', '')
|
|
|
|
# If at least one known_bug_platforms is specified, add
|
|
# each platform in platforms to known_bug_platforms set
|
|
if platforms.strip(' :,\f\n\r\t\v'):
|
|
known_bug_platforms |= set(re.split('[ :,\f\n\r\t\v]+',
|
|
platforms))
|
|
else:
|
|
test['category'] = 'known_bug'
|
|
break
|
|
|
|
# Unless category is already set to known_bug or disabled, set
|
|
# known_bug_platforms to a space-separated list of platforms
|
|
test['known_bug_platforms'] = ' ' . join(known_bug_platforms) if test[
|
|
'category'] not in ('known_bug') else ''
|
|
|
|
write_test(test)
|
|
|
|
except KeyError as err:
|
|
sys.exit("Undefined value " + str(err) + "\n" + str(test))
|
|
|
|
|
|
def generate(test, function):
|
|
"""Generate test combinations by iterating across lists recursively"""
|
|
test = test.copy()
|
|
|
|
def should_expand(key):
|
|
grouped_gemm_cond = (test['grouped_gemm'] and key not in ('M', 'N', 'K'))
|
|
normal_cond = type(test[key]) in (tuple, list) and\
|
|
key not in param['lists_to_not_expand'] and\
|
|
key != 'matrix_size'
|
|
|
|
if test['grouped_gemm']:
|
|
return grouped_gemm_cond and normal_cond
|
|
return normal_cond
|
|
|
|
def should_expand_dict_lists(argname):
|
|
normal_cond = argname in test and type(test[argname]) in (tuple, list, dict)
|
|
grouped_gemm_cond = argname != 'matrix_size'
|
|
|
|
if test['grouped_gemm']:
|
|
return normal_cond and grouped_gemm_cond
|
|
return normal_cond
|
|
|
|
# For specially named lists, they are expanded and merged into the test
|
|
# argument list. When the list name is a dictionary of length 1, its pairs
|
|
# indicate that the argument named by its key takes on values paired with
|
|
# the argument named by its value, which is another dictionary list. We
|
|
# process the value dictionaries' keys in alphabetic order, to ensure
|
|
# deterministic test ordering.
|
|
for argname in param['dict_lists_to_expand']:
|
|
if type(argname) == dict:
|
|
if len(argname) == 1:
|
|
arg, target = list(argname.items())[0]
|
|
if arg in test and type(test[arg]) == dict:
|
|
pairs = sorted(list(test[arg].items()), key=lambda x: x[0])
|
|
for test[arg], test[target] in pairs:
|
|
generate(test, function)
|
|
return
|
|
elif should_expand_dict_lists(argname):#argname in test and type(test[argname]) in (tuple, list, dict):
|
|
# Pop the list and iterate across it
|
|
ilist = test.pop(argname)
|
|
|
|
# For a bare dictionary, wrap it in a list and apply it once
|
|
for item in [ilist] if type(ilist) == dict else ilist:
|
|
try:
|
|
case = test.copy()
|
|
case.update(item) # original test merged with each item
|
|
generate(case, function)
|
|
except TypeError as err:
|
|
sys.exit("TypeError: " + str(err) + " for " + argname +
|
|
", which has type " + str(type(item)) +
|
|
"\nA name listed in \"Dictionary lists to "
|
|
"expand\" must be a defined as a dictionary.\n")
|
|
return
|
|
|
|
for key in sorted(list(test)):
|
|
# Integer arguments which are ranges (A..B[..C]) are expanded
|
|
if type(test[key]) == str:
|
|
match = INT_RANGE_RE.match(str(test[key]))
|
|
if match:
|
|
for test[key] in range(int(match.group(1)),
|
|
int(match.group(2))+1,
|
|
int(match.group(3) or 1)):
|
|
generate(test, function)
|
|
return
|
|
|
|
# For sequence arguments, they are expanded into scalars
|
|
elif should_expand(key):
|
|
for test[key] in test[key]:
|
|
generate(test, function)
|
|
return
|
|
|
|
# Replace typed function names with generic functions and types
|
|
if 'hipblaslt_function' in test:
|
|
func = test.pop('hipblaslt_function')
|
|
if func in param['Functions']:
|
|
test.update(param['Functions'][func])
|
|
else:
|
|
test['function'] = func.rpartition('hipblaslt_')[2]
|
|
generate(test, function)
|
|
return
|
|
|
|
function(test)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|