Files
TheRock/rocm-libraries/projects/hipblaslt/tensilelite/Tensile/TensileLibLogicToYaml.py
T
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

473 lines
15 KiB
Python

################################################################################
#
# Copyright (C) 2022-2026 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 Tensile import __version__
from Tensile import LibraryIO
from Tensile.Common.GlobalParameters import defaultBenchmarkCommonParameters
from Tensile.Common.Constants import HR
from Tensile.SolutionStructs.Problem import _defaultProblemType as defaultProblemType
from Tensile.Common.GlobalParameters import globalParameters
import argparse
import os
import sys
import re
import yaml
from typing import Optional, Tuple
class Quoted(str):
pass
# print ""
def quotedPresenter(dumper, data):
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style='"')
class FlowList(list):
pass
def makeFlow(value):
if isinstance(value, list):
return FlowList(value)
return value
# print list in format of []
def flowSeq(dumper, value):
return dumper.represent_sequence("tag:yaml.org,2002:seq", value, flow_style=True)
# ignore null
def representNone(self, _):
return self.represent_scalar("tag:yaml.org,2002:null", "")
yaml.add_representer(Quoted, quotedPresenter)
yaml.add_representer(FlowList, flowSeq)
yaml.add_representer(type(None), representNone)
def tPrint(verbosity: int, arg) -> None:
"""Conditionally prints input to stdout.
If the global print level is greater than or equal to the verbosity,
the argument is printed to stdout.
Args:
verbosity: Level to use for printing arg.
arg: Item to print to stdout.
"""
if globalParameters["ClientLogLevel"] >= verbosity:
print(arg)
sys.stdout.flush()
def setGlobalParams(versionString: dict, problemTypeState: dict) -> dict:
res = {}
res["MinimumRequiredVersion"] = versionString["MinimumRequiredVersion"]
res["SleepPercent"] = 0
res["KernelTime"] = True
res["NumElementsToValidate"] = 0
res["DataInitTypeBeta"] = 1
res["DataInitTypeAlpha"] = 1
res["DataInitTypeA"] = 12 if problemTypeState["DataType"] != "I8" else 3
res["DataInitTypeB"] = 13 if problemTypeState["DataType"] != "I8" else 3
res["DataInitTypeC"] = 12 if problemTypeState["DataType"] != "I8" else 3
res["DataInitTypeD"] = 12 if problemTypeState["DataType"] != "I8" else 3
res["PreciseKernelTime"] = False
res["Device"] = 0
res["SkipSlowSolutionRatio"] = 0.0
res["KeepBuildTmp"] = False
return res
def formProblemTypeYamlData(problemTypeState: dict) -> dict:
if len(problemTypeState) == 0:
raise RuntimeError(
"Length of problem Type Parameters is empty!!, Please re-check the library logic file !"
)
data = {}
data["OperationType"] = problemTypeState["OperationType"]
for problemTypeKey, problemTypeValue in problemTypeState.items():
# Always print HighPrecisionAccumulate, TransposeA, TransposeB fields
if problemTypeKey in [
"DataType",
"DestDataType",
"ComputeDataType",
"HighPrecisionAccumulate",
"TransposeA",
"TransposeB",
]:
data[problemTypeKey] = problemTypeValue
continue
# Print default keys with no default values
if problemTypeKey in defaultProblemType:
if problemTypeValue != defaultProblemType[problemTypeKey]:
# Shipped library-logic encodes some bool fields (e.g.
# Activation) as int 0/1; restore the bool type expected by the
# strict ProblemType type gate when the registry default is a
# bool (int-typed fields like UseBias are left untouched).
if isinstance(defaultProblemType[problemTypeKey], bool):
problemTypeValue = bool(problemTypeValue)
data[problemTypeKey] = makeFlow(problemTypeValue)
continue
return data
def formGroups(MIInstruction9Bits: dict) -> dict:
data = {}
data["Groups"] = [[]]
group = {}
for forkKey, forkValue in MIInstruction9Bits.items():
group[forkKey] = forkValue
data["Groups"][0].append(group)
return data
def form9BitMIInst(currentSolutionState: dict) -> dict:
MIBlock = currentSolutionState["MIBlock"]
MIWaveTile = currentSolutionState["MIWaveTile"]
MIWaveGroup = currentSolutionState["MIWaveGroup"]
if len(MIBlock) == 0 or len(MIWaveTile) == 0 or len(MIWaveGroup) == 0:
raise RuntimeError(
"Length of MIBlock:{0}, MIWave Tile:{1},MIWaveGroup:{2} cannot be empty".format(
len(MIBlock), len(MIWaveTile), len(MIWaveGroup)
)
)
MIBlock1 = MIBlock[0:5]
MIInstruction9Bits = MIBlock1 + MIWaveTile + MIWaveGroup
groups = {}
groups["MatrixInstruction"] = FlowList(MIInstruction9Bits)
groups["WorkGroup"] = FlowList(currentSolutionState["WorkGroup"])
groups["MIArchVgpr"] = currentSolutionState["MIArchVgpr"]
return groups
def formForkParams(currentIndexSolution: dict, skipMI: bool) -> dict:
data = {}
data["InitialSolutionParameters"] = None
kernelLang = {}
kernelLang["KernelLanguage"] = FlowList(["Assembly"])
data["BenchmarkCommonParameters"] = [kernelLang]
forkData = []
for forkKey, forkValue in currentIndexSolution.items():
temp = {}
# # ignore MatrixInstruction
if forkKey in ["MatrixInstruction", "WorkGroup"]:
continue
# Find the matching index for fork key name from list of dictionaries => defaultBenchmarkCommonParameters
index = next(
(i for i, d in enumerate(defaultBenchmarkCommonParameters) if forkKey in d),
None,
)
if index is not None:
forkValue = [forkValue] # convert to list
if forkValue != defaultBenchmarkCommonParameters[index][forkKey]:
temp[forkKey] = FlowList(forkValue)
forkData.append(temp)
# Skip the MI calculation if 9 bit MI is not needed or MatrixInstruction field is disabled
isMatrixInsEnabled = False
if "EnableMatrixInstruction" in currentIndexSolution:
isMatrixInsEnabled = currentIndexSolution["EnableMatrixInstruction"]
if (
currentIndexSolution["EnableMatrixInstruction"]
and currentIndexSolution["MatrixInstruction"]
):
isMatrixInsEnabled = True
else:
tPrint(
1,
"Matrix instruction is disabled skipping the matrix instruction parameter ..",
)
# Iterate over MIs in Group
if skipMI != True and isMatrixInsEnabled:
temp = form9BitMIInst(currentIndexSolution)
else:
temp = "None"
forkData.append(formGroups(temp))
data["ForkParameters"] = forkData
return data
def formProblemSize(
exactLogic: Optional[list[Tuple[list, list]]],
solutionIndex: int,
problemTypeStat: dict,
) -> dict:
data = {}
data["BenchmarkJoinParameters"] = None
data["BenchmarkFinalParameters"] = []
temp = {}
# for origami exactLogic is not present so we need to create it
if exactLogic is None:
tPrint(
1, "Warning: For Origami liblogics, Exact logic needs to be set manually"
)
temp["ProblemSizes"] = [{"Exact": FlowList([1, 1, 1, 1])}]
else:
for size, mapping in exactLogic:
if mapping[0] == solutionIndex:
temp["ProblemSizes"] = [{"Exact": FlowList(size)}]
data["BenchmarkFinalParameters"].append(temp)
temp = {}
biasTypeArgs = problemTypeStat["BiasDataTypeList"]
temp["BiasTypeArgs"] = FlowList(biasTypeArgs)
gateTypeArgs = problemTypeStat.get("GateResidualDataTypeList", [])
if gateTypeArgs:
temp["GateTypeArgs"] = FlowList(gateTypeArgs)
data["BenchmarkFinalParameters"].append(temp)
return data
def formLibraryLogic(
scheduleName: str, deviceNames: list, architectureName: str
) -> dict:
data = {}
# Form final library logic string
data["ScheduleName"] = Quoted(scheduleName)
data["DeviceNames"] = FlowList([Quoted(deviceNames[0])])
# rawLibraryLogic may return the architecture as a dict
# ({'Architecture': 'gfx950', 'CUCount': 128}); Quoted() would str()-ify it
# into a repr string that downstream arch matching (load_logic_gfx_arch)
# cannot resolve. Emit the plain arch name expected by createLibraryLogic.
if isinstance(architectureName, dict):
architectureName = architectureName.get("Architecture", architectureName)
data["ArchitectureName"] = Quoted(architectureName)
return data
def writeToTensileYamlFile(tensileYamlFile: str, tensileYamlData: str) -> Optional[str]:
ret = None
try:
fileDir = os.path.dirname(tensileYamlFile)
if fileDir:
os.makedirs(fileDir, exist_ok=True)
with open(tensileYamlFile, "w") as f:
yaml.dump(
tensileYamlData,
f,
default_flow_style=False,
sort_keys=False,
Dumper=yaml.Dumper,
)
tPrint(1, "Config library is written to {}".format(tensileYamlFile))
ret = tensileYamlFile
except (OSError, IOError):
tPrint(
1,
"Error: Creating file {} Please provide file name in this format <filename>.yaml.".format(
tensileYamlFile
),
)
return ret
def TensileLibLogicToYaml(
logicFilePath: str, solutionIndex: int, tensileYamlFile: str, skipMI: bool
) -> Optional[str]:
"""Generate config from a library logic.
This function generates a config yaml by extracting a solution from a given a library
logic and a solution index.
Args:
logicFilePath: Yaml format file. Input library logic to extract from.
solutionIndex: Solution index to extract solution from the library.
tensileYamlFile: Config yaml file name. Creates the dir if path is given.
skipMI: If False ignores the MI instruction.
Returns:
If generated the config file name otherwise None.
Raises:
RuntimeError: If logicFilePath cannot be read.
RuntimeError: If solutionIndex is not in the logicFilePath.
RuntimeError: If tensileYamlFile string is empty or name is not valid.
Example:
TensileLibLogicToYaml("gfx950_Cijk_Alik_Bljk_BSS_BH_BiasS_HAS_SAV_UserArgs.yaml", 0, "config.yaml", False)
"""
tPrint(1, "")
tPrint(1, HR)
tPrint(1, "#")
tPrint(1, "# TensileLibLogicToYaml Library v{}".format(__version__))
tPrint(1, "# Library Logic: {}".format(logicFilePath))
tPrint(1, "# Solution Index: {}".format(solutionIndex))
tPrint(1, "#")
tPrint(1, HR)
tPrint(1, "")
libYaml = LibraryIO.readYAML(logicFilePath)
if libYaml == "":
raise RuntimeError(
"Yaml file data is empty, read yaml file :{} failed".format(logicFilePath)
)
if solutionIndex == "":
raise RuntimeError("At least one solution idx should be provided")
# reads library logic file. AllSolutionStates=>has solution data for all solution index
fields = LibraryIO.rawLibraryLogic(libYaml)
(
versionString,
scheduleName,
architectureName,
deviceNames,
problemTypeState,
allSolutionStates,
_, # indexOrder
exactLogic,
_, # rangeLogic
_, # otherFields
) = fields
# Extract the solution data for the user specified solution Index
currentIndexSolution = allSolutionStates[solutionIndex]
if currentIndexSolution == "":
raise RuntimeError(
"Could not find the matching data for the solution index:{} from the library logic file, Try different solution index".format(
solutionIndex
)
)
tensileYamlFileData = {}
# Iterate over problem type parameters and form problem type yaml data
tensileYamlFileData["GlobalParameters"] = setGlobalParams(
versionString, problemTypeState
)
benchmarkProblems = [[]]
benchmarkProblemsData = formProblemTypeYamlData(problemTypeState)
benchmarkProblems[0].append(benchmarkProblemsData)
# # Iterate over Fork parameters and form the Yaml data
benchmarkProblemsData = formForkParams(currentIndexSolution, skipMI)
benchmarkProblemsData.update(
formProblemSize(
exactLogic,
solutionIndex,
problemTypeState,
)
)
benchmarkProblems[0].append(benchmarkProblemsData)
tensileYamlFileData["BenchmarkProblems"] = benchmarkProblems
# # Forms the Library logic string
problemSizeData = formLibraryLogic(scheduleName, deviceNames, architectureName)
tensileYamlFileData["LibraryLogic"] = problemSizeData
# Write the Formed Yaml data into the Yaml File
return writeToTensileYamlFile(tensileYamlFile, tensileYamlFileData)
def parseArgs():
argParser = argparse.ArgumentParser()
argHelp = {
"input": "Library logic file to be converted to tensile input yaml file.",
"indices": "Comma-separated list of Solution indices from library logic File to extract. Ex: 0,3,4,5",
"output": "Base Output file name.",
"skipMI": "Skips the MatrixInstruction field in the tensile yaml file",
}
argParser.add_argument(
"--input",
"-i",
action="store",
type=os.path.realpath,
required=True,
default=None,
help=argHelp["input"],
)
argParser.add_argument(
"--indices",
"-d",
action="store",
type=str,
required=True,
default="0",
help=argHelp["indices"],
)
argParser.add_argument(
"--output",
"-o",
action="store",
type=os.path.realpath,
required=True,
default=None,
help=argHelp["output"],
)
argParser.add_argument(
"--skipMI",
"-s",
action="store_true",
default=None,
help=argHelp["skipMI"],
required=False,
)
return argParser.parse_args()
def main():
args = parseArgs()
ids = [int(x.strip()) for x in args.indices.split(",")]
tensileYamlFiles = []
for id in ids:
if len(ids) == 1:
tensileYamlFile = args.output
else:
tensileYamlFile = re.sub(".yaml", f"_{int(id)}.yaml", args.output)
TensileLibLogicToYaml(args.input, int(id), tensileYamlFile, args.skipMI)
tensileYamlFiles.append(tensileYamlFile)
tPrint(1, f"Tensile Files generated: {tensileYamlFiles}")