Files
TheRock/rocm-libraries/projects/hipblaslt/tensilelite/include/Tensile/ContractionProblemPredicates.hpp
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

3189 lines
119 KiB
C++
Executable File

/*******************************************************************************
*
* MIT License
*
* Copyright (C) 2022-2026 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.
*
*******************************************************************************/
#pragma once
#include <Tensile/ContractionProblem.hpp>
#include <Tensile/ContractionSolution.hpp>
#include <Tensile/KernelLanguageTypes.hpp>
#include <Tensile/PredicateDebugger.hpp>
#include <Tensile/Predicates.hpp>
#include <Tensile/AMDGPU.hpp>
#include <Tensile/hip/HipHardware.hpp>
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <limits>
#include <sstream>
#include <vector>
#include <tensilelitehost/export.h>
namespace TensileLite
{
namespace Predicates
{
/**
* \addtogroup Predicates
* @{
*/
/**
* @brief ContractionProblemGemm predicates
*/
namespace Contraction
{
struct Free0SizeMultiple
: public Predicate_CRTP<Free0SizeMultiple, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
Free0SizeMultiple() = default;
Free0SizeMultiple(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "Free0SizeMultiple";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (!problem.transposeC01() ? problem.freeSizeA(index)
: problem.freeSizeB(index))
% value
== 0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int freeSize = !problem.transposeC01() ? problem.freeSizeA(index)
: problem.freeSizeB(index);
return debugEvalCmp(problem, stream, "prob", freeSize, "%", "sol", value);
}
};
struct Free1SizeMultiple
: public Predicate_CRTP<Free1SizeMultiple, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
Free1SizeMultiple() = default;
Free1SizeMultiple(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "Free1SizeMultiple";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (!problem.transposeC01() ? problem.freeSizeB(index)
: problem.freeSizeA(index))
% value
== 0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int freeSize = !problem.transposeC01() ? problem.freeSizeB(index)
: problem.freeSizeA(index);
return debugEvalCmp(problem, stream, "prob", freeSize, "%", "sol", value);
}
};
struct BatchSizeMultiple
: public Predicate_CRTP<BatchSizeMultiple, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
BatchSizeMultiple() = default;
BatchSizeMultiple(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "BatchSizeMultiple";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.batchSize(index) % value == 0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.batchSize(index), "%", "sol", value);
}
};
struct BatchSizeEqual : public Predicate_CRTP<BatchSizeEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
BatchSizeEqual() = default;
BatchSizeEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "BatchSizeEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.batchSize(index) == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.batchSize(index), "==", "sol", value);
}
};
struct SynchronizerSizeCheck
: public Predicate_CRTP<SynchronizerSizeCheck, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
std::array<int, 6> value;
SynchronizerSizeCheck() = default;
SynchronizerSizeCheck(size_t index, std::array<int, 6> value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "SynchronizerSizeCheck";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
int16_t gsu = problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[5];
if(gsu == -1 || gsu == 1)
return 1;
// WorkGroup numbers x number of global write instruction x Wave numbers
// M/MT0 x N/MT1 x NumElementsPerThread/StoreVectorWidth x x Wavenumbers x batch
uint32_t synchronizerUsage = (std::ceil(static_cast<float>(problem.freeSizeA(0)) / value[0])
* std::ceil(static_cast<float>(problem.freeSizeB(0)) / value[1]))
* value[2] * value[4] * value[3] * problem.d().sizes()[2];
if(problem.groupedGemm())
return synchronizerUsage <= 409600 * 16 / problem.groupedGemmCount();
else
return synchronizerUsage <= 409600 * 16;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
uint32_t synchronizerSize = 409600 * 16;
if(problem.groupedGemm())
synchronizerSize /= problem.groupedGemmCount();
return debugEvalCmp(
problem,
stream,
"prob",
(std::ceil(static_cast<float>(problem.freeSizeA(0)) / value[0])
* std::ceil(static_cast<float>(problem.freeSizeB(0)) / value[1]))
* (value[2]) * (value[4]) * value[3] * problem.d().sizes()[2],
">=",
"limit",
synchronizerSize);
}
};
struct BoundSizeMultiple
: public Predicate_CRTP<BoundSizeMultiple, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
int64_t index;
size_t value;
BoundSizeMultiple() = default;
BoundSizeMultiple(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "BoundSizeMultiple";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(index < 0)
return problem.boundSize(problem.boundIndices().size() + index) % value
== 0;
else
return problem.boundSize(index) % value == 0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int index_mod = index < 0 ? problem.boundIndices().size() + index : index;
return debugEvalCmp(
problem, stream, "prob", problem.boundSize(index_mod), "%", "sol", value);
}
};
struct ProblemSizeEqual
: public Predicate_CRTP<ProblemSizeEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
ProblemSizeEqual() = default;
ProblemSizeEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "ProblemSizeEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.problemSizes()[index] == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.problemSizes()[index], "==", "sol", value);
}
};
struct MaxProblemSizeGreaterThan
: public Predicate_CRTP<MaxProblemSizeGreaterThan, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
size_t value;
MaxProblemSizeGreaterThan() = default;
MaxProblemSizeGreaterThan(size_t value)
: value(value)
{
}
static std::string Type()
{
return "MaxProblemSizeGreaterThan";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.maxProblemSize() > value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.maxProblemSize(), ">", "sol", value);
}
};
// If the tensor contains no free dimensions, then the first batch dimension
// serves as the leading free size
struct LeadingFree0SizesGreaterOrEqual
: public Predicate_CRTP<LeadingFree0SizesGreaterOrEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
size_t value;
LeadingFree0SizesGreaterOrEqual() = default;
LeadingFree0SizesGreaterOrEqual(size_t value)
: value(value)
{
}
static std::string Type()
{
return "LeadingFree0SizesGreaterOrEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
assert(problem.batchIndices().size() <= 1);
// TODO: this is not quite right since it assumes batchSize(0) is lowest
// order in index assignments
// If tensor contains multiple batch dims this may not be true.
// Really should modify Contractions.py to select SizeN >= value, based on
// desired index requirement
return (problem.freeIndicesA().size() ? problem.freeSizeA(0) >= value
: problem.batchSize(0) >= value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int size = problem.freeIndicesA().size() ? problem.freeSizeA(0)
: problem.batchSize(0);
return debugEvalCmp(problem, stream, "prob", size, ">=", "sol", value);
}
};
struct LeadingFree1SizesGreaterOrEqual
: public Predicate_CRTP<LeadingFree1SizesGreaterOrEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
size_t value;
LeadingFree1SizesGreaterOrEqual() = default;
LeadingFree1SizesGreaterOrEqual(size_t value)
: value(value)
{
}
static std::string Type()
{
return "LeadingFree1SizesGreaterOrEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
assert(problem.batchIndices().size() <= 1);
// TODO: this is not quite right since it assumes batchSize(0) is lowest
// order in index assignments
// If tensor contains multiple batch dims this may not be true.
// Really should modify Contractions.py to select SizeN >= value, based on
// desired index requirement
if(problem.groupedGemm())
return (problem.freeIndicesB().size()
? problem.freeSizeB(0) >= value || problem.freeSizeB(0) == 0
: problem.batchSize(0) >= value || problem.freeSizeB(0) == 0);
return (problem.freeIndicesB().size() ? problem.freeSizeB(0) >= value
: problem.batchSize(0) >= value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int size = problem.freeIndicesB().size() ? problem.freeSizeB(0)
: problem.batchSize(0);
return debugEvalCmp(problem, stream, "prob", size, ">=", "sol", value);
}
};
struct SizeEqual : public Predicate_CRTP<SizeEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
SizeEqual() = default;
SizeEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "SizeEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.size(index) == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.size(index), "==", "sol", value);
}
};
struct SizeGreaterThan : public Predicate_CRTP<SizeGreaterThan, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
SizeGreaterThan() = default;
SizeGreaterThan(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "SizeGreaterThan";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (problem.size(index) > value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.size(index), ">", "sol", value);
}
};
struct SizeLessThan : public Predicate_CRTP<SizeLessThan, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
SizeLessThan() = default;
SizeLessThan(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "SizeLessThan";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (problem.size(index) < value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.size(index), "<", "sol", value);
}
};
struct SizeMultiple : public Predicate_CRTP<SizeMultiple, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
SizeMultiple() = default;
SizeMultiple(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "SizeMultiple";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return ((problem.size(index) % value) == 0);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.size(index), "%", "sol", value);
}
};
struct Range
{
size_t min = 0;
size_t max = std::numeric_limits<size_t>::max();
};
inline std::ostream& operator<<(std::ostream& stream, Range const& range)
{
return stream << "min: " << range.min << ", max: " << range.max;
}
struct SizeInRange : public Predicate_CRTP<SizeInRange, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
Range value;
SizeInRange() = default;
SizeInRange(size_t index, Range value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "SizeInRange";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (problem.size(index) >= value.min) && (problem.size(index) < value.max);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob_low",
problem.size(index),
">=",
"sol_low",
value.min,
"prob_high",
problem.size(index),
"<",
"sol_high",
value.max);
}
};
struct StrideAEqual : public Predicate_CRTP<StrideAEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
StrideAEqual() = default;
StrideAEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "StrideAEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.a().strides()[index] == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.a().strides()[index], "==", "sol", value);
}
};
struct StrideBEqual : public Predicate_CRTP<StrideBEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
StrideBEqual() = default;
StrideBEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "StrideBEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.b().strides()[index] == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.b().strides()[index], "==", "sol", value);
}
};
struct StrideCEqual : public Predicate_CRTP<StrideCEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
StrideCEqual() = default;
StrideCEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "StrideCEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.c().strides()[index] == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.c().strides()[index], "==", "sol", value);
}
};
struct StrideDEqual : public Predicate_CRTP<StrideDEqual, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
size_t value;
StrideDEqual() = default;
StrideDEqual(size_t index, size_t value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "StrideDEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.d().strides()[index] == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.d().strides()[index], "==", "sol", value);
}
};
struct LDCEqualsLDD : public Predicate_CRTP<LDCEqualsLDD, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
static std::string Type()
{
return "LDCEqualsLDD";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.c().strides()[1] == problem.d().strides()[1];
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob_c_stride",
problem.c().strides()[1],
"==",
"prob_d_stride",
problem.d().strides()[1]);
}
};
struct CEqualsD : public Predicate_CRTP<CEqualsD, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
static std::string Type()
{
return "CEqualsD";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.cEqualsD();
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.cEqualsD(), "==", "sol", true);
}
};
struct AmaxDCheck : public Predicate_CRTP<AmaxDCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
AmaxDCheck() = default;
AmaxDCheck(bool value)
: value(value)
{
}
static std::string Type()
{
return "AmaxDCheck";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
bool amaxDStatusEqual = (problem.outputAmaxD() == value);
// if value is true, then we also need to check gsu
// otherwise we just check outputAmaxD
if(value)
return amaxDStatusEqual && (problem.getParams().gsu() == 0 || problem.getParams().gsu() == 1);
else
return amaxDStatusEqual;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "prob_amaxD=" << problem.outputAmaxD() << " == sol_amaxD=" << value;
if(value)
details << ", prob_gsu=" << problem.getParams().gsu() << " (must be 0 or 1)";
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct BetaZero : public Predicate_CRTP<BetaZero, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
BetaZero() = default;
static std::string Type()
{
return "BetaZero";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.beta() == 0.0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem, stream, "prob", problem.beta(), "==", "sol", 0.0);
}
};
struct BetaOne : public Predicate_CRTP<BetaOne, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
BetaOne() = default;
static std::string Type()
{
return "BetaOne";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.beta() == 1.0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem, stream, "prob", problem.beta(), "==", "sol", 1.0);
}
};
struct HighPrecisionAccumulateEqual
: public Predicate_CRTP<HighPrecisionAccumulateEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
HighPrecisionAccumulateEqual() = default;
HighPrecisionAccumulateEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "HighPrecisionAccumulate";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.highPrecisionAccumulate() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob",
problem.highPrecisionAccumulate(),
"==",
"sol",
value);
}
};
struct KernelLanguageCompatible
: public Predicate_CRTP<KernelLanguageCompatible, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
KernelLanguage value;
KernelLanguageCompatible() = default;
KernelLanguageCompatible(KernelLanguage value)
: value(value)
{
}
static std::string Type()
{
return "KernelLanguageCompatible";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.kernelLanguage() == value
|| problem.kernelLanguage() == KernelLanguage::Any;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob",
problem.kernelLanguage(),
"==",
"sol",
value,
"prob",
problem.kernelLanguage(),
"==",
"sol_any",
KernelLanguage::Any);
}
};
struct DeterministicModeEqual
: public Predicate_CRTP<DeterministicModeEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
DeterministicModeEqual() = default;
DeterministicModeEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "DeterministicMode";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.deterministicMode() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.deterministicMode(), "==", "sol", value);
}
};
struct AIGreaterThanEqual
: public Predicate_CRTP<AIGreaterThanEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
double value;
AIGreaterThanEqual() = default;
AIGreaterThanEqual(double value)
: value(value)
{
}
static std::string Type()
{
return "AIGreaterThanEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.arithmeticIntensity() >= value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem, stream, "prob", problem.arithmeticIntensity(), ">=", "sol", value);
}
};
struct AILessThanEqual : public Predicate_CRTP<AILessThanEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
double value;
AILessThanEqual() = default;
AILessThanEqual(double value)
: value(value)
{
}
static std::string Type()
{
return "AILessThanEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.arithmeticIntensity() <= value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem, stream, "prob", problem.arithmeticIntensity(), "<=", "sol", value);
}
};
struct AlphaValue : public Predicate_CRTP<AlphaValue, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
ScalarValue value;
AlphaValue() = default;
AlphaValue(ScalarValue value)
: value(value)
{
}
static std::string Type()
{
return "AlphaValue";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.alphaRestriction() == value || value == ScalarValue::Any;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob",
problem.alphaRestriction(),
"==",
"sol",
value,
"sol",
value,
"==",
"sol_any",
ScalarValue::Any);
}
};
struct BetaValue : public Predicate_CRTP<BetaValue, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
ScalarValue value;
BetaValue() = default;
BetaValue(ScalarValue value)
: value(value)
{
}
static std::string Type()
{
return "BetaValue";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.betaRestriction() == value || value == ScalarValue::Any;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob",
problem.betaRestriction(),
"==",
"sol",
value,
"sol",
value,
"==",
"sol_any",
ScalarValue::Any);
}
};
struct TypesEqual : public Predicate_CRTP<TypesEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
TypesEqual() = default;
std::array<rocisa::DataType, 6> value;
static std::string Type()
{
return "TypesEqual";
}
// This function checks if the computeInputType of a problem matches the computeInputType of a
// solution. Because for Float8{_fnuz}/BFloat8{_fnuz}, the computeInputTypeA and computeInputTypeB
// might be concatenated like this: computeInputTypeAcomputeInputTypeB{_fnuz}, this function
// includes special logic to inspect types at the concatenation position.
//
bool validateComputeType(rocisa::DataType const& problemComputeInputType, bool const isComputeInputTypeA) const
{
using ArrType = std::array<std::pair<rocisa::DataType, rocisa::DataType>, 4>;
// computeInputTypeA corresponds to the first type in the concatenated type
ArrType const computeInputTypeAMapping =
{{
{rocisa::DataType::BFloat8_fnuz, rocisa::DataType::BFloat8Float8_fnuz},
{rocisa::DataType::Float8_fnuz, rocisa::DataType::Float8BFloat8_fnuz},
{rocisa::DataType::BFloat8, rocisa::DataType::BFloat8Float8},
{rocisa::DataType::Float8, rocisa::DataType::Float8BFloat8}
}};
// computeInputTypeB corresponds to the second type in the concatenated type
ArrType const computeInputTypeBMapping =
{{
{rocisa::DataType::Float8_fnuz, rocisa::DataType::BFloat8Float8_fnuz},
{rocisa::DataType::BFloat8_fnuz, rocisa::DataType::Float8BFloat8_fnuz},
{rocisa::DataType::Float8, rocisa::DataType::BFloat8Float8},
{rocisa::DataType::BFloat8, rocisa::DataType::Float8BFloat8}
}};
auto validate = [](ArrType const& arr,
rocisa::DataType const& t1, rocisa::DataType const& t2){
if(t1 == t2)
return true;
return std::any_of(arr.begin(), arr.end(), [&](const auto& p){
return (p == std::make_pair(t1, t2)) or (p == std::make_pair(t2, t1));
});
};
if(isComputeInputTypeA)
{
// value[4] is computeInputTypeA
return
validate(computeInputTypeAMapping, problemComputeInputType, value[4]);
}
else
{
// value[5] is computeInputTypeB
return
validate(computeInputTypeBMapping, problemComputeInputType, value[5]);
}
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.a().dataType() == value[0] && problem.b().dataType() == value[1]
&& problem.c().dataType() == value[2]
&& problem.d().dataType() == value[3]
&& problem.computeInputTypeA() == value[4]
&& problem.computeInputTypeB() == value[5];
}
virtual std::string toString() const override
{
return concatenate(this->type(),
"(a:",
value[0],
", b:",
value[1],
", c:",
value[2],
", d:",
value[3],
", compute input typeA:",
value[4],
", compute input typeB:",
value[5]);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob_a",
problem.a().dataType(),
"==",
"sol_a",
value[0],
"prob_b",
problem.b().dataType(),
"==",
"sol_b",
value[1],
"prob_c",
problem.c().dataType(),
"==",
"sol_c",
value[2],
"prob_d",
problem.d().dataType(),
"==",
"sol_d",
value[3],
"prob_compute_a",
problem.computeInputTypeA(),
"==",
"sol_compute_a",
value[4],
"prob_compute_b",
problem.computeInputTypeB(),
"==",
"sol_compute_b",
value[5]);
}
};
struct OperationIdentifierEqual
: public Predicate_CRTP<OperationIdentifierEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
OperationIdentifierEqual() = default;
std::string value;
static std::string Type()
{
return "OperationIdentifierEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.operationIdentifier() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.operationIdentifier(), "==", "sol", value);
}
};
struct BufferLoadOffsetLimitCheck
: public Predicate_CRTP<BufferLoadOffsetLimitCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
BufferLoadCheckPacket value;
BufferLoadOffsetLimitCheck() = default;
BufferLoadOffsetLimitCheck(BufferLoadCheckPacket value)
: value(value)
{
}
static std::string Type()
{
return "BufferLoadOffsetLimitCheck";
}
// The min operator is used to handle cases where size_M/size_K is smaller than the value.depthUorMT0
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
const uint64_t TWO_POW_32 = 4294967296;
return multiplyElementSize((problem.a().strides()[1] * std::min(value.depthUorMT0, problem.a().sizes()[1]) + value.shiftPtrElemA),
problem.a().elementBytes())
< TWO_POW_32
&& multiplyElementSize((problem.b().strides()[1] * std::min(value.depthUorMT1, problem.b().sizes()[1]) + value.shiftPtrElemB)
,problem.b().elementBytes())
< TWO_POW_32;
}
virtual std::string toString() const override
{
return concatenate(this->type(),
"(DU/MT0:",
value.depthUorMT0,
", DU/MT1:",
value.depthUorMT1,
", ShiftPtrPadElementA:",
value.shiftPtrElemA,
", ShiftPtrPadElementB:",
value.shiftPtrElemB,
")");
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "A:(" << problem.a().strides()[1] << "*" << value.depthUorMT0 << "+"
<< value.shiftPtrElemA << ")*" << problem.a().elementBytes()
<< "<2^32, B:(" << problem.b().strides()[1] << "*" << value.depthUorMT1
<< "+" << value.shiftPtrElemB << ")*" << problem.b().elementBytes()
<< "<2^32";
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct BufferLoadOffsetLimitCheck_Beta
: public Predicate_CRTP<BufferLoadOffsetLimitCheck_Beta, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
size_t value;
BufferLoadOffsetLimitCheck_Beta() = default;
BufferLoadOffsetLimitCheck_Beta(size_t value)
: value(value)
{
}
static std::string Type()
{
return "BufferLoadOffsetLimitCheck_Beta";
}
// The min operator is used to handle cases where size_N is smaller than the value(usually is MacroTile1)
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.c().empty() || problem.beta() == 0)
{
return true;
}
else
{
const uint64_t TWO_POW_32 = 4294967296;
return multiplyElementSize(problem.c().strides()[1] * std::min(value, problem.c().sizes()[1]), problem.c().elementBytes())
< TWO_POW_32;
}
}
virtual std::string toString() const override
{
return concatenate(this->type(), "(MT1:", value, ")");
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "C:" << problem.c().strides()[1] << "*"
<< problem.c().elementBytes() << "*" << value << "<2^32";
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct BufferStoreOffsetLimitCheck
: public Predicate_CRTP<BufferStoreOffsetLimitCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
size_t value;
BufferStoreOffsetLimitCheck() = default;
BufferStoreOffsetLimitCheck(size_t value)
: value(value)
{
}
static std::string Type()
{
return "BufferStoreOffsetLimitCheck";
}
// The min operator is used to handle cases where size_N is smaller than the value(usually is MacroTile1)
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
const uint64_t TWO_POW_32 = 4294967296;
return multiplyElementSize(problem.d().strides()[1] * std::min(value, problem.d().sizes()[1]), problem.d().elementBytes())
< TWO_POW_32;
}
virtual std::string toString() const override
{
return concatenate(this->type(), "(MT1:", value, ")");
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "D:" << problem.d().strides()[1] << "*"
<< problem.d().elementBytes() << "*" << value << "<2^32";
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct WorkgroupNumberCheck
: public Predicate_CRTP<WorkgroupNumberCheck, ContractionProblemGemm>
{
enum
{
HasIndex = true,
HasValue = true
};
size_t index;
std::array<int, 3> value;
WorkgroupNumberCheck() = default;
WorkgroupNumberCheck(size_t index, std::array<int, 3> value)
: index(index)
, value(value)
{
}
// If the number is larger than 2^24, it may lose precision when converted into fp32.
// TODO: REMOVE custom kernel, then REMOVE the behavior that compressed 3 DIM workgroups into 1 DIM
#define MAX_WORKGROUP_NUMBER 16777216
static std::string Type()
{
return "WorkgroupNumberCheck";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
int16_t gsu = problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[2];
// auto gsu will consider workgroup number, so bypassed
if(gsu == -1)
return 1;
gsu = gsu > 1 ? gsu : 1;
return (std::ceil(static_cast<float>(problem.freeSizeA(0)) / value[0])
* std::ceil(static_cast<float>(problem.freeSizeB(0)) / value[1]) * gsu
* problem.batchSize(0))
<= MAX_WORKGROUP_NUMBER;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int16_t gsu = problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[2];
if(gsu == -1)
{
bool rv = (*this)(problem);
PredicateDebugger::printRow(stream, rv, this->type(), "auto gsu (bypassed)");
return rv;
}
gsu = gsu > 1 ? gsu : 1;
int workgroupNumber = std::ceil(static_cast<float>(problem.freeSizeA(0)) / value[0])
* std::ceil(static_cast<float>(problem.freeSizeB(0)) / value[1])
* gsu * problem.batchSize(0);
return debugEvalCmp(problem, stream, "wg_num", workgroupNumber, "<=", "max", MAX_WORKGROUP_NUMBER);
}
};
struct PersistentKernelCheck
: public Predicate_CRTP<PersistentKernelCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
PersistentKernelCheck() = default;
static std::string Type()
{
return "PersistentKernelCheck";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.getPersistentKernelEligibility();
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
PredicateDebugger::printRow(
stream, rv, this->type(), rv ? "eligible" : "not eligible");
return rv;
}
};
struct GlobalSplitUCheckMinK
: public Predicate_CRTP<GlobalSplitUCheckMinK, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
std::array<int, 2> value;
GlobalSplitUCheckMinK() = default;
GlobalSplitUCheckMinK(std::array<int, 2> value)
: value(value)
{
}
static std::string Type()
{
return "GlobalSplitUCheckMinK";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
size_t minK
= (problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[1]);
// auto gsu will consider MinK, so bypassed
if(minK == -1)
return 1;
if(minK == 1)
minK = 0;
minK *= value[0];
return problem.boundSize(0) >= minK;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
size_t gsu = (problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[1]);
if(gsu == static_cast<size_t>(-1))
{
bool rv = (*this)(problem);
PredicateDebugger::printRow(stream, rv, this->type(), "auto gsu (bypassed)");
return rv;
}
size_t minK = (gsu == 1) ? 0 : gsu * value[0];
return debugEvalCmp(problem, stream, "prob", problem.boundSize(0), ">=", "sol", minK);
}
};
struct CDStridesEqual : public Predicate_CRTP<CDStridesEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
CDStridesEqual() = default;
static std::string Type()
{
return "CDStridesEqual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.c().strides() == problem.d().strides();
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob_c_stride",
problem.c().strides(),
"==",
"prob_d_stride",
problem.d().strides());
}
};
struct StridedBatchedEqual
: public Predicate_CRTP<StridedBatchedEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
StridedBatchedEqual() = default;
StridedBatchedEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "StridedBatched";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.stridedBatched() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.stridedBatched(), "==", "sol", value);
}
};
struct GroupedGemmEqual
: public Predicate_CRTP<GroupedGemmEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
GroupedGemmEqual() = default;
GroupedGemmEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "GroupedGemm";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.groupedGemm() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.groupedGemm(), "==", "sol", value);
}
};
struct CUEfficiency : public Predicate_CRTP<CUEfficiency, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
CUEfficiency() = default;
static std::string Type()
{
return "CUEfficiency";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.performanceMetric() == PerformanceMetric::CUEfficiency)
{
return true;
}
else if(problem.performanceMetric() == PerformanceMetric::Auto)
{
// True if total flops below a constant threshold
// Current threshold chosen naively as the flops for a
// 1500x1500 square matrix multiply
return problem.flopCount() < size_t(1500ll * 1500ll * 1500ll * 2);
}
else
{
return false;
}
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
if(problem.performanceMetric() == PerformanceMetric::CUEfficiency)
details << "metric=CUEfficiency";
else if(problem.performanceMetric() == PerformanceMetric::Auto)
details << "metric=Auto, flopCount=" << problem.flopCount();
else
details << "metric=other (not CUEfficiency or Auto)";
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct ExperimentalStreamK
: public Predicate_CRTP<ExperimentalStreamK, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
ExperimentalStreamK() = default;
static std::string Type()
{
return "ExperimentalStreamK";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (problem.performanceMetric() == PerformanceMetric::ExperimentalStreamK);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob",
problem.performanceMetric(),
"==",
"sol: PerformanceMetric::ExperimentalStreamK",
PerformanceMetric::ExperimentalStreamK);
}
};
struct ExperimentalMLP : public Predicate_CRTP<ExperimentalMLP, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
ExperimentalMLP() = default;
static std::string Type()
{
return "ExperimentalMLP";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return (problem.performanceMetric() == PerformanceMetric::ExperimentalMLP);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(problem,
stream,
"prob",
problem.performanceMetric(),
"==",
"sol: PerformanceMetric::ExperimentalMLP",
PerformanceMetric::ExperimentalMLP);
}
};
struct EqualityMatching
: public Predicate_CRTP<EqualityMatching, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
EqualityMatching() = default;
static std::string Type()
{
return "EqualityMatching";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
stream << "Searching " << this->type() << " Library..." << std::endl;
return rv;
}
};
struct RangeMatching
: public Predicate_CRTP<RangeMatching, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
RangeMatching() = default;
static std::string Type()
{
return "RangeMatching";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
stream << "Searching " << this->type() << " Library..." << std::endl;
return rv;
}
};
struct FreeSizeMatching
: public Predicate_CRTP<FreeSizeMatching, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
FreeSizeMatching() = default;
static std::string Type()
{
return "FreeSizeMatching";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
stream << "Searching " << this->type() << " Library..." << std::endl;
return rv;
}
};
struct PredictionMatching : public Predicate_CRTP<PredictionMatching, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
PredictionMatching() = default;
static std::string Type()
{
return "PredictionMatching";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
PredicateDebugger::printRow(stream, rv, this->type());
return rv;
}
};
struct GridBasedMatching
: public Predicate_CRTP<GridBasedMatching, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = false
};
GridBasedMatching() = default;
static std::string Type()
{
return "GridBasedMatching";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
PredicateDebugger::printRow(stream, rv, this->type());
return rv;
}
};
struct UseGradientEqual
: public Predicate_CRTP<UseGradientEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
UseGradientEqual() = default;
UseGradientEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "UseGradient";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.useGradient() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.useGradient(), "==", "sol", value);
}
};
// Activation
struct ActivationCheck : public Predicate_CRTP<ActivationCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
ActivationType value;
ActivationCheck() = default;
ActivationCheck(ActivationType value)
: value(value)
{
}
static std::string Type()
{
return "Activation";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(value == ActivationType::All)
return true;
if(problem.activationType() == value
|| problem.activationType() == ActivationType::None)
return true;
if(value == ActivationType::Hipblaslt_all
&& (problem.activationType() == ActivationType::DGelu
|| problem.activationType() == ActivationType::DRelu
|| problem.activationType() == ActivationType::Gelu
|| problem.activationType() == ActivationType::Relu
|| problem.activationType() == ActivationType::Silu
|| problem.activationType() == ActivationType::Clamp))
return true;
return false;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.activationType(), "==", "sol", value);
}
};
struct ActivationEnumWhiteList
: public Predicate_CRTP<ActivationEnumWhiteList, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
ActivationEnumWhiteList() = default;
std::vector<ActivationType> value;
static std::string Type()
{
return "ActivationEnumWhiteList";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.activationType() == ActivationType::All
|| problem.activationType() == ActivationType::Hipblaslt_all)
{
for(size_t i = 0; i < value.size(); i++)
{
if(value[i] == problem.getParams().activationEnum())
{
return true;
}
}
return false;
}
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "supported=[";
for(size_t i = 0; i < value.size(); i++)
{
details << ToString(value[i]);
if(i < value.size() - 1)
details << ", ";
}
details << "], prob=" << ToString(problem.getParams().activationEnum());
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct ActivationComputeTypeEqual
: public Predicate_CRTP<ActivationComputeTypeEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
rocisa::DataType value;
ActivationComputeTypeEqual() = default;
ActivationComputeTypeEqual(rocisa::DataType value)
: value(value)
{
}
static std::string Type()
{
return "ActivationComputeType";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.activationType() == ActivationType::None)
return true;
return problem.activationComputeType() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
if(problem.activationType() != ActivationType::None)
return debugEvalCmp(problem,
stream,
"prob",
problem.activationComputeType(),
"==",
"sol",
value);
return rv;
}
};
struct ActivationNoGuardEqual
: public Predicate_CRTP<ActivationNoGuardEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
ActivationNoGuardEqual() = default;
ActivationNoGuardEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "ActivationNoGuard";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.activationNoGuard() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.activationNoGuard(), "==", "sol", value);
}
};
struct UseBiasCheck : public Predicate_CRTP<UseBiasCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
int value;
UseBiasCheck() = default;
UseBiasCheck(int value)
: value(value)
{
}
static std::string Type()
{
return "UseBias";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return !problem.useBias() || value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "prob=" << problem.useBias() << ", sol_supports=" << value;
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct UseGateResidualEqual
: public Predicate_CRTP<UseGateResidualEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
UseGateResidualEqual() = default;
UseGateResidualEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "UseGateResidual";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.useGateResidual() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "prob=" << problem.useGateResidual() << ", sol=" << value;
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct UseEEqual : public Predicate_CRTP<UseEEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
UseEEqual() = default;
UseEEqual(bool value)
: value(value)
{
}
static std::string Type()
{
return "UseE";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.useE() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.useE(), "==", "sol", value);
}
};
struct DataTypeEEqual : public Predicate_CRTP<DataTypeEEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
rocisa::DataType value;
DataTypeEEqual() = default;
DataTypeEEqual(rocisa::DataType value)
: value(value)
{
}
static std::string Type()
{
return "DataTypeE";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.useE())
{
return problem.e().dataType() == value;
}
return true;
}
virtual std::string toString() const override
{
return concatenate(this->type(), "(e:", value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
debugEvalCmp(
problem, stream, "prob_e", problem.e().dataType(), "==", "sol_e", value);
return rv;
}
};
struct UseScaleABCheck : public Predicate_CRTP<UseScaleABCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
std::string value;
UseScaleABCheck() = default;
UseScaleABCheck(std::string value)
: value(value)
{
}
static std::string Type()
{
return "UseScaleAB";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.useScaleAB().empty() || (problem.useScaleAB() == value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "prob=" << problem.useScaleAB() << ", sol_supports=" << value;
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct UseScaleCDCheck : public Predicate_CRTP<UseScaleCDCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
UseScaleCDCheck() = default;
UseScaleCDCheck(bool value)
: value(value)
{
}
static std::string Type()
{
return "UseScaleCD";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return !problem.useScaleCD() || value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "prob=" << problem.useScaleCD() << ", sol_supports=" << value;
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct UseScaleAlphaVecCheck
: public Predicate_CRTP<UseScaleAlphaVecCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
int value;
UseScaleAlphaVecCheck() = default;
UseScaleAlphaVecCheck(int value)
: value(value)
{
}
static std::string Type()
{
return "UseScaleAlphaVec";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return !problem.useScaleAlphaVec() || (problem.useScaleAlphaVec() & value);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "prob=" << problem.useScaleAlphaVec() << ", sol_supports=" << value;
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct BiasDataTypeWhiteList
: public Predicate_CRTP<BiasDataTypeWhiteList, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
BiasDataTypeWhiteList() = default;
std::vector<rocisa::DataType> value;
static std::string Type()
{
return "BiasDataTypeWhiteList";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.useBias())
{
for(size_t i = 0; i < value.size(); i++)
{
if(value[i] == problem.bias().dataType())
{
return true;
}
}
return false;
}
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "supported_types=[";
for(size_t i = 0; i < value.size(); i++)
{
details << ToString(value[i]);
if(i < value.size() - 1)
details << ", ";
}
details << "]";
if(problem.useBias())
details << ", prob_type=" << ToString(problem.bias().dataType());
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct GateResidualDataTypeWhiteList
: public Predicate_CRTP<GateResidualDataTypeWhiteList, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
GateResidualDataTypeWhiteList() = default;
std::vector<rocisa::DataType> value;
static std::string Type()
{
return "GateResidualDataTypeWhiteList";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.useGateResidual())
{
for(size_t i = 0; i < value.size(); i++)
{
if(value[i] == problem.gateResidual().dataType())
{
return true;
}
}
return false;
}
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "supported_types=[";
for(size_t i = 0; i < value.size(); i++)
{
details << ToString(value[i]);
if(i < value.size() - 1)
details << ", ";
}
details << "]";
if(problem.useGateResidual())
details << ", prob_type=" << ToString(problem.gateResidual().dataType());
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct BiasSrcWhiteList
: public Predicate_CRTP<BiasSrcWhiteList, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
BiasSrcWhiteList() = default;
// This is actually the index of the problem type
std::vector<int> value;
static std::string Type()
{
return "BiasSrcWhiteList";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
if(problem.useBias() && problem.useScaleAlphaVec()
&& problem.useBias() != problem.useScaleAlphaVec())
return false;
int factorDim = (problem.useBias() == 1) ? 0
: problem.useBias() == 2 ? 1
: problem.useBias() == 3 ? problem.getParams().factorDim()
: 0;
if(problem.useBias())
{
auto& tensor = problem.tensor(ContractionProblemGemm::TENSOR::BIAS);
if(tensor.sizes().size() == 0)
return false;
for(size_t i = 0; i < value.size(); i++)
{
if(value[i] == static_cast<int>(problem.biasSrc()))
{
// Check if the length is set correctly.
auto& length = tensor.sizes()[0];
if(problem.biasSrc() == ContractionProblemGemm::TENSOR::A
|| problem.biasSrc() == ContractionProblemGemm::TENSOR::D)
{
auto eLength = (problem.useBias() == 1
|| problem.biasSrc()
!= ContractionProblemGemm::TENSOR::D)
? problem.d().sizes()[0]
: (problem.useBias() <= 3)
? problem.d().sizes()[factorDim]
: -1;
if(length < eLength)
return false;
}
else if(problem.biasSrc() == ContractionProblemGemm::TENSOR::B)
{
if(length != problem.d().sizes()[1])
return false;
}
return true;
}
}
return false;
}
return true;
}
virtual std::string toString() const override
{
std::string biasString = "";
for(size_t i = 0; i < value.size(); i++)
{
biasString += ToString(value[i]) + ", ";
}
return std::string("The supported bias source are: " + biasString);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
std::ostringstream details;
details << "supported_sources=[";
for(size_t i = 0; i < value.size(); i++)
{
details << value[i];
if(i < value.size() - 1)
details << ", ";
}
details << "]";
if(problem.useBias())
details << ", bias_src=" << static_cast<int>(problem.biasSrc());
PredicateDebugger::printRow(stream, rv, this->type(), details.str());
return rv;
}
};
struct Sparse : public Predicate_CRTP<Sparse, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
int value;
Sparse() = default;
Sparse(int value)
: value(value)
{
}
static std::string Type()
{
return "Sparse";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.sparse() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.sparse(), "==", "sol", value);
}
};
struct SwizzleTensorA : public Predicate_CRTP<SwizzleTensorA, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
SwizzleTensorA() = default;
SwizzleTensorA(bool value)
: value(value)
{
}
static std::string Type()
{
return "SwizzleTensorA";
}
bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.swizzleTensorA() == value;
}
bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.swizzleTensorA(), "==", "sol", value);
}
};
struct SwizzleTensorB : public Predicate_CRTP<SwizzleTensorB, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
SwizzleTensorB() = default;
SwizzleTensorB(bool value)
: value(value)
{
}
static std::string Type()
{
return "SwizzleTensorB";
}
bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.swizzleTensorB() == value;
}
bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.swizzleTensorB(), "==", "sol", value);
}
};
struct F32XdlMathOpEqual
: public Predicate_CRTP<F32XdlMathOpEqual, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
rocisa::DataType value;
F32XdlMathOpEqual() = default;
F32XdlMathOpEqual(rocisa::DataType value)
: value(value)
{
}
static std::string Type()
{
return "F32XdlMathOp";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.f32XdlMathOp() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.f32XdlMathOp(), "==", "sol", value);
}
};
struct SupportDeviceUserArguments
: public Predicate_CRTP<SupportDeviceUserArguments, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
bool value;
SupportDeviceUserArguments() = default;
SupportDeviceUserArguments(bool value)
: value(value)
{
}
static std::string Type()
{
return "SupportDeviceUserArguments";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
// Currently some solutions in gemm cannot enable this feature because lack of sgpr.
if(problem.getUseDeviceUserArguments() && problem.groupedGemm())
return problem.getUseDeviceUserArguments() == value;
return true;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
bool rv = (*this)(problem);
if(problem.getUseDeviceUserArguments())
return debugEvalCmp(problem,
stream,
"prob",
problem.getUseDeviceUserArguments(),
"==",
"sol",
value);
return rv;
}
};
struct WorkgroupMappingXCCCheck
: public Predicate_CRTP<WorkgroupMappingXCCCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
// value = [XCC, XCCG]
std::array<int, 2> value;
size_t cuCount;
WorkgroupMappingXCCCheck()
{
auto pHardware = hip::GetCurrentDevice();
assert(pHardware != nullptr);
Hardware const& hardware = *pHardware;
AMDGPU const* pAMDGPU = dynamic_cast<AMDGPU const*>(&hardware);
cuCount = pAMDGPU->computeUnitCount;
}
WorkgroupMappingXCCCheck(std::array<int, 2> value)
: value(value)
{
auto pHardware = hip::GetCurrentDevice();
assert(pHardware != nullptr);
Hardware const& hardware = *pHardware;
AMDGPU const* pAMDGPU = dynamic_cast<AMDGPU const*>(&hardware);
cuCount = pAMDGPU->computeUnitCount;
}
/// Constructor for testing: inject cuCount so selection logic can be
/// unit-tested without a GPU (e.g. ROCM-2963: 38-CU partition alignment).
WorkgroupMappingXCCCheck(std::array<int, 2> value, size_t cuCountForTest)
: value(value)
, cuCount(cuCountForTest)
{
}
static std::string Type()
{
return "WorkgroupMappingXCCCheck";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
// If XCC == -1, we automatically set it to the number XCCs.
// In this case, no predicate is needed.
if(value[0] == -1)
return true;
// NB: If this solution is a cu-fallback for current hardware.
// We overwrite the XCC to 1 to make sure this can pass.
// But we also have to notice we are passing the correct XCC to kernel.
// (i.e. Remember to do param.setWGMXCC(1) when running the kernel)
size_t XCC = (problem.getParams().fallbackStatus()) ? 1 : value[0];
size_t XCCG = (value[1] == -1) ? cuCount : value[1];
return ((XCC & (XCC - 1)) == 0) && XCCG % XCC == 0;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
if(value[0] == -1)
return true;
size_t XCC = (problem.getParams().fallbackStatus()) ? 1 : value[0];
size_t XCCG = (value[1] == -1) ? cuCount : value[1];
return debugEvalCmp(problem,
stream,
"WGMXCCG",
XCCG,
"%",
"WGMXCC",
XCC,
"==",
0);
}
};
struct MXBlockA
: public Predicate_CRTP<MXBlockA, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
int value;
MXBlockA() = default;
MXBlockA(int value)
: value(value)
{
}
static std::string Type()
{
return "MXBlockA";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.mxBlockA() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.mxBlockA(), "==", "sol", value);
}
};
struct MXBlockB
: public Predicate_CRTP<MXBlockB, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
int value;
MXBlockB() = default;
MXBlockB(int value)
: value(value)
{
}
static std::string Type()
{
return "MXBlockB";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.mxBlockB() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.mxBlockB(), "==", "sol", value);
}
};
struct DataTypeMXSA
: public Predicate_CRTP<DataTypeMXSA, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
rocisa::DataType value;
DataTypeMXSA() = default;
DataTypeMXSA(rocisa::DataType value)
: value(value)
{
}
static std::string Type()
{
return "DataTypeMXSA";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.mxTypeA() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.mxTypeA(), "==", "sol", value);
}
};
struct DataTypeMXSB
: public Predicate_CRTP<DataTypeMXSB, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
rocisa::DataType value;
DataTypeMXSB() = default;
DataTypeMXSB(rocisa::DataType value)
: value(value)
{
}
static std::string Type()
{
return "DataTypeMXSB";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
return problem.mxTypeB() == value;
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
return debugEvalCmp(
problem, stream, "prob", problem.mxTypeB(), "==", "sol", value);
}
};
struct ClusterDimCheck
: public Predicate_CRTP<ClusterDimCheck, ContractionProblemGemm>
{
enum
{
HasIndex = false,
HasValue = true
};
size_t index;
std::array<int, 5> value;
ClusterDimCheck() = default;
ClusterDimCheck(size_t index, std::array<int, 5> value)
: index(index)
, value(value)
{
}
static std::string Type()
{
return "ClusterDimCheck";
}
virtual bool operator()(ContractionProblemGemm const& problem) const override
{
int gsu = problem.getParams().gsu() > 0 ? problem.getParams().gsu() : value[2];
gsu = gsu > 1 ? gsu : 1;
int numWG_x = static_cast<int>(
std::ceil(static_cast<float>(problem.freeSizeA(0)) / value[0])
);
int numWG_y = static_cast<int>(
std::ceil(static_cast<float>(problem.freeSizeB(0)) / value[1])
) * gsu;
bool divisible_x = (numWG_x % value[3]) == 0;
bool divisible_y = (numWG_y % value[4]) == 0;
return (divisible_x and divisible_y);
}
virtual bool debugEval(ContractionProblemGemm const& problem,
std::ostream& stream) const override
{
int gsu = problem.getParams().gsu() > 0 ? problem.getParams().gsu() : value[2];
gsu = gsu > 1 ? gsu : 1;
int numWG_x = static_cast<int>(
std::ceil(static_cast<float>(problem.freeSizeA(0)) / value[0])
);
int numWG_y = static_cast<int>(
std::ceil(static_cast<float>(problem.freeSizeB(0)) / value[1])
) * gsu;
std::vector<int> numWG = {numWG_x, numWG_y};
std::vector<int> clusterDim = {value[3], value[4]};
return debugEvalCmp(problem,
stream,
"prob's workgroup number [x, y]",
numWG,
"%",
"cluster dimension [x, y]",
clusterDim);
}
};
} // namespace Contraction
/**
* @}
*/
} // namespace Predicates
} // namespace TensileLite