Skip to content

Commit bf05992

Browse files
authored
Merge pull request #1905 from yenong-amd/release/rocm-rel-6.1
Hotfix: Fix MasterSolutionLibrary indexing for multiple architecture build (#1888)
2 parents be9f7da + 2b55ccf commit bf05992

File tree

4 files changed

+164
-11
lines changed

4 files changed

+164
-11
lines changed

Tensile/SolutionLibrary.py

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
################################################################################
2424

2525
import itertools
26+
import re
2627

2728
from . import Properties
2829
from . import Hardware
@@ -248,6 +249,28 @@ def remapSolutionIndices(self, indexMap):
248249

249250
class MasterSolutionLibrary:
250251
StateKeys = ["solutions", "library"]
252+
ArchitectureSet = set()
253+
254+
@classmethod
255+
def ArchitectureIndexMap(cls, architectureName):
256+
# 'fallback', 'gfx803', 'gfx900', 'gfx906', 'gfx908', 'gfx90a',
257+
# 'gfx940', 'gfx941', 'gfx942', 'gfx1010', 'gfx1011', 'gfx1012',
258+
# 'gfx1030', 'gfx1031', 'gfx1032', 'gfx1034', 'gfx1035', 'gfx1100',
259+
# 'gfx1101', 'gfx1102'
260+
archval = -1
261+
if architectureName == "fallback":
262+
archval = 0
263+
elif architectureName.startswith("gfx"):
264+
archString = re.search('(?<=gfx)[0-9a-f]*', architectureName)
265+
if archString is not None:
266+
archLiteral = archString.group(0)
267+
archval = (int(archLiteral, 16) << 18)
268+
# Check for duplicate architecture values
269+
if archval >= 0 and not archval in cls.ArchitectureSet:
270+
cls.ArchitectureSet.add(archval)
271+
else:
272+
raise RuntimeError("ERROR in architecture solution index mapping.")
273+
return archval
251274

252275
@classmethod
253276
def FixSolutionIndices(cls, solutions):
@@ -478,17 +501,44 @@ def applyNaming(self, naming=None):
478501
s.name = OriginalSolution.getNameMin(s.originalSolution.getKernels()[0], naming)
479502

480503
def remapSolutionIndicesStartingFrom(self, curIndex):
504+
if self.lazyLibraries:
505+
lazyLibrary = {}
506+
for name, lib in self.lazyLibraries.items():
507+
reIndexMap = {}
508+
newSolutions = {}
509+
510+
for k, s in lib.solutions.items():
511+
reIndexMap[s.index] = curIndex
512+
s.index = curIndex
513+
newSolutions[curIndex] = s
514+
curIndex += 1
515+
516+
lib.solutions = newSolutions
517+
lib.library.remapSolutionIndices(reIndexMap)
518+
519+
lazyLibrary[name] = lib
520+
self.lazyLibraries = lazyLibrary
521+
481522
reIndexMap = {}
482-
solutionCopy = self.solutions
483-
self.solutions = dict()
484-
for k, s in solutionCopy.items():
523+
newSolutions = {}
524+
for k, s in self.solutions.items():
485525
reIndexMap[s.index] = curIndex
486526
s.index = curIndex
487-
self.solutions[curIndex] = s
527+
newSolutions[curIndex] = s
488528
curIndex += 1
489-
529+
self.solutions = newSolutions
490530
self.library.remapSolutionIndices(reIndexMap)
491531

532+
def insert(self, other):
533+
assert self.__class__ == other.__class__
534+
535+
for name, lib in other.lazyLibraries.items():
536+
self.lazyLibraries[name] = lib
537+
538+
for _, s in other.solutions.items():
539+
self.solutions[s.index] = s
540+
self.library.merge(other.library)
541+
492542
def merge(self, other, startIndex=0):
493543
assert self.__class__ == other.__class__
494544

Tensile/Source/lib/source/UserDrivenTuningParser.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ namespace Tensile
122122
strideB = 1;
123123
strideC = 1;
124124

125+
if(b > 1)
126+
{
127+
strideA = ldA * (transA ? m : k);
128+
strideB = ldB * (transB ? k : n);
129+
strideC = ldC * n;
130+
}
131+
125132
if(entries_n == 15)
126133
{
127134
// Expected layout: transA,transB,M,N,batch_count,K,alpha,beta,lda,ldb,ldc,input_type,output_type,compute_type,solution_index

Tensile/TensileCreateLibrary.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,8 +911,7 @@ def generateLogicDataAndSolutions(logicFiles, args):
911911
masterLibraries = {}
912912
fullMasterLibrary = None
913913

914-
nextSolIndex = 0
915-
914+
nextSolIndex = {}
916915
for logic in Utils.tqdm(libraries, "Processing logic data"):
917916
(_, architectureName, _, solutionsForSchedule, _, newLibrary) = logic
918917

@@ -923,10 +922,14 @@ def generateLogicDataAndSolutions(logicFiles, args):
923922
masterLibraries[architectureName] = deepcopy(newLibrary)
924923
masterLibraries[architectureName].version = args.version
925924
elif globalParameters["SeparateArchitectures"] or globalParameters["LazyLibraryLoading"]:
925+
926926
if architectureName in masterLibraries:
927-
nextSolIndex = masterLibraries[architectureName].merge(deepcopy(newLibrary), nextSolIndex)
927+
nextSolIndex[architectureName] = masterLibraries[architectureName].merge(deepcopy(newLibrary), nextSolIndex[architectureName])
928928
else:
929929
masterLibraries[architectureName] = deepcopy(newLibrary)
930+
archIndexMap = MasterSolutionLibrary.ArchitectureIndexMap(architectureName)
931+
masterLibraries[architectureName].remapSolutionIndicesStartingFrom(archIndexMap)
932+
nextSolIndex[architectureName] = archIndexMap
930933
masterLibraries[architectureName].version = args.version
931934
else:
932935
if fullMasterLibrary is None:
@@ -944,8 +947,7 @@ def generateLogicDataAndSolutions(logicFiles, args):
944947
if "fallback" in masterLibraries.keys():
945948
for key, value in masterLibraries.items():
946949
if key != "fallback":
947-
value.merge(deepcopy(masterLibraries["fallback"]))
948-
950+
value.insert(deepcopy(masterLibraries["fallback"]))
949951
masterLibraries.pop("fallback")
950952

951953
for _, masterLibrary in masterLibraries.items():
@@ -1017,6 +1019,23 @@ def WriteClientLibraryFromSolutions(solutionList, libraryWorkingPath, tensileSou
10171019

10181020
return (codeObjectFiles, newLibrary)
10191021

1022+
################################################################################
1023+
# Write Master Solution Index CSV
1024+
################################################################################
1025+
def writeMasterSolutionIndexCSV(outputPath, masterLibraries):
1026+
libraryPath = os.path.join(outputPath, "library")
1027+
ensurePath(libraryPath)
1028+
try:
1029+
with open(os.path.join(libraryPath, "TensileMasterSolutionIndex.csv"), "w") as indexFile:
1030+
indexFile.write("architectureName,libraryName,libraryIndex,solutionIndex,solutionName\n")
1031+
for arch,lib in masterLibraries.items():
1032+
for lazylibname,lazylibvals in lib.lazyLibraries.items():
1033+
for solidx,solution in lazylibvals.solutions.items():
1034+
line = ",".join(str(x) for x in [arch, lazylibname, solidx, solution.index, solution.name])
1035+
indexFile.write("%s\n" %(line))
1036+
except IOError as err:
1037+
print1("Error writing MasterSolutionIndex %s" % err)
1038+
10201039
################################################################################
10211040
# Tensile Create Library
10221041
################################################################################
@@ -1084,6 +1103,8 @@ def splitExtraParameters(par):
10841103
argParser.add_argument("--global-parameters", nargs="+", type=splitExtraParameters, default=[])
10851104
argParser.add_argument("--ignore-asm-cap-cache", dest="IgnoreAsmCapCache", action="store_true", default=False,
10861105
help="Ignore asm cap cache and derive the asm caps at runtime")
1106+
argParser.add_argument("--write-master-solution-index", dest="WriteMasterSolutionIndex", action="store_true",
1107+
default=False, help="Output master solution index in csv format.")
10871108
args = argParser.parse_args()
10881109

10891110
logicPath = args.LogicPath
@@ -1123,7 +1144,8 @@ def splitExtraParameters(par):
11231144
arguments["CpuThreads"] = args.CpuThreads
11241145
arguments["PrintLevel"] = args.PrintLevel
11251146
arguments["IgnoreAsmCapCache"] = args.IgnoreAsmCapCache
1126-
1147+
arguments["WriteMasterSolutionIndex"] = args.WriteMasterSolutionIndex
1148+
11271149
for key, value in args.global_parameters:
11281150
arguments[key] = value
11291151

@@ -1174,6 +1196,9 @@ def splitExtraParameters(par):
11741196
# Parse logicData, solutions, and masterLibraries from logic files
11751197
solutions, masterLibraries, fullMasterLibrary = generateLogicDataAndSolutions(logicFiles, args)
11761198

1199+
if globalParameters["LazyLibraryLoading"] and arguments["WriteMasterSolutionIndex"]:
1200+
writeMasterSolutionIndexCSV(outputPath, masterLibraries)
1201+
11771202
kernels, kernelHelperObjs, _ = generateKernelObjectsFromSolutions(solutions)
11781203

11791204
# if any kernels are assembly, append every ISA supported

Tensile/Utilities/validate_library.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
################################################################################
2+
#
3+
# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
#
23+
################################################################################
24+
25+
import argparse
26+
import csv
27+
import pathlib
28+
import sys
29+
30+
from collections import defaultdict
31+
32+
def gather_data(indexFile):
33+
34+
indexData = defaultdict(set)
35+
with open(indexFile, "rt") as csvfile:
36+
indexreader = csv.DictReader(csvfile, delimiter=",")
37+
for row in indexreader: # read a row as {column1: value1, column2: value2,...}
38+
for key, value in row.items():
39+
indexData[key].add(value)
40+
return indexData
41+
42+
if __name__ == "__main__":
43+
argParser = argparse.ArgumentParser()
44+
argParser.add_argument("library_path", help="Tensile library path")
45+
args = argParser.parse_args()
46+
libraryPath = args.library_path
47+
indexFileName = "TensileMasterSolutionIndex.csv"
48+
49+
# Check that path exists
50+
if not pathlib.Path(libraryPath).is_dir():
51+
print(f"ERROR: {libraryPath} does not exists.")
52+
sys.exit(1)
53+
54+
# Check that TensileMasterSolutionIndex.csv exists
55+
csvpath = pathlib.Path(libraryPath) / indexFileName
56+
if not csvpath.is_file():
57+
print(f"ERROR: {csvpath} does not exists.")
58+
sys.exit(1)
59+
60+
data = gather_data(csvpath)
61+
62+
# List files in library path
63+
datFiles = [f.stem for f in pathlib.Path(libraryPath).glob("*.dat")]
64+
coFiles = [f.stem for f in pathlib.Path(libraryPath).glob("*.co")]
65+
lazyArchFiles = [f for f in datFiles if "_lazy_" in f]
66+
metaDataFiles = [f for f in datFiles if not "_lazy_" in f]
67+
nonfallback = set([f for f in data['libraryName'] if not "fallback" in f])
68+
69+
print(f"MetaData files should match library names in index file: {set(metaDataFiles) == data['libraryName']}")
70+
print(f"Asm files should match non-fallback library names in index file: {set(coFiles) == nonfallback}")
71+
print(f"Lazy library files should match number of architectures in index file: {len(set(lazyArchFiles)) == len(data['architectureName'])}")

0 commit comments

Comments
 (0)