Files
TheRock/rocm-libraries/projects/hipblaslt/tensilelite/Tensile/SolutionStructs/Naming.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

260 lines
10 KiB
Python

################################################################################
#
# Copyright (C) 2025 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 functools import lru_cache
from Tensile.Common.Constants import MAX_FILENAME_LENGTH
from Tensile.Common.RequiredParameters import getRequiredParametersMin, getRequiredParametersFull
from .Problem import ProblemType
# Parameters that are "internal args" — runtime dispatch parameters that don't
# affect the generated kernel assembly. Two kernels differing only in these
# fields compile to identical code objects.
_INTERNAL_ARGS = (
"WorkGroupMapping",
# "WorkGroupMappingXCC", # WGMXCC affects asm code gen
"WorkGroupMappingXCCGroup",
"StaggerU",
"StaggerUStride",
"StaggerUMapping",
"GlobalSplitUCoalesced",
"GlobalSplitUWorkGroupMappingRoundRobin",
"SFCWGM",
)
def getKeyNoInternalArgs(state, splitGSU: bool) -> str:
"""Return a string key that identifies a kernel ignoring internal args.
Internal args (WorkGroupMapping, StaggerU, etc.) are runtime dispatch
parameters — they don't change the generated assembly. This function
produces a canonical key where those parameters are masked to "M" and
GroupedGemm is forced to False, so that kernels differing only in
internal args map to the same key.
Used to:
- Deduplicate kernels before code generation (BenchmarkProblems.py,
Run.py:getUniqueKernels) — avoids compiling the same assembly twice.
- Identify invalid kernels after compilation and propagate failures
to all solutions sharing that kernel (Run.py:removeInvalidSolutionsAndKernels).
- Build kernel-to-solution mappings for post-processing
(Run.py:passPostKernelInfoToSolution).
"""
# Work on the raw dict to avoid Solution.__setitem__ invalidating _name cache
s = state._state if hasattr(state, '_state') else state
pt = s["ProblemType"]
# Save originals
backups = {k: s[k] for k in _INTERNAL_ARGS}
gsu_backup = s["GlobalSplitU"]
gg_backup = pt["GroupedGemm"]
wgmxcc_backup = s["WorkGroupMappingXCC"]
# Mask internal args
pt["GroupedGemm"] = False
if splitGSU:
s["GlobalSplitU"] = "M" if (gsu_backup > 1 or gsu_backup == -1) else gsu_backup
elif gsu_backup != 0:
s["GlobalSplitU"] = "M"
if "WorkGroupMappingXCC" in s and s["WorkGroupMappingXCC"] != -1:
s["WorkGroupMappingXCC"] = 1
for k in _INTERNAL_ARGS:
s[k] = "M"
# Compute string key (same as what str(deep_copied_solution) would produce)
key = _getName(s, getRequiredParametersFull(), splitGSU, False)
# Restore
pt["GroupedGemm"] = gg_backup
s["GlobalSplitU"] = gsu_backup
s["WorkGroupMappingXCC"] = wgmxcc_backup
for k in _INTERNAL_ARGS:
s[k] = backups[k]
# Include codeObjectFile and DeviceNames in the key to prevent
# over-deduplication across different code object files / devices.
# The old code returned a Solution object whose __hash__ included these
# fields, so kernels targeting different .co files were kept separate.
cof = s.get("codeObjectFile", "")
dn = str(s.get("DeviceNames", ""))
return key + cof + dn
@lru_cache(maxsize=None)
def getParameterNameAbbreviation( name: str ):
return ''.join(c for c in name if c.isupper())
@ lru_cache(maxsize=None)
def getPrimitiveParameterValueAbbreviation(key, value):
if isinstance(value, str):
return getParameterNameAbbreviation(value)
elif isinstance(value, bool):
return "1" if value else "0"
elif isinstance(value, int):
if value >= 0:
return "%u" % value
else: # -1 -> n1
return "n%01u" % abs(value)
elif isinstance(value, ProblemType): # will need to deal with this
return str(value)
elif isinstance(value, float):
val1 = int(value)
val2 = int(round(value*100)) - int(value)*100
if val2 > 0:
s = "%dp%s" % (val1,str(val2).zfill(2))
else:
s = "%d" % (val1)
return s
def getParameterValueAbbreviation(key, value):
if key == "ISA":
return f"{value[0]}{value[1]}{value[2]:x}"
compositieTypes = (dict, list, tuple,)
if not isinstance(value, compositieTypes):
return getPrimitiveParameterValueAbbreviation(key, value)
elif isinstance(value, tuple):
return ''.join(str(v) for v in value)
elif isinstance(value, list):
return '_'.join(getParameterValueAbbreviation(key, v) for v in value)
elif isinstance(value, dict):
return "_".join(f"{pos:d}{k:d}" for pos,k in value.items())
else:
raise Exception(f"Parameter {key}={value} is new object type ({type(value)})")
def _getName(state, requiredParameters: frozenset, splitGSU: bool, ignoreInternalArgs):
if "CustomKernelName" in state and state["CustomKernelName"]:
return state["CustomKernelName"]
gsuBackup = state["GlobalSplitU"]
ggBackup = state["ProblemType"]["GroupedGemm"]
wgmxccBackup = state["WorkGroupMappingXCC"]
# Include WGMXCC in kernel name as either n1 for auto or 1 for set value
# Fixed values produce different assembly code
# If the key is missing from name, kernels are dropped as duplicates when they should be kept
if "WorkGroupMappingXCC" in state and state["WorkGroupMappingXCC"] != -1:
state["WorkGroupMappingXCC"] = 1
if ignoreInternalArgs:
state["ProblemType"]["GroupedGemm"] = False
if splitGSU:
state["GlobalSplitU"] = "M" if (state["GlobalSplitU"] > 1 or state["GlobalSplitU"] == -1) else state["GlobalSplitU"]
requiredParametersTemp = set(requiredParameters.union(["GlobalSplitU"]))
if ignoreInternalArgs:
if state["GlobalSplitU"] > 0 or state["GlobalSplitU"] == -1:
requiredParametersTemp.discard("GlobalSplitU")
else:
requiredParametersTemp = requiredParametersTemp.union(["WorkGroupMapping",
# "WorkGroupMappingXCC", # WGMXCC affects asm code gen
"WorkGroupMappingXCCGroup",
"StaggerU",
"StaggerUStride",
"StaggerUMapping",
"GlobalSplitUCoalesced",
"GlobalSplitUWorkGroupMappingRoundRobin"])
pt = state["ProblemType"]
if isinstance(pt, ProblemType):
components = [str(pt)]
else:
components = [str(ProblemType(pt, printIndexAssignmentInfo=False))]
if "MacroTile0" in state \
and "MacroTile1" in state \
and "DepthU" in state:
components.append(f'{getParameterNameAbbreviation("MacroTile")}{state["MacroTile0"]}x{state["MacroTile1"]}x{state["DepthU"]}')
if "MatrixInstM" in state:
# Use the physical opcode dims (MIBlock) for the name, not the possibly-swapped
# effective MatrixInstM/N, so the kernel identity matches the user-specified MI.
_miName = state.get("MIBlock", [state["MatrixInstM"], state["MatrixInstN"]])
components.append(f'{getParameterNameAbbreviation("MatrixInstruction")}{_miName[0]}x{_miName[1]}x{state["MatrixInstB"]}')
requiredParametersTemp.add("MIWaveTile")
else:
requiredParametersTemp.add("ThreadTile")
if state["UseCustomMainLoopSchedule"]:
components.append('CMS')
components.append('SN')
# Skip SFA tag if using default wgm algo
if "SpaceFillingAlgo" in requiredParametersTemp and len(state["SpaceFillingAlgo"]) == 0:
requiredParametersTemp.discard("SpaceFillingAlgo")
# Only name LDSSegmentInterleave when applied (==1), so the applied kernel is distinct from its
# baseline twin without tagging every other kernel. Same idiom as WorkGroupMappingXCC above.
if state.get("LDSSegmentInterleave") == 1:
requiredParametersTemp.add("LDSSegmentInterleave")
for key in sorted(requiredParametersTemp):
if key not in state or key == "CustomKernelName":
continue
components.append(f'{getParameterNameAbbreviation(key)}{getParameterValueAbbreviation(key, state[key])}')
state["GlobalSplitU"] = gsuBackup
state["ProblemType"]["GroupedGemm"] = ggBackup
state["WorkGroupMappingXCC"] = wgmxccBackup
return '_'.join(components)
def shortenFileBase(splitGSU, kernel):
base = getKernelNameMin(kernel, splitGSU)
if len(base) <= MAX_FILENAME_LENGTH:
return base
import hashlib
import base64
pivot = MAX_FILENAME_LENGTH * 3 // 4
firstPart = base[:pivot]
secondPart = base[pivot:]
secondHash = hashlib.sha256(secondPart.encode()).digest()
secondPart = base64.b64encode(secondHash, b'_-').decode()
return firstPart + secondPart
def getKernelFileBase(splitGSU: bool, kernel):
if "CustomKernelName" in kernel and kernel["CustomKernelName"]:
fileBase = kernel["CustomKernelName"]
else:
fileBase = shortenFileBase(splitGSU, kernel)
return fileBase
def getKernelNameMin(kernel, splitGSU: bool):
return _getName(kernel, getRequiredParametersMin(), splitGSU, True)
def getSolutionNameMin(solution, splitGSU: bool):
return _getName(solution, getRequiredParametersMin(), splitGSU, False)
def getSolutionNameFull(state, splitGSU: bool):
return _getName(state, getRequiredParametersFull(), splitGSU, False)