Book contents +

XI · Hexagon NPU (welvet.qnn) / CHAPTER 76

QNN: go_v_qnn RESULTS (large shapes)

Samuel Watson · Welvet feature bookOriginal source ↗

github.com/openfluke/w2a/suites/go_v_qnn✅ matrix published


Why it exists

Toy shapes lie. The w2a large matrix (dense 32×512×512, softmax 64×4096, …) is the honest Snapdragon X story: NPU DLL graphExecute vs Go/native f32 CPU, plus Go→NPU call overhead (cgo + pack + online compose).

What it is

Published tables in w2a/suites/go_v_qnn/RESULTS.md. Dense prepare-once wins ~93-98% vs Go/native. Softmax/norms/CNN/SwiGLU/MHA win on DLL exec; online layers pay compose cost on the call timer. LSTM large FAIL. Host compares f32 only: dtype matrix is NPU-side.

How to read the timers

  • NPU DLL exec: mono inside welvet.qnn around graphExecute only.
  • Go→NPU call: full C ABI from Go (cgo + pack/unpack + online create/finalize).
  • Dense = prepare-once + warmed execute; other layers = online compose today.
  • % = (slower−faster)/slower×100 vs that host column.

Headline NPU wins (DLL exec vs Go f32)

LayerdtypeGoNPUvs Go
denseu83.05ms164µsNPU 95%
densef323.05ms201µsNPU 93%
softmaxf164.31ms446µsNPU 90%
rmsnormu89.40ms897µsNPU 90%
layernormf166.82ms553µsNPU 92%
cnn2i812.56ms763µsNPU 94%
swigluu161.92ms352µsNPU 82%
mhaf164.51ms372µsNPU 92%

Full status / call overhead / NPU-wins-only tables: RESULTS.md. Re-run: cd w2a && go test ./tests/go_v_qnn -v -count=1 -run TestGoVQNNMatrix -timeout 180m.

Failures today: lstm float32/float16: code=2 execute on large shapes.

Go example

examples/81-qnn-results/main.go

Run:cd welvet/examples/81-qnn-results && source ../env.sh && go run .
package main

import "fmt"

// Snapshot of w2a/suites/go_v_qnn/RESULTS.md (2026-10-23, Snapdragon X).
// This example is host-only: no DLL required.
func main() {
	fmt.Println("welvet.qnn 1.0.0 · go_v_qnn large matrix")
	fmt.Println("host: Windows ARM64 · shapes: dense 32x512x512 …")
	fmt.Println()
	fmt.Println("NPU DLL wins (subset vs Go f32):")
	rows := []struct{ layer, dt, goT, npu, pct string }{
		{"dense", "u8", "3.05ms", "164µs", "95%"},
		{"dense", "f32", "3.05ms", "201µs", "93%"},
		{"softmax", "f16", "4.31ms", "446µs", "90%"},
		{"rmsnorm", "u8", "9.40ms", "897µs", "90%"},
		{"layernorm", "f16", "6.82ms", "553µs", "92%"},
		{"cnn2", "i8", "12.56ms", "763µs", "94%"},
		{"swiglu", "u16", "1.92ms", "352µs", "82%"},
		{"mha", "f16", "4.51ms", "372µs", "92%"},
	}
	for _, r := range rows {
		fmt.Printf("  %-10s %-4s  Go %s  NPU %s  → %s\n", r.layer, r.dt, r.goT, r.npu, r.pct)
	}
	fmt.Println()
	fmt.Println("note: call timer ≫ DLL exec on online layers (compose each call)")
	fmt.Println("fail: lstm f32/f16 execute code=2")
	fmt.Println("full: w2a/suites/go_v_qnn/RESULTS.md")
}

Output

exit 0 · last run via go run .

welvet.qnn 1.0.0 · go_v_qnn large matrix
host: Windows ARM64 · shapes: dense 32x512x512 …

NPU DLL wins (subset vs Go f32):
  dense      u8    Go 3.05ms  NPU 164µs  → 95%
  dense      f32   Go 3.05ms  NPU 201µs  → 93%
  softmax    f16   Go 4.31ms  NPU 446µs  → 90%
  rmsnorm    u8    Go 9.40ms  NPU 897µs  → 90%
  layernorm  f16   Go 6.82ms  NPU 553µs  → 92%
  cnn2       i8    Go 12.56ms  NPU 763µs  → 94%
  swiglu     u16   Go 1.92ms  NPU 352µs  → 82%
  mha        f16   Go 4.51ms  NPU 372µs  → 92%

note: call timer ≫ DLL exec on online layers (compose each call)
fail: lstm f32/f16 execute code=2
full: w2a/suites/go_v_qnn/RESULTS.md

Validate (harness)

cd welvet/examples/81-qnn-results && source ../env.sh && go run .