From a344e8a1a83787c5481dff3d20f95ff7f6fd8388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Sun, 13 Sep 2026 14:59:30 +0200 Subject: [PATCH] Vulkan: use the 1x1 depthwise output tile for 5x5 kernels on Mali too The 3x3 depthwise shader already drops to a 1x1 output tile on Mali. The 5x5 one kept the default 4x2 tile, so each invocation held 8 accumulators and gathered a separate 25 tap window for every one of them. That spills, and the cost is easy to see next to a 3x3 in the same model: a 5x5 dispatch covering 6000 work items took 4.6 ms while a 3x3 covering 20000 took 0.27 ms, roughly 57x the time per work item for 2.8x the arithmetic. Same rule as 3x3, so Adreno and every other device are untouched. Measured on a Mali-G76 (Galaxy S10+), fp16, interleaved GPU timestamps over 3 to 4 rounds. Depthwise convolution time, median: | model | before | after | | --- | --- | --- | | ssdlite320_mobilenet_v3_large | 19.05 ms | 12.08 ms | | lraspp_mobilenet_v3_large | 15.04 ms | 11.49 ms | | deeplabv3_mobilenet_v3_large | 14.93 ms | 11.52 ms | Ranges do not overlap on any of the three. The individual 5x5 dispatches go from 4.52-4.68 ms to 1.42-1.46 ms (3.2x) and from 0.87-1.12 ms to 0.34-0.44 ms (2.6x). Output is bit identical before and after. --- .../runtime/graph/ops/glsl/conv2d_dw_output_tile.yaml | 9 +++++++++ backends/vulkan/runtime/graph/ops/impl/Conv2dDW.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/backends/vulkan/runtime/graph/ops/glsl/conv2d_dw_output_tile.yaml b/backends/vulkan/runtime/graph/ops/glsl/conv2d_dw_output_tile.yaml index 19cacdef178..3dbdb802796 100644 --- a/backends/vulkan/runtime/graph/ops/glsl/conv2d_dw_output_tile.yaml +++ b/backends/vulkan/runtime/graph/ops/glsl/conv2d_dw_output_tile.yaml @@ -32,3 +32,12 @@ conv2d_dw_output_tile: OPERATOR: clamp(X, A, B) BATCH_SIZE_X: 1 BATCH_SIZE_Y: 1 + - NAME: conv2d_dw_output_tile_5x5_b1x1 + TILE_SIZE: 5 + BATCH_SIZE_X: 1 + BATCH_SIZE_Y: 1 + - NAME: conv2d_dw_output_tile_5x5_b1x1_clamp + OPERATOR: clamp(X, A, B) + TILE_SIZE: 5 + BATCH_SIZE_X: 1 + BATCH_SIZE_Y: 1 diff --git a/backends/vulkan/runtime/graph/ops/impl/Conv2dDW.cpp b/backends/vulkan/runtime/graph/ops/impl/Conv2dDW.cpp index a9d8483b2e2..74649051635 100644 --- a/backends/vulkan/runtime/graph/ops/impl/Conv2dDW.cpp +++ b/backends/vulkan/runtime/graph/ops/impl/Conv2dDW.cpp @@ -81,13 +81,13 @@ std::string pick_conv2d_dw_shader( kernel_name += "_sned"; } - if (is_3x3) { - kernel_name += "_output_tile_3x3"; + if (is_3x3 || is_5x5) { + kernel_name += is_3x3 ? "_output_tile_3x3" : "_output_tile_5x5"; + // Mali spills with the default 4x2 output tile: each invocation holds 8 + // accumulators and loads an overlapping input window for each of them. if (stride_equals_dilation && graph.device_is_mali()) { kernel_name += "_b1x1"; } - } else if (is_5x5) { - kernel_name += "_output_tile_5x5"; } if (clamp_out) {