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
467 lines
16 KiB
Python
467 lines
16 KiB
Python
################################################################################
|
|
#
|
|
# Copyright (C) 2016-2024 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
|
|
# 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.
|
|
#
|
|
################################################################################
|
|
|
|
from .Common import architectureMap, gfxArch, printExit, printWarning, versionIsCompatible
|
|
from .SolutionStructs import Solution, ProblemSizes, ProblemType
|
|
from . import __version__
|
|
from . import SolutionLibrary
|
|
from .Utilities.ConditionalImports import yamlLoader, yamlDumper
|
|
|
|
from typing import NamedTuple, Optional
|
|
|
|
import os
|
|
|
|
try:
|
|
import yaml
|
|
except ImportError:
|
|
printExit(
|
|
"You must install PyYAML to use Tensile (to parse config files). See http://pyyaml.org/wiki/PyYAML for installation instructions."
|
|
)
|
|
|
|
try:
|
|
import msgpack
|
|
except ImportError:
|
|
print("Message pack python library not detected. Must use YAML backend instead.")
|
|
|
|
|
|
def updateProblemDatatypes(problemType):
|
|
problemType["DataType"] = problemType["DataType"].value
|
|
problemType["DestDataType"] = problemType["DestDataType"].value
|
|
problemType["ComputeDataType"] = problemType["ComputeDataType"].value
|
|
problemType["F32XdlMathOp"] = problemType["F32XdlMathOp"].value
|
|
|
|
|
|
###################
|
|
# Writing functions
|
|
###################
|
|
def write(filename_noExt, data, format="yaml"):
|
|
"""Writes data to file with specified format; extension is appended based on format."""
|
|
if format == "yaml":
|
|
writeYAML(filename_noExt + ".yaml", data)
|
|
elif format == "msgpack":
|
|
writeMsgPack(filename_noExt + ".dat", data)
|
|
else:
|
|
printExit("Unrecognized format {}".format(format))
|
|
|
|
|
|
def writeYAML(filename, data, **kwargs):
|
|
"""Writes data to file in YAML format."""
|
|
# set default kwags for yaml dump
|
|
if "explicit_start" not in kwargs:
|
|
kwargs["explicit_start"] = True
|
|
if "explicit_end" not in kwargs:
|
|
kwargs["explicit_end"] = True
|
|
if "default_flow_style" not in kwargs:
|
|
kwargs["default_flow_style"] = None
|
|
|
|
with open(filename, "w") as f:
|
|
yaml.dump(data, f, yamlDumper, **kwargs)
|
|
|
|
|
|
def writeMsgPack(filename, data):
|
|
"""Writes data to file in Message Pack format."""
|
|
with open(filename, "wb") as f:
|
|
msgpack.pack(data, f)
|
|
|
|
|
|
def writeSolutions(filename, problemSizes, solutions, cache=False):
|
|
"""Writes solution YAML file."""
|
|
|
|
# convert objects to nested dictionaries
|
|
solutionStates = []
|
|
|
|
if cache:
|
|
solYaml = readYAML(filename)
|
|
solutionStates = solYaml[2:]
|
|
else:
|
|
for solution in solutions:
|
|
solutionState = solution.getAttributes()
|
|
solutionState["ProblemType"] = solutionState["ProblemType"].state
|
|
updateProblemDatatypes(solutionState["ProblemType"])
|
|
solutionStates.append(solutionState)
|
|
# write dictionaries
|
|
with open(filename, "w") as f:
|
|
f.write("- MinimumRequiredVersion: {}\n".format(__version__))
|
|
f.write("- ProblemSizes:\n")
|
|
if problemSizes:
|
|
for sizeRange in problemSizes.ranges:
|
|
f.write(" - Range: {}\n".format(sizeRange))
|
|
for problemExact in problemSizes.exacts:
|
|
#FIXME-problem, this ignores strides:
|
|
f.write(" - Exact: {}\n".format(problemExact))
|
|
|
|
yaml.dump(solutionStates, f, yamlDumper, default_flow_style=None)
|
|
|
|
|
|
###############################
|
|
# Reading and parsing functions
|
|
###############################
|
|
def readYAML(filename):
|
|
"""Reads and returns YAML data from file."""
|
|
with open(filename, "r") as f:
|
|
data = yaml.load(f, yamlLoader)
|
|
return data
|
|
|
|
|
|
def parseSolutionsFile(filename):
|
|
"""Wrapper function to read and parse a solutions file."""
|
|
return parseSolutionsData(readYAML(filename), filename)
|
|
|
|
|
|
def parseSolutionsData(data, srcFile="?"):
|
|
"""Parses problem sizes and solutions from the data of a solutions file."""
|
|
if len(data) < 3:
|
|
printExit("Solution file {} is missing required fields (len = {} < 3" \
|
|
.format(srcFile, len(data)))
|
|
|
|
versionString = data[0]["MinimumRequiredVersion"]
|
|
if not versionIsCompatible(versionString):
|
|
printWarning("Version = {} in solution file {} does not match Tensile version = {}" \
|
|
.format(srcFile, versionString, __version__) )
|
|
|
|
if "ProblemSizes" not in data[1]:
|
|
printExit("Solution file {} doesn't begin with ProblemSizes".format(srcFile))
|
|
|
|
problemSizesConfig = data[1]["ProblemSizes"]
|
|
|
|
solutions = []
|
|
for i in range(2, len(data)):
|
|
solutionState = data[i]
|
|
# force redo the deriving of parameters, make sure old version logic yamls can be validated
|
|
solutionState["AssignedProblemIndependentDerivedParameters"] = False
|
|
solutionState["AssignedDerivedParameters"] = False
|
|
solutionObject = Solution(solutionState)
|
|
solutions.append(solutionObject)
|
|
problemType = solutions[0]["ProblemType"]
|
|
problemSizes = ProblemSizes(problemType, problemSizesConfig)
|
|
return (problemSizes, solutions)
|
|
|
|
|
|
class LibraryLogic(NamedTuple):
|
|
"""Return tuple for parseLibraryLogicData()"""
|
|
schedule: str
|
|
architecture: str
|
|
problemType: ProblemType
|
|
solutions: list
|
|
exactLogic: list
|
|
library: SolutionLibrary.MasterSolutionLibrary
|
|
|
|
|
|
def parseLibraryLogicFile(filename):
|
|
"""Wrapper function to read and parse a library logic file."""
|
|
return parseLibraryLogicData(readYAML(filename), filename)
|
|
|
|
|
|
def parseLibraryLogicData(data, srcFile="?"):
|
|
"""Parses the data of a library logic file."""
|
|
if type(data) is list:
|
|
data = parseLibraryLogicList(data, srcFile)
|
|
|
|
if "CUCount" not in data:
|
|
data["CUCount"] = None
|
|
|
|
if "IsAPU" not in data:
|
|
data["IsAPU"] = None
|
|
|
|
if "Fp16AltImpl" not in data:
|
|
data["Fp16AltImpl"] = False
|
|
|
|
if "Fp16AltImplRound" not in data:
|
|
data["Fp16AltImplRound"] = False
|
|
|
|
if "ArchitectureName" not in data:
|
|
raise ValueError("'ArchitectureName' not found in logic file data" \
|
|
f" Review the library logic file {srcFile}.")
|
|
elif data["ArchitectureName"] not in architectureMap:
|
|
raise ValueError(f"{data['ArchitectureName']} is not a supported architecture." \
|
|
f" Review the library logic file {srcFile}.")
|
|
|
|
if not versionIsCompatible(data["MinimumRequiredVersion"]):
|
|
printWarning("Version = {} in library logic file {} does not match Tensile version = {}" \
|
|
.format(srcFile, data["MinimumRequiredVersion"], __version__) )
|
|
|
|
# unpack problemType
|
|
problemType = ProblemType(data["ProblemType"])
|
|
# unpack solutions
|
|
solutions = []
|
|
for solutionState in data["Solutions"]:
|
|
if solutionState["ProblemType"] == "derive":
|
|
solutionState["ProblemType"] = problemType
|
|
if solutionState["KernelLanguage"] == "Assembly":
|
|
# Set solution ISA based on the top-level gfx architecture in the library logic file
|
|
solutionState["ISA"] = gfxArch(data["ArchitectureName"])
|
|
else:
|
|
solutionState["ISA"] = (0, 0, 0)
|
|
# force redo the deriving of parameters, make sure old version logic yamls can be validated
|
|
solutionState["AssignedProblemIndependentDerivedParameters"] = False
|
|
solutionState["AssignedDerivedParameters"] = False
|
|
solutionObject = Solution(solutionState)
|
|
|
|
if solutionObject["ProblemType"] != problemType:
|
|
printExit("ProblemType in library logic file {} doesn't match solution: {} != {}" \
|
|
.format(srcFile, problemType, solutionObject["ProblemType"]))
|
|
solutions.append(solutionObject)
|
|
|
|
newLibrary = SolutionLibrary.MasterSolutionLibrary.FromOriginalState(data, solutions)
|
|
|
|
return LibraryLogic(data["ScheduleName"], data["ArchitectureName"], problemType, solutions, \
|
|
data.get("ExactLogic"), newLibrary)
|
|
|
|
|
|
def parseLibraryLogicList(data, srcFile="?"):
|
|
"""Parses the data of a matching table style library logic file."""
|
|
if len(data) < 9:
|
|
printExit("Library logic file {} is missing required fields (len = {} < 9)" \
|
|
.format(srcFile, len(data)))
|
|
|
|
rv = {}
|
|
rv["MinimumRequiredVersion"] = data[0]["MinimumRequiredVersion"]
|
|
rv["ScheduleName"] = data[1]
|
|
rv["DeviceNames"] = data[3]
|
|
rv["ProblemType"] = data[4]
|
|
rv["Solutions"] = data[5]
|
|
|
|
if type(data[2]) is dict:
|
|
rv["ArchitectureName"] = data[2]["Architecture"]
|
|
if "CUCount" in data[2]:
|
|
rv["CUCount"] = data[2]["CUCount"]
|
|
if "IsAPU" in data[2]:
|
|
rv["IsAPU"] = data[2]["IsAPU"]
|
|
else:
|
|
rv["ArchitectureName"] = data[2]
|
|
rv["CUCount"] = None
|
|
rv["IsAPU"] = None
|
|
|
|
if architectureMap[rv["ArchitectureName"]] != rv["ScheduleName"]:
|
|
raise ValueError(f"Architecture mismatch: {rv['ArchitectureName']} does not match " \
|
|
f" {rv['ScheduleName']}. Review the library logic file {srcFile}.")
|
|
|
|
rv["ExactLogic"] = data[7]
|
|
# data[8] previously contained range logic, which has been retired
|
|
|
|
# optional fields
|
|
if len(data) > 10 and data[10]:
|
|
rv["PerfMetric"] = data[10]
|
|
|
|
if len(data) > 11 and data[11] == "Fp16AltImpl":
|
|
rv["Fp16AltImpl"] = True
|
|
|
|
if len(data) > 13 and data[13] == "Fp16AltImplRound":
|
|
rv["Fp16AltImplRound"] = True
|
|
|
|
# library logic fields
|
|
rv["LibraryType"] = "Matching"
|
|
rv["Library"] = {}
|
|
rv["Library"]["indexOrder"] = data[6]
|
|
rv["Library"]["table"] = data[7]
|
|
rv["Library"]["distance"] = "Euclidean"
|
|
if len(data) > 12 and data[12]:
|
|
rv["Library"]["distance"] = data[12]
|
|
|
|
return rv
|
|
|
|
|
|
def rawLibraryLogic(data):
|
|
"""Returns a tuple of the data in a library logic file."""
|
|
versionString = data[0]
|
|
scheduleName = data[1]
|
|
architectureName = data[2]
|
|
deviceNames = data[3]
|
|
problemTypeState = data[4]
|
|
solutionStates = data[5]
|
|
indexOrder = data[6]
|
|
exactLogic = data[7]
|
|
rangeLogic = data[8]
|
|
otherFields = []
|
|
|
|
dataLength = len(data)
|
|
if dataLength > 9:
|
|
for idx in range(9, dataLength):
|
|
otherFields.append(data[idx])
|
|
|
|
return (versionString, scheduleName, architectureName, deviceNames,\
|
|
problemTypeState, solutionStates, indexOrder, exactLogic, rangeLogic, otherFields)
|
|
|
|
|
|
########################
|
|
# Library logic creation
|
|
########################
|
|
def createLibraryLogic(schedulePrefix, architectureName, deviceNames, logicTuple, dictFormat):
|
|
if not dictFormat:
|
|
return createLibraryLogicList(schedulePrefix, architectureName, deviceNames, logicTuple)
|
|
|
|
rv = {}
|
|
rv["MinimumRequiredVersion"] = __version__
|
|
rv["ScheduleName"] = schedulePrefix
|
|
rv["DeviceNames"] = deviceNames
|
|
rawProblemType = logicTuple[0]
|
|
rawSolutions = logicTuple[1]
|
|
|
|
# architecture
|
|
if type(architectureName) is dict:
|
|
rv["ArchitectureName"] = architectureName["Architecture"]
|
|
if "CUCount" in architectureName:
|
|
rv["CUCount"] = architectureName["CUCount"]
|
|
if "IsAPU" in architectureName:
|
|
rv["IsAPU"] = architectureName["IsAPU"]
|
|
else:
|
|
rv["ArchitectureName"] = architectureName
|
|
|
|
# problem type
|
|
problemTypeState = rawProblemType.state
|
|
updateProblemDatatypes(problemTypeState)
|
|
rv["ProblemType"] = problemTypeState
|
|
|
|
# solutions
|
|
solutionList = []
|
|
for solution in rawSolutions:
|
|
solutionState = solution.getAttributes()
|
|
solutionState["ProblemType"] = "derive"
|
|
solutionList.append(solutionState)
|
|
|
|
rv["Solutions"] = solutionList
|
|
|
|
# library logic
|
|
exactLogic = logicTuple[3]
|
|
exactLogicList = []
|
|
for key in exactLogic:
|
|
exactLogicList.append([list(key), exactLogic[key]])
|
|
|
|
rv["LibraryType"] = "Matching"
|
|
rv["Library"] = {}
|
|
rv["Library"]["indexOrder"] = logicTuple[2]
|
|
rv["Library"]["table"] = exactLogicList
|
|
rv["Library"]["distance"] = "Euclidean"
|
|
rv["PerfMetric"] = logicTuple[7]
|
|
|
|
return rv
|
|
|
|
|
|
def createLibraryLogicList(schedulePrefix, architectureName, deviceNames, logicTuple):
|
|
"""Creates the data for a library logic file suitable for writing to YAML."""
|
|
problemType = logicTuple[0]
|
|
solutions = logicTuple[1]
|
|
indexOrder = logicTuple[2]
|
|
exactLogic = logicTuple[3]
|
|
rangeLogic = logicTuple[4]
|
|
|
|
tileSelection = False
|
|
if len(logicTuple) > 5 and logicTuple[5]:
|
|
tileSelection = True
|
|
|
|
data = []
|
|
# Tensile version
|
|
data.append({"MinimumRequiredVersion": __version__})
|
|
# schedule name
|
|
data.append(schedulePrefix) # change from Tensile to vega10
|
|
data.append(architectureName)
|
|
# schedule device names
|
|
data.append(deviceNames)
|
|
|
|
# problem type
|
|
problemTypeState = problemType.state
|
|
updateProblemDatatypes(problemTypeState)
|
|
data.append(problemTypeState)
|
|
|
|
# solutions
|
|
solutionList = []
|
|
for solution in solutions:
|
|
solutionState = solution.getAttributes()
|
|
solutionState["ProblemType"] = solutionState["ProblemType"].state
|
|
updateProblemDatatypes(solutionState["ProblemType"])
|
|
solutionList.append(solutionState)
|
|
|
|
if tileSelection:
|
|
tileSolutions = logicTuple[5]
|
|
for solution in tileSolutions:
|
|
solutionState = solution.getAttributes()
|
|
solutionState["ProblemType"] = solutionState["ProblemType"].state
|
|
updateProblemDatatypes(solutionState["ProblemType"])
|
|
solutionList.append(solutionState)
|
|
|
|
data.append(solutionList)
|
|
# index order
|
|
data.append(indexOrder)
|
|
|
|
# exactLogic
|
|
exactLogicList = []
|
|
for key in exactLogic:
|
|
exactLogicList.append([list(key), exactLogic[key]])
|
|
data.append(exactLogicList)
|
|
|
|
# rangeLogic
|
|
data.append(rangeLogic)
|
|
|
|
if tileSelection:
|
|
tileSelectionLogic = {}
|
|
tileSelectionIndices = logicTuple[6]
|
|
tileSelectionLogic["TileSelectionIndices"] = tileSelectionIndices
|
|
data.append(tileSelectionLogic)
|
|
else:
|
|
data.append(None)
|
|
|
|
data.append(logicTuple[7])
|
|
return data
|
|
|
|
|
|
def initAsmCapsCache(cacheFile: str) -> Optional[dict]:
|
|
"""
|
|
If requested and exists, reads an assembler capabilities cache from disk.
|
|
|
|
Arguments:
|
|
cacheFile: Cache file (YAML format).
|
|
|
|
Returns:
|
|
newcache: If cachFile is empty, None. Otherwise, if file exists, a dictionary containing
|
|
capabilities cache; if not, an empty dict
|
|
"""
|
|
# if cacheFile str is empty, do not use cache
|
|
if not cacheFile:
|
|
return None
|
|
|
|
cacheExists = os.path.exists(cacheFile)
|
|
if not cacheExists:
|
|
return {}
|
|
|
|
cache = readYAML(cacheFile)
|
|
|
|
# gaurd against inconsistent state
|
|
if not cache:
|
|
return None
|
|
|
|
toTuple = lambda s: tuple(int(i.strip()) for i in s.split(","))
|
|
newcache = {toTuple(k): v for k,v in cache.items()}
|
|
return newcache
|
|
|
|
def writeAsmCapsCache(cacheFile: str, data: dict):
|
|
"""
|
|
Writes an asm cache to disk.
|
|
|
|
Arguments:
|
|
cacheFile: User spedified file to write the cache.
|
|
data: dict containg the computed cache.
|
|
"""
|
|
newdata = {", ".join(map(str, k)): v for k, v in data.items()}
|
|
writeYAML(cacheFile, newdata)
|