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
438 lines
16 KiB
Python
438 lines
16 KiB
Python
#!/usr/bin/python
|
|
|
|
"""Copyright (C) 2016-2022 Advanced Micro Devices, Inc. All rights reserved.
|
|
|
|
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 cop-
|
|
ies 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 IM-
|
|
PLIED, 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 CONNE-
|
|
CTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
"""
|
|
|
|
import yaml
|
|
import sys
|
|
import os
|
|
import subprocess
|
|
from subprocess import PIPE
|
|
from tempfile import mkdtemp
|
|
from shutil import rmtree
|
|
|
|
#
|
|
minimumVersionIdx = 0
|
|
prefixIdx = 1
|
|
architectureIdx = 2
|
|
deviceNamesIdx = 3
|
|
problemTypeStateIdx = 4
|
|
solutionListIdx = 5
|
|
indexOrderIdx = 6
|
|
exactLogicListIdx = 7 #[[m, n, batch_size, k, ...], [kernelIdx, GFLOPS]]
|
|
mIdx = 0
|
|
nIdx = 1
|
|
batchIdx = 2
|
|
kIdx = 3
|
|
rangeLogicIdx = 8
|
|
tileSelectionLogicIdx = 9 #Only if tile aware selection is enabled
|
|
|
|
helpMessage = """Script for determining which problem sizes in a log file have been pre-tuned for
|
|
by Tensile.
|
|
Usage:
|
|
python3 check-for-pretuned-sizes.py -f logfilePath
|
|
[-c commit] [-a architecture] [-u] [-l] [--help]
|
|
Options:
|
|
-f Log file containing benchmark tests.
|
|
-a Architecture. Matches any problem containing this argument.
|
|
ex: vega10
|
|
-c Specify commit of rocBLAS to check. If unspecified, will use most recent master.
|
|
-l Attempt to detect the installed version of rocBLAS
|
|
(Currently just works when installing from cloned repository)
|
|
-u Compares detected problem sizes to those found in the most recent develop commit.
|
|
--help Displays this message.
|
|
NOTE: Flags cannot currently be combined together as in -lu, they must be specified
|
|
separately in the form -l -u
|
|
"""
|
|
|
|
usageMessage = """Usage:
|
|
python3 check-for-pretuned-sizes.py -f logfilePath
|
|
[-c commit] [-a architecture] [-u] [-l] [--help]"""
|
|
|
|
|
|
def removeChar(text, removedChar):
|
|
return "".join(filter(lambda c : c != removedChar, text))
|
|
|
|
class ParseOptionError(Exception):
|
|
pass
|
|
|
|
#Same usage as getopt but doesn't fail on unknown args and returns dict
|
|
def parseOptions(textList, shortArgs, longArgs=[]):
|
|
hasArg = []
|
|
lastChar = ':'
|
|
optionList = []
|
|
#Set keys for short arguments
|
|
for c in shortArgs:
|
|
#':' indicates c takes an argument
|
|
if c == ':':
|
|
if not lastChar.isalpha():
|
|
raise ParseOptionError("Error: Colon must follow alphabetic character")
|
|
hasArg[-1] = True
|
|
else:
|
|
optionList.append('-' + c)
|
|
hasArg.append(False)
|
|
lastChar = c
|
|
|
|
#Set keys for long arguments
|
|
for s in longArgs:
|
|
#'=' indicates s takes an argument
|
|
if s[-1] == '=':
|
|
hasArg.append(True)
|
|
optionList.append("--" + s[:-1])
|
|
else:
|
|
hasArg.append(False)
|
|
optionList.append("--" + s)
|
|
|
|
hasArg = dict(zip(optionList,
|
|
hasArg))
|
|
|
|
#Extract options from textList
|
|
optionDict = dict([])
|
|
needsArg = None
|
|
for item in textList:
|
|
#If this is an argument of a previous option...
|
|
if needsArg != None:
|
|
#Store associated with it
|
|
optionDict[needsArg] = item
|
|
needsArg = None
|
|
#Otherwise check if it's a valid option
|
|
elif item in optionList:
|
|
optionDict[item] = None #Set as none for now
|
|
if hasArg[item]:
|
|
needsArg = item #Set to capture next item
|
|
|
|
return dict(zip(
|
|
list(map(lambda s : removeChar(s, '-'), optionDict.keys())),
|
|
optionDict.values()))
|
|
|
|
#assumes b has at least as many periods as a
|
|
def isVersionGreaterThanOrEqual(versionA, versionB):
|
|
for a, b in zip(versionA.split('.'), versionB.split('.')):
|
|
if int(a) != int(b):
|
|
return int(a) > int(b)
|
|
return True #Is equal
|
|
|
|
|
|
def shellCmd(command):
|
|
spReturn = subprocess.run(command, shell=True, stdout=PIPE, stderr=PIPE)
|
|
return spReturn.stdout.decode('utf-8').rstrip('\n')
|
|
|
|
|
|
def getInstalledRocBLASCommitHash():
|
|
versionString = shellCmd("dpkg -s rocblas | grep Version") #Format "Version X.XX.X.XXXX-CommitHash"
|
|
spaceSplit = versionString.split()
|
|
if len(spaceSplit) > 1:
|
|
dashSplit = spaceSplit[1].split('-')
|
|
if len(dashSplit) > 1:
|
|
return dashSplit[1]
|
|
else:
|
|
print("Error: No commit hash found in \"dpkg -s rocblas | grep Version\" command")
|
|
return ""
|
|
else:
|
|
print("Error: Could not parse output from \"dpkg -s rocblas | grep Version\" command")
|
|
return ""
|
|
|
|
|
|
def cloneRepository(destinationPath):
|
|
print("Cloning repository...")
|
|
shellCmd("git clone https://github.com/ROCm/rocBLAS.git %s" % destinationPath)
|
|
|
|
def checkoutSpecifiedCommit(destinationPath, commit):
|
|
originalPath = shellCmd("pwd").rstrip('\n')
|
|
os.chdir(destinationPath)
|
|
shellCmd("git checkout %s" % commit)
|
|
os.chdir(originalPath)
|
|
|
|
def checkoutInstalledBranch(destinationPath):
|
|
rocBLASCommitHash = getInstalledRocBLASCommitHash()
|
|
checkoutSpecifiedCommit(destinationPath, rocBLASCommitHash)
|
|
|
|
def checkoutMostRecentBranch(destinationPath, branchname):
|
|
originalPath = shellCmd("pwd").rstrip('\n')
|
|
os.chdir(destinationPath)
|
|
shellCmd("git checkout %s" % branchname)
|
|
os.chdir(originalPath)
|
|
|
|
def convertToExplicitType(t):
|
|
typeMap = {
|
|
'h': 'f16_r',
|
|
's': 'f32_r',
|
|
'd': 'f64_r',
|
|
'c': 'f32_r',
|
|
'z': 'f64_r'}
|
|
if t in typeMap:
|
|
return typeMap[t]
|
|
else:
|
|
return t
|
|
|
|
def convertArgumentTypesToKernelIdentifier(aType, bType, cType, dType, computeType):
|
|
aType = convertToExplicitType(aType)
|
|
bType = convertToExplicitType(bType)
|
|
cType = convertToExplicitType(cType)
|
|
dType = convertToExplicitType(dType)
|
|
computeType = convertToExplicitType(computeType)
|
|
|
|
argumentsToRocblasType = {
|
|
('f16_r', 'f16_r', 'f16_r', 'f16_r', 'f16_r') : 'half_precision',
|
|
('f16_r', 'f16_r', 'f16_r', 'f16_r', 'f32_r') : 'hpa_half_precision',
|
|
('f32_r', 'f32_r', 'f32_r', 'f32_r', 'f32_r') : 'single_precision',
|
|
('f64_r', 'f64_r', 'f64_r', 'f64_r', 'f64_r') : 'double_precision',
|
|
('i8_r', 'i8_r', 'i8_r', 'i8_r', 'i32_r') : 'int8_precision',
|
|
('bf16_r', 'bf16_r', 'bf16_r', 'bf16_r', 'bf16_r'): 'bf16_precision',
|
|
('bf16_r', 'bf16_r', 'bf16_r', 'bf16_r', 'f32_r') : 'hpa_bf16_precision',
|
|
('f16_c', 'f16_c', 'f16_c', 'f16_c', 'f16_c') : 'half_precision_complex',
|
|
('f16_c', 'f16_c', 'f16_c', 'f16_c', 'f32_c') : 'hpa_half_precision_complex',
|
|
('f32_c', 'f32_c', 'f32_c', 'f32_c', 'f32_c') : 'single_precision_complex',
|
|
('f64_c', 'f64_c', 'f64_c', 'f64_c', 'f64_c') : 'double_precision_complex',
|
|
('i8_c', 'i8_c', 'i8_c', 'i8_c', 'i32_c') : 'int8_precision_complex',
|
|
('bf16_c', 'bf16_c', 'bf16_c', 'bf16_c', 'bf16_c'): 'bf16_precision_complex',
|
|
('bf16_c', 'bf16_c', 'bf16_c', 'bf16_c', 'f32_c') : 'hpa_bf16_precision_complex'}
|
|
rocblasTypeToKernelIdentifier = {
|
|
'half_precision' : 'HB.',
|
|
'hpa_half_precision' : 'HBH.',
|
|
'single_precision' : 'SB.',
|
|
'double_precision' : 'DB.',
|
|
'int8_precision' : '4xi8BH.',
|
|
'bf16_precision' : 'BB.',
|
|
'hpa_bf16_precision' : 'BBH.',
|
|
'single_precision_complex': 'CB.',
|
|
'double_precision_complex': 'ZB.'}
|
|
|
|
try:
|
|
rocblasType = argumentsToRocblasType[(aType, bType, cType, dType, computeType)]
|
|
kernelIdentifier = rocblasTypeToKernelIdentifier[rocblasType]
|
|
except KeyError:
|
|
print("Error: Unrecognized argument type combination (a_type %s b_type %s c_type %s d_type %s compute_type %s)" %(aType, bType, cType, dType, computeType))
|
|
return 'NOT VALID'
|
|
return kernelIdentifier
|
|
#Comes from the roblas_common.yaml file
|
|
|
|
#Gets one of the first or second keys provided
|
|
def getOne(d, key1, key2):
|
|
if key1 in d:
|
|
return d[key1]
|
|
else:
|
|
return d[key2]
|
|
|
|
def supportedProblemType(problemType):
|
|
return 'gemm' in problemType
|
|
|
|
|
|
#Bind as member variable to dict
|
|
|
|
class ProblemDescription:
|
|
def __init__(self, benchmarkText):
|
|
self.m = 1
|
|
self.n = 1
|
|
self.k = 1
|
|
self.batch_count = 1
|
|
|
|
try:
|
|
optDict= parseOptions(
|
|
benchmarkText.split(),
|
|
"m:n:k:f:r:",
|
|
[
|
|
"batch_count=", "transposeA=", "transposeB=", \
|
|
"a_type=", "b_type=", "c_type=", "d_type=", "compute_type=",\
|
|
"precision=", "sizem=", "sizen=", "sizek="\
|
|
]
|
|
)
|
|
self.gemmType = getOne(optDict, 'f','function')
|
|
if not supportedProblemType(self.gemmType):
|
|
return
|
|
self.m = int(getOne(optDict, 'm', 'sizem'))
|
|
self.n = int(getOne(optDict, 'n', 'sizen'))
|
|
self.k = int(getOne(optDict, 'k', 'sizek'))
|
|
transposeA = optDict['transposeA'] == 'T'
|
|
transposeB = optDict['transposeB'] == 'T'
|
|
if 'ex' in self.gemmType:
|
|
aType = optDict['a_type']
|
|
bType = optDict['b_type']
|
|
cType = optDict['c_type']
|
|
dType = optDict['d_type']
|
|
computeType = optDict['compute_type']
|
|
else:
|
|
aType =\
|
|
bType =\
|
|
cType =\
|
|
dType =\
|
|
computeType = getOne(optDict, 'r', 'precision')
|
|
self.kernel_flags = convertArgumentTypesToKernelIdentifier(
|
|
aType, bType, cType, dType, computeType)
|
|
|
|
except ValueError:
|
|
print("Error: Problem description parameters have invalid type")
|
|
except ParseOptionError:
|
|
print("Error: Input arguments ill formed")
|
|
|
|
if 'batch_count' in optDict:
|
|
self.batch_count = int(optDict['batch_count'])
|
|
|
|
self.matrix_A = 'Alik' if transposeA else 'Ailk'
|
|
self.matrix_B = 'Bjlk' if transposeB else 'Bljk'
|
|
|
|
def __str__(self):
|
|
return "(m=%d n=%d k=%d batch_count=%d transpose_A=%r transpose_B=%r kernel_flags=%s)" \
|
|
% (self.m, self.n, self.k, self.batch_count, self.matrix_A == 'Alik', self.matrix_B == 'Bjlk', self.kernel_flags)
|
|
|
|
def loadBenchmarkDescriptions(logfilePath):
|
|
try:
|
|
f = open(logfilePath)
|
|
except OSError:
|
|
print("%s file not found." % logfilePath)
|
|
return []
|
|
|
|
lines = f.read().split('\n')
|
|
benchmarkList = []
|
|
|
|
for line in lines:
|
|
pieces = line.split(maxsplit=1)
|
|
if pieces and "rocblas-bench" in pieces[0]:
|
|
try:
|
|
problem = ProblemDescription(line)
|
|
except KeyError:
|
|
raise KeyError(line)
|
|
if supportedProblemType(problem.gemmType):
|
|
benchmarkList.append(problem)
|
|
return benchmarkList
|
|
|
|
|
|
def matchBetween(matrixFormSet, filename):
|
|
for matrixForm in matrixFormSet:
|
|
if matrixForm[0] in filename and matrixForm[1] in filename and matrixForm[2] in filename:
|
|
return True
|
|
return False
|
|
|
|
#Search through library logic files in directory to find a matching kernel
|
|
def findMatchingKernel(benchDescriptions, architecture, directoryPath):
|
|
#Whether a benchmark description has found a match
|
|
print("Searching %s for logic files..." % directoryPath)
|
|
foundMatch = [False for x in range(len(benchDescriptions))]
|
|
|
|
problemSet = set()
|
|
for bench in benchDescriptions:
|
|
problemSet.add((bench.matrix_A, bench.matrix_B, bench.kernel_flags))
|
|
|
|
#Filter files by problem types in benchmarks
|
|
fileList = []
|
|
for filename in os.listdir(directoryPath):
|
|
if filename.endswith(".yaml") \
|
|
and architecture in filename \
|
|
and matchBetween(problemSet, filename):
|
|
fileList.append(filename)
|
|
|
|
success = False
|
|
#Find a kernel with a matching problem size in the file list
|
|
for filename in fileList:
|
|
foundMatchingKernel = False
|
|
f = open(directoryPath + filename, 'r')
|
|
if f.closed:
|
|
sys.exit("File %s could not be opened" % directoryPath + filename)
|
|
libraryLogic = yaml.safe_load(f)
|
|
f.close()
|
|
logicList = libraryLogic[exactLogicListIdx]
|
|
for i in range(len(benchDescriptions)):
|
|
bench = benchDescriptions[i]
|
|
if bench.matrix_A in filename and bench.matrix_B in filename and bench.kernel_flags in filename:
|
|
#Iterate through kernels to find one with matching size
|
|
for [problemInfo, winningKernelInfo] in logicList:
|
|
foundMatchingKernel = \
|
|
problemInfo[mIdx] == bench.m and \
|
|
problemInfo[nIdx] == bench.n and \
|
|
problemInfo[kIdx] == bench.k and \
|
|
problemInfo[batchIdx] == bench.batch_count
|
|
if foundMatchingKernel: break
|
|
|
|
if foundMatchingKernel:
|
|
print("Match found for %s in file %s" % \
|
|
( bench, filename))
|
|
foundMatch[i] = True
|
|
return foundMatch
|
|
|
|
def findBenchmarkInFile(problemDescriptions):
|
|
pass
|
|
|
|
|
|
def main(argv):
|
|
try:
|
|
optdict = parseOptions(argv, "f:a:c:ul", ["help"])
|
|
if 'help' in optdict.keys():
|
|
print(helpMessage)
|
|
sys.exit()
|
|
except KeyError:
|
|
sys.exit(usageMessage)
|
|
except ParseOptionError:
|
|
sys.exit(usageMessage)
|
|
|
|
logpath = ""
|
|
if 'f' in optdict:
|
|
logpath = optdict['f']
|
|
else:
|
|
sys.exit(usageMessage)
|
|
architecture = ""
|
|
if 'a' in optdict:
|
|
architecture = optdict['a']
|
|
|
|
directoryPath = mkdtemp() #"./rocBLASTemp" #Default path
|
|
libraryPathExtension="/library/src/blas3/Tensile/Logic/asm_full/"
|
|
print("Created temporary directory %s" % directoryPath)
|
|
cloneRepository(directoryPath)
|
|
|
|
#Benchmarked problem sizes in log file
|
|
benchDescriptions = loadBenchmarkDescriptions(logpath)
|
|
print("\
|
|
-------------------------------------------------------------\n\
|
|
-- Finding pre-tuned sizes in specified version of rocblas --\n\
|
|
-------------------------------------------------------------")
|
|
if not ('c' in optdict or 'l' in optdict):
|
|
checkoutMostRecentBranch(directoryPath, "master")
|
|
else:
|
|
specifiedCommitHash = optdict['c'] if 'c' in optdict \
|
|
else getInstalledRocBLASCommitHash()
|
|
checkoutSpecifiedCommit(directoryPath, specifiedCommitHash)
|
|
localMatches = findMatchingKernel(
|
|
benchDescriptions,
|
|
architecture,
|
|
directoryPath+libraryPathExtension)
|
|
|
|
if 'u' in optdict:
|
|
print("\
|
|
---------------------------------------------------------------\n\
|
|
-- Finding pre-tuned sizes in most recent version of rocblas --\n\
|
|
---------------------------------------------------------------")
|
|
checkoutMostRecentBranch(directoryPath, "develop")
|
|
recentMatches = findMatchingKernel(
|
|
benchDescriptions,
|
|
architecture,
|
|
directoryPath+libraryPathExtension)
|
|
|
|
print("\nMatches in most recent version of rocBLAS but not specified version:")
|
|
for i in range(len(benchDescriptions)):
|
|
if recentMatches[i] and not localMatches[i]:
|
|
print("\t%s" % benchDescriptions[i])
|
|
|
|
|
|
#Remove temporary directory only if it wasn't provided by user
|
|
print("Removing temporary directory")
|
|
rmtree(directoryPath) #shellCmd("rm -rf %s" % directoryPath)
|
|
|
|
if __name__=="__main__":
|
|
main(sys.argv[1:])
|