/******************************************************************************* * * MIT License * * Copyright (C) 2019-2023 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. * *******************************************************************************/ #include #include #include #include namespace Tensile { int dataTypeSize(DataType dt) { switch(dt) { case DataType::Int8: return 1; case DataType::Half: case DataType::BFloat16: return 2; case DataType::Float: case DataType::Int32: return 4; case DataType::Double: case DataType::ComplexFloat: return 8; case DataType::ComplexDouble: return 18; default: case DataType::None: return 0; }; } DataType convertToDataType(const std::string& DataTypeStr) { return DataTypeStr == "f16_r" || DataTypeStr == "h" ? DataType::Half : DataTypeStr == "f32_r" || DataTypeStr == "s" ? DataType::Float : DataTypeStr == "f64_r" || DataTypeStr == "d" ? DataType::Double : DataTypeStr == "bf16_r" ? DataType::BFloat16 : DataTypeStr == "f16_c" ? DataType::None : DataTypeStr == "f32_c" || DataTypeStr == "c" ? DataType::ComplexFloat : DataTypeStr == "f64_c" || DataTypeStr == "z" ? DataType::ComplexDouble : DataTypeStr == "bf16_c" ? DataType::None : DataTypeStr == "i8_r" ? DataType::Int8 : DataTypeStr == "i32_r" ? DataType::Int32 : DataTypeStr == "i8_c" ? DataType::None : DataTypeStr == "i32_c" ? DataType::None : DataTypeStr == "u8_r" ? DataType::None : DataTypeStr == "u32_r" ? DataType::None : DataTypeStr == "u8_c" ? DataType::None : DataTypeStr == "u32_c" ? DataType::None : DataType::None; } template <> std::pair, int> problemFromEntries(const std::vector& entries) { const size_t entries_n = entries.size(); if((entries_n != 15) && (entries_n != 18)) { return std::make_pair(ProblemOverride{}, -1); } // Common bool transA = (entries[0] != "N"); bool transB = (entries[1] != "N"); size_t m, n, b, k; size_t ldA, ldB, ldC; size_t strideA, strideB, strideC; double alpha, beta; DataType inputType = DataType::None; DataType outputType = DataType::None; DataType computeType = DataType::None; int solution_idx = -1; try { m = std::stol(entries[2]); n = std::stol(entries[3]); b = std::stol(entries[4]); k = std::stol(entries[5]); beta = std::stod(entries[7]); ldA = std::stol(entries[8]); ldB = std::stol(entries[9]); ldC = std::stol(entries[10]); strideA = 1; strideB = 1; strideC = 1; if(b > 1) { strideA = ldA * (transA ? m : k); strideB = ldB * (transB ? k : n); strideC = ldC * n; } if(entries_n == 15) { // Expected layout: transA,transB,M,N,batch_count,K,alpha,beta,lda,ldb,ldc,input_type,output_type,compute_type,solution_index inputType = convertToDataType(entries[11]); outputType = convertToDataType(entries[12]); computeType = convertToDataType(entries[13]); solution_idx = std::stoi(entries[14]); } else if(entries_n == 18) { // Expected layout: transA,transB,M,N,batch_count,K,alpha,beta,lda,ldb,ldc,stride_a,stride_b,stride_c,input_type,output_type,compute_type,solution_index strideA = std::stol(entries[11]); strideB = std::stol(entries[12]); strideC = std::stol(entries[13]); inputType = convertToDataType(entries[14]); outputType = convertToDataType(entries[15]); computeType = convertToDataType(entries[16]); solution_idx = std::stoi(entries[17]); } } catch(std::invalid_argument const& ex) { return std::make_pair(ProblemOverride{}, -1); } catch(std::out_of_range const& ex) { return std::make_pair(ProblemOverride{}, -1); } if(inputType == DataType::None || outputType == DataType::None || computeType == DataType::None) { return std::make_pair(ProblemOverride{}, -1); } bool HPA = (dataTypeSize(computeType) > dataTypeSize(inputType)); ProblemOverride po(transA, transB, inputType, outputType, HPA, m, n, k, b, beta, ldA, strideA, ldB, strideB, ldC, strideC); return std::make_pair(po, solution_idx); } template ProblemOverride::ProblemOverride() : m_transA(false) , m_transB(false) , m_inputType(DataType::None) , m_outputType(DataType::None) , m_HPA(false) , m_m(0) , m_n(0) , m_k(0) , m_batchSize(0) , m_beta(0) , m_ldA(0) , m_strideA(0) , m_ldB(0) , m_strideB(0) , m_ldC(0) , m_strideC(0) { } template ProblemOverride::ProblemOverride(bool transA, bool transB, DataType inputType, DataType outputType, bool HPA, size_t m, size_t n, size_t k, size_t batchSize, double beta, size_t ldA, size_t strideA, size_t ldB, size_t strideB, size_t ldC, size_t strideC) : m_transA(transA) , m_transB(transB) , m_inputType(inputType) , m_outputType(outputType) , m_HPA(HPA) , m_m(m) , m_n(n) , m_k(k) , m_batchSize(batchSize) , m_beta(beta) , m_ldA(ldA) , m_strideA(strideA) , m_ldB(ldB) , m_strideB(strideB) , m_ldC(ldC) , m_strideC(strideC) { } template <> ProblemOverride::ProblemOverride(const ContractionProblem& problem) { m_transA = problem.transA(); m_transB = problem.transB(); m_inputType = problem.a().dataType(); m_outputType = problem.c().dataType(); m_HPA = problem.highPrecisionAccumulate(); m_m = problem.freeSizeA(0); m_n = problem.freeSizeB(0); m_k = problem.boundSize(0); m_batchSize = problem.batchSize(0); m_beta = problem.beta(); m_ldA = problem.a().strides()[1]; m_strideA = problem.a().strides()[2]; m_ldB = problem.b().strides()[1]; m_strideB = problem.b().strides()[2]; m_ldC = problem.c().strides()[1]; m_strideC = problem.c().strides()[2]; } template <> ContractionProblem ProblemOverride::problem() const { auto problem = ContractionProblem::GEMM_Strides(m_transA, m_transB, m_inputType, m_inputType, m_outputType, m_outputType, m_m, m_n, m_k, m_batchSize, m_ldA, m_strideA, m_ldB, m_strideB, m_ldC, m_strideC, m_ldC, m_strideC, m_beta); problem.setHighPrecisionAccumulate(m_HPA); return problem; } template <> std::vector, int>> getContractionProblemsFromFile(const std::string& path) { std::vector, int>> out; std::ifstream file(path); std::string line, entry; const auto delim = ','; const auto first_heading = "transA"; const int max_entries = 18; while(std::getline(file, line)) { // Ignore lines without delimiter if(line.find(delim) == std::string::npos) { continue; } // Check for section start if(line.find(first_heading) != std::string::npos) { // TODO: Get param index from headings? continue; } std::vector entries{}; entries.reserve(max_entries); std::stringstream line_ss(line); while(getline(line_ss, entry, delim)) { entries.push_back(entry); } auto problemSolution = problemFromEntries(entries); if(problemSolution.second > 0) { out.push_back(problemSolution); } } return out; } };