Files
TheRock/rocm-libraries/shared/tensile/Tensile/Tests/unit/test_mergeLogic.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

335 lines
11 KiB
Python

################################################################################
#
# Copyright (C) 2020-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
# 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.Utilities.merge import cmpHelper, fixSizeInconsistencies, removeUnusedKernels, mergeLogic
from Tensile.Utilities.ConditionalImports import yamlLoader
import yaml, pytest
# the merge scripts does not differentiate solutions based on index or name
# so "DummyParam" is used to mark if solutions should be equal or not
logicPrefix = r"""
- DummyVersionRequirement
- DummyLanguage
- DummyScheduleName
- DummyDevice
- DummyProblemType
"""
baseLogic=logicPrefix + r"""
-
- SolutionIndex: 2
SolutionNameMin: InUseForSize256
DummyParam: InUseForSize256
- SolutionIndex: 1
SolutionNameMin: UnusedSolution
DummyParam: UnusedSolution
- SolutionIndex: 0
SolutionNameMin: InUseForSize128or64
DummyParam: InUseForSize128or64
- DummyIndexAssignment
-
- - [256, 256, 1, 256]
- [2, 111.1]
- - [128, 128, 1, 128]
- [0, 99.9]
- - [64, 64, 1, 64]
- [0, 88.8]
"""
incLogic=logicPrefix + r"""
-
- SolutionIndex: 39
SolutionNameMin: InUseForSize256or1024xxx
DummyParam: InUseForSize256or1024xxx
- SolutionIndex: 1
SolutionNameMin: InUseForSize128xxx
DummyParam: InUseForSize128xxx
- DummyIndexAssignment
-
- - [128, 128, 1, 128]
- [1, 999.9]
- - [256, 256, 1, 256]
- [39, 999.9]
- - [1024, 1024, 1, 1024]
- [39, 999.9]
"""
notUniqueSolution=logicPrefix+r"""
-
- SolutionIndex: 0
SolutionNameMin: Kernel0
DummyParam: Kernel0
- SolutionIndex: 1
SolutionNameMin: Kernel0
DummyParam: Kernel0
"""
uniqueSolution=logicPrefix+r"""
-
- SolutionIndex: 0
SolutionNameMin: Kernel0
DummyParam: Kernel0
- SolutionIndex: 1
SolutionNameMin: Kernel1
DummyParam: Kernel1
"""
notTrimmedSize=r"""
-
- - [128, 128, 1, 128, 128, 128, 128, 128]
- [1, 999.9]
- - [1024, 1024, 1, 1024]
- [42, 0.0]
- - [128, 128, 1, 128]
- [39, 0.0]
- - [1024, 1024, 1, 1024, 1024, 1024, 1024, 1024]
- [39, 999.9]
- - [1024, 1024, 1, 1024, 1044, 1044, 1044, 1044]
- [39, 999.9]
"""
trimmedSize=r"""
-
- - [128, 128, 1, 128]
- [1, 999.9]
- - [512, 512, 1, 512]
- [39, 999.9]
- - [1024, 1024, 1, 1024]
- [42, 999.9]
"""
mfmaMergeBaseLogic=logicPrefix+r"""
-
- SolutionIndex: 0
SolutionNameMin: MFMA_base
DummyParam: MFMA_base
EnableMatrixInstruction: True
MatrixInstruction: [16, 16, 4, 1]
- SolutionIndex: 1
SolutionNameMin: VALU_base
DummyParam: VALU_base
EnableMatrixInstruction: False
MatrixInstruction: []
- DummyIndexAssignment
"""
mfmaMergeIncLogic=logicPrefix+r"""
-
- SolutionIndex: 0
SolutionNameMin: MFMA_inc
DummyParam: MFMA_inc
EnableMatrixInstruction: True
MatrixInstruction: [16, 16, 4, 1]
- SolutionIndex: 1
SolutionNameMin: VALU_inc
DummyParam: VALU_inc
EnableMatrixInstruction: False
MatrixInstruction: []
- DummyIndexAssignment
"""
mfmaMergeBaseSizes=r"""
-
- - [128, 128, 1, 128]
- [0, 3.0]
- - [128, 128, 1, 128]
- [1, 6.0]
- - [130, 128, 1, 128]
- [1, 9.0]
- - [131, 128, 1, 128]
- [0, 12.0]
"""
mfmaMergeIncFasterSizes=r"""
-
- - [128, 128, 1, 128]
- [0, 4.0]
- - [128, 128, 1, 128]
- [1, 7.0]
- - [131, 128, 1, 128]
- [0, 13.0]
- - [130, 128, 1, 128]
- [1, 10.0]
"""
mfmaMergeIncSlowerSizes=r"""
-
- - [128, 128, 1, 128]
- [0, 2.0]
- - [128, 128, 1, 128]
- [1, 5.0]
- - [131, 128, 1, 128]
- [0, 11.0]
- - [130, 128, 1, 128]
- [1, 8.0]
"""
mfmaMergeIncNotMatchingMFMA=r"""
-
- - [130, 128, 1, 128]
- [0, 7.0]
- - [131, 128, 1, 128]
- [1, 12.0]
"""
mfmaMergeResNotMatchingMFMA=r"""
-
- - [128, 128, 1, 128]
- [0, 3.0]
- - [128, 128, 1, 128]
- [1, 6.0]
- - [130, 128, 1, 128]
- [1, 9.0]
- - [131, 128, 1, 128]
- [0, 12.0]
- - [130, 128, 1, 128]
- [2, 7.0]
- - [131, 128, 1, 128]
- [3, 12.0]
"""
def checkUniqueSolution(solutionPool):
uniq = set()
# note: any([False or None, True or None]) -> True
return not any(frozenset(cmpHelper(i).items()) in uniq or uniq.add(frozenset(cmpHelper(i).items()))
for i in solutionPool)
@pytest.mark.parametrize("sizes, expected", [
( trimmedSize, [[128,128,1,128],[512,512,1,512],[1024,1024,1,1024]]),
(notTrimmedSize, [[1024,1024,1,1024],[128,128,1,128]])
])
def test_fixSizeInconsistencies(sizes, expected):
data = yaml.load(sizes, yamlLoader)
data_ = fixSizeInconsistencies(data[0], "dummy")
for [size, [_,_]], expected_ in zip(data_[0], expected):
assert size == expected_
@pytest.mark.parametrize("input,expectedNumKernelRemoved", [(baseLogic, 1),
(incLogic, 0)])
def test_removeUnusedKernels(input, expectedNumKernelRemoved):
data = yaml.load(input, yamlLoader)
dataFiltered, numKernelRemoved = removeUnusedKernels(data)
# test if number of solution removed is correct
assert numKernelRemoved == expectedNumKernelRemoved
# test if solution is re-indexed
for index, s in enumerate(dataFiltered[5]):
assert index == s["SolutionIndex"]
# check if size-kernel mapping is not compromised
solutionMapBefore = {}
solutionMapAfter = {}
for [size, [index, _]] in data[7]:
solutionMapBefore[tuple(size)] = [s["SolutionNameMin"] for s in data[5] if s["SolutionIndex"]==index][0]
for [size, [index, _]] in dataFiltered[7]:
solutionMapAfter[tuple(size)] = [s["SolutionNameMin"] for s in dataFiltered[5] if s["SolutionIndex"]==index][0]
assert solutionMapBefore == solutionMapAfter
# print final yaml for visual inspection
# stream = io.StringIO("")
# yaml.safe_dump(dataFiltered, stream, default_flow_style=None)
# print(stream.getvalue())
@pytest.mark.parametrize("baseLogic, incLogic, expectedStats, expectedSizes, expectedSolutions", [
# test case #1: merge incLogic into baseLogic
(baseLogic, incLogic, [1,2,2], # 1 sizes added, 2 kernels added, 2 kernels removed/replaced
[(1024,1024,1,1024), (256,256,1,256), (128,128,1,128), (64,64,1,64)],
["InUseForSize256or1024xxx", "InUseForSize256or1024xxx", "InUseForSize128xxx", "InUseForSize128or64"]),
# test case #2: merge baseLogic into itself
(baseLogic, baseLogic, [0,0,1], # 0 sizes added, 0 kernels added, 1 kernel removed because it's unused
[(256,256,1,256), (128,128,1,128), (64,64,1,64)],
["InUseForSize256", "InUseForSize128or64", "InUseForSize128or64"]),
])
def test_mergeLogic(baseLogic, incLogic, expectedStats, expectedSizes, expectedSolutions):
baseData = yaml.load(baseLogic, yamlLoader)
incData = yaml.load(incLogic, yamlLoader)
mergedData, *stats = mergeLogic(baseData, incData, False)
# check if stats are as expected
assert stats == expectedStats
# check if solution matches expected. assumes SolutionNameMin is uniqueSolution
# (which is satisfied by the test data given here)
solutionMap = {} # size -> solutionName
for size, [index, _] in mergedData[7]:
solutionMap[tuple(size)] = [s["SolutionNameMin"] for s in mergedData[5] if s["SolutionIndex"]==index][0]
for size, expected in zip(expectedSizes, expectedSolutions):
assert solutionMap[size] == expected
# check if each solution in merged data is uniqueSolution
assert checkUniqueSolution(mergedData[5])
@pytest.mark.parametrize("input,expected", [(uniqueSolution, True), (notUniqueSolution, False)])
def test_checkUniqueSolution(input, expected):
data = yaml.load(input, yamlLoader)
assert checkUniqueSolution(data[5]) == expected
@pytest.mark.parametrize("baseLogic, incLogic, expectedSizesYaml, expectedSolutions", [
# test case #1: Slower sizes in incremental logic file
(mfmaMergeBaseLogic+mfmaMergeBaseSizes, mfmaMergeIncLogic+mfmaMergeIncSlowerSizes,
mfmaMergeBaseSizes, ["MFMA_base", "VALU_base"]),
# test case #2: Faster sizes in incremental logic file
(mfmaMergeBaseLogic+mfmaMergeBaseSizes, mfmaMergeIncLogic+mfmaMergeIncFasterSizes,
mfmaMergeIncFasterSizes, ["MFMA_inc", "VALU_inc"]),
# test case #3: Test that VALU size is included alongside MFMA size, and vice versa (regardless of efficiency)
(mfmaMergeBaseLogic+mfmaMergeBaseSizes, mfmaMergeIncLogic+mfmaMergeIncNotMatchingMFMA,
mfmaMergeResNotMatchingMFMA, ["MFMA_base", "VALU_base", "MFMA_inc", "VALU_inc"])
])
def test_mfmaMergeLogic(baseLogic, incLogic, expectedSizesYaml, expectedSolutions):
baseData = yaml.load(baseLogic, yamlLoader)
incData = yaml.load(incLogic, yamlLoader)
expectedSizes = yaml.load(expectedSizesYaml, yamlLoader)[0]
mergedData, _, _, _ = mergeLogic(baseData, incData, False, True, True)
solutionIndices = {s['SolutionNameMin']: s['SolutionIndex'] for s in mergedData[5]} # size -> solutionName
#Ensure all correct solutions are present in merged data
for solution in expectedSolutions:
assert solution in solutionIndices.keys()
assert len(expectedSolutions) == len(mergedData[5])
#Convert expected sizes to use mergedData's solution indices
expectedSizes = [ [size, [solutionIndices[expectedSolutions[solIndex]], eff]] for size, [solIndex, eff] in expectedSizes ]
#Ensure all expected sizes are present in merged data
for item in expectedSizes:
assert item in mergedData[7]
assert len(expectedSizes) == len(mergedData[7])
if __name__ == "__main__":
# test_mergeLogic(baseLogic, incLogic, [1,2,2], [(1024, 1024, 1, 1024), (256, 256, 1, 256), (128, 128, 1, 128), (64, 64, 1, 64)], [ "InUseForSize256or1024xxx", "InUseForSize256or1024xxx", "InUseForSize128xxx", "InUseForSize128or64"])
# test_checkUniqueSolution(uniqueSolution, True)
# test_fixSizeInconsistencies(trimmedSize, [[128,128,1,128],[512,512,1,512],[1024,1024,1,1024]])
test_fixSizeInconsistencies(notTrimmedSize, [[1024,1024,1,1024],[128,128,1,128]])