Files
2026-07-13 12:40:42 +08:00

299 lines
12 KiB
Python

# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
head_template = """// auto-generated by generate_configs.py
#pragma once
#include "cutlass/gemm_coord.h"
namespace ap {
constexpr int kNumConfigsHalf = ${num_configs_fp16};
constexpr int kNumConfigsFloat = ${num_configs_fp32};
template <int SwizzleFactor, bool Batched> struct SwizzleWrapper {
using Type =
cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<SwizzleFactor>;
};
// template <int SwizzleFactor>
// struct SwizzleWrapper<SwizzleFactor, true> {
// using Type =
// cutlass::gemm::threadblock::GemmBatchedIdentityThreadblockSwizzle;
// };
"""
autotune_wrapper_template = """
#define AP_AUTOTUNE_${datatype}(func, stream, ...) { \\
using FuncType = decltype(func<0>); \\
static int selected_config_id = -1; \\
static std::vector<std::function<FuncType>> \\
matmul_functions = { \\
${repeat_functions} \\
}; \\
if (selected_config_id == -1) { \\
selected_config_id = ap::ProfileBestConfig(matmul_functions, stream, ##__VA_ARGS__); \\
} \\
matmul_functions[selected_config_id](__VA_ARGS__); \\
}
"""
fp16_config_template_0 = """
template <typename ElementT, int SwizzleFactor, bool Batched, int Id = 0>
struct GemmTuningConfigs {
using TShape = cutlass::gemm::GemmShape<${tshape}>;
using WShape = cutlass::gemm::GemmShape<${wshape}>;
using IShape = cutlass::gemm::GemmShape<${ishape}>;
static constexpr int kNumStages = ${stages};
using SwizzleThreadBlock =
typename SwizzleWrapper<SwizzleFactor, Batched>::Type;
static constexpr int kId = Id;
};
"""
fp16_config_template = """
template <typename ElementT, int SwizzleFactor, bool Batched>
struct GemmTuningConfigs<ElementT, SwizzleFactor, Batched, ${config_id}> {
using TShape = cutlass::gemm::GemmShape<${tshape}>;
using WShape = cutlass::gemm::GemmShape<${wshape}>;
using IShape = cutlass::gemm::GemmShape<${ishape}>;
static constexpr int kNumStages = ${stages};
using SwizzleThreadBlock =
typename SwizzleWrapper<SwizzleFactor, Batched>::Type;
static constexpr int kId = ${config_id};
};
"""
fp32_config_template_0 = """
// Specialization for float
template <int SwizzleFactor, bool Batched, int Id>
struct GemmTuningConfigs<float, SwizzleFactor, Batched, Id> {
using TShape = cutlass::gemm::GemmShape<${tshape}>;
using WShape = cutlass::gemm::GemmShape<${wshape}>;
using IShape = cutlass::gemm::GemmShape<${ishape}>;
static constexpr int kNumStages = ${stages};
using SwizzleThreadBlock =
typename SwizzleWrapper<SwizzleFactor, Batched>::Type;
static constexpr int kId = Id;
};
"""
fp32_config_template = """
template <int SwizzleFactor, bool Batched>
struct GemmTuningConfigs<float, SwizzleFactor, Batched, ${config_id}> {
using TShape = cutlass::gemm::GemmShape<${tshape}>;
using WShape = cutlass::gemm::GemmShape<${wshape}>;
using IShape = cutlass::gemm::GemmShape<${ishape}>;
static constexpr int kNumStages = ${stages};
using SwizzleThreadBlock =
typename SwizzleWrapper<SwizzleFactor, Batched>::Type;
static constexpr int kId = ${config_id};
};
"""
tail_code_str = """
} // namespace ap
"""
class GemmTuningConfig:
def __init__(self, tshape, wshape, ishape, stages, level):
self.tshape = tshape
self.wshape = wshape
self.ishape = ishape
self.stages = stages
self.level = level
def __eq__(self, other):
def check_shape(s1, s2):
assert len(s1) == len(s2)
res = True
for i in range(len(s1)):
if s1[i] != s2[i]:
res = False
break
return res
res = check_shape(self.tshape, other.tshape)
res = res and check_shape(self.wshape, other.wshape)
res = res and check_shape(self.ishape, other.ishape)
res = res and self.stages == other.stages
return res
def all_configs_sm80_fp16():
all_tuning_configs_fp16 = [
GemmTuningConfig([16, 128, 64], [16, 32, 64], [16, 8, 16], 2, 2),
GemmTuningConfig([32, 128, 64], [32, 32, 64], [16, 8, 16], 2, 2),
GemmTuningConfig([64, 128, 64], [64, 64, 64], [16, 8, 16], 2, 2),
GemmTuningConfig([128, 128, 64], [64, 64, 64], [16, 8, 16], 2, 2),
GemmTuningConfig([128, 128, 64], [128, 32, 64], [16, 8, 16], 2, 2),
GemmTuningConfig([128, 256, 64], [64, 64, 64], [16, 8, 16], 2, 2),
GemmTuningConfig([256, 128, 64], [64, 64, 64], [16, 8, 16], 2, 1),
GemmTuningConfig([16, 128, 64], [16, 32, 64], [16, 8, 16], 3, 3),
GemmTuningConfig([32, 128, 64], [32, 32, 64], [16, 8, 16], 3, 2),
GemmTuningConfig([64, 128, 64], [32, 64, 64], [16, 8, 16], 3, 1),
GemmTuningConfig([64, 128, 64], [64, 64, 64], [16, 8, 16], 3, 1),
GemmTuningConfig([64, 256, 64], [64, 64, 64], [16, 8, 16], 3, 3),
GemmTuningConfig([128, 64, 64], [64, 32, 64], [16, 8, 16], 3, 1),
GemmTuningConfig([128, 128, 32], [64, 64, 32], [16, 8, 16], 3, 1),
GemmTuningConfig([128, 128, 64], [64, 64, 64], [16, 8, 16], 3, 1),
GemmTuningConfig([128, 128, 64], [128, 32, 64], [16, 8, 16], 3, 2),
GemmTuningConfig([128, 256, 32], [64, 64, 32], [16, 8, 16], 3, 2),
GemmTuningConfig([128, 256, 64], [64, 64, 64], [16, 8, 16], 3, 2),
GemmTuningConfig([256, 64, 32], [64, 64, 32], [16, 8, 16], 3, 1),
GemmTuningConfig([256, 64, 64], [64, 64, 64], [16, 8, 16], 3, 1),
GemmTuningConfig([256, 128, 32], [64, 64, 32], [16, 8, 16], 3, 1),
GemmTuningConfig([256, 128, 64], [64, 64, 64], [16, 8, 16], 3, 1),
GemmTuningConfig([16, 128, 64], [16, 32, 64], [16, 8, 16], 4, 3),
GemmTuningConfig([32, 128, 64], [32, 32, 64], [16, 8, 16], 4, 2),
GemmTuningConfig([64, 128, 64], [64, 64, 64], [16, 8, 16], 4, 2),
GemmTuningConfig([64, 256, 32], [64, 64, 32], [16, 8, 16], 4, 2),
GemmTuningConfig([64, 256, 64], [64, 64, 64], [16, 8, 16], 4, 3),
GemmTuningConfig([128, 32, 64], [32, 32, 64], [16, 8, 16], 4, 1),
GemmTuningConfig([128, 128, 32], [64, 64, 32], [16, 8, 16], 4, 1),
GemmTuningConfig([128, 128, 64], [64, 64, 64], [16, 8, 16], 4, 1),
GemmTuningConfig([128, 128, 64], [128, 32, 64], [16, 8, 16], 4, 2),
GemmTuningConfig([256, 64, 64], [64, 64, 64], [16, 8, 16], 4, 1),
GemmTuningConfig([256, 64, 32], [64, 64, 32], [16, 8, 16], 4, 1),
GemmTuningConfig([16, 64, 64], [16, 32, 64], [16, 8, 16], 5, 2),
GemmTuningConfig([16, 128, 64], [16, 32, 64], [16, 8, 16], 5, 3),
GemmTuningConfig([32, 64, 64], [16, 32, 64], [16, 8, 16], 5, 1),
GemmTuningConfig([32, 128, 64], [32, 32, 64], [16, 8, 16], 5, 3),
GemmTuningConfig([64, 64, 64], [32, 32, 64], [16, 8, 16], 5, 1),
GemmTuningConfig([64, 128, 64], [64, 64, 64], [16, 8, 16], 5, 3),
GemmTuningConfig([128, 128, 32], [64, 64, 32], [16, 8, 16], 5, 1),
GemmTuningConfig([128, 128, 64], [64, 64, 64], [16, 8, 16], 5, 1),
GemmTuningConfig([128, 128, 64], [128, 32, 64], [16, 8, 16], 5, 2),
GemmTuningConfig([64, 128, 32], [32, 64, 32], [16, 8, 16], 6, 1),
GemmTuningConfig([128, 64, 32], [64, 32, 32], [16, 8, 16], 6, 1),
GemmTuningConfig([128, 32, 32], [32, 32, 32], [16, 8, 16], 7, 1),
GemmTuningConfig([64, 64, 32], [32, 32, 32], [16, 8, 16], 10, 1),
]
return all_tuning_configs_fp16
def all_configs_sm80_fp32():
all_tuning_configs_fp32 = [
GemmTuningConfig([64, 64, 16], [32, 32, 16], [16, 8, 8], 3, 1),
GemmTuningConfig([64, 64, 32], [32, 32, 32], [16, 8, 8], 3, 1),
GemmTuningConfig([64, 128, 32], [32, 64, 32], [16, 8, 8], 3, 1),
GemmTuningConfig([64, 256, 16], [32, 64, 16], [16, 8, 8], 3, 1),
GemmTuningConfig([64, 256, 32], [32, 64, 32], [16, 8, 8], 3, 1),
GemmTuningConfig([128, 64, 32], [64, 32, 32], [16, 8, 8], 3, 1),
GemmTuningConfig([128, 128, 16], [32, 64, 16], [16, 8, 8], 3, 1),
GemmTuningConfig([128, 128, 32], [32, 64, 32], [16, 8, 8], 3, 1),
GemmTuningConfig([256, 64, 16], [64, 32, 16], [16, 8, 8], 3, 1),
GemmTuningConfig([256, 64, 32], [64, 32, 32], [16, 8, 8], 3, 1),
GemmTuningConfig([64, 128, 16], [32, 64, 16], [16, 8, 8], 4, 1),
GemmTuningConfig([128, 64, 16], [64, 32, 16], [16, 8, 8], 4, 1),
GemmTuningConfig([128, 128, 16], [32, 64, 16], [16, 8, 8], 4, 1),
]
return all_tuning_configs_fp32
def generate_autotune_wrapper(datatype, num_configs):
repeat_func_strs = []
for i in range(num_configs):
repeat_func_strs.append(f"func<{i}>")
code_str = autotune_wrapper_template.replace(
"${datatype}", datatype
).replace("${repeat_functions}", ", \\\n ".join(repeat_func_strs))
return code_str
def get_configs(all_configs_list, level=3):
consigs_list = []
for i in range(len(all_configs_list)):
if all_configs_list[i].level <= level:
already_have = False
for config in consigs_list:
if config == all_configs_list[i]:
print(f"-- The {i}-th config is repeat.")
already_have = True
break
if not already_have:
consigs_list.append(all_configs_list[i])
return consigs_list
def generate_configs(configs_list, config_template_0, config_template):
code_str = ""
config_id = 0
for config in configs_list:
if config_id == 0:
config_code_str = (
config_template_0.replace(
"${tshape}", ", ".join(map(str, config.tshape))
)
.replace("${wshape}", ", ".join(map(str, config.wshape)))
.replace("${ishape}", ", ".join(map(str, config.ishape)))
.replace("${stages}", str(config.stages))
)
else:
config_code_str = (
config_template.replace(
"${tshape}", ", ".join(map(str, config.tshape))
)
.replace("${wshape}", ", ".join(map(str, config.wshape)))
.replace("${ishape}", ", ".join(map(str, config.ishape)))
.replace("${stages}", str(config.stages))
.replace("${config_id}", str(config_id))
)
code_str += config_code_str
config_id += 1
return len(configs_list), code_str
def main():
level = 1
num_fp16_configs, fp16_configs_code_str = generate_configs(
configs_list=get_configs(all_configs_sm80_fp16(), level=level),
config_template_0=fp16_config_template_0,
config_template=fp16_config_template,
)
num_fp32_configs, fp32_configs_code_str = generate_configs(
configs_list=get_configs(all_configs_sm80_fp32(), level=level),
config_template_0=fp32_config_template_0,
config_template=fp32_config_template,
)
print(
f"-- Total {num_fp16_configs} fp16 configs, {num_fp32_configs} fp32 configs"
)
head_code_str = head_template.replace(
"${num_configs_fp16}", str(num_fp16_configs)
).replace("${num_configs_fp32}", str(num_fp32_configs))
fp16_autotune_wrapper_code_str = generate_autotune_wrapper(
"half", num_fp16_configs
)
fp32_autotune_wrapper_code_str = generate_autotune_wrapper(
"float", num_fp32_configs
)
with open("all_tuning_configs.h", "w") as f:
f.write(head_code_str)
f.write(fp16_autotune_wrapper_code_str)
f.write(fp32_autotune_wrapper_code_str)
f.write(fp16_configs_code_str)
f.write(fp32_configs_code_str)
f.write(tail_code_str)
if __name__ == "__main__":
main()