Files
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

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)