use std::sync::LazyLock;
use cubecl::{ir::ElemType, prelude::*};
use cubek_test_utils::CatalogEntry;
use crate::components::instructions::ReduceOperationConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReduceBenchKind {
Single,
TwoLaunch,
Fused,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReduceBenchPrecision {
F32,
F16,
}
impl ReduceBenchPrecision {
pub fn dtype(self) -> ElemType {
match self {
ReduceBenchPrecision::F32 => f32::elem_type_native(),
ReduceBenchPrecision::F16 => half::f16::elem_type_native(),
}
}
pub fn suffix(self) -> &'static str {
match self {
ReduceBenchPrecision::F32 => "",
ReduceBenchPrecision::F16 => "_f16",
}
}
fn label(self) -> &'static str {
match self {
ReduceBenchPrecision::F32 => "",
ReduceBenchPrecision::F16 => " [f16]",
}
}
}
static PRECISIONS: LazyLock<Vec<ReduceBenchPrecision>> = LazyLock::new(|| {
let client = cubecl::test_device().client();
let mut precisions = vec![ReduceBenchPrecision::F32];
if cubek_test_utils::supports_f16_arithmetic(&client) {
precisions.push(ReduceBenchPrecision::F16);
}
precisions
});
pub fn precisions() -> Vec<ReduceBenchPrecision> {
PRECISIONS.clone()
}
pub struct ReduceProblem {
pub shape: Vec<usize>,
pub axis: usize,
pub config: ReduceOperationConfig,
pub kind: ReduceBenchKind,
pub precision: ReduceBenchPrecision,
}
fn extended_tier() -> bool {
!matches!(
std::env::var("CUBEK_BENCH_TIER")
.unwrap_or_default()
.to_lowercase()
.as_str(),
"" | "light"
)
}
pub fn problems() -> Vec<CatalogEntry<ReduceProblem>> {
precisions().into_iter().flat_map(problems_at).collect()
}
fn problems_at(precision: ReduceBenchPrecision) -> Vec<CatalogEntry<ReduceProblem>> {
let shape = || vec![32, 512, 4095];
let id = |name: String| format!("{name}{}", precision.suffix());
let label = |text: String| format!("{text}{}", precision.label());
let problem = |config, kind| ReduceProblem {
shape: shape(),
axis: 2,
config,
kind,
precision,
};
let mut entries = vec![
CatalogEntry::new(
id("sum_axis2_32x512x4095".to_string()),
label("Sum axis=2 (32x512x4095)".to_string()),
problem(ReduceOperationConfig::Sum, ReduceBenchKind::Single),
),
CatalogEntry::new(
id("arg_topk1_axis2_32x512x4095".to_string()),
label("ArgTopK(1) axis=2 (32x512x4095)".to_string()),
problem(ReduceOperationConfig::ArgTopK(1), ReduceBenchKind::Single),
),
CatalogEntry::new(
id("arg_topk2_axis2_32x512x4095".to_string()),
label("ArgTopK(2) axis=2 (32x512x4095)".to_string()),
problem(ReduceOperationConfig::ArgTopK(2), ReduceBenchKind::Single),
),
CatalogEntry::new(
id("arg_topk3_axis2_32x512x4095".to_string()),
label("ArgTopK(3) axis=2 (32x512x4095)".to_string()),
problem(ReduceOperationConfig::ArgTopK(3), ReduceBenchKind::Single),
),
];
for k in [1, 2, 3, 5] {
entries.push(CatalogEntry::new(
id(format!("topk{k}_single_axis2_32x512x4095")),
label(format!(
"TopK({k}) values only, 1 launch, axis=2 (32x512x4095)"
)),
problem(ReduceOperationConfig::TopK(k), ReduceBenchKind::Single),
));
entries.push(CatalogEntry::new(
id(format!("topk{k}_two_launch_axis2_32x512x4095")),
label(format!(
"TopK({k}) values+indices, 2 launches, axis=2 (32x512x4095)"
)),
problem(ReduceOperationConfig::TopK(k), ReduceBenchKind::TwoLaunch),
));
entries.push(CatalogEntry::new(
id(format!("topk{k}_fused_axis2_32x512x4095")),
label(format!(
"TopK({k}) values+indices, 1 fused launch, axis=2 (32x512x4095)"
)),
problem(ReduceOperationConfig::TopK(k), ReduceBenchKind::Fused),
));
}
let mut large_k = vec![16, 32, 64];
if extended_tier() {
large_k.extend([128, 256]);
}
for k in large_k {
entries.push(CatalogEntry::new(
id(format!("topk{k}_fused_axis2_32x512x4095")),
label(format!(
"TopK({k}) values+indices, 1 fused launch, axis=2 (32x512x4095)"
)),
problem(ReduceOperationConfig::TopK(k), ReduceBenchKind::Fused),
));
}
for (name, text, config) in [
("max", "Max", ReduceOperationConfig::Max),
("min", "Min", ReduceOperationConfig::Min),
] {
entries.push(CatalogEntry::new(
id(format!("{name}_single_axis2_32x512x4095")),
label(format!(
"{text} values only, 1 launch, axis=2 (32x512x4095)"
)),
problem(config, ReduceBenchKind::Single),
));
entries.push(CatalogEntry::new(
id(format!("{name}_two_launch_axis2_32x512x4095")),
label(format!(
"{text} values+indices, 2 launches, axis=2 (32x512x4095)"
)),
problem(config, ReduceBenchKind::TwoLaunch),
));
entries.push(CatalogEntry::new(
id(format!("{name}_fused_axis2_32x512x4095")),
label(format!(
"{text} values+indices, 1 fused launch, axis=2 (32x512x4095)"
)),
problem(config, ReduceBenchKind::Fused),
));
}
entries
}