Beispiel #1
0
def readSolutions(filename):
    try:
        stream = open(filename, "r")
    except IOError:
        printExit("Cannot open file: %s" % filename)
    solutionStates = yaml.load(stream, yaml.SafeLoader)
    stream.close()

    # verify
    if len(solutionStates) < 2:
        printExit("len(%s) %u < 2" % (filename, len(solutionStates)))
    versionString = solutionStates[0]["MinimumRequiredVersion"]
    if not versionIsCompatible(versionString):
        printWarning("File \"%s\" version=%s does not match current Tensile version=%s" \
            % (filename, versionString, __version__) )

    if "ProblemSizes" not in solutionStates[1]:
        printExit("%s doesn't begin with ProblemSizes" % filename)
    else:
        problemSizesConfig = solutionStates[1]["ProblemSizes"]

    solutions = []
    for i in range(2, len(solutionStates)):
        solutionState = solutionStates[i]
        solutionObject = Solution(solutionState)
        solutions.append(solutionObject)
    problemType = solutions[0]["ProblemType"]
    problemSizes = ProblemSizes(problemType, problemSizesConfig)
    return (problemSizes, solutions)
Beispiel #2
0
    def __init__(self, problemTypeConfig, problemSizeGroupConfig):
        # read problem type
        #if "ProblemType" in config:
        #  problemTypeConfig = config["ProblemType"]
        #else:
        #  problemTypeConfig = {}
        #  print2("No ProblemType in config: %s; using defaults." % str(config) )
        self.problemType = ProblemType(problemTypeConfig)
        self.isBatched = True \
            if "Batched" in problemTypeConfig and problemTypeConfig["Batched"] \
            else False
        print2("# BenchmarkProcess beginning %s" % str(self.problemType))

        # read initial solution parameters
        self.initialSolutionParameters = {"ProblemType": problemTypeConfig}
        self.initialSolutionParameters.update(defaultSolution)
        if "InitialSolutionParameters" not in problemSizeGroupConfig:
            print2("No InitialSolutionParameters; using defaults.")
        else:
            if problemSizeGroupConfig["InitialSolutionParameters"] != None:
                for paramDict in problemSizeGroupConfig[
                        "InitialSolutionParameters"]:
                    for paramName in paramDict:
                        paramValueList = paramDict[paramName]
                        if isinstance(paramValueList, list):
                            if len(paramValueList) != 1:
                                printWarning(
                                    "InitialSolutionParameters must have length=1: %s:%s"
                                    % (paramName, paramValueList))
                            self.initialSolutionParameters[
                                paramName] = paramValueList[0]
                        else:
                            self.initialSolutionParameters[
                                paramName] = paramValueList
        print2("# InitialSolutionParameters: %s" %
               str(self.initialSolutionParameters))

        # fill in missing steps using defaults
        self.benchmarkCommonParameters = []
        self.forkParameters = []
        self.benchmarkForkParameters = []
        self.joinParameters = []
        self.benchmarkJoinParameters = []
        self.benchmarkFinalParameters = []
        self.benchmarkSteps = []
        self.hardcodedParameters = [{}]
        self.singleValueParameters = {}

        # (I)
        self.fillInMissingStepsWithDefaults(self.isBatched,
                                            problemSizeGroupConfig)

        # convert list of parameters to list of steps
        self.currentProblemSizes = []
        self.benchmarkStepIdx = 0

        # (II)
        self.convertParametersToSteps()
Beispiel #3
0
def readLibraryLogicForSchedule(filename):
    print1("# Reading Library Logic: %s" % (filename))
    try:
        stream = open(filename, "r")
    except IOError:
        printExit("Cannot open file: %s" % filename)
    data = yaml.load(stream, yaml.SafeLoader)
    stream.close()

    # verify
    if len(data) < 6:
        printExit("len(%s) %u < 7" % (filename, len(data)))

    # parse out objects
    versionString = data[0]["MinimumRequiredVersion"]
    scheduleName = data[1]
    architectureName = data[2]
    deviceNames = data[3]
    problemTypeState = data[4]
    solutionStates = data[5]
    indexOrder = data[6]
    exactLogic = data[7]
    rangeLogic = data[8]

    # does version match
    if not versionIsCompatible(versionString):
        printWarning("File \"%s\" version=%s does not match Tensile version=%s" \
            % (filename, versionString, __version__) )

    # unpack problemType
    problemType = ProblemType(problemTypeState)
    # unpack solutions
    solutions = []
    for i in range(0, len(solutionStates)):
        solutionState = solutionStates[i]
        if solutionState["KernelLanguage"] == "Assembly":
            isa0 = int(architectureName[3])
            isa1 = int(architectureName[4])
            isa2 = int(architectureName[5])
            solutionState["ISA"] = (isa0, isa1, isa2)
        else:
            solutionState["ISA"] = (0, 0, 0)
        solutionObject = Solution(solutionState)
        if solutionObject["ProblemType"] != problemType:
            printExit("ProblemType of file doesn't match solution: %s != %s" \
                % (problemType, solutionObject["ProblemType"]))
        solutions.append(solutionObject)

    return (scheduleName, deviceNames, problemType, solutions, indexOrder, \
        exactLogic, rangeLogic )
Beispiel #4
0
def getResults(resultsFileName, solutions):
    try:
        resultsFile = open(resultsFileName, "r")
    except IOError:
        printExit("Can't open \"%s\" to get results" % resultsFileName)

    # setup data structures
    numSolutions = 0
    results = []
    for solutionsForHardcoded in solutions:
        results.append([])
        for solution in solutionsForHardcoded:
            problemSizeIdx = solution["ProblemType"]["TotalIndices"] + 1
            results[-1].append([])
            numSolutions += 1

    # read results in gflops
    csvFile = csv.reader(resultsFile)
    startIdx = problemSizeIdx + 1
    rowLength = startIdx + numSolutions

    rowIdx = 0
    for row in csvFile:
        rowIdx += 1
        if rowIdx == 1:
            continue
        else:
            if len(row) < rowLength:
                printWarning("CSV File %s row %u doesn't have %u elements; ignoring remainer of file." \
                    % (resultsFileName, rowIdx, rowLength) )
                break
            idx = startIdx
            for i in range(0, len(solutions)):
                solutionsForHardcoded = solutions[i]
                for j in range(0, len(solutionsForHardcoded)):
                    solution = solutionsForHardcoded[j]
                    gflops = float(row[idx])
                    results[i][j].append(gflops)
                    idx += 1
    if rowIdx < 2:
        printExit("CSV File %s only has %u row(s); prior benchmark must not have run long enough to produce data." \
            % (resultsFileName, rowIdx) )
    return results
Beispiel #5
0
def benchmarkProblemType( problemTypeConfig, problemSizeGroupConfig, \
    problemSizeGroupIdx ):

    benchmarkTestFails = 0

    # convert config to full benchmark process (resolves defaults)
    print1("")
    print1(HR)
    print1("# Converting Config to BenchmarkProcess Object")
    print1(HR)
    print1("")
    benchmarkProcess = BenchmarkProcess( problemTypeConfig, \
        problemSizeGroupConfig )

    problemTypeName = str(benchmarkProcess.problemType)
    problemSizeGroupName = "%s_%02u" % (problemTypeName, problemSizeGroupIdx)
    pushWorkingPath(problemSizeGroupName)
    ensurePath(os.path.join(globalParameters["WorkingPath"], "Data"))

    totalBenchmarkSteps = len(benchmarkProcess)
    resultsFileBaseFinal = None
    winners = WinningParameterDict()
    print1("# NumBenchmarkSteps: %u" % totalBenchmarkSteps)
    print1("")
    print1(HR)
    print1("# Done Creating BenchmarkProcess Object")
    print1(HR)

    ##############################################################################
    # For Each Benchmark Step
    ##############################################################################
    for benchmarkStepIdx in range(0, totalBenchmarkSteps):

        benchmarkStep = benchmarkProcess[benchmarkStepIdx]
        if winners.winners == {}:
            # perf optimization to skip the initial winners creation
            # this helps a little here but really helps below with avoiding the super-expensive
            # removeHardcoded step below - that can use a fast-path to create
            # winners when needed.
            print1(
                "# Empty winners - use fast initialization of hardcodedParameters"
            )
            resultingHardcodedParameterList = benchmarkStep.hardcodedParameters
        else:
            resultingHardcodedParameterList = \
                winners.wpdUpdate( benchmarkStep.hardcodedParameters )

        benchmarkStep.hardcodedParameters = resultingHardcodedParameterList
        numHardcoded = len(benchmarkStep.hardcodedParameters)
        stepName = str(benchmarkStep)
        shortName = benchmarkStep.abbreviation()
        print1("\n")
        print1(HR)
        currentTime = time.time()
        elapsedTime = currentTime - startTime
        print1("# BenchmarkStep: %s - %s %.3fs" %
               (problemSizeGroupName, stepName, elapsedTime))
        print1("# NumProblems: %u" %
               benchmarkStep.problemSizes.totalProblemSizes)
        print1("# BenchmarkParameters:")
        for paramName in benchmarkStep.benchmarkParameters:
            paramValues = benchmarkStep.benchmarkParameters[paramName]
            printStr = "#     %s = { %s" % (paramName, paramValues[0])
            for paramValueIdx in range(1, len(paramValues)):
                printStr += ", %s" % str(paramValues[paramValueIdx])
            printStr += " }"
            print1(printStr)

        if False:
            # print1(hardcoded parameters and their winners
            print1("# HardcodedParameters | WinningParameters:")
            paramDictIdx = 0
            hardcodedMinNaming = \
                Solution.getMinNaming(benchmarkStep.hardcodedParameters)
            for paramDict in benchmarkStep.hardcodedParameters:
                winningParameters = winners[paramDict]
                print1("#    (%u) %s | %s" % (paramDictIdx, \
                    Solution.getNameMin(paramDict, hardcodedMinNaming), \
                    Solution.getNameFull(winningParameters) ))
                paramDictIdx += 1
        pushWorkingPath(shortName)

        ############################################################################
        # Copy Files to Benchmark Source Directory
        ############################################################################
        stepBaseDir = globalParameters["WorkingPath"]
        sourceDir = \
          os.path.join(stepBaseDir, "source" )
        ensurePath(sourceDir)
        pushWorkingPath("sourceTmp")
        filesToCopy = [
            "SolutionMapper.h",
            "Client.cpp",
            "Client.h",
            "CMakeLists.txt",
            "DeviceStats.h",
            "TensorUtils.h",
            "MathTemplates.cpp",
            "MathTemplates.h",
            "TensileTypes.h",
            "tensile_bfloat16.h",
            "KernelHeader.h",
            "ReferenceCPU.h",
            "SolutionHelper.cpp",
            "SolutionHelper.h",
            "Tools.cpp",
            "Tools.h",
        ]

        for f in filesToCopy:
            shutil_copy(os.path.join(globalParameters["SourcePath"], f),
                        globalParameters["WorkingPath"])
        if globalParameters["RuntimeLanguage"] == "OCL":
            shutil_copy(
                os.path.join(globalParameters["SourcePath"],
                             "FindOpenCL.cmake"),
                globalParameters["WorkingPath"])
        else:
            shutil_copy(
                os.path.join(globalParameters["SourcePath"], "FindHIP.cmake"),
                globalParameters["WorkingPath"])
            shutil_copy(
                os.path.join(globalParameters["SourcePath"], "FindHCC.cmake"),
                globalParameters["WorkingPath"])

        ############################################################################
        # Enumerate Benchmark Permutations
        ############################################################################
        solutions = []
        totalBenchmarkPermutations = 1
        for benchmarkParamName in benchmarkStep.benchmarkParameters:
            totalBenchmarkPermutations *= len(
                benchmarkStep.benchmarkParameters[benchmarkParamName])
        maxPossibleSolutions = totalBenchmarkPermutations * numHardcoded
        print1("# MaxPossibleSolutions: %u = %u (hardcoded) * %u (benchmark)" % \
            (maxPossibleSolutions, numHardcoded, totalBenchmarkPermutations))

        benchmarkPermutations = []
        for i in range(0, totalBenchmarkPermutations):
            permutation = {}
            pIdx = i
            for benchmarkParamName in benchmarkStep.benchmarkParameters:
                benchmarkParamValues = deepcopy( \
                    benchmarkStep.benchmarkParameters[benchmarkParamName])
                valueIdx = pIdx % len(benchmarkParamValues)
                permutation[benchmarkParamName] = benchmarkParamValues[
                    valueIdx]
                pIdx /= len(benchmarkParamValues)
            benchmarkPermutations.append(permutation)

        ############################################################################
        # Enumerate Solutions = Hardcoded * Benchmark
        ############################################################################
        print1("# Enumerating Solutions")
        if globalParameters["PrintLevel"] >= 1:
            progressBar = ProgressBar(maxPossibleSolutions)
        solutionSet = set()  # avoid duplicates for nlca=-1, 1
        for hardcodedIdx in range(0, numHardcoded):
            solutions.append([])
            hardcodedParamDict = benchmarkStep.hardcodedParameters[
                hardcodedIdx]
            for benchmarkIdx in range(0, len(benchmarkPermutations)):
                benchmarkPermutation = benchmarkPermutations[benchmarkIdx]
                solution = {
                    "ProblemType": deepcopy(benchmarkProcess.problemType.state)
                }
                solution.update(benchmarkPermutation)
                solution.update(hardcodedParamDict)
                if benchmarkStepIdx > 0:
                    winningParameters = winners[hardcodedParamDict]
                    if winningParameters == None:
                        # this is a joined parameter that didn't have a winner, that's okay
                        continue
                    solution.update(winningParameters)

                # append default parameters where necessary
                for initialSolutionParameterName in benchmarkStep.initialSolutionParameters:
                    if initialSolutionParameterName not in solution:
                        solution[initialSolutionParameterName] = \
                            benchmarkStep.initialSolutionParameters[initialSolutionParameterName]
                # TODO check if solution matches problem size for exact tile kernels
                solutionObject = Solution(solution)
                if solutionObject["Valid"]:
                    if solutionObject not in solutionSet:
                        solutionSet.add(solutionObject)
                        solutions[hardcodedIdx].append(solutionObject)
                else:
                    if globalParameters["PrintSolutionRejectionReason"]:
                        print1("rejecting solution %s" % str(solutionObject))
                if globalParameters["PrintLevel"] >= 1:
                    progressBar.increment()

        # remove hardcoded that don't have any valid benchmarks
        removeHardcoded = []
        for hardcodedIdx in range(0, numHardcoded):
            if len(solutions[hardcodedIdx]) == 0:
                hardcodedParamDict = benchmarkStep.hardcodedParameters[
                    hardcodedIdx]
                removeHardcoded.append(hardcodedParamDict)
        removesExist = len(removeHardcoded) > 0
        for hardcodedParam in removeHardcoded:
            benchmarkStep.hardcodedParameters.remove(hardcodedParam)

        if removesExist:
            print1(
                "# Updating winners since enumeration removed unused hardcoded solutions.  removeHardcoded=%u winners=%u"
                % (len(removeHardcoded), len(winners.winners)))
            winners.wpdUpdate(benchmarkStep.hardcodedParameters)
            if globalParameters["PrintLevel"] >= 1:
                print1("")
            numHardcoded = len(benchmarkStep.hardcodedParameters)
            # remove from solution 2D list also
            for solutionList in shallowcopy(solutions):
                if len(solutionList) == 0:
                    solutions.remove(solutionList)
        elif winners.winners == {}:
            print1("# Populating initial winners (%u solutions)\n" %
                   len(benchmarkStep.hardcodedParameters))
            for hcParm in benchmarkStep.hardcodedParameters:
                winners.winners[FrozenDictionary(hcParm)] = [{}, -1]

        print1("# Actual Solutions: %u / %u\n" % ( len(solutions), \
            maxPossibleSolutions ))

        # create linear list
        solutionList = []
        for i in range(0, len(solutions)):
            solutionsForHardcoded = solutions[i]
            for j in range(0, len(solutionsForHardcoded)):
                solution = solutionsForHardcoded[j]
                solutionList.append(solution)
        if len(solutionList) == 0:
            msg = "Your parameters resulted in 0 valid solutions."
            if globalParameters["PrintSolutionRejectionReason"]:
                msg += "\nExamine reject and backtrace messages above to see why and where solutions were rejected."
            else:
                msg += "\nYou should re-run with \"PrintSolutionRejectionReason: True\" to see why each parameter combination was rejected."
            printExit(msg)
        if globalParameters["PrintLevel"] >= 1:
            for i in range(0, len(solutions)):
                solutionsForHardcoded = solutions[i]
                for j in range(0, len(solutionsForHardcoded)):
                    solution = solutionsForHardcoded[j]
                    print2("#    (%u:%u) %s" % (i, j, \
                        Solution.getNameFull(solution) ))
            print2(HR)

        # write benchmarkFiles
        writeBenchmarkFiles(stepBaseDir, solutionList, benchmarkStep.problemSizes, \
            shortName, filesToCopy)

        print1("# Copying files that differ from sourceTmp -> source")
        sourceTmp = globalParameters["WorkingPath"]
        files = os.listdir(sourceTmp)
        for f in files:
            f0 = os.path.join(sourceTmp, f)
            f1 = os.path.join(sourceDir, f)
            if os.path.isdir(f0):
                #print "cpDir:", f0, f1
                if os.path.isdir(f1):
                    shutil.rmtree(f1, True)
                shutil.copytree(f0, f1)
            elif not os.path.exists(f1) or not filecmp.cmp(f0, f1):
                #print "cp:", f0, f1
                shutil.copy(f0, f1)
        shutil.rmtree(sourceTmp, True)

        popWorkingPath()  # source

        ############################################################################
        # Run Benchmark Script
        ############################################################################
        resultsFileBase = os.path.normpath(os.path.join( \
            globalParameters["WorkingPath"], "../Data", shortName))
        if benchmarkStep.isFinal():
            resultsFileBaseFinal = resultsFileBase
        resultsFileName = resultsFileBase + ".csv"
        solutionsFileName = resultsFileBase + ".yaml"
        if not os.path.exists(resultsFileName) or \
            globalParameters["ForceRedoBenchmarkProblems"]:
            pushWorkingPath("build")

            # write runScript
            libraryLogicPath = None
            path = globalParameters["WorkingPath"]
            forBenchmark = True
            runScriptName = writeRunScript(path, libraryLogicPath,
                                           forBenchmark)

            # run runScript
            process = Popen(runScriptName, cwd=globalParameters["WorkingPath"])
            process.communicate()
            if process.returncode:
                benchmarkTestFails += 1
                printWarning(
                    "BenchmarkProblems: Benchmark Process exited with code %u"
                    % process.returncode)
            popWorkingPath()  # build
        else:
            print1("# Already benchmarked; skipping.")

        ############################################################################
        # Winners -> Determined Parameters
        ############################################################################
        results = getResults(resultsFileName, solutions)
        print2("CSV Results: %s" % results)
        winners.addResults(benchmarkStep.hardcodedParameters, \
            benchmarkPermutations, solutions, results)

        ############################################################################
        # Write Solutions YAML
        ############################################################################
        YAMLIO.writeSolutions(solutionsFileName, benchmarkStep.problemSizes, \
            solutions )

        # End Iteration
        popWorkingPath()  # stepName
        currentTime = time.time()
        elapsedTime = currentTime - startTime
        print1("%s\n# %s\n# %s: End - %.3fs\n%s\n" \
            % (HR, problemSizeGroupName, shortName, elapsedTime, HR))

    popWorkingPath()  # ProblemType
    return (resultsFileBaseFinal, benchmarkTestFails)
Beispiel #6
0
def main(config):
    libraryLogicPath = os.path.join(globalParameters["WorkingPath"], \
        globalParameters["LibraryLogicPath"])
    pushWorkingPath(globalParameters["LibraryClientPath"])

    ##############################################################################
    # Copy Source Files
    ##############################################################################
    pushWorkingPath("source")
    filesToCopy = [
        "Client.cpp", "Client.h", "DeviceStats.h", "ReferenceCPU.h",
        "TensorUtils.h", "MathTemplates.cpp", "MathTemplates.h",
        "KernelHeader.h", "Tools.h", "CMakeLists.txt", "TensileConfig.cmake",
        "TensileConfigVersion.cmake"
    ]

    for f in filesToCopy:
        shutil_copy(os.path.join(globalParameters["SourcePath"], f),
                    globalParameters["WorkingPath"])
    if globalParameters["RuntimeLanguage"] == "OCL":
        shutil_copy(
            os.path.join(globalParameters["SourcePath"], "FindOpenCL.cmake"),
            globalParameters["WorkingPath"])
    else:
        shutil_copy(
            os.path.join(globalParameters["SourcePath"], "FindHIP.cmake"),
            globalParameters["WorkingPath"])
        shutil_copy(
            os.path.join(globalParameters["SourcePath"], "FindHCC.cmake"),
            globalParameters["WorkingPath"])

    ##############################################################################
    # Read Logic Files
    ##############################################################################
    logicFiles = [os.path.join(libraryLogicPath, f) for f \
        in os.listdir(libraryLogicPath) \
        if (os.path.isfile(os.path.join(libraryLogicPath, f)) \
        and os.path.splitext(f)[1]==".yaml")]
    print1("LogicFiles: %s" % logicFiles)
    functions = []
    functionNames = []
    enableHalf = False
    for logicFileName in logicFiles:
        (scheduleName, deviceNames, problemType, solutionsForType, \
            indexOrder, exactLogic, rangeLogic) \
            = YAMLIO.readLibraryLogicForSchedule(logicFileName)
        if problemType["DataType"].isHalf():
            enableHalf = True
        functions.append((scheduleName, problemType))
        functionNames.append("tensile_%s" % (problemType))
    globalParameters["EnableHalf"] = enableHalf

    ##############################################################################
    # Write Generated Header
    ##############################################################################
    forBenchmark = False
    solutions = None
    problemSizes = None
    stepName = None
    writeClientParameters(forBenchmark, solutions, problemSizes, stepName, \
        functions)
    popWorkingPath()  # source

    ##############################################################################
    # Run Build Script
    ##############################################################################
    # if redo=true, clobber the build directory
    if globalParameters["ForceRedoLibraryClient"]:
        rmtree(os.path.join(globalParameters["WorkingPath"], "build"), \
            ignore_errors=True)
    pushWorkingPath("build")

    # write runScript
    path = globalParameters["WorkingPath"]
    forBenchmark = False
    runScriptName = writeRunScript(path, libraryLogicPath, forBenchmark)

    # run runScript
    process = Popen(runScriptName, cwd=globalParameters["WorkingPath"])
    process.communicate()
    if process.returncode:
        printWarning("ClientWriter Benchmark Process exited with code %u" %
                     process.returncode)
    popWorkingPath()  # build

    popWorkingPath()  # LibraryClient

    return process.returncode
Beispiel #7
0
def TensileCreateLibrary():
    print1("")
    print1(HR)
    print1("# Tensile Create Library")
    print2(HR)
    print2("")

    ##############################################################################
    # Parse Command Line Arguments
    ##############################################################################
    print2("Arguments: %s" % sys.argv)
    argParser = argparse.ArgumentParser()
    argParser.add_argument("LogicPath",
                           help="Path to LibraryLogic.yaml files.")
    argParser.add_argument("OutputPath", help="Where to write library files?")
    argParser.add_argument("RuntimeLanguage", help="Which runtime language?", \
        choices=["OCL", "HIP", "HSA"])
    argParser.add_argument("--merge-files", dest="MergeFiles", \
        action="store_true")
    argParser.add_argument("--no-merge-files", dest="MergeFiles", \
        action="store_false")
    argParser.add_argument("--short-file-names", dest="ShortNames", \
        action="store_true")
    argParser.add_argument("--no-short-file-names", dest="ShortNames", \
        action="store_false")
    argParser.add_argument("--library-print-debug", dest="LibraryPrintDebug", \
        action="store_true")
    argParser.add_argument("--no-library-print-debug", dest="LibraryPrintDebug", \
        action="store_false")
    argParser.add_argument(
        "--isa",
        dest="isa",
        action="append",
        help="which architectures for assembly kernels to target")
    args = argParser.parse_args()

    logicPath = args.LogicPath
    outputPath = args.OutputPath
    print2("OutputPath: %s" % outputPath)
    ensurePath(outputPath)
    arguments = {}
    arguments["RuntimeLanguage"] = args.RuntimeLanguage
    arguments["MergeFiles"] = args.MergeFiles
    arguments["ShortNames"] = args.ShortNames
    arguments["LibraryPrintDebug"] = args.LibraryPrintDebug
    if args.isa:
        newISA = []
        for isa in args.isa:
            gfxIdx = isa.find("gfx")
            if gfxIdx >= 0:
                major = int(isa[gfxIdx + 3:gfxIdx + 4])
                minor = int(isa[gfxIdx + 4:gfxIdx + 5])
                step = int(isa[gfxIdx + 5:gfxIdx + 6])
                isaTuple = (major, minor, step)
                if isaTuple in globalParameters[
                        "SupportedISA"] and isaTuple not in newISA:
                    print1("# User-Specified ISA: gfx%u%u%u" %
                           (major, minor, step))
                    newISA.append(isaTuple)
            else:
                printWarning("isa parameter must be formed as: --isa gfx803")
        arguments["SupportedISA"] = newISA
    assignGlobalParameters(arguments)

    if not os.path.exists(logicPath):
        printExit("LogicPath %s doesn't exist" % logicPath)

    logicFiles = [os.path.join(logicPath, f) for f in os.listdir(logicPath) \
        if (os.path.isfile(os.path.join(logicPath, f)) \
        and os.path.splitext(f)[1]==".yaml")]

    print1("# LibraryLogicFiles:" % logicFiles)
    for logicFile in logicFiles:
        print1("#   %s" % logicFile)

    ##############################################################################
    # Parse config files
    ##############################################################################
    solutions = []
    logicData = {}  # keys are problemTypes, values are schedules
    for logicFileName in logicFiles:
        (scheduleName, deviceNames, problemType, solutionsForSchedule, \
            indexOrder, exactLogic, rangeLogic) \
            = YAMLIO.readLibraryLogicForSchedule(logicFileName)
        if problemType not in logicData:
            logicData[problemType] = []
        logicData[problemType].append((scheduleName, deviceNames, \
            solutionsForSchedule, indexOrder, exactLogic, rangeLogic ))
        for solution in solutionsForSchedule:
            if solution not in solutions:
                solutions.append(solution)

    # create solution writer and kernel writer
    kernels = []
    kernelsBetaOnly = []
    for solution in solutions:
        solutionKernels = solution.getKernels()
        for kernel in solutionKernels:
            if kernel not in kernels:
                kernels.append(kernel)
        solutionKernelsBetaOnly = solution.getKernelsBetaOnly()
        for kernel in solutionKernelsBetaOnly:
            if kernel not in kernelsBetaOnly:
                kernelsBetaOnly.append(kernel)

    # if any kernels are assembly, append every ISA supported
    if globalParameters["RuntimeLanguage"] == "HIP":
        newKernels = []
        for kernel in kernels:
            if kernel["KernelLanguage"] == "Assembly":
                kernel["ISA"] = globalParameters["SupportedISA"][0]
                for i in range(1, len(globalParameters["SupportedISA"])):
                    newKernel = deepcopy(kernel)
                    newKernel["ISA"] = globalParameters["SupportedISA"][i]
                    newKernels.append(newKernel)
            else:
                kernel["ISA"] = (0, 0, 0)
        kernels.extend(newKernels)

    if globalParameters["ShortNames"] and not globalParameters["MergeFiles"]:
        solutionSerialNaming = Solution.getSerialNaming(solutions)
        kernelSerialNaming = Solution.getSerialNaming(kernels)
    else:
        solutionSerialNaming = None
        kernelSerialNaming = None
    solutionMinNaming = Solution.getMinNaming(solutions)
    kernelMinNaming = Solution.getMinNaming(kernels)
    solutionWriter = SolutionWriter( \
        solutionMinNaming, solutionSerialNaming, \
        kernelMinNaming, kernelSerialNaming)
    kernelWriterSource = KernelWriterSource( \
        kernelMinNaming, kernelSerialNaming)
    kernelWriterAssembly = KernelWriterAssembly( \
        kernelMinNaming, kernelSerialNaming)

    # write solutions and kernels
    writeSolutionsAndKernels(outputPath, solutions, kernels, kernelsBetaOnly, \
        solutionWriter, kernelWriterSource, kernelWriterAssembly)

    libraryStaticFiles = [
        "TensileTypes.h", "KernelHeader.h", "SolutionHelper.cpp",
        "SolutionHelper.h", "Tools.cpp", "Tools.h"
    ]

    # write cmake
    clientName = "LibraryClient"
    writeCMake(outputPath, solutions, kernels, libraryStaticFiles, clientName)

    # write logic
    writeLogic(outputPath, logicData, solutionWriter)
    print1("# Tensile Library Writer DONE")
    print1(HR)
    print1("")