Skip to content

Commit 40149b8

Browse files
committed
Stop auto-routing aarch64 3x3 convs to the indirect path
The indirect convolution round-trips the c_out accumulator through memory once per (tap, in-channel), so it loses to the blocked-GEMM im2col path for any non-trivial channel count. Gate it on output channels, off by default; YSCV_INDIRECT_MAX_COUT re-enables it for narrow convs. A53 yolo11n (4 threads): 3.0s -> 1.1s, tracker unchanged.
1 parent d6db7d6 commit 40149b8

1 file changed

Lines changed: 17 additions & 7 deletions

File tree

  • crates/yscv-onnx/src/runner/conv

crates/yscv-onnx/src/runner/conv/mod.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -473,14 +473,24 @@ fn conv_compute_nhwc(
473473
// simple strided indexing.
474474
#[cfg(target_arch = "aarch64")]
475475
{
476-
// The first-layer 3-channel 3×3 stride-2 Conv routes to its
477-
// dedicated microkernel (via conv2d_nhwc_padded below), which holds
478-
// the c_out accumulators in registers across the 27 taps. The
479-
// generic indirect path round-trips the accumulator through memory
480-
// once per (tap, in-channel) — fine when c_in is wide enough to
481-
// amortise it, but ~27× off peak at c_in = 3.
476+
// The indirect path round-trips the c_out accumulator through memory
477+
// once per (tap, in-channel), so it loses to the blocked-GEMM im2col
478+
// below once the channel counts are non-trivial. It is off by default;
479+
// YSCV_INDIRECT_MAX_COUT sets an output-channel ceiling under which it
480+
// is used. The first-layer 3-channel 3×3 stride-2 Conv keeps its own
481+
// register-blocked microkernel in conv2d_nhwc_padded.
482482
let is_first_layer_3ch = input_nhwc.shape()[3] == 3 && sh == 2 && sw == 2;
483-
if kh == 3 && kw == 3 && group == 1 && !cfg!(miri) && !is_first_layer_3ch {
483+
let indirect_max_cout = std::env::var("YSCV_INDIRECT_MAX_COUT")
484+
.ok()
485+
.and_then(|v| v.parse::<usize>().ok())
486+
.unwrap_or(0);
487+
if kh == 3
488+
&& kw == 3
489+
&& group == 1
490+
&& !cfg!(miri)
491+
&& !is_first_layer_3ch
492+
&& o_ch <= indirect_max_cout
493+
{
484494
let t = yscv_kernels::conv2d_nhwc_indirect_padded(
485495
input_nhwc, w_nhwc, bias, sh, sw, pt, pl, pb, pr, activation,
486496
)

0 commit comments

Comments
 (0)