Skip to content

causal_conv1d kernel improvement using PTO kernel & benchmark results - #601

Open
ChristosMatzoros wants to merge 19 commits into
sgl-project:mainfrom
ChristosMatzoros:causal-conv1d-tiling-onmain
Open

causal_conv1d kernel improvement using PTO kernel & benchmark results#601
ChristosMatzoros wants to merge 19 commits into
sgl-project:mainfrom
ChristosMatzoros:causal-conv1d-tiling-onmain

Conversation

@ChristosMatzoros

@ChristosMatzoros ChristosMatzoros commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

causal_conv1d: PTO-ISA tiling kernel vs main (AscendC) — benchmark results

Reimplements causal_conv1d (Mamba/GDN depthwise causal conv1d + bias + optional SiLU) on the PTO tile ISA, and improves the launch tiling. Closes #596

Head-to-head of this branch's PTO-ISA causal_conv1d against the AscendC kernel on main, on an Ascend 910B2 (48 AIV cores).

  • baseline mainf451a59 (AscendC)
  • branchcausal-conv1d-tiling-onmain@13ad3a2 (PTO-ISA), rebased onto main (f451a59)
  • 400 shapes, both layouts (3D dense + varlen/packed), 0 correctness failures (max-abs vs an fp32 reference, tol 6e-3).
  • Two metrics per shape, each a geometric mean over 100 warmed iterations: end-to-end per-call latency (torch.npu.Event, per-iteration synchronized) and kernel on-device time (torch_npu.profiler).
  • speedup = main / branch (>1 ⇒ this branch is faster). One idle NPU, idle-gated before + after each run.

The two layouts. Every shape is measured in both input layouts the op supports:

  • 3D dense[batch, seq, dim]: every sequence in the batch has the same length seq (a rectangular, padded tensor).
  • varlen / packed[cu_seqlen, dim]: variable-length sequences concatenated end-to-end into one flat 2D tensor, with query_start_loc marking the boundaries — the real continuous-batching / serving layout. The causal conv resets its window at each sequence boundary (a sequence never reads the previous one's tokens).

Summary

Geometric-mean speedup (main / branch, >1 ⇒ branch faster), by channel count (dim):

Qwen 3.5-4B, 35B Qwen 3.5-27B
layout metric dim=1024 dim=2048 dim=4096 dim=5120 dim=6144
3D dense kernel 1.83× 1.70× 1.49× 2.14× 1.86×
3D dense e2e 1.74× 1.62× 1.49× 1.93× 1.85×
varlen kernel 1.52× 1.38× 1.24× 1.80× 1.57×
varlen e2e 1.58× 1.55× 1.40× 1.83× 1.64×

Full per-shape results

3D dense · dim=1024 — 40 shapes (kernel median 1.78×, e2e median 1.71×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 213.3 125.0 1.71× 19.5 7.9 2.47× ok
3 128 204.9 120.0 1.71× 24.0 10.1 2.37× ok
4 128 202.7 119.9 1.69× 25.6 11.2 2.29× ok
6 128 193.7 117.3 1.65× 28.4 13.2 2.15× ok
12 128 194.9 116.3 1.68× 36.4 19.0 1.91× ok
16 128 195.8 114.6 1.71× 44.2 22.9 1.93× ok
32 128 199.9 114.6 1.74× 69.3 39.7 1.74× ok
64 128 246.7 126.5 1.95× 116.1 71.7 1.62× ok
128 128 340.1 189.0 1.80× 210.5 134.2 1.57× ok
256 128 529.5 315.1 1.68× 400.9 259.9 1.54× ok
1 256 227.2 133.2 1.71× 18.3 8.6 2.15× ok
3 256 228.6 125.2 1.83× 27.7 12.8 2.17× ok
4 256 227.0 118.4 1.92× 33.2 14.8 2.25× ok
6 256 227.5 112.3 2.03× 37.8 18.6 2.04× ok
12 256 228.3 132.5 1.72× 54.9 29.8 1.84× ok
16 256 194.8 115.8 1.68× 67.6 37.5 1.80× ok
32 256 242.9 122.8 1.98× 116.0 68.6 1.69× ok
64 256 336.4 185.5 1.81× 209.0 129.7 1.61× ok
128 256 527.9 313.4 1.68× 398.4 250.3 1.59× ok
256 256 905.3 569.8 1.59× 779.0 498.6 1.56× ok
1 512 196.4 122.5 1.60× 22.7 10.9 2.08× ok
3 512 191.6 117.0 1.64× 36.5 18.2 2.01× ok
4 512 199.2 116.9 1.70× 46.2 22.0 2.10× ok
6 512 190.8 119.4 1.60× 56.3 29.4 1.92× ok
12 512 217.3 108.7 2.00× 91.0 51.4 1.77× ok
16 512 244.8 119.6 2.05× 116.8 66.3 1.76× ok
32 512 336.4 176.0 1.91× 209.1 126.5 1.65× ok
64 512 525.8 297.1 1.77× 398.1 244.9 1.63× ok
128 512 907.3 539.5 1.68× 778.1 484.6 1.61× ok
256 512 1674.4 1015.9 1.65× 1536.7 959.1 1.60× ok
1 1024 190.2 116.3 1.64× 30.0 14.3 2.09× ok
3 1024 194.0 116.8 1.66× 54.0 29.0 1.86× ok
4 1024 195.6 121.7 1.61× 66.8 36.4 1.84× ok
6 1024 218.6 118.0 1.85× 90.9 50.9 1.79× ok
12 1024 292.1 152.7 1.91× 160.9 94.8 1.70× ok
16 1024 340.5 188.8 1.80× 208.9 124.2 1.68× ok
32 1024 528.8 300.8 1.76× 397.5 242.0 1.64× ok
64 1024 922.8 534.2 1.73× 777.6 478.5 1.62× ok
128 1024 1661.5 1208.5 1.38× 1534.8 948.2 1.62× ok
256 1024 3174.9 1960.2 1.62× 3045.5 1886.2 1.61× ok
3D dense · dim=2048 — 40 shapes (kernel median 1.62×, e2e median 1.63×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 196.8 115.1 1.71× 18.4 8.5 2.16× ok
3 128 194.6 113.8 1.71× 26.6 12.2 2.18× ok
4 128 195.8 114.5 1.71× 29.9 13.9 2.15× ok
6 128 195.1 114.2 1.71× 33.5 17.2 1.95× ok
12 128 198.0 114.2 1.73× 46.6 26.8 1.74× ok
16 128 196.6 113.9 1.73× 59.4 33.3 1.78× ok
32 128 220.1 121.0 1.82× 96.0 60.5 1.59× ok
64 128 296.8 175.3 1.69× 173.3 113.9 1.52× ok
128 128 452.2 280.1 1.61× 325.8 217.5 1.50× ok
256 128 755.8 495.0 1.53× 631.5 434.2 1.45× ok
1 256 192.0 125.6 1.53× 21.8 10.3 2.12× ok
3 256 190.0 116.8 1.63× 33.4 16.9 1.98× ok
4 256 189.3 125.6 1.51× 38.9 20.3 1.92× ok
6 256 191.8 124.5 1.54× 47.7 26.4 1.81× ok
12 256 200.1 123.1 1.63× 74.7 45.1 1.65× ok
16 256 217.8 121.6 1.79× 96.4 57.8 1.67× ok
32 256 292.8 172.6 1.70× 172.8 109.9 1.57× ok
64 256 446.0 275.8 1.62× 324.4 212.5 1.53× ok
128 256 752.5 482.2 1.56× 628.0 420.0 1.50× ok
256 256 1364.8 894.4 1.53× 1236.0 828.5 1.49× ok
1 512 191.9 122.2 1.57× 29.3 13.7 2.15× ok
3 512 195.9 114.2 1.72× 47.9 26.1 1.83× ok
4 512 200.0 121.9 1.64× 58.3 32.4 1.80× ok
6 512 208.8 120.8 1.73× 75.7 44.8 1.69× ok
12 512 264.7 206.4 1.28× 131.7 82.0 1.61× ok
16 512 305.1 248.2 1.23× 172.6 106.9 1.61× ok
32 512 457.7 269.9 1.70× 325.1 207.8 1.56× ok
64 512 760.9 469.6 1.62× 627.6 410.7 1.53× ok
128 512 1366.9 871.0 1.57× 1233.9 810.9 1.52× ok
256 512 2581.6 1676.6 1.54× 2446.7 1612.5 1.52× ok
1 1024 191.7 126.2 1.52× 39.9 19.9 2.00× ok
3 1024 201.3 117.7 1.71× 76.3 44.5 1.72× ok
4 1024 221.1 123.0 1.80× 96.0 57.1 1.68× ok
6 1024 246.6 139.8 1.76× 132.5 81.6 1.62× ok
12 1024 374.1 225.4 1.66× 245.5 155.8 1.58× ok
16 1024 451.4 278.5 1.62× 324.8 205.2 1.58× ok
32 1024 754.6 542.9 1.39× 626.6 405.8 1.54× ok
64 1024 1367.2 823.6 1.66× 1233.2 804.0 1.53× ok
128 1024 2583.2 1614.2 1.60× 2445.2 1599.1 1.53× ok
256 1024 5000.5 3247.1 1.54× 4872.9 3186.0 1.53× ok
3D dense · dim=4096 — 40 shapes (kernel median 1.40×, e2e median 1.48×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 188.1 151.1 1.25× 23.4 10.4 2.25× ok
3 128 189.6 156.4 1.21× 33.8 17.0 1.99× ok
4 128 192.4 140.1 1.37× 38.8 20.2 1.92× ok
6 128 192.2 121.3 1.58× 44.2 26.5 1.67× ok
12 128 193.4 111.9 1.73× 68.4 46.0 1.49× ok
16 128 215.0 123.9 1.74× 88.2 60.1 1.47× ok
32 128 281.4 205.8 1.37× 153.9 113.3 1.36× ok
64 128 414.3 273.3 1.52× 288.3 216.3 1.33× ok
128 128 682.7 500.4 1.36× 554.6 435.4 1.27× ok
256 128 1219.5 896.3 1.36× 1087.7 838.6 1.30× ok
1 256 198.7 121.9 1.63× 30.5 13.9 2.19× ok
3 256 189.4 121.0 1.57× 46.4 26.2 1.77× ok
4 256 188.8 123.8 1.52× 55.9 32.5 1.72× ok
6 256 196.4 123.5 1.59× 68.7 45.0 1.53× ok
12 256 242.4 145.8 1.66× 118.1 82.8 1.43× ok
16 256 279.5 172.3 1.62× 155.3 109.6 1.42× ok
32 256 414.7 272.2 1.52× 287.5 212.5 1.35× ok
64 256 682.1 479.6 1.42× 553.6 419.3 1.32× ok
128 256 1210.3 902.6 1.34× 1085.0 830.2 1.31× ok
256 256 2272.9 1715.8 1.32× 2149.6 1651.1 1.30× ok
1 512 195.3 118.6 1.65× 36.1 20.1 1.79× ok
3 512 204.0 120.2 1.70× 71.1 44.7 1.59× ok
4 512 220.7 117.5 1.88× 89.1 57.1 1.56× ok
6 512 249.7 136.6 1.83× 118.5 81.9 1.45× ok
12 512 343.9 215.5 1.60× 217.4 156.4 1.39× ok
16 512 416.3 261.7 1.59× 287.4 207.5 1.39× ok
32 512 681.9 472.4 1.44× 552.8 410.4 1.35× ok
64 512 1212.1 871.7 1.39× 1083.8 810.4 1.34× ok
128 512 2281.3 1674.8 1.36× 2147.5 1613.4 1.33× ok
256 512 4405.2 3273.7 1.35× 4272.6 3215.7 1.33× ok
1 1024 198.9 143.8 1.38× 56.0 32.3 1.73× ok
3 1024 254.6 153.1 1.66× 120.8 81.5 1.48× ok
4 1024 286.1 176.1 1.62× 155.8 106.1 1.47× ok
6 1024 351.5 228.8 1.54× 220.3 155.6 1.42× ok
12 1024 548.2 377.2 1.45× 416.9 304.0 1.37× ok
16 1024 684.5 476.1 1.44× 552.6 405.5 1.36× ok
32 1024 1215.7 876.9 1.39× 1082.9 803.5 1.35× ok
64 1024 2278.8 1660.7 1.37× 2146.1 1598.0 1.34× ok
128 1024 4414.2 3340.3 1.32× 4269.4 3187.4 1.34× ok
256 1024 8648.0 6557.6 1.32× 8519.0 6366.1 1.34× ok
3D dense · dim=5120 — 40 shapes (kernel median 2.15×, e2e median 2.13×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 189.5 134.6 1.41× 22.1 11.2 1.97× ok
3 128 195.6 183.4 1.07× 38.5 19.0 2.03× ok
4 128 192.4 145.2 1.32× 46.1 22.9 2.01× ok
6 128 195.0 132.9 1.47× 63.0 30.5 2.06× ok
12 128 238.4 187.4 1.27× 110.8 53.5 2.07× ok
16 128 272.4 132.3 2.06× 146.7 70.5 2.08× ok
32 128 409.4 199.2 2.06× 280.2 134.1 2.09× ok
64 128 679.4 318.2 2.13× 546.6 258.1 2.12× ok
128 128 1208.2 580.1 2.08× 1080.5 520.4 2.08× ok
256 128 2286.6 1066.8 2.14× 2148.4 1006.2 2.13× ok
1 256 189.4 122.5 1.55× 29.2 15.2 1.93× ok
3 256 194.5 121.7 1.60× 63.6 30.2 2.11× ok
4 256 203.7 121.5 1.68× 79.3 37.6 2.11× ok
6 256 237.0 121.1 1.96× 113.7 52.6 2.16× ok
12 256 335.4 157.8 2.13× 212.5 97.9 2.17× ok
16 256 403.1 196.1 2.06× 279.6 130.1 2.15× ok
32 256 666.7 319.6 2.09× 545.7 254.4 2.15× ok
64 256 1200.8 567.8 2.12× 1076.9 501.8 2.15× ok
128 256 2264.2 1058.0 2.14× 2142.2 995.1 2.15× ok
256 256 4403.3 2053.2 2.15× 4271.2 1986.8 2.15× ok
1 512 196.4 117.3 1.67× 46.2 22.9 2.02× ok
3 512 244.9 127.8 1.92× 112.5 52.2 2.15× ok
4 512 280.1 123.8 2.26× 147.8 67.3 2.19× ok
6 512 344.4 154.7 2.23× 212.4 97.0 2.19× ok
12 512 542.4 245.3 2.21× 412.0 186.9 2.21× ok
16 512 671.1 310.9 2.16× 543.9 248.2 2.19× ok
32 512 1201.1 550.0 2.18× 1076.2 492.3 2.19× ok
64 512 2271.8 1033.5 2.20× 2138.5 973.7 2.20× ok
128 512 4397.8 2006.5 2.19× 4264.9 1939.6 2.20× ok
256 512 8648.8 3926.5 2.20× 8519.4 3868.0 2.20× ok
1 1024 208.2 170.4 1.22× 80.1 37.4 2.15× ok
3 1024 340.1 164.3 2.07× 212.1 96.7 2.19× ok
4 1024 408.6 190.8 2.14× 280.6 126.4 2.22× ok
6 1024 541.1 247.7 2.18× 410.4 185.9 2.21× ok
12 1024 941.4 427.0 2.21× 810.9 364.7 2.22× ok
16 1024 1205.8 546.0 2.21× 1075.0 486.6 2.21× ok
32 1024 2275.0 1029.9 2.21× 2139.3 966.9 2.21× ok
64 1024 4418.4 1991.1 2.22× 4262.3 1922.2 2.22× ok
128 1024 8660.2 3906.1 2.22× 8512.2 3836.9 2.22× ok
256 1024 17148.7 7783.4 2.20× 17011.3 7664.6 2.22× ok
3D dense · dim=6144 — 40 shapes (kernel median 1.88×, e2e median 1.90×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 190.1 118.6 1.60× 21.9 12.1 1.81× ok
3 128 192.5 120.1 1.60× 37.1 20.9 1.77× ok
4 128 190.7 119.2 1.60× 49.2 25.7 1.92× ok
6 128 191.0 119.1 1.60× 63.4 34.4 1.85× ok
12 128 238.9 122.1 1.96× 112.7 61.1 1.84× ok
16 128 274.2 139.8 1.96× 147.7 80.8 1.83× ok
32 128 403.9 213.3 1.89× 280.4 154.7 1.81× ok
64 128 690.5 364.1 1.90× 548.6 301.2 1.82× ok
128 128 1211.5 667.7 1.81× 1079.4 604.5 1.79× ok
256 128 2282.4 1238.8 1.84× 2149.7 1173.5 1.83× ok
1 256 189.9 121.2 1.57× 30.3 16.7 1.82× ok
3 256 198.5 121.8 1.63× 62.2 34.0 1.83× ok
4 256 201.8 115.3 1.75× 81.2 42.7 1.90× ok
6 256 242.8 121.2 2.00× 112.8 60.3 1.87× ok
12 256 344.1 171.9 2.00× 213.7 113.3 1.89× ok
16 256 409.6 212.3 1.93× 279.9 150.6 1.86× ok
32 256 676.9 357.1 1.90× 546.3 295.3 1.85× ok
64 256 1209.7 647.8 1.87× 1078.4 583.7 1.85× ok
128 256 2274.1 1218.5 1.87× 2141.5 1159.0 1.85× ok
256 256 4395.1 2383.7 1.84× 4272.7 2319.6 1.84× ok
1 512 197.8 112.0 1.77× 47.4 25.6 1.85× ok
3 512 242.9 116.7 2.08× 112.8 60.0 1.88× ok
4 512 276.5 135.2 2.04× 146.8 77.6 1.89× ok
6 512 343.8 192.2 1.79× 213.3 112.3 1.90× ok
12 512 543.0 273.7 1.98× 410.6 216.9 1.89× ok
16 512 675.2 346.9 1.95× 545.5 289.2 1.89× ok
32 512 1202.9 634.4 1.90× 1075.8 573.0 1.88× ok
64 512 2272.3 1193.4 1.90× 2140.2 1134.7 1.89× ok
128 512 4398.2 2319.3 1.90× 4266.0 2263.2 1.89× ok
256 512 8664.2 4663.9 1.86× 8519.1 4517.9 1.89× ok
1 1024 197.5 116.1 1.70× 79.4 42.6 1.86× ok
3 1024 342.6 177.0 1.94× 212.3 112.0 1.90× ok
4 1024 412.9 209.8 1.97× 278.0 146.6 1.90× ok
6 1024 543.8 276.5 1.97× 411.8 216.1 1.91× ok
12 1024 941.9 484.8 1.94× 808.9 425.0 1.90× ok
16 1024 1160.3 628.0 1.85× 1076.8 567.3 1.90× ok
32 1024 2279.2 1190.4 1.92× 2139.2 1127.9 1.90× ok
64 1024 4393.4 2301.0 1.91× 4263.8 2244.9 1.90× ok
128 1024 8627.3 4548.2 1.90× 8512.4 4481.8 1.90× ok
256 1024 17162.3 9221.9 1.86× 17010.9 8960.5 1.90× ok
varlen / packed · dim=1024 — 40 shapes (kernel median 1.45×, e2e median 1.61×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 198.5 119.0 1.67× 18.1 8.1 2.24× ok
3 128 199.1 115.9 1.72× 21.9 10.2 2.15× ok
4 128 238.1 117.7 2.02× 25.8 12.1 2.13× ok
6 128 190.8 116.6 1.64× 27.6 14.4 1.92× ok
12 128 195.2 117.0 1.67× 35.7 23.1 1.55× ok
16 128 199.8 117.2 1.71× 42.5 28.1 1.51× ok
32 128 199.2 119.9 1.66× 66.4 45.2 1.47× ok
64 128 252.3 140.1 1.80× 119.4 81.5 1.47× ok
128 128 342.7 285.5 1.20× 211.5 146.7 1.44× ok
256 128 516.5 348.4 1.48× 391.9 293.2 1.34× ok
1 256 200.8 155.1 1.29× 16.7 8.7 1.93× ok
3 256 202.2 117.9 1.72× 28.2 15.2 1.86× ok
4 256 198.2 122.3 1.62× 28.4 17.3 1.64× ok
6 256 201.6 123.3 1.64× 37.0 22.8 1.62× ok
12 256 203.0 121.0 1.68× 59.7 38.1 1.57× ok
16 256 186.9 115.3 1.62× 63.7 48.3 1.32× ok
32 256 242.1 138.8 1.75× 115.6 83.7 1.38× ok
64 256 338.6 212.7 1.59× 211.2 158.5 1.33× ok
128 256 535.8 349.6 1.53× 402.6 294.2 1.37× ok
256 256 899.0 653.7 1.38× 755.4 546.7 1.38× ok
1 512 192.3 125.1 1.54× 19.2 8.9 2.17× ok
3 512 195.5 120.5 1.62× 36.2 20.7 1.75× ok
4 512 196.6 122.2 1.61× 42.5 28.7 1.48× ok
6 512 196.3 123.9 1.58× 56.9 39.5 1.44× ok
12 512 207.2 123.5 1.68× 91.4 70.8 1.29× ok
16 512 250.1 155.1 1.61× 118.8 92.2 1.29× ok
32 512 343.5 222.6 1.54× 196.2 159.9 1.23× ok
64 512 531.9 348.4 1.53× 399.9 289.5 1.38× ok
128 512 869.7 588.9 1.48× 738.0 518.8 1.42× ok
256 512 1686.5 1081.5 1.56× 1542.0 1029.2 1.50× ok
1 1024 196.0 122.1 1.60× 28.2 14.5 1.95× ok
3 1024 214.0 120.7 1.77× 47.5 38.2 1.24× ok
4 1024 221.7 122.9 1.80× 72.3 47.5 1.52× ok
6 1024 214.6 127.5 1.68× 91.1 70.0 1.30× ok
12 1024 319.4 258.6 1.24× 190.1 134.9 1.41× ok
16 1024 334.6 210.3 1.59× 197.2 153.2 1.29× ok
32 1024 556.7 382.1 1.46× 430.0 326.1 1.32× ok
64 1024 929.8 658.7 1.41× 792.2 584.2 1.36× ok
128 1024 1682.2 1198.6 1.40× 1553.8 1145.8 1.36× ok
256 1024 3188.4 2081.1 1.53× 3045.6 2026.6 1.50× ok
varlen / packed · dim=2048 — 40 shapes (kernel median 1.33×, e2e median 1.61×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 199.7 114.8 1.74× 19.8 9.7 2.04× ok
3 128 197.8 140.5 1.41× 26.4 14.4 1.83× ok
4 128 198.5 126.3 1.57× 27.5 15.7 1.76× ok
6 128 200.2 121.7 1.65× 32.2 19.9 1.61× ok
12 128 198.4 120.4 1.65× 49.2 34.6 1.42× ok
16 128 199.6 121.3 1.65× 50.6 43.3 1.17× ok
32 128 218.9 130.6 1.68× 88.6 70.7 1.25× ok
64 128 300.2 198.1 1.52× 169.3 134.4 1.26× ok
128 128 466.6 330.8 1.41× 335.8 265.2 1.27× ok
256 128 763.5 580.3 1.32× 635.1 520.3 1.22× ok
1 256 199.3 113.8 1.75× 20.2 10.1 2.00× ok
3 256 205.9 120.3 1.71× 30.6 20.1 1.52× ok
4 256 200.1 119.4 1.68× 43.5 25.6 1.70× ok
6 256 203.2 118.7 1.71× 41.1 29.4 1.40× ok
12 256 219.2 120.7 1.82× 88.3 60.8 1.45× ok
16 256 224.9 135.8 1.66× 100.7 80.5 1.25× ok
32 256 301.1 202.8 1.49× 171.3 143.9 1.19× ok
64 256 444.6 312.7 1.42× 308.2 256.1 1.20× ok
128 256 772.3 528.2 1.46× 636.8 470.9 1.35× ok
256 256 1332.9 955.0 1.40× 1204.9 898.8 1.34× ok
1 512 201.1 110.8 1.81× 32.5 16.6 1.96× ok
3 512 201.7 122.0 1.65× 45.5 27.1 1.68× ok
4 512 199.6 80.2 2.49× 58.4 40.8 1.43× ok
6 512 208.3 121.8 1.71× 75.8 57.9 1.31× ok
12 512 251.9 152.9 1.65× 118.7 106.1 1.12× ok
16 512 314.7 208.7 1.51× 180.1 150.7 1.20× ok
32 512 443.0 354.5 1.25× 308.5 297.8 1.04× ok
64 512 750.9 588.0 1.28× 616.7 523.4 1.18× ok
128 512 1345.5 956.4 1.41× 1211.8 911.3 1.33× ok
256 512 2495.3 1894.4 1.32× 2363.2 1840.6 1.28× ok
1 1024 199.9 118.9 1.68× 38.6 20.3 1.90× ok
3 1024 210.0 120.7 1.74× 71.7 49.6 1.44× ok
4 1024 231.9 129.6 1.79× 101.2 74.4 1.36× ok
6 1024 284.8 168.0 1.70× 133.5 112.0 1.19× ok
12 1024 404.5 282.5 1.43× 257.8 228.1 1.13× ok
16 1024 447.0 330.6 1.35× 314.1 271.6 1.16× ok
32 1024 757.4 621.8 1.22× 628.5 562.4 1.12× ok
64 1024 1392.7 1019.9 1.37× 1263.1 961.2 1.31× ok
128 1024 2528.4 1881.7 1.34× 2396.1 1811.0 1.32× ok
256 1024 5166.8 3769.4 1.37× 5032.0 3710.5 1.36× ok
varlen / packed · dim=4096 — 40 shapes (kernel median 1.20×, e2e median 1.32×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 199.1 118.4 1.68× 23.2 11.1 2.09× ok
3 128 196.6 123.4 1.59× 31.0 20.6 1.50× ok
4 128 201.4 123.6 1.63× 34.7 24.2 1.43× ok
6 128 200.7 121.0 1.66× 44.9 34.9 1.29× ok
12 128 201.0 126.6 1.59× 69.2 62.6 1.10× ok
16 128 215.8 133.2 1.62× 86.2 72.7 1.19× ok
32 128 275.2 182.1 1.51× 146.3 122.4 1.20× ok
64 128 414.7 322.8 1.28× 284.7 258.1 1.10× ok
128 128 683.4 564.6 1.21× 551.0 499.3 1.10× ok
256 128 1199.7 997.7 1.20× 1068.2 941.8 1.13× ok
1 256 200.5 117.7 1.70× 25.5 14.5 1.76× ok
3 256 201.7 115.9 1.74× 48.2 34.0 1.42× ok
4 256 201.2 115.8 1.74× 52.1 34.0 1.53× ok
6 256 202.5 115.5 1.75× 66.0 50.3 1.31× ok
12 256 277.8 165.5 1.68× 146.1 113.2 1.29× ok
16 256 297.5 219.2 1.36× 166.0 156.4 1.06× ok
32 256 414.7 326.1 1.27× 279.5 242.6 1.15× ok
64 256 709.3 557.0 1.27× 571.9 500.9 1.14× ok
128 256 1234.9 969.3 1.27× 1101.9 914.5 1.21× ok
256 256 2362.3 2048.1 1.15× 2232.4 1988.0 1.12× ok
1 512 202.4 121.0 1.67× 29.4 18.0 1.63× ok
3 512 201.1 124.0 1.62× 54.5 40.9 1.33× ok
4 512 231.9 135.0 1.72× 100.2 78.7 1.27× ok
6 512 240.8 187.3 1.29× 109.7 86.1 1.27× ok
12 512 355.0 290.9 1.22× 223.6 219.2 1.02× ok
16 512 419.4 367.3 1.14× 286.6 266.6 1.07× ok
32 512 666.9 504.1 1.32× 535.9 448.7 1.19× ok
64 512 1165.7 958.5 1.22× 1033.2 902.7 1.15× ok
128 512 2338.4 1984.7 1.18× 2208.3 1930.6 1.14× ok
256 512 4360.2 3441.4 1.27× 4225.4 3372.6 1.25× ok
1 1024 198.7 124.0 1.60× 51.7 31.2 1.66× ok
3 1024 252.0 164.2 1.53× 122.5 104.3 1.18× ok
4 1024 305.5 226.5 1.35× 171.3 148.1 1.16× ok
6 1024 309.9 247.8 1.25× 178.0 189.4 0.94× ok
12 1024 581.4 532.0 1.09× 449.9 449.8 1.00× ok
16 1024 685.4 567.8 1.21× 559.2 512.0 1.09× ok
32 1024 1200.5 917.4 1.31× 1067.2 864.1 1.24× ok
64 1024 2239.5 1900.0 1.18× 2108.8 1738.6 1.21× ok
128 1024 4525.9 3739.8 1.21× 4395.4 3679.5 1.20× ok
256 1024 8453.9 6810.9 1.24× 8304.8 6750.4 1.23× ok
varlen / packed · dim=5120 — 40 shapes (kernel median 1.83×, e2e median 1.88×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 197.5 120.6 1.64× 20.9 10.7 1.96× ok
3 128 199.9 123.4 1.62× 36.5 20.8 1.76× ok
4 128 199.6 120.4 1.66× 46.0 27.3 1.68× ok
6 128 202.5 122.8 1.65× 66.3 38.1 1.74× ok
12 128 228.3 126.0 1.81× 93.3 66.7 1.40× ok
16 128 296.2 153.4 1.93× 160.9 94.9 1.69× ok
32 128 408.1 224.8 1.81× 277.4 162.1 1.71× ok
64 128 721.2 375.5 1.92× 587.3 314.2 1.87× ok
128 128 1217.0 646.6 1.88× 1062.3 573.4 1.85× ok
256 128 2298.1 1193.8 1.93× 2167.3 1137.2 1.91× ok
1 256 199.7 120.3 1.66× 28.2 14.1 2.00× ok
3 256 197.7 119.9 1.65× 56.8 30.0 1.89× ok
4 256 211.1 120.7 1.75× 79.7 48.8 1.63× ok
6 256 262.2 136.8 1.92× 132.0 74.2 1.78× ok
12 256 368.3 203.2 1.81× 238.0 141.6 1.68× ok
16 256 412.1 209.3 1.97× 281.0 145.6 1.93× ok
32 256 728.5 389.3 1.87× 598.7 325.9 1.84× ok
64 256 1202.8 620.2 1.94× 1070.6 558.8 1.92× ok
128 256 2338.1 1177.8 1.99× 2199.3 1112.6 1.98× ok
256 256 4621.8 2322.7 1.99× 4485.9 2263.2 1.98× ok
1 512 245.1 123.0 1.99× 44.9 21.5 2.09× ok
3 512 242.8 123.4 1.97× 115.5 66.7 1.73× ok
4 512 276.2 150.8 1.83× 144.2 95.9 1.50× ok
6 512 312.3 187.6 1.67× 180.7 127.9 1.41× ok
12 512 645.1 332.0 1.94× 437.1 269.9 1.62× ok
16 512 752.9 447.6 1.68× 621.9 359.2 1.73× ok
32 512 1221.8 684.1 1.79× 1090.0 623.7 1.75× ok
64 512 2350.0 1160.3 2.02× 2193.8 1109.7 1.98× ok
128 512 4306.6 2132.1 2.02× 4146.4 2073.0 2.00× ok
256 512 8440.1 4188.1 2.02× 8303.0 4135.1 2.01× ok
1 1024 201.1 119.3 1.69× 64.5 30.7 2.10× ok
3 1024 439.9 193.1 2.28× 305.5 138.8 2.20× ok
4 1024 466.9 239.4 1.95× 330.5 181.9 1.82× ok
6 1024 500.2 337.7 1.48× 370.1 274.3 1.35× ok
12 1024 921.7 657.0 1.40× 790.9 508.7 1.55× ok
16 1024 1145.9 678.0 1.69× 1012.7 611.2 1.66× ok
32 1024 2217.2 1256.0 1.76× 2088.7 1196.1 1.75× ok
64 1024 4538.3 2388.9 1.90× 4410.9 2326.4 1.90× ok
128 1024 8495.7 4386.5 1.94× 8368.7 4328.1 1.93× ok
256 1024 16834.9 8304.9 2.03× 16698.6 8235.8 2.03× ok
varlen / packed · dim=6144 — 40 shapes (kernel median 1.58×, e2e median 1.67×)
B seq main_e2e (µs) branch_e2e (µs) e2e× main_ker (µs) branch_ker (µs) ker× ok
1 128 200.3 116.8 1.72× 19.2 11.9 1.61× ok
3 128 206.4 122.3 1.69× 33.8 20.1 1.68× ok
4 128 200.9 146.6 1.37× 50.5 32.5 1.56× ok
6 128 201.1 143.4 1.40× 60.9 44.1 1.38× ok
12 128 253.0 156.3 1.62× 117.6 84.1 1.40× ok
16 128 274.0 161.3 1.70× 137.6 80.5 1.71× ok
32 128 388.2 252.2 1.54× 268.1 189.4 1.42× ok
64 128 694.3 418.8 1.66× 558.8 348.1 1.61× ok
128 128 1245.4 717.4 1.74× 1110.2 655.8 1.69× ok
256 128 2307.0 1477.2 1.56× 2174.3 1415.3 1.54× ok
1 256 200.9 116.3 1.73× 24.2 14.2 1.71× ok
3 256 198.7 118.8 1.67× 61.2 40.4 1.52× ok
4 256 203.2 117.2 1.73× 71.4 56.5 1.26× ok
6 256 228.8 123.2 1.86× 98.2 65.8 1.49× ok
12 256 352.6 214.0 1.65× 222.6 152.1 1.46× ok
16 256 381.2 257.8 1.48× 252.8 196.2 1.29× ok
32 256 698.8 443.1 1.58× 567.1 351.8 1.61× ok
64 256 1229.1 815.1 1.51× 1095.7 748.6 1.46× ok
128 256 2280.9 1300.2 1.75× 2147.0 1235.4 1.74× ok
256 256 4316.5 2721.6 1.59× 4179.1 2657.5 1.57× ok
1 512 202.1 119.3 1.69× 47.2 25.7 1.84× ok
3 512 218.6 122.1 1.79× 89.0 51.8 1.72× ok
4 512 303.9 166.2 1.83× 173.7 106.9 1.62× ok
6 512 531.5 213.6 2.49× 245.4 153.4 1.60× ok
12 512 458.0 371.1 1.23× 442.2 305.4 1.45× ok
16 512 567.3 428.6 1.32× 529.5 372.1 1.42× ok
32 512 1221.2 731.8 1.67× 1070.3 677.9 1.58× ok
64 512 2187.8 1346.7 1.62× 2021.2 1287.3 1.57× ok
128 512 4265.1 2554.5 1.67× 4101.8 2484.7 1.65× ok
256 512 8780.2 5033.9 1.74× 8638.5 4976.0 1.74× ok
1 1024 238.1 123.9 1.92× 107.0 56.6 1.89× ok
3 1024 373.1 223.1 1.67× 240.8 162.7 1.48× ok
4 1024 426.3 290.2 1.47× 296.8 190.5 1.56× ok
6 1024 517.8 332.2 1.56× 387.2 275.0 1.41× ok
12 1024 923.0 672.2 1.37× 792.4 610.2 1.30× ok
16 1024 1093.7 680.3 1.61× 957.4 619.1 1.55× ok
32 1024 2138.7 1278.0 1.67× 2008.4 1227.6 1.64× ok
64 1024 4475.9 2595.1 1.73× 4344.2 2535.0 1.71× ok
128 1024 8498.8 4808.8 1.77× 8359.9 4756.6 1.76× ok
256 1024 17238.0 9468.4 1.82× 17084.0 9410.2 1.81× ok

Reproduce these numbers

The benchmark scripts live in the convolution_benchmarking branch of the fork:

https://github.com/ChristosMatzoros/sgl-kernel-npu/tree/convolution_benchmarking/benchmark/causal_conv1d

Take the two files from that directory — you don't need anything else from that branch:

  • bench_causal_conv1d_compare.py — the benchmark/compare tool
  • compare.md — step-by-step guide (environment setup, build, run, compare)

Then, following compare.md: build main and run it, build this branch and run it, then compare the two result files. Each run auto-detects the op signature (AscendC or PTO), times every shape both ways (e2e + kernel), checks correctness against an fp32 reference, and idle-gates the NPU. Example:

# (in each repo/branch, after building)  see compare.md step 1 for env setup
SGL_KERNEL_SO=<main-build>/.../libsgl_kernel_npu.so   python3 bench_causal_conv1d_compare.py run --label main   --out main.json
SGL_KERNEL_SO=<branch-build>/.../libsgl_kernel_npu.so python3 bench_causal_conv1d_compare.py run --label tiling --out tiling.json
python3 bench_causal_conv1d_compare.py compare main.json tiling.json --csv cmp.csv

ChristosMatzoros and others added 18 commits July 20, 2026 11:31
Replace the depthwise causal conv1d + bias + (optional) SiLU op with a
PTO-ISA tile kernel, built as its own ascendc_library (like mega_chunk_gdn).
The op name and signature are unchanged, so this is a drop-in replacement:
pytorch_extensions.cpp and the Python wrapper are untouched.

Improvements over the previous AscendC kernel:
- faster on the GDN prefill matrix (1.5-5.8x e2e on Ascend 910B2);
- numerically correct at large batch, where the previous kernel raced;
- generic over dim (the previous kernel only supported a fixed dim set).

conv_states / varlen (query_start_loc) / has_initial_state / pad_slot_id
semantics are preserved and verified against the prefill contract test
(tests/python/sgl_kernel_npu/test_conv1d_prefill.py), which also covers the
exact conv_states writeback.

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
…guard

- Template the PTO kernel on the filter width K (and per-K tile width MAX_W) and
  compile a dedicated entry per supported width {2,3,4,5,8,16,32,64} x {fp16,bf16};
  the host dispatches by weight.size(0). (Previously width-4 only.)
- Fix a state-writeback race: when the writeback grid has more tasks than cores a
  core reuses its UB tiles across tasks, so the next task's load must wait for the
  previous task's store (MTE3 -> MTE2). conv_states was silently wrong at large
  batch (the common stateful-decode path) before this.
- Guard the GM_ADDR define with clang-format off: PointerAlignment: Right rewrote
  'type* name' to 'type *name', which broke the AscendC launch codegen.
- Tidy the host launcher (compact per-width dispatch, constexpr helpers, comments).

Verified vs an fp32 reference: the prefill contract test (all widths, fp16/bf16,
dense/varlen, initial-state, bias, activation, pad-slot) and a 1024-case
width x dim sweep, all exact (conv_states bit-exact).

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
Replace the per-width (K) template with a per-ring-size template (RS = roundUpToPow2(K)) and pass the filter width K as a runtime argument. Six compiled variants {2,4,8,16,32,64} x {fp16,bf16} now serve any width in [2,64] (e.g. 3->rs4, 5/6/7->rs8), replacing the eight per-width entries. The UB layout is sized for the worst case K==RS so every offset stays compile-time (no codegen regression).

Collapse the (RS, MAX_W) set into one X-macro list (CC1D_RS) inlined in the kernel and host; the host forward-declares the launch stubs from it instead of including 24 generated aclrtlaunch headers, and the entry-definition macros are compacted.

Tests: extend the contract test and fp32-reference sweep to non-power-of-two widths (runtime K < RS). Validated on Ascend 910B2: contract test all-pass (conv_states bit-exact), fp32 sweep 0/1664 failures; e2e and kernel-only performance unchanged vs the per-width build.

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
Move the fp16/bf16 -> fp32 widening of weight/bias from the host
(.to(at::kFloat)) into the kernel: stage the native tiles into the idle
accumulator-region scratch (loads pipeline), one MTE2->V barrier, then
pipelined TCVT into the resident fp32 tiles. Matches the main/PR-555 pattern
(cast on device) and drops two per-call host cast launches.

Numerically identical (bit-exact vs fp32 ref; 1664-case sweep + contract test
pass for fp16/bf16). Faster: up to ~2.1x e2e at small batch and 1.02-1.19x
kernel-only, tied at large batch. Also adds bias dtype/shape validation.

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
Unify the per-sequence row-index/length space as int32 (start, len, l0, l1,
cacheIdx) and add a signed halo = K-1, so the signed<->unsigned cast churn in
the index/halo/offset arithmetic disappears. Also drop the redundant bitmask
casts (the & already converts a non-negative operand), consolidate the lanes
ternary, and remove the dead `len` parameter from convChunk. Explicit casts
40 -> 16; the rest are load-bearing (uint64_t offset-overflow guards, the halo
derivation, (int32_t)k, lanes).

Bit-exact vs the fp32 reference (contract + 1664-case sweep pass, fp16/bf16)
and perf-neutral (kernel-only TaskDur tied with the prior commit on all shapes).

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
Format the PTO kernel/host to the repo clang-format style (csrc/.clang-format)
so `pre-commit run --all-files` (CI lint) passes. No functional change: the
GM_ADDR / launch-stub regions stay under `// clang-format off` because their
pointer glueing is required by the AscendC launch codegen. Rebuild confirms all
24 kernel entries still compile; whitespace-only, so numerics are unchanged.

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
Signed-off-by: Raphael Steiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
Signed-off-by: raphaelsteiner <raphael.steiner@huawei.com>
…ode/num_accepted)

sgl-project#592 replaced this op with the AscendC kernel and changed the registered
schema (added num_accepted_tokens + run_mode, made activation_mode an int).
The PTO kernel this PR restores uses the original signature — bias as an
optional after the required index tensors, bool activation_mode, no run_mode —
so update pytorch_extensions.cpp to match. Callers on sgl-project#592's signature (with
run_mode) must adapt; the Python wrapper and other ops are untouched.

Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the causal_conv1d NPU kernel and host-side implementation by replacing the legacy AscendC code with a new implementation based on the PTO tile ISA, simplifying the dispatch logic and removing several obsolete files. The code review highlights several critical correctness and robustness issues: in the kernel, negative index loading when hasInit is false can read stale history or uninitialized memory, requiring dummy loads and zeroing; on the host side, the defined MIN_CHUNK_ROWS constant is unused, leading to excessive sequence chunking overhead; there is a lack of validation for input tensor sizes (query_start_loc, cache_indices, and has_initial_state) which could cause underflows or out-of-bounds reads; and finally, the PyTorch extension wrapper needs explicit type casting for default integer and boolean tensors to prevent strict type assertion failures.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread csrc/causal_conv1d/op_kernel/causal_conv1d.cpp
Comment thread csrc/causal_conv1d/op_kernel/causal_conv1d.cpp
Comment thread csrc/causal_conv1d/op_kernel/causal_conv1d.cpp
Comment thread csrc/causal_conv1d/op_host/causal_conv1d.cpp
Comment thread csrc/causal_conv1d/op_host/causal_conv1d.cpp
Comment thread csrc/causal_conv1d/op_host/causal_conv1d.cpp
Comment thread csrc/pytorch_extensions.cpp
Signed-off-by: Christos Konstantinos Matzoros <christos.konstantinos.matzoros@h-partners.com>
@ChristosMatzoros

ChristosMatzoros commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

All points addressed:

  • Kernel !hasInit stale-history read (1–3): rather than zeroing loaded history, we clamp the per-sequence chunk length to ≥ K−1, so no non-first chunk can start inside the causal halo. The conv_states load is then only reachable for the first chunk with has_initial_state (correct), for both 3D and varlen, matching how the AscendC kernel this replaces already handles it. It's also perf-neutral (see below).
  • Unused MIN_CHUNK_ROWS (4): removed the dead constant. Deliberately not wired as a chunk-size floor , that caps parallelism at low batch (e.g. 43→4 cores at B=1, seq=128), regressing this kernel's main advantage. The clamp above already prevents the degenerate tiny chunks that motivated the concern.
  • Input validation (5–6): added TORCH_CHECKs — query_start_loc must be 1D with ≥2 elements (varlen), and cache_indices/has_initial_state must be 1D with size ≥ batch — plus tests.
  • Wrapper dtype casts (7): the wrapper now casts query_start_loc/cache_indices → int32 and has_initial_state → bool, and makes bias contiguous (all no-ops when already correct), plus a test.

Correctness & perf: unit tests + 656/656 fp32-reference configs pass; a 400-shape kernel-time A/B (this branch vs the pre-fix commit) gives geomean 1.00× (0/400 shapes outside ±2%). No performance change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance regression in causal_conv1d

2 participants