From 7fd19899bf9bfea16bf890f9eb9ea01572768567 Mon Sep 17 00:00:00 2001 From: David Dixon Date: Tue, 12 Nov 2024 21:44:16 +0000 Subject: [PATCH 1/4] Source kernel compilation --- Tensile/TensileCreateLibrary.py | 158 +++++++++++++++----------------- 1 file changed, 76 insertions(+), 82 deletions(-) diff --git a/Tensile/TensileCreateLibrary.py b/Tensile/TensileCreateLibrary.py index 36037e0de..1c267fcfe 100644 --- a/Tensile/TensileCreateLibrary.py +++ b/Tensile/TensileCreateLibrary.py @@ -270,7 +270,7 @@ def buildSourceKernelObjectFile( + [kernelFile, "-c", "-o", os.path.join(buildPath, objectFilename)] ) - tPrint(0, f"Build object file command: {compileArgs}") + tPrint(2, f"Build object file command: {compileArgs}") # change to use check_output to force windows cmd block util command finish try: out = subprocess.check_output(compileArgs, stderr=subprocess.STDOUT) @@ -326,7 +326,7 @@ def setInOutFlags(): def buildSourceKernelCodeObjectFile( - CxxCompiler, outputPath, base, caps: Capabilities, rocmPaths: RocmPaths, archInfo: ArchInfo, removeTemporaries + CxxCompiler, outputPath, caps: Capabilities, rocmPaths: RocmPaths, archInfo: ArchInfo, removeTemporaries, base ): buildPath = Path(outputPath).parent / Path("build_tmp") / Path(outputPath).stem.upper() / "code_object_tmp" destDir = Path(outputPath) / "library" @@ -381,11 +381,11 @@ def buildSourceKernelCodeObjectFiles(CxxCompiler, baseNames, outputPath, caps, r args = zip( itertools.repeat(CxxCompiler), itertools.repeat(outputPath), - baseNames, itertools.repeat(caps), itertools.repeat(rocmPaths), - itertools.repeat(archInfo), + itertools.repeat(archInfo), itertools.repeat(removeTemporaries), + baseNames, ) return Common.ParallelMap(buildSourceKernelCodeObjectFile, args, cores, "Compiling source kernels") @@ -474,8 +474,6 @@ def prepAsm( def collectFilesToWrite( results: List[ProcessedKernelResult], outputPath: Path, - lazyLoading: bool, - numMergedFiles: int, ) -> ProcessedKernelLookup: """Collects and organizes kernel files to be written based on the provided results. @@ -499,21 +497,11 @@ def collectFilesToWrite( for err, src, header, kernelName, filename in results: if not src.strip(): continue - kernPath = pathJoin(kernelName) + if filename: kernPath = pathJoin(filename) - else: - suffix = str(validKernelCount % numMergedFiles) if numMergedFiles > 1 else "" - kernPath = pathJoin(f"Kernels{suffix}") - - srcKernelMap[kernPath].append(ProcessedKernelResult(err, src, header, kernelName)) - validKernelCount += 1 - - # Ensure there's at least one kernel file for helper kernels - if lazyLoading or (validKernelCount == 0): - kernelSuffix = "0" if numMergedFiles > 1 else "" - srcKernelMap[pathJoin(f"Kernels{kernelSuffix}")] = [] + srcKernelMap[kernPath].append(ProcessedKernelResult(err, src, header, kernelName)) return srcKernelMap @@ -554,7 +542,7 @@ def writeSourcePreface(srcFile, filename): # fmt: on writeHeaderPreface(hdrFile) writeSourcePreface(srcFile, filename) - for _, src, header, _ in kernelList: + for _, src, header, _, _ in kernelList: srcFile.write(src) hdrFile.write(header) @@ -698,8 +686,6 @@ def writeKernelHelpers( kernelHelperObj: KernelWriterBase, kernelSourceFile: Optional[TextIOWrapper], kernelHeaderFile: Optional[TextIOWrapper], - outputPath: Path, - kernelFiles: List[str], ): """Writes the source and header code generated by a kernel helper object to specified files or a new file. @@ -727,25 +713,47 @@ def writeKernelHelpers( toFile(kernelHeaderFile, hdrCode) -################################################################################ -# Write Solutions and Kernels for BenchmarkClient or LibraryClient -################################################################################ +def relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries): + buildPath = Path(outputPath).parent / Path("build_tmp") / Path(outputPath).stem.upper() / "code_object_tmp" + destDir = Path(outputPath) / "library" + + extractedCOs = [os.path.join(buildPath, name) for name in coFilenames] + destCOsList = [os.path.join(destDir, name) for name in coFilenames] + for src, dst in zip(extractedCOs, destCOsList): + if removeTemporaries: + shutil.move(src, dst) + else: + shutil.copyfile(src, dst) + + def writeSourceKernels( outputPath: str, params: Dict[str, Any], kernels: List[Solution], kernelWriterSource: KernelWriterSource, + cxxCompiler, + capabilities, + rocmPaths, + archInfo, + removeTemporaries ): start = time.time() + outPath = Path(outputPath) results = [processKernelSource(k, kernelWriterSource) for k in kernels] - srcKernelMap= collectFilesToWrite(results, outPath, params["LazyLibraryLoading"], numMergedFiles=1) + srcKernelMap = collectFilesToWrite(results, outPath) + kernelFiles = generateKernelSourceAndHeaderFiles(srcKernelMap) + basenames = [buildSourceKernelObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, k) for k in kernelFiles] + coFilenames = [buildSourceKernelCodeObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, removeTemporaries, basename) for basename in basenames] + for cofileList in coFilenames: + relocateSourceKernelCodeObjectFiles(cofileList, outputPath, removeTemporaries) + stop = time.time() total = stop - start numKernels = len(srcKernelMap) tPrint(1, f"# Source kernel Writing elapsed time = {total} secs, kps = {float(numKernels)/total}, kernels = {numKernels}") - return srcKernelMap + return kernelFiles # should be writeAssemblyKernelsAndBuildCodeObjects @@ -963,9 +971,7 @@ def parseLibraryLogicFiles( #for d in logicFiles: # print(d) files = glob.glob(logicFiles + "/*.yaml") - print(files) for f in files: - print(f) yamlDict = LibraryIO.readYAML(f) logic = LibraryIO.parseLibraryLogicData(yamlDict, caps) libraryLogics.append(logic) @@ -1018,6 +1024,7 @@ def run( removeTemporaries, outputPath, args, + cxxCompiler, capabilities: Capabilities, rocmPaths: RocmPaths, archInfo: ArchInfo, @@ -1025,54 +1032,46 @@ def run( logicFiles, ): procnum = os.getpid() - tPrint(0, f"processing on: {procnum}") libraryLogics = parseLibraryLogicFiles(logicFiles, capabilities) solns = list(generateSolutions(libraryLogics)) kernels = list((s.getKernels() for s in solns)) # tPrint(0, f"Library logic file: {logicFiles}, kernels: {kernels}") - kernelHelperObjs = generateKernelObjectsFromSolutions(kernels) asmDir = Path(os.path.join(Path(outputPath).parent, "build_tmp", Path(outputPath).stem.upper(), "assembly")) asmDir.mkdir(parents=True, exist_ok=True) kernelWriterSource, kernelWriterAssembly = getKernelWriters( kernels, removeTemporaries, rocmPaths, capabilities, archInfo, str(asmDir), kernelMinNaming ) - #srcKernels = [k for k in kernels if k["KernelLanguage"] == "Source"] - #filesToWrite = writeSourceKernels( - # outputPath, - # args, - # srcKernels, - # kernelWriterSource, - #) - - asmKernels = [k for k in kernels if k["KernelLanguage"] == "Assembly"] - asmKernels = writeAssemblyKernels( - outputPath, - asmKernels, - kernelWriterAssembly, - ) + srcKernels = [k for k in kernels if k["KernelLanguage"] == "Source"] + if srcKernels: + kernelFiles = writeSourceKernels( + outputPath, + args, + srcKernels, + kernelWriterSource, + cxxCompiler, + capabilities, + rocmPaths, + archInfo, + kernelMinNaming, + ) - coFileMap = gatherCOFilesForLinking(asmKernels, kernelMinNaming) + #kernelHelperObjs = generateKernelObjectsFromSolutions(kernels) - return getAssemblyCodeObjectFiles( - coFileMap, - outputPath, - ) + asmKernels = [k for k in kernels if k["KernelLanguage"] == "Assembly"] + if asmKernels: + asmKernels = writeAssemblyKernels( + outputPath, + asmKernels, + kernelWriterAssembly, + ) + coFileMap = gatherCOFilesForLinking(asmKernels, kernelMinNaming) + getAssemblyCodeObjectFiles(coFileMap, outputPath) -# # Relevant to source kernel compilation -# def relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries): -# buildPath = Path(outputPath).parent / Path("build_tmp") / Path(outputPath).stem.upper() / "code_object_tmp" -# destDir = Path(outputPath) / "library" -# extractedCOs = [os.path.join(buildPath, name) for name in set(coFilenames)] -# destCOsList = [os.path.join(destDir, name) for name in set(coFilenames)] -# for src, dst in zip(extractedCOs, destCOsList): -# if removeTemporaries: -# shutil.move(src, dst) -# else: -# shutil.copyfile(src, dst) + return generateKernelObjectsFromSolutions(kernels) @profile @@ -1110,7 +1109,7 @@ def TensileCreateLibrary(): kernelMinNaming = getRequiredParametersMin() - parallelFunc = functools.partial(run, removeTemporaries, outputPath, args, capabilities, rocmPaths, archInfo, kernelMinNaming) + parallelFunc = functools.partial(run, removeTemporaries, outputPath, args, cxxCompiler, capabilities, rocmPaths, archInfo, kernelMinNaming) logicFiles = list(findLogicFiles(Path(logicPath), logicArchs)) @@ -1118,33 +1117,28 @@ def TensileCreateLibrary(): chunk_size = int(total / numPasses) remainder = total % numPasses - coFiles = [] + kho = [] for p in range(0, numPasses): start = p * chunk_size stop = (p+1) * chunk_size rvs = Common.ParallelMap(parallelFunc, logicFiles[start:stop], cpuThreads, "Running TCL...", multiArg=False) - for r in rvs: - coFiles.extend(r) + for ko in rvs: + kho.extend(ko) if remainder: rvs = Common.ParallelMap(parallelFunc, logicFiles[-remainder:], cpuThreads, "Running TCL...", multiArg=False) - for r in rvs: - coFiles.extend(r) - - # # Relevant to source kernel compilation - #for coFileMap_, files, kho in rvs: - # filesToWrite.append(files) - # kernelHelperObjs.extend(kho) - #kernelFiles = generateKernelSourceAndHeaderFiles(filesToWrite) - #with KernelFileContextManager(True, True, 1, outputPath, kernelFiles) as (srcFile, hdrFile): - # for ko in kernelHelperObjs: - # writeKernelHelpers(ko, srcFile, hdrFile, outputPath, kernelFiles) - #parallelFunc = functools.partial(buildSourceKernelObjectFile, cxxCompiler, outputPath, capabilities, rocmPaths, archInfo) - #basenames = Common.ParallelMap(parallelFunc, kernelFiles, cpuThreads, "Building Source Kernel Code objects", multiArg=False) - #results = buildSourceKernelCodeObjectFiles(cxxCompiler, basenames, outputPath, capabilities, rocmPaths, archInfo, removeTemporaries, cpuThreads) - #coFilenames = [] - #for result in results: - # coFilenames.extend(result) - #relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries) + for ko in rvs: + kho.extend(ko) + + # make into a function? + kernelsCpp = Path(outputPath) / "Kernels.cpp" + kernelsH = Path(outputPath) / "Kernels.h" + with open(kernelsCpp, "w") as srcFile, open(kernelsH, "w") as hdrFile: + for ko in kho: + writeKernelHelpers(ko, srcFile, hdrFile, outputPath) + basenames = buildSourceKernelObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, str(kernelsCpp)) + coFilenames = buildSourceKernelCodeObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, removeTemporaries, basenames) + relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries) + # make into a function? # # MSL creation # newLibraryDir = Path(outputPath) / "library" From 0ede207aad8f70b1a1bf79963ee1d1dec0e6f9be Mon Sep 17 00:00:00 2001 From: Braden Stefanuk <121893577+bstefanuk@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:21:15 +0000 Subject: [PATCH 2/4] feat: add msl creation to parallel run --- Tensile/SolutionLibrary.py | 17 ++++--- Tensile/TensileCreateLibrary.py | 80 +++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 29 deletions(-) diff --git a/Tensile/SolutionLibrary.py b/Tensile/SolutionLibrary.py index ea35474dd..d955eb6b4 100644 --- a/Tensile/SolutionLibrary.py +++ b/Tensile/SolutionLibrary.py @@ -275,12 +275,19 @@ def ArchitectureIndexMap(cls, architectureName: str) -> int: if archString is not None: archLiteral = archString.group(0) archval = (int(archLiteral, 16) << 18) + + # TODO(@bstefanuk) this section of code needs to be removed when dealing with + # parallel processing since each process may operate on multiple fallbacks that + # match a problem type. + # Check for duplicate architecture values - if archval >= 0 and not archval in cls.ArchitectureSet: - cls.ArchitectureSet.add(archval) - else: - tPrint(1, f"ERROR: Duplicate architecture value {archval} for {architectureName}, with arch set {cls.ArchitectureSet}") - raise RuntimeError("ERROR in architecture solution index mapping.") + # if archval >= 0 and not archval in cls.ArchitectureSet: + # cls.ArchitectureSet.add(archval) + # else: + # tPrint(1, f"ERROR: Duplicate architecture value {archval} for {architectureName}, with arch set {cls.ArchitectureSet}") + # raise RuntimeError("ERROR in architecture solution index mapping.") + + cls.ArchitectureSet.add(archval) return archval @classmethod diff --git a/Tensile/TensileCreateLibrary.py b/Tensile/TensileCreateLibrary.py index 36037e0de..7551c0924 100644 --- a/Tensile/TensileCreateLibrary.py +++ b/Tensile/TensileCreateLibrary.py @@ -43,7 +43,6 @@ from io import TextIOWrapper from pathlib import Path from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple, Union -from itertools import chain from . import Common, LibraryIO, Utils from .Kernel import Name @@ -77,6 +76,7 @@ from .Utilities.toFile import toFile from .Utilities.String import splitDelimitedString from .Utilities.RequiredParameters import getRequiredParametersMin +from .Contractions import Solution as ContractionSolution TENSILE_MANIFEST_FILENAME = "TensileManifest.txt" TENSILE_LIBRARY_DIR = "library" @@ -834,30 +834,30 @@ def generateKernelObjectsFromSolutions(kernels: List[Solution]): return helpers -def addNewLibrary( - masterLibraries: Dict[str, MasterSolutionLibrary], - newLibrary: MasterSolutionLibrary, - architectureName: str, -) -> int: - """Adds new master solution library to a master solution libraries dict. +# def addNewLibrary( +# masterLibraries: Dict[str, MasterSolutionLibrary], +# newLibrary: MasterSolutionLibrary, +# architectureName: str, +# ) -> int: +# """Adds new master solution library to a master solution libraries dict. - For a given architecture, add the new library to a dictionary containing - libraries for all architectures, compute the starting index for the new - library, then remap the indexes for all of the solutions associated with - the library. +# For a given architecture, add the new library to a dictionary containing +# libraries for all architectures, compute the starting index for the new +# library, then remap the indexes for all of the solutions associated with +# the library. - Args: - masterLibraries: A dictionary containing all master solution libraries for all architectures. - newLibrary: A master solution library to add to the dictionary. - architectureName: The name of the architecture (or key) associated with the library. +# Args: +# masterLibraries: A dictionary containing all master solution libraries for all architectures. +# newLibrary: A master solution library to add to the dictionary. +# architectureName: The name of the architecture (or key) associated with the library. - Returns: - Index to the last solution of the library associated with current architecture. - """ - masterLibraries[architectureName] = newLibrary - archIndex = MasterSolutionLibrary.ArchitectureIndexMap(architectureName) - masterLibraries[architectureName].remapSolutionIndicesStartingFrom(archIndex) - return archIndex +# Returns: +# Index to the last solution of the library associated with current architecture. +# """ +# masterLibraries[architectureName] = newLibrary +# archIndex = MasterSolutionLibrary.ArchitectureIndexMap(architectureName) +# masterLibraries[architectureName].remapSolutionIndicesStartingFrom(archIndex) +# return archIndex def updateMasterLibrary( @@ -870,7 +870,24 @@ def updateMasterLibrary( if gfxName in masterLibraries: nextIdx[gfxName] = masterLibraries[gfxName].merge(masterLib, nextIdx[gfxName]) else: - nextIdx[gfxName] = addNewLibrary(masterLibraries, masterLib, gfxName) + masterLibraries[gfxName] = masterLib + archIndex = MasterSolutionLibrary.ArchitectureIndexMap(gfxName) + masterLibraries[gfxName].remapSolutionIndicesStartingFrom(archIndex) + nextIdx[gfxName] = archIndex + + +# def updateMasterLibrary2( +# gfxName: str, +# masterLib: MasterSolutionLibrary, +# masterLibPrev: MasterSolutionLibrary, +# nextIdx: int, +# ) -> None: +# if masterLibPrev is not None: +# nextIdx = masterLibPrev.merge(masterLib, nextIdx) +# else: +# masterLibPrev = masterLib +# nextIdx = MasterSolutionLibrary.ArchitectureIndexMap(gfxName) +# masterLibPrev.remapSolutionIndicesStartingFrom(nextIdx) def addFallbacksToMasterLibraries(masterLibraries: Dict[str, MasterSolutionLibrary], caps, archInfo) -> None: @@ -963,7 +980,7 @@ def parseLibraryLogicFiles( #for d in logicFiles: # print(d) files = glob.glob(logicFiles + "/*.yaml") - print(files) + # print(files) for f in files: print(f) yamlDict = LibraryIO.readYAML(f) @@ -1054,6 +1071,21 @@ def run( kernelWriterAssembly, ) + masterLibraries = {} + nextSolutionIdx = {} + for _, gfxName, _, _, _, lib in libraryLogics: + updateMasterLibrary(gfxName, lib, masterLibraries, nextSolutionIdx) + + tPrint(0, f"masterLibraries: {masterLibraries}") + + newLibraryDir = Path(outputPath) / "library" + newLibraryDir.mkdir(exist_ok=True) + for masterLib in masterLibraries.values(): + for name, lib in list(masterLib.lazyLibraries.items()): + tPrint(1, f"Writing MSLibrary: {name}") + lib.applyNaming(getRequiredParametersMin()) # <-- This should be able to be replaced directly with `name`? + LibraryIO.write(str(newLibraryDir / name), Utils.state(lib), args["LibraryFormat"]) + coFileMap = gatherCOFilesForLinking(asmKernels, kernelMinNaming) return getAssemblyCodeObjectFiles( From bcd548d29fd507e4899ae059ad9c503c86969264 Mon Sep 17 00:00:00 2001 From: Braden Stefanuk <121893577+bstefanuk@users.noreply.github.com> Date: Wed, 13 Nov 2024 07:24:41 +0000 Subject: [PATCH 3/4] draft: msl reintegrate --- Tensile/SolutionLibrary.py | 24 ++-- Tensile/TensileCreateLibrary.py | 232 ++++++++++++++++---------------- 2 files changed, 129 insertions(+), 127 deletions(-) diff --git a/Tensile/SolutionLibrary.py b/Tensile/SolutionLibrary.py index d955eb6b4..bd6337fbc 100644 --- a/Tensile/SolutionLibrary.py +++ b/Tensile/SolutionLibrary.py @@ -246,11 +246,20 @@ def remapSolutionIndices(self, indexMap): for row in self.rows: row["library"].remapSolutionIndices(indexMap) + def __repr__(self) -> str: + return str(self.rows) + class MasterSolutionLibrary: StateKeys = ["solutions", "library"] ArchitectureSet = set() + def __init__(self, solutions, library, version=None): + self.lazyLibraries = {} + self.solutions = solutions + self.library = library + self.version = version + @classmethod def ArchitectureIndexMap(cls, architectureName: str) -> int: """Maps hex characters from gfx name to an index. @@ -462,10 +471,10 @@ def selection(d, problemType, solutions, library, placeholderName): library = None placeholderName = "TensileLibrary" placeholderLibrary = None - for libName in reversed(libraryOrder): - library, placeholderName = libName(origData, problemType, allSolutions, library, + for updateNameFunc in reversed(libraryOrder): + library, placeholderName = updateNameFunc(origData, problemType, allSolutions, library, placeholderName) - if libName == placeholder: + if updateNameFunc == placeholder: placeholderLibrary = library solutions = {s.index: s for s in allSolutions} @@ -493,12 +502,6 @@ def BenchmarkingLibrary(cls, solutions): return cls(solutionMap, library) - def __init__(self, solutions, library, version=None): - self.lazyLibraries = {} - self.solutions = solutions - self.library = library - self.version = version - def state(self): rv = { "solutions": state(iter(list(self.solutions.values()))), @@ -606,6 +609,9 @@ def merge(self, other, startIndex=0): return curIndex #Next unused index + def __repr__(self) -> str: + return str(self.library) + @property def cpp_base_class(self): return "SolutionLibrary" diff --git a/Tensile/TensileCreateLibrary.py b/Tensile/TensileCreateLibrary.py index 7551c0924..5e41f4121 100644 --- a/Tensile/TensileCreateLibrary.py +++ b/Tensile/TensileCreateLibrary.py @@ -270,7 +270,7 @@ def buildSourceKernelObjectFile( + [kernelFile, "-c", "-o", os.path.join(buildPath, objectFilename)] ) - tPrint(0, f"Build object file command: {compileArgs}") + tPrint(2, f"Build object file command: {compileArgs}") # change to use check_output to force windows cmd block util command finish try: out = subprocess.check_output(compileArgs, stderr=subprocess.STDOUT) @@ -326,7 +326,7 @@ def setInOutFlags(): def buildSourceKernelCodeObjectFile( - CxxCompiler, outputPath, base, caps: Capabilities, rocmPaths: RocmPaths, archInfo: ArchInfo, removeTemporaries + CxxCompiler, outputPath, caps: Capabilities, rocmPaths: RocmPaths, archInfo: ArchInfo, removeTemporaries, base ): buildPath = Path(outputPath).parent / Path("build_tmp") / Path(outputPath).stem.upper() / "code_object_tmp" destDir = Path(outputPath) / "library" @@ -381,11 +381,11 @@ def buildSourceKernelCodeObjectFiles(CxxCompiler, baseNames, outputPath, caps, r args = zip( itertools.repeat(CxxCompiler), itertools.repeat(outputPath), - baseNames, itertools.repeat(caps), itertools.repeat(rocmPaths), - itertools.repeat(archInfo), + itertools.repeat(archInfo), itertools.repeat(removeTemporaries), + baseNames, ) return Common.ParallelMap(buildSourceKernelCodeObjectFile, args, cores, "Compiling source kernels") @@ -474,8 +474,6 @@ def prepAsm( def collectFilesToWrite( results: List[ProcessedKernelResult], outputPath: Path, - lazyLoading: bool, - numMergedFiles: int, ) -> ProcessedKernelLookup: """Collects and organizes kernel files to be written based on the provided results. @@ -499,21 +497,11 @@ def collectFilesToWrite( for err, src, header, kernelName, filename in results: if not src.strip(): continue - kernPath = pathJoin(kernelName) + if filename: kernPath = pathJoin(filename) - else: - suffix = str(validKernelCount % numMergedFiles) if numMergedFiles > 1 else "" - kernPath = pathJoin(f"Kernels{suffix}") - - srcKernelMap[kernPath].append(ProcessedKernelResult(err, src, header, kernelName)) - validKernelCount += 1 - - # Ensure there's at least one kernel file for helper kernels - if lazyLoading or (validKernelCount == 0): - kernelSuffix = "0" if numMergedFiles > 1 else "" - srcKernelMap[pathJoin(f"Kernels{kernelSuffix}")] = [] + srcKernelMap[kernPath].append(ProcessedKernelResult(err, src, header, kernelName)) return srcKernelMap @@ -554,7 +542,7 @@ def writeSourcePreface(srcFile, filename): # fmt: on writeHeaderPreface(hdrFile) writeSourcePreface(srcFile, filename) - for _, src, header, _ in kernelList: + for _, src, header, _, _ in kernelList: srcFile.write(src) hdrFile.write(header) @@ -698,8 +686,6 @@ def writeKernelHelpers( kernelHelperObj: KernelWriterBase, kernelSourceFile: Optional[TextIOWrapper], kernelHeaderFile: Optional[TextIOWrapper], - outputPath: Path, - kernelFiles: List[str], ): """Writes the source and header code generated by a kernel helper object to specified files or a new file. @@ -727,25 +713,47 @@ def writeKernelHelpers( toFile(kernelHeaderFile, hdrCode) -################################################################################ -# Write Solutions and Kernels for BenchmarkClient or LibraryClient -################################################################################ +def relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries): + buildPath = Path(outputPath).parent / Path("build_tmp") / Path(outputPath).stem.upper() / "code_object_tmp" + destDir = Path(outputPath) / "library" + + extractedCOs = [os.path.join(buildPath, name) for name in coFilenames] + destCOsList = [os.path.join(destDir, name) for name in coFilenames] + for src, dst in zip(extractedCOs, destCOsList): + if removeTemporaries: + shutil.move(src, dst) + else: + shutil.copyfile(src, dst) + + def writeSourceKernels( outputPath: str, params: Dict[str, Any], kernels: List[Solution], kernelWriterSource: KernelWriterSource, + cxxCompiler, + capabilities, + rocmPaths, + archInfo, + removeTemporaries ): start = time.time() + outPath = Path(outputPath) results = [processKernelSource(k, kernelWriterSource) for k in kernels] - srcKernelMap= collectFilesToWrite(results, outPath, params["LazyLibraryLoading"], numMergedFiles=1) + srcKernelMap = collectFilesToWrite(results, outPath) + kernelFiles = generateKernelSourceAndHeaderFiles(srcKernelMap) + basenames = [buildSourceKernelObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, k) for k in kernelFiles] + coFilenames = [buildSourceKernelCodeObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, removeTemporaries, basename) for basename in basenames] + for cofileList in coFilenames: + relocateSourceKernelCodeObjectFiles(cofileList, outputPath, removeTemporaries) + stop = time.time() total = stop - start numKernels = len(srcKernelMap) tPrint(1, f"# Source kernel Writing elapsed time = {total} secs, kps = {float(numKernels)/total}, kernels = {numKernels}") - return srcKernelMap + return kernelFiles # should be writeAssemblyKernelsAndBuildCodeObjects @@ -876,19 +884,22 @@ def updateMasterLibrary( nextIdx[gfxName] = archIndex -# def updateMasterLibrary2( -# gfxName: str, -# masterLib: MasterSolutionLibrary, -# masterLibPrev: MasterSolutionLibrary, -# nextIdx: int, -# ) -> None: -# if masterLibPrev is not None: -# nextIdx = masterLibPrev.merge(masterLib, nextIdx) -# else: -# masterLibPrev = masterLib -# nextIdx = MasterSolutionLibrary.ArchitectureIndexMap(gfxName) -# masterLibPrev.remapSolutionIndicesStartingFrom(nextIdx) - +def updateMasterLibrary2( + gfxName: str, + currMasterLib: MasterSolutionLibrary, + prevMasterLib: MasterSolutionLibrary, + nextIdx: int, +) -> None: + if prevMasterLib is not None: + nextIdx = prevMasterLib.merge(currMasterLib, nextIdx) + else: + prevMasterLib = currMasterLib + nextIndex = MasterSolutionLibrary.ArchitectureIndexMap(gfxName) + prevMasterLib.remapSolutionIndicesStartingFrom(nextIndex) + # nextIdx[gfxName] = archIndex + + tPrint(0, f"gfxNames in MSL: {prevMasterLib}") + return prevMasterLib, nextIdx def addFallbacksToMasterLibraries(masterLibraries: Dict[str, MasterSolutionLibrary], caps, archInfo) -> None: """Adds fallback library. @@ -976,13 +987,8 @@ def parseLibraryLogicFiles( List of library logic tuples. """ libraryLogics = [] - #print(logicFiles) - #for d in logicFiles: - # print(d) files = glob.glob(logicFiles + "/*.yaml") - # print(files) for f in files: - print(f) yamlDict = LibraryIO.readYAML(f) logic = LibraryIO.parseLibraryLogicData(yamlDict, caps) libraryLogics.append(logic) @@ -1035,6 +1041,7 @@ def run( removeTemporaries, outputPath, args, + cxxCompiler, capabilities: Capabilities, rocmPaths: RocmPaths, archInfo: ArchInfo, @@ -1042,69 +1049,59 @@ def run( logicFiles, ): procnum = os.getpid() - tPrint(0, f"processing on: {procnum}") libraryLogics = parseLibraryLogicFiles(logicFiles, capabilities) solns = list(generateSolutions(libraryLogics)) kernels = list((s.getKernels() for s in solns)) # tPrint(0, f"Library logic file: {logicFiles}, kernels: {kernels}") - kernelHelperObjs = generateKernelObjectsFromSolutions(kernels) asmDir = Path(os.path.join(Path(outputPath).parent, "build_tmp", Path(outputPath).stem.upper(), "assembly")) asmDir.mkdir(parents=True, exist_ok=True) kernelWriterSource, kernelWriterAssembly = getKernelWriters( kernels, removeTemporaries, rocmPaths, capabilities, archInfo, str(asmDir), kernelMinNaming ) - #srcKernels = [k for k in kernels if k["KernelLanguage"] == "Source"] - #filesToWrite = writeSourceKernels( - # outputPath, - # args, - # srcKernels, - # kernelWriterSource, - #) + srcKernels = [k for k in kernels if k["KernelLanguage"] == "Source"] + if srcKernels: + kernelFiles = writeSourceKernels( + outputPath, + args, + srcKernels, + kernelWriterSource, + cxxCompiler, + capabilities, + rocmPaths, + archInfo, + kernelMinNaming, + ) + asmKernels = [k for k in kernels if k["KernelLanguage"] == "Assembly"] - asmKernels = writeAssemblyKernels( - outputPath, - asmKernels, - kernelWriterAssembly, - ) + if asmKernels: + asmKernels = writeAssemblyKernels( + outputPath, + asmKernels, + kernelWriterAssembly, + ) - masterLibraries = {} - nextSolutionIdx = {} + coFileMap = gatherCOFilesForLinking(asmKernels, kernelMinNaming) + getAssemblyCodeObjectFiles(coFileMap, outputPath) + + _masterLib = None + _nextSolutionIdx = 0 for _, gfxName, _, _, _, lib in libraryLogics: - updateMasterLibrary(gfxName, lib, masterLibraries, nextSolutionIdx) + _masterLib, _nextSolutionIdx = updateMasterLibrary2(gfxName, lib, _masterLib, _nextSolutionIdx) - tPrint(0, f"masterLibraries: {masterLibraries}") + tPrint(0, f"masterLibraries: {_masterLib}") newLibraryDir = Path(outputPath) / "library" newLibraryDir.mkdir(exist_ok=True) - for masterLib in masterLibraries.values(): - for name, lib in list(masterLib.lazyLibraries.items()): - tPrint(1, f"Writing MSLibrary: {name}") - lib.applyNaming(getRequiredParametersMin()) # <-- This should be able to be replaced directly with `name`? - LibraryIO.write(str(newLibraryDir / name), Utils.state(lib), args["LibraryFormat"]) - - coFileMap = gatherCOFilesForLinking(asmKernels, kernelMinNaming) - - return getAssemblyCodeObjectFiles( - coFileMap, - outputPath, - ) + for name, lib in list(_masterLib.lazyLibraries.items()): + tPrint(1, f"Writing MSLibrary: {name}") + lib.applyNaming(getRequiredParametersMin()) # <-- This should be able to be replaced directly with `name`? + LibraryIO.write(str(newLibraryDir / name), Utils.state(lib), args["LibraryFormat"]) - -# # Relevant to source kernel compilation -# def relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries): -# buildPath = Path(outputPath).parent / Path("build_tmp") / Path(outputPath).stem.upper() / "code_object_tmp" -# destDir = Path(outputPath) / "library" -# extractedCOs = [os.path.join(buildPath, name) for name in set(coFilenames)] -# destCOsList = [os.path.join(destDir, name) for name in set(coFilenames)] -# for src, dst in zip(extractedCOs, destCOsList): -# if removeTemporaries: -# shutil.move(src, dst) -# else: -# shutil.copyfile(src, dst) + return generateKernelObjectsFromSolutions(kernels), libraryLogics @profile @@ -1142,7 +1139,7 @@ def TensileCreateLibrary(): kernelMinNaming = getRequiredParametersMin() - parallelFunc = functools.partial(run, removeTemporaries, outputPath, args, capabilities, rocmPaths, archInfo, kernelMinNaming) + parallelFunc = functools.partial(run, removeTemporaries, outputPath, args, cxxCompiler, capabilities, rocmPaths, archInfo, kernelMinNaming) logicFiles = list(findLogicFiles(Path(logicPath), logicArchs)) @@ -1150,45 +1147,44 @@ def TensileCreateLibrary(): chunk_size = int(total / numPasses) remainder = total % numPasses - coFiles = [] + kho = [] + masterLibs = {} + nextIdx = {} for p in range(0, numPasses): start = p * chunk_size stop = (p+1) * chunk_size rvs = Common.ParallelMap(parallelFunc, logicFiles[start:stop], cpuThreads, "Running TCL...", multiArg=False) - for r in rvs: - coFiles.extend(r) + for ko, libLogics in rvs: + kho.extend(ko) + for _, gfxName, _, _, _, lib in libLogics: + updateMasterLibrary(gfxName, lib, masterLibs, nextIdx) if remainder: rvs = Common.ParallelMap(parallelFunc, logicFiles[-remainder:], cpuThreads, "Running TCL...", multiArg=False) - for r in rvs: - coFiles.extend(r) - - # # Relevant to source kernel compilation - #for coFileMap_, files, kho in rvs: - # filesToWrite.append(files) - # kernelHelperObjs.extend(kho) - #kernelFiles = generateKernelSourceAndHeaderFiles(filesToWrite) - #with KernelFileContextManager(True, True, 1, outputPath, kernelFiles) as (srcFile, hdrFile): - # for ko in kernelHelperObjs: - # writeKernelHelpers(ko, srcFile, hdrFile, outputPath, kernelFiles) - #parallelFunc = functools.partial(buildSourceKernelObjectFile, cxxCompiler, outputPath, capabilities, rocmPaths, archInfo) - #basenames = Common.ParallelMap(parallelFunc, kernelFiles, cpuThreads, "Building Source Kernel Code objects", multiArg=False) - #results = buildSourceKernelCodeObjectFiles(cxxCompiler, basenames, outputPath, capabilities, rocmPaths, archInfo, removeTemporaries, cpuThreads) - #coFilenames = [] - #for result in results: - # coFilenames.extend(result) - #relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries) + for ko in rvs: + kho.extend(ko) + + # make into a function? + kernelsCpp = Path(outputPath) / "Kernels.cpp" + kernelsH = Path(outputPath) / "Kernels.h" + with open(kernelsCpp, "w") as srcFile, open(kernelsH, "w") as hdrFile: + for ko in kho: + writeKernelHelpers(ko, srcFile, hdrFile, outputPath) + basenames = buildSourceKernelObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, str(kernelsCpp)) + coFilenames = buildSourceKernelCodeObjectFile(cxxCompiler, outputPath, capabilities, rocmPaths, archInfo, removeTemporaries, basenames) + relocateSourceKernelCodeObjectFiles(coFilenames, outputPath, removeTemporaries) + # make into a function? # # MSL creation - # newLibraryDir = Path(outputPath) / "library" - # newLibraryDir.mkdir(exist_ok=True) - # baseName = "TensileLibrary_" - # if "fallback" in masterLibraries: - # addFallbacksToMasterLibraries(masterLibraries, capabilities, archInfo) - # for arch, masterLib in masterLibraries.items(): - # for name, lib in [(baseName + "lazy_" + arch, masterLib)] + list(masterLib.lazyLibraries.items()): - # tPrint(1, f"Writing MSLibrary: {name}") - # lib.applyNaming(getRequiredParametersMin()) # <-- This should be able to be replaced directly with `name`? - # LibraryIO.write(str(newLibraryDir / name), Utils.state(lib), args["LibraryFormat"]) + newLibraryDir = Path(outputPath) / "library" + newLibraryDir.mkdir(exist_ok=True) + baseName = "TensileLibrary_" + if "fallback" in masterLibs: + addFallbacksToMasterLibraries(masterLibs, capabilities, archInfo) + for arch, masterLib in masterLibs.items(): + name = baseName + "lazy_" + arch + tPrint(1, f"Writing MSLibrary FINAL: {name}") + masterLib.applyNaming(getRequiredParametersMin()) # <-- This should be able to be replaced directly with `name`? + LibraryIO.write(str(newLibraryDir / name), Utils.state(masterLib), args["LibraryFormat"]) if removeTemporaries: buildTmp = Path(outputPath).parent / "build_tmp" From bf4a1eadad1b8dca167c8c1aa45192e66de8e1b8 Mon Sep 17 00:00:00 2001 From: David Dixon Date: Wed, 13 Nov 2024 21:24:16 +0000 Subject: [PATCH 4/4] Minor updates to TCL remove global state --- Tensile/Common.py | 31 +++++++++++++++++-------------- Tensile/TensileCreateLibrary.py | 26 ++++++++++---------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/Tensile/Common.py b/Tensile/Common.py index 32116e583..b250f7a56 100644 --- a/Tensile/Common.py +++ b/Tensile/Common.py @@ -441,19 +441,6 @@ def supportedCompiler(compiler: str) -> bool: validMFMA["I8"] = validMFMA["H"] + validMFMA["F8"] validWMMA = [[16,16,16,1], ] validTT = 64 -validMFMA["_format9"] = [] - -for MFMA in [validMFMA["H"], validMFMA["S"], validMFMA["B"], validMFMA["D"], validMFMA["X"], validMFMA["F8"], validWMMA]: - for MI in MFMA: - for bm in range(int(math.log(MI[3],2))+1): - for tt0 in range(1,validTT+1): - for tt1 in range(1,validTT+1): - for wave_m in range (3): - for wave_n in range(3): - validMFMA["_format9"].append([MI[0],MI[1],MI[2],MI[3],2**bm,tt0,tt1,2**wave_m, 2**wave_n]) - -validMatrixInstructions = [[], [-1]] + validMFMA["H"] + validMFMA["S"] + validMFMA["B"] + validMFMA["D"] + validMFMA["X"] + validMFMA["F8"] -validMatrixInstructions = validMatrixInstructions + validMFMA["_format9"] # The supported typed GEMM, each entry is (Ti, To, Tc). # DataType (Ti) = The data-type of the input matrices: A/B @@ -1060,7 +1047,7 @@ def supportedCompiler(compiler: str) -> bool: # MatrixInst BlkM WT Wave # - means (32x64) per MI * (4x1) per wave * (2x2) per workgroup = (32*4*2)x(64*1*2) = 256x128 macro tile # Tensile will ignore the parameters ThreadTile and WorkGroup when the alternative format is used - "MatrixInstruction": validMatrixInstructions, + "MatrixInstruction": -1, # StoreRemap: Optimize MatrixInstruction store patterns to enhance performance. # MI output data between each threads are along N dims. @@ -2407,6 +2394,22 @@ def assignGlobalParameters( config, capabilitiesCache: Optional[dict] = None ): """ global globalParameters + if False: + validMFMA["_format9"] = [] + + for MFMA in [validMFMA["H"], validMFMA["S"], validMFMA["B"], validMFMA["D"], validMFMA["X"], validMFMA["F8"], validWMMA]: + for MI in MFMA: + for bm in range(int(math.log(MI[3],2))+1): + for tt0 in range(1,validTT+1): + for tt1 in range(1,validTT+1): + for wave_m in range (3): + for wave_n in range(3): + validMFMA["_format9"].append([MI[0],MI[1],MI[2],MI[3],2**bm,tt0,tt1,2**wave_m, 2**wave_n]) + + validMatrixInstructions = [[], [-1]] + validMFMA["H"] + validMFMA["S"] + validMFMA["B"] + validMFMA["D"] + validMFMA["X"] + validMFMA["F8"] + validMatrixInstructions = validMatrixInstructions + validMFMA["_format9"] + validParameters["MatrixInstruction"] = validMatrixInstructions + # Minimum Required Version if "MinimumRequiredVersion" in config: if not versionIsCompatible(config["MinimumRequiredVersion"]): diff --git a/Tensile/TensileCreateLibrary.py b/Tensile/TensileCreateLibrary.py index 1c267fcfe..8a59bcd5f 100644 --- a/Tensile/TensileCreateLibrary.py +++ b/Tensile/TensileCreateLibrary.py @@ -751,7 +751,7 @@ def writeSourceKernels( stop = time.time() total = stop - start numKernels = len(srcKernelMap) - tPrint(1, f"# Source kernel Writing elapsed time = {total} secs, kps = {float(numKernels)/total}, kernels = {numKernels}") + tPrint(2, f"# Source kernel Writing elapsed time = {total} secs, kps = {float(numKernels)/total}, kernels = {numKernels}") return kernelFiles @@ -779,7 +779,7 @@ def writeAssemblyKernels( stop = time.time() total = stop-start numKernels = len(kernelsToBuild) - tPrint(1, f"# Assembly kernel Building elapsed time = {total} secs, kps = {float(numKernels)/total}, kernels = {numKernels}") + tPrint(2, f"# Assembly kernel Building elapsed time = {total} secs, kps = {float(numKernels)/total}, kernels = {numKernels}") return kernelsToBuild # we realy just need the .co files on disk @@ -1031,12 +1031,10 @@ def run( kernelMinNaming, logicFiles, ): - procnum = os.getpid() libraryLogics = parseLibraryLogicFiles(logicFiles, capabilities) solns = list(generateSolutions(libraryLogics)) - kernels = list((s.getKernels() for s in solns)) - # tPrint(0, f"Library logic file: {logicFiles}, kernels: {kernels}") + kernels = list(s.getKernels() for s in solns) asmDir = Path(os.path.join(Path(outputPath).parent, "build_tmp", Path(outputPath).stem.upper(), "assembly")) asmDir.mkdir(parents=True, exist_ok=True) @@ -1058,8 +1056,6 @@ def run( kernelMinNaming, ) - #kernelHelperObjs = generateKernelObjectsFromSolutions(kernels) - asmKernels = [k for k in kernels if k["KernelLanguage"] == "Assembly"] if asmKernels: asmKernels = writeAssemblyKernels( @@ -1072,7 +1068,8 @@ def run( getAssemblyCodeObjectFiles(coFileMap, outputPath) return generateKernelObjectsFromSolutions(kernels) - + #return getAssemblyCodeObjectFiles(coFileMap, outputPath) + #return os.getpid() @profile def TensileCreateLibrary(): @@ -1115,19 +1112,16 @@ def TensileCreateLibrary(): total = len(logicFiles) chunk_size = int(total / numPasses) - remainder = total % numPasses kho = [] for p in range(0, numPasses): + print(f"pass {p}") start = p * chunk_size - stop = (p+1) * chunk_size + stop = total if p == numPasses - 1 else (p+1) * chunk_size rvs = Common.ParallelMap(parallelFunc, logicFiles[start:stop], cpuThreads, "Running TCL...", multiArg=False) - for ko in rvs: - kho.extend(ko) - if remainder: - rvs = Common.ParallelMap(parallelFunc, logicFiles[-remainder:], cpuThreads, "Running TCL...", multiArg=False) - for ko in rvs: - kho.extend(ko) + for rv in rvs: + kho.extend(rv) + print(f"processing {rv}") # make into a function? kernelsCpp = Path(outputPath) / "Kernels.cpp"